PhilipL commited on
Commit
bf9af45
·
verified ·
1 Parent(s): cfb6ec3

Update emotion.py

Browse files
Files changed (1) hide show
  1. emotion.py +43 -34
emotion.py CHANGED
@@ -49,11 +49,8 @@ EMO_TO_SCORE = {
49
  "unknown": 3,
50
  }
51
 
52
- # ### [整合需求 新增] ###
53
- # 為了讓主程式 (app.py) 可以呼叫這個轉換邏輯,將其包裝成函式
54
  def get_emotion_score(emo: str) -> int:
55
  return EMO_TO_SCORE.get(emo, 3)
56
- # ######################
57
 
58
  SCORE_LABELS = {
59
  1: "1(心情差)",
@@ -70,7 +67,7 @@ SCORE_CHOICES = [SCORE_LABELS[i] for i in [1, 2, 3, 4, 5]]
70
  # =========================
71
  @dataclass
72
  class AppState:
73
- mode: str = "攝影機辨識" # 保留欄位但固定為攝影機
74
 
75
  running: bool = True
76
  finished: bool = False
@@ -92,18 +89,16 @@ class AppState:
92
  final_emo: Optional[str] = None
93
  final_conf: Optional[float] = None
94
 
95
- # ### [整合需求 新增] ###
96
- # 用來儲存最後計算出的整數分數 (1~5),讓外部程式容易讀取
97
  final_score: int = 3
98
- # ######################
99
 
100
 
101
  # =========================
102
- # UI HTML
103
  # =========================
104
  def _hint_html(msg: str) -> str:
 
105
  return f"""
106
- <div style="border-radius:14px;padding:14px;border:1px dashed #DADADA;background:#FAFAFA;color:#111;">
107
  {msg}
108
  </div>
109
  """
@@ -130,16 +125,16 @@ def _result_card_html(emo_key: str, conf: Optional[float]) -> str:
130
  conf_txt = "" if conf is None else f"{conf:.1f}%"
131
  score_desc = SCORE_LABELS[score].split("(")[1].rstrip(")")
132
 
133
- # ✅ 結果字體用黑色,避免你說的灰字看不清楚
134
  return f"""
135
  <div style="
136
  border-radius:16px;
137
  padding:20px;
138
  border:1px solid #E6E6E6;
139
  background:#FFFFFF;
140
- color:#111;
141
  ">
142
- <div style="font-size:14px;color:#444;margin-bottom:8px;">
143
  辨識結果
144
  </div>
145
 
@@ -148,16 +143,16 @@ def _result_card_html(emo_key: str, conf: Optional[float]) -> str:
148
  font-weight:800;
149
  line-height:1.1;
150
  margin-bottom:14px;
151
- color:#000;
152
  ">
153
  {zh}
154
  </div>
155
 
156
- <div style="font-size:16px;color:#111;margin-bottom:6px;">
157
  心情分數:<b>{score}</b>({score_desc})
158
  </div>
159
 
160
- <div style="font-size:14px;color:#111;">
161
  信心值:{conf_txt}
162
  </div>
163
  </div>
@@ -246,11 +241,7 @@ def _reset_state_for_camera(st: AppState) -> AppState:
246
  st.candidate_since = None
247
  st.final_emo = None
248
  st.final_conf = None
249
-
250
- # ### [整合需求 新增] ###
251
  st.final_score = 3
252
- # ######################
253
-
254
  return st
255
 
256
 
@@ -258,7 +249,6 @@ def _reset_state_for_camera(st: AppState) -> AppState:
258
  # Camera streaming
259
  # =========================
260
  def on_stream(frame_rgb: np.ndarray, st: AppState):
261
- # ✅ 完成/停止狀態:不要再顯示「Click to access…/Record…」
262
  if st.finished or (not st.running):
263
  cam_visible = False
264
 
@@ -280,7 +270,6 @@ def on_stream(frame_rgb: np.ndarray, st: AppState):
280
  gr.update(value="重新攝影機辨識"),
281
  )
282
 
283
- # ✅ 還沒拿到 frame:提示使用者按允許/Record(而不是亂寫已開啟)
284
  if frame_rgb is None:
285
  return (
286
  gr.update(visible=True),
@@ -393,11 +382,7 @@ def on_stream(frame_rgb: np.ndarray, st: AppState):
393
  if confirmed and st.final_emo is None:
394
  st.final_emo = stable_key
395
  st.final_conf = top_conf
396
-
397
- # ### [整合需求 新增] ###
398
- # 在辨識完成的瞬間,順便存入整數分數
399
  st.final_score = EMO_TO_SCORE.get(stable_key, 3)
400
- # ######################
401
 
402
  st.running = False
403
  st.finished = True
@@ -428,19 +413,18 @@ def on_stream(frame_rgb: np.ndarray, st: AppState):
428
  def on_restart(st: AppState):
429
  st = _reset_state_for_camera(st)
430
  return (
431
- gr.update(visible=True), # cam
432
- gr.update(value=_hint_html("等待影像…(尚未開始串流)")), # result
433
- gr.update(value=_score_radio_value(3)), # mood
434
- gr.update(value=_camera_hint_before_start()), # hint
435
  st,
436
- gr.update(value="重新攝影機辨識"), # btn label
437
  )
438
 
439
 
440
  def on_stop(st: AppState):
441
  st.running = False
442
  st.finished = True
443
- # ✅ 停止後也不要再顯示 Click/Record 提示,改成「已停止/可重新」
444
  if st.final_emo is None:
445
  return (
446
  gr.update(visible=False),
@@ -462,15 +446,41 @@ def on_stop(st: AppState):
462
 
463
 
464
  # =========================
465
- # Gradio UI
466
  # =========================
467
  css = """
 
468
  #app_container { max-width: 960px; margin: 0 auto; }
469
  .gradio-container { background: #f1f5f9 !important; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
470
  """
471
 
472
  if __name__ == "__main__":
473
- with gr.Blocks(title="Emotion Detector") as demo:
474
  st = gr.State(AppState())
475
 
476
  gr.Markdown("## 情緒辨識")
@@ -489,7 +499,6 @@ if __name__ == "__main__":
489
  btn_restart = gr.Button("重新攝影機辨識", variant="primary")
490
  btn_stop = gr.Button("停止", variant="secondary")
491
 
492
- # ✅ 你要的排序:結果在上、分數在下
493
  gr.Markdown("### 辨識結果")
494
  result = gr.HTML(_hint_html("等待影像…(尚未開始串流)"))
495
 
 
49
  "unknown": 3,
50
  }
51
 
 
 
52
  def get_emotion_score(emo: str) -> int:
53
  return EMO_TO_SCORE.get(emo, 3)
 
54
 
55
  SCORE_LABELS = {
56
  1: "1(心情差)",
 
67
  # =========================
68
  @dataclass
69
  class AppState:
70
+ mode: str = "攝影機辨識"
71
 
72
  running: bool = True
73
  finished: bool = False
 
89
  final_emo: Optional[str] = None
90
  final_conf: Optional[float] = None
91
 
 
 
92
  final_score: int = 3
 
93
 
94
 
95
  # =========================
96
+ # UI HTML (強制黑色文字)
97
  # =========================
98
  def _hint_html(msg: str) -> str:
99
+ # 加入 color:#000000 強制黑色
100
  return f"""
101
+ <div style="border-radius:14px;padding:14px;border:1px dashed #DADADA;background:#FAFAFA;color:#000000;">
102
  {msg}
103
  </div>
104
  """
 
125
  conf_txt = "" if conf is None else f"{conf:.1f}%"
126
  score_desc = SCORE_LABELS[score].split("(")[1].rstrip(")")
127
 
128
+ # ✅ 強制設定 color: #000000
129
  return f"""
130
  <div style="
131
  border-radius:16px;
132
  padding:20px;
133
  border:1px solid #E6E6E6;
134
  background:#FFFFFF;
135
+ color:#000000;
136
  ">
137
+ <div style="font-size:14px;color:#000000;margin-bottom:8px;">
138
  辨識結果
139
  </div>
140
 
 
143
  font-weight:800;
144
  line-height:1.1;
145
  margin-bottom:14px;
146
+ color:#000000;
147
  ">
148
  {zh}
149
  </div>
150
 
151
+ <div style="font-size:16px;color:#000000;margin-bottom:6px;">
152
  心情分數:<b>{score}</b>({score_desc})
153
  </div>
154
 
155
+ <div style="font-size:14px;color:#000000;">
156
  信心值:{conf_txt}
157
  </div>
158
  </div>
 
241
  st.candidate_since = None
242
  st.final_emo = None
243
  st.final_conf = None
 
 
244
  st.final_score = 3
 
 
245
  return st
246
 
247
 
 
249
  # Camera streaming
250
  # =========================
251
  def on_stream(frame_rgb: np.ndarray, st: AppState):
 
252
  if st.finished or (not st.running):
253
  cam_visible = False
254
 
 
270
  gr.update(value="重新攝影機辨識"),
271
  )
272
 
 
273
  if frame_rgb is None:
274
  return (
275
  gr.update(visible=True),
 
382
  if confirmed and st.final_emo is None:
383
  st.final_emo = stable_key
384
  st.final_conf = top_conf
 
 
 
385
  st.final_score = EMO_TO_SCORE.get(stable_key, 3)
 
386
 
387
  st.running = False
388
  st.finished = True
 
413
  def on_restart(st: AppState):
414
  st = _reset_state_for_camera(st)
415
  return (
416
+ gr.update(visible=True),
417
+ gr.update(value=_hint_html("等待影像…(尚未開始串流)")),
418
+ gr.update(value=_score_radio_value(3)),
419
+ gr.update(value=_camera_hint_before_start()),
420
  st,
421
+ gr.update(value="重新攝影機辨識"),
422
  )
423
 
424
 
425
  def on_stop(st: AppState):
426
  st.running = False
427
  st.finished = True
 
428
  if st.final_emo is None:
429
  return (
430
  gr.update(visible=False),
 
446
 
447
 
448
  # =========================
449
+ # Gradio UI & CSS (重要修改處)
450
  # =========================
451
  css = """
452
+ /* 讓 App 容器置中且維持淺色背景 */
453
  #app_container { max-width: 960px; margin: 0 auto; }
454
  .gradio-container { background: #f1f5f9 !important; }
455
+
456
+ /* 1. 全域強制標題與文字為黑色 (針對 Markdown 生成的內容) */
457
+ .prose h1, .prose h2, .prose h3, .prose h4, .prose h5, .prose h6,
458
+ .prose p, .prose strong, .prose em, .prose li {
459
+ color: #000000 !important;
460
+ }
461
+
462
+ /* 2. 針對 Tab 按鈕文字強制為黑色 */
463
+ .tab-nav button {
464
+ color: #000000 !important;
465
+ }
466
+ .tab-nav button.selected {
467
+ color: #000000 !important;
468
+ font-weight: bold; /* 選中時加粗 */
469
+ }
470
+
471
+ /* 3. 針對輸入元件的 Label (例如 Radio, Textbox 上方的文字) */
472
+ label span {
473
+ color: #000000 !important;
474
+ }
475
+
476
+ /* 4. 其他一般文字區塊 */
477
+ .markdown-text {
478
+ color: #000000 !important;
479
+ }
480
  """
481
 
482
  if __name__ == "__main__":
483
+ with gr.Blocks(title="Emotion Detector", css=css) as demo:
484
  st = gr.State(AppState())
485
 
486
  gr.Markdown("## 情緒辨識")
 
499
  btn_restart = gr.Button("重新攝影機辨識", variant="primary")
500
  btn_stop = gr.Button("停止", variant="secondary")
501
 
 
502
  gr.Markdown("### 辨識結果")
503
  result = gr.HTML(_hint_html("等待影像…(尚未開始串流)"))
504