Spaces:
Configuration error
Configuration error
Create src\streamlit_app.py
Browse files- src//streamlit_app.py +98 -0
src//streamlit_app.py
ADDED
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# ─────────────────────────────────────────────────────────────────────────────
|
2 |
+
# src/streamlit_app.py
|
3 |
+
# ─────────────────────────────────────────────────────────────────────────────
|
4 |
+
import os
|
5 |
+
os.environ["STREAMLIT_HOME"] = "/tmp/.streamlit"
|
6 |
+
# 關閉 CORS、關掉使用者統計(可選)
|
7 |
+
os.environ["STREAMLIT_SERVER_ENABLE_CORS"] = "false"
|
8 |
+
os.environ["STREAMLIT_GATHER_USAGE_STATS"] = "false"
|
9 |
+
# 建目錄
|
10 |
+
os.makedirs("/tmp/.streamlit", exist_ok=True)
|
11 |
+
|
12 |
+
# ─────────────── 2. 把 DeepFace 的 HOME 指到 /tmp/.deepface ───────────────
|
13 |
+
os.environ["DEEPFACE_HOME"] = "/tmp/.deepface"
|
14 |
+
# 建好 weights 子目錄,DeepFace 下載權重就不會再 mkdir /
|
15 |
+
os.makedirs("/tmp/.deepface/weights", exist_ok=True)
|
16 |
+
|
17 |
+
|
18 |
+
|
19 |
+
import streamlit as st
|
20 |
+
import cv2, numpy as np, base64, io
|
21 |
+
import librosa, joblib
|
22 |
+
from deepface import DeepFace
|
23 |
+
|
24 |
+
|
25 |
+
# ── 1️⃣ 載入所有模型(DeepFace + 你的語音模型)──
|
26 |
+
@st.cache_resource(show_spinner=False)
|
27 |
+
def load_models():
|
28 |
+
# a) DeepFace 預熱
|
29 |
+
DeepFace.analyze(
|
30 |
+
img_path = np.zeros((224,224,3), dtype=np.uint8),
|
31 |
+
actions = ['emotion'],
|
32 |
+
enforce_detection=False
|
33 |
+
)
|
34 |
+
# b) 載入你 commit 到 repo 的語音模型檔案
|
35 |
+
# 取得目前檔案 (streamlit_app.py) 的資料夾路徑
|
36 |
+
root = os.path.dirname(__file__)
|
37 |
+
# 然後從 src/ 底下讀模型檔
|
38 |
+
model_path = os.path.join(root, "voice_model.joblib")
|
39 |
+
audio_model = joblib.load(model_path)
|
40 |
+
|
41 |
+
return audio_model
|
42 |
+
|
43 |
+
audio_model = load_models()
|
44 |
+
|
45 |
+
|
46 |
+
# ── 2️⃣ 文本情緒分析函式 ─────────────────────────────────────────────────────
|
47 |
+
def analyze_text_fn(text: str) -> str:
|
48 |
+
if any(w in text for w in ["開心","快樂","愉快","喜悦","喜悅","歡喜","興奮","高興"]):
|
49 |
+
return "happy"
|
50 |
+
if any(w in text for w in ["生氣","憤怒","不爽","發火","火大","氣憤"]):
|
51 |
+
return "angry"
|
52 |
+
if any(w in text for w in ["傷心","難過","哭","難受","心酸","憂","悲","哀","痛苦","慘","愁"]):
|
53 |
+
return "sad"
|
54 |
+
if any(w in text for w in ["驚訝","意外","嚇","驚詫","詫異","訝異","好奇"]):
|
55 |
+
return "surprise"
|
56 |
+
if any(w in text for w in ["怕","恐懼","緊張","懼","膽怯","畏"]):
|
57 |
+
return "fear"
|
58 |
+
return "neutral"
|
59 |
+
|
60 |
+
|
61 |
+
# ── 3️⃣ 語音情緒分析函式 ─────────────────────────────────────────────────────
|
62 |
+
def analyze_audio_fn(wav_bytes: bytes) -> str:
|
63 |
+
# 讀 wav bytes
|
64 |
+
y, sr = librosa.load(io.BytesIO(wav_bytes), sr=None)
|
65 |
+
mfccs = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13)
|
66 |
+
mf = np.mean(mfccs.T, axis=0)
|
67 |
+
return audio_model.predict([mf])[0]
|
68 |
+
|
69 |
+
|
70 |
+
# ── 4️⃣ Streamlit 介面 ───────────────────────────────────────────────────────
|
71 |
+
st.set_page_config(page_title="多模態即時情緒分析", layout="wide")
|
72 |
+
st.title("📱 多模態即時情緒分析")
|
73 |
+
|
74 |
+
tabs = st.tabs(["🔴 Face(本地測試)", "🎤 上傳語音檔", "⌨️ 輸入文字"])
|
75 |
+
with tabs[0]:
|
76 |
+
st.header("Live Face(僅限本地瀏覽器測試)")
|
77 |
+
st.info("⚠️ Hugging Face Spaces 無法直接開啟攝影機,請在本機使用 `streamlit run app.py` 測試。")
|
78 |
+
|
79 |
+
# 這邊如果用 streamlit-webrtc 才能在本地呼叫攝影機
|
80 |
+
# 省略示範,或改成 gradio demo
|
81 |
+
|
82 |
+
with tabs[1]:
|
83 |
+
st.header("🎤 上傳 WAV 檔進行分析")
|
84 |
+
# 支援 .wav 上傳
|
85 |
+
wav_file = st.file_uploader("請選擇 .wav 音檔", type=["wav"])
|
86 |
+
if wav_file is not None:
|
87 |
+
# 讀 bytes,呼叫分析函式
|
88 |
+
wav_bytes = wav_file.read()
|
89 |
+
emo = analyze_audio_fn(wav_bytes)
|
90 |
+
st.success(f"🎤 語音偵測到的情緒:**{emo}**")
|
91 |
+
|
92 |
+
|
93 |
+
with tabs[2]:
|
94 |
+
st.header("輸入文字進行情緒分析")
|
95 |
+
txt = st.text_area("請在此輸入文字")
|
96 |
+
if st.button("開始分析"):
|
97 |
+
emo = analyze_text_fn(txt)
|
98 |
+
st.success(f"📝 文本偵測到的情緒:**{emo}**")
|