Spaces:
Configuration error
Configuration error
# ───────────────────────────────────────────────────────────────────────────── | |
# src/streamlit_app.py | |
# ───────────────────────────────────────────────────────────────────────────── | |
import os, joblib | |
MODEL_PATH = os.path.join(os.getcwd(), "src", "voice_model.joblib") | |
if not os.path.exists(MODEL_PATH): | |
# 第一次启动时训练并保存 | |
clf = train_voice_model() | |
os.makedirs(os.path.dirname(MODEL_PATH), exist_ok=True) | |
joblib.dump(clf, MODEL_PATH) | |
# 然后再加载 | |
voice_clf = joblib.load(MODEL_PATH) | |
os.environ["STREAMLIT_HOME"] = "/tmp/.streamlit" | |
# 關閉 CORS、關掉使用者統計(可選) | |
os.environ["STREAMLIT_SERVER_ENABLE_CORS"] = "false" | |
os.environ["STREAMLIT_GATHER_USAGE_STATS"] = "false" | |
# 建目錄 | |
os.makedirs("/tmp/.streamlit", exist_ok=True) | |
# ─────────────── 2. 把 DeepFace 的 HOME 指到 /tmp/.deepface ─────────────── | |
os.environ["DEEPFACE_HOME"] = "/tmp/.deepface" | |
# 建好 weights 子目錄,DeepFace 下載權重就不會再 mkdir / | |
os.makedirs("/tmp/.deepface/weights", exist_ok=True) | |
import streamlit as st | |
import cv2, numpy as np, base64, io | |
import librosa, joblib | |
from deepface import DeepFace | |
# ── 1️⃣ 載入所有模型(DeepFace + 你的語音模型)── | |
def load_models(): | |
# a) DeepFace 預熱 | |
DeepFace.analyze( | |
img_path = np.zeros((224,224,3), dtype=np.uint8), | |
actions = ['emotion'], | |
enforce_detection=False | |
) | |
# b) 載入你 commit 到 repo 的語音模型檔案 | |
# 取得目前檔案 (streamlit_app.py) 的資料夾路徑 | |
root = os.path.dirname(__file__) | |
# 然後從 src/ 底下讀模型檔 | |
model_path = os.path.join(root, "voice_model.joblib") | |
audio_model = joblib.load(model_path) | |
return audio_model | |
audio_model = load_models() | |
# ── 2️⃣ 文本情緒分析函式 ───────────────────────────────────────────────────── | |
def analyze_text_fn(text: str) -> str: | |
if any(w in text for w in ["開心","快樂","愉快","喜悦","喜悅","歡喜","興奮","高興"]): | |
return "happy" | |
if any(w in text for w in ["生氣","憤怒","不爽","發火","火大","氣憤"]): | |
return "angry" | |
if any(w in text for w in ["傷心","難過","哭","難受","心酸","憂","悲","哀","痛苦","慘","愁"]): | |
return "sad" | |
if any(w in text for w in ["驚訝","意外","嚇","驚詫","詫異","訝異","好奇"]): | |
return "surprise" | |
if any(w in text for w in ["怕","恐懼","緊張","懼","膽怯","畏"]): | |
return "fear" | |
return "neutral" | |
# ── 3️⃣ 語音情緒分析函式 ───────────────────────────────────────────────────── | |
def analyze_audio_fn(wav_bytes: bytes) -> str: | |
# 讀 wav bytes | |
y, sr = librosa.load(io.BytesIO(wav_bytes), sr=None) | |
mfccs = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13) | |
mf = np.mean(mfccs.T, axis=0) | |
return audio_model.predict([mf])[0] | |
# ── 4️⃣ Streamlit 介面 ─────────────────────────────────────────────────────── | |
st.set_page_config(page_title="多模態即時情緒分析", layout="wide") | |
st.title("📱 多模態即時情緒分析") | |
tabs = st.tabs(["🔴 Face(本地測試)", "🎤 上傳語音檔", "⌨️ 輸入文字"]) | |
with tabs[0]: | |
st.header("Live Face(僅限本地瀏覽器測試)") | |
st.info("⚠️ Hugging Face Spaces 無法直接開啟攝影機,請在本機使用 `streamlit run app.py` 測試。") | |
# 這邊如果用 streamlit-webrtc 才能在本地呼叫攝影機 | |
# 省略示範,或改成 gradio demo | |
with tabs[1]: | |
st.header("🎤 上傳 WAV 檔進行分析") | |
# 支援 .wav 上傳 | |
wav_file = st.file_uploader("請選擇 .wav 音檔", type=["wav"]) | |
if wav_file is not None: | |
# 讀 bytes,呼叫分析函式 | |
wav_bytes = wav_file.read() | |
emo = analyze_audio_fn(wav_bytes) | |
st.success(f"🎤 語音偵測到的情緒:**{emo}**") | |
with tabs[2]: | |
st.header("輸入文字進行情緒分析") | |
txt = st.text_area("請在此輸入文字") | |
if st.button("開始分析"): | |
emo = analyze_text_fn(txt) | |
st.success(f"📝 文本偵測到的情緒:**{emo}**") | |