File size: 5,272 Bytes
283d228 439571f 7b9bebe 439571f c7ec63e 439571f 287ab51 439571f 9c17f8d 283d228 439571f 283d228 439571f 2a89f5d 439571f 283d228 439571f 283d228 439571f 283d228 439571f 283d228 439571f 283d228 439571f 36c201f 7b9bebe 439571f dfd5bb6 7b9bebe 439571f 7b9bebe c7ec63e 439571f 7b9bebe 439571f c0131be 7b9bebe 439571f 7b9bebe 439571f 287ab51 439571f 287ab51 439571f c0131be 439571f c0131be 439571f c0131be 439571f 287ab51 439571f 82dd2b7 439571f 287ab51 439571f b9af6a3 439571f b9af6a3 439571f c0131be 287ab51 7b9bebe c7ec63e b9af6a3 439571f |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
import os
import gradio as gr
import requests
import joblib
import numpy as np
import librosa
from huggingface_hub import hf_hub_download
from deepface import DeepFace
# --- 配置:Hugging Face Inference API 文本分析 ---
HF_API_TOKEN = os.getenv("Hhf_ZfPJkShFNeheFJQZwkZFEOCkYKCBwNhLAw")
if HF_API_TOKEN is None:
print("警告:未检测到 HF_API_TOKEN,文字分析可能失败或限流。")
# 选用公开存在的中文情感分类模型 ID
HF_TEXT_MODEL = "uer/roberta-base-finetuned-dianping-chinese"
HF_API_URL = f"https://api-inference.huggingface.co/models/{HF_TEXT_MODEL}"
HEADERS = {"Authorization": f"Bearer {HF_API_TOKEN}"} if HF_API_TOKEN else {}
def call_text_api(text: str):
if not text or text.strip() == "":
return {}
payload = {"inputs": text}
try:
res = requests.post(HF_API_URL, headers=HEADERS, json=payload, timeout=15)
res.raise_for_status()
data = res.json()
result = {}
if isinstance(data, list):
for item in data:
label = item.get("label", "")
score = item.get("score", 0.0)
result[label] = float(score)
else:
# 如果返回不同结构,可根据实际调整
print("call_text_api 返回格式未预期:", data)
return {}
return result
except Exception as e:
print("call_text_api error:", e)
return {"中性": 1.0}
# --- 语音情绪分析 SVM 模型加载 ---
USE_VOICE = True
svm_model = None
if USE_VOICE:
try:
print("下载并加载语音 SVM 模型...")
model_path = hf_hub_download(repo_id="GCLing/emotion-svm-model", filename="svm_emotion_model.joblib")
svm_model = joblib.load(model_path)
print("SVM 模型加载完成")
except Exception as e:
print("语音 SVM 模型加载失败,禁用语音模块:", e)
USE_VOICE = False
def extract_feature(signal: np.ndarray, sr: int) -> np.ndarray:
mfcc = librosa.feature.mfcc(y=signal, sr=sr, n_mfcc=13)
feat = np.concatenate([np.mean(mfcc, axis=1), np.var(mfcc, axis=1)])
return feat
def predict_voice(audio_path: str):
if not USE_VOICE or svm_model is None:
return {"error": 1.0}
if not audio_path:
return {}
try:
signal, sr = librosa.load(audio_path, sr=None)
feat = extract_feature(signal, sr)
probs = svm_model.predict_proba([feat])[0]
labels = svm_model.classes_
return {labels[i]: float(probs[i]) for i in range(len(labels))}
except Exception as e:
print("predict_voice error:", e)
return {}
# --- 臉部情緒分析,使用 DeepFace 分析上傳或拍照圖片 ---
def predict_face(img: np.ndarray):
# img 為 numpy array,或 None
if img is None:
return {}
try:
res = DeepFace.analyze(img, actions=["emotion"], detector_backend="opencv")
if isinstance(res, list):
first = res[0] if res else {}
emo = first.get("emotion", {}) if isinstance(first, dict) else {}
else:
emo = res.get("emotion", {}) if isinstance(res, dict) else {}
emo_fixed = {k: float(v) for k, v in emo.items()}
return emo_fixed
except Exception as e:
print("DeepFace.analyze error:", e)
return {}
# --- Gradio 界面 ---
def build_interface():
with gr.Blocks() as demo:
gr.Markdown("## 多模態情緒分析(簡化版:上傳/拍照人臉 + 語音 + 文字)")
with gr.Tabs():
# 臉部 Tab:上傳或拍照
with gr.TabItem("臉部情緒"):
gr.Markdown("### 臉部情緒 分析 (上傳或拍照圖片)")
with gr.Row():
# sources=["upload"] 在手機上點上傳可調出相機拍照
face_input = gr.Image(sources=["upload"], type="numpy", label="上傳或拍照圖片")
face_out = gr.Label(label="情緒分布")
face_input.change(fn=predict_face, inputs=face_input, outputs=face_out)
# 語音 Tab
with gr.TabItem("語音情緒"):
gr.Markdown("### 語音情緒 分析 (錄音並上傳)")
if USE_VOICE:
with gr.Row():
audio_input = gr.Audio(source="microphone", streaming=False, type="filepath", label="錄音")
voice_out = gr.Label(label="語音情緒結果")
audio_input.change(fn=predict_voice, inputs=audio_input, outputs=voice_out)
else:
gr.Markdown("語音模塊不可用。")
# 文字 Tab
with gr.TabItem("文字情緒"):
gr.Markdown("### 文字情緒 分析 (Hugging Face Inference API)")
with gr.Row():
text_input = gr.Textbox(lines=3, placeholder="請輸入中文文字…")
text_out = gr.Label(label="文字情緒結果")
text_input.submit(fn=call_text_api, inputs=text_input, outputs=text_out)
return demo
if __name__ == "__main__":
demo = build_interface()
# share=True 可生成临时公开链接;部署到 Spaces 时无需此参数
demo.launch()
|