Dusit-P commited on
Commit
d65ba09
·
verified ·
1 Parent(s): aa409de

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +98 -95
app.py CHANGED
@@ -28,38 +28,28 @@ NEUTRAL_COLOR = "#94A3B8"
28
  TEMPLATE = "plotly_white"
29
  CACHE = {}
30
 
31
- # ================= Date Presets =================
32
  DATE_PRESETS = {
33
  "ทั้งหมด": None,
34
  "7 วันล่าสุด": 7,
 
35
  "30 วันล่าสุด": 30,
36
- "90 วันล่าสุด": 90,
37
- "เดือนนี้": "current_month",
38
- "เดือนที่แล้ว": "last_month"
39
  }
40
 
41
  def apply_date_preset(df, date_col, preset_key):
42
  """กรองข้อมูลตาม preset ที่เลือก"""
43
- if preset_key == "ทั้งหมด":
44
  return df
45
 
46
- now = pd.Timestamp.now()
47
-
48
- if isinstance(DATE_PRESETS[preset_key], int):
49
- days = DATE_PRESETS[preset_key]
50
- cutoff = now - pd.Timedelta(days=days)
51
- return df[df[date_col] >= cutoff]
52
-
53
- elif DATE_PRESETS[preset_key] == "current_month":
54
- start = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
55
- return df[df[date_col] >= start]
56
 
57
- elif DATE_PRESETS[preset_key] == "last_month":
58
- end_last = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
59
- start_last = (end_last - pd.Timedelta(days=1)).replace(day=1)
60
- return df[(df[date_col] >= start_last) & (df[date_col] < end_last)]
61
 
62
- return df
63
 
64
  # ================= Loader =================
65
  def _import_models():
@@ -206,20 +196,26 @@ def make_summary_chart(df, chart_type="pie"):
206
 
207
  return fig, info
208
 
209
- def _resample_counts(df, date_col, freq):
210
- """รวมข้อมูลตามช่วงเวลา"""
 
 
 
 
 
 
 
 
 
 
211
  g = df.groupby([pd.Grouper(key=date_col, freq=freq),"label"]).size().unstack(fill_value=0)
212
  for c in ["negative","positive"]:
213
  if c not in g.columns: g[c]=0
214
- return g[["negative","positive"]].sort_index()
215
 
216
- def make_time_chart(df, date_col, freq, use_smooth):
217
  """กราฟแนวโน้มตามเวลา"""
218
- ts = _resample_counts(df, date_col, freq)
219
-
220
- if use_smooth:
221
- window = 7 if freq=="D" else (4 if freq=="W" else 3)
222
- ts = ts.rolling(window, min_periods=1).mean()
223
 
224
  fig = go.Figure()
225
  fig.add_scatter(
@@ -238,10 +234,9 @@ def make_time_chart(df, date_col, freq, use_smooth):
238
  )
239
 
240
  freq_map = {"D": "รายวัน", "W": "รายสัปดาห์", "M": "รายเดือน"}
241
- smooth_text = " (ปรับให้เรียบแล้ว)" if use_smooth else ""
242
 
243
  fig.update_layout(
244
- title=f"📈 แนวโน้มรีวิวตามเวลา ({freq_map[freq]}){smooth_text}",
245
  template=TEMPLATE,
246
  xaxis_title="วันที่",
247
  yaxis_title="จำนวนรีวิว",
@@ -251,7 +246,7 @@ def make_time_chart(df, date_col, freq, use_smooth):
251
 
252
  return fig
253
 
254
- def make_shop_analysis(df, shop_col, date_col=None, freq="D"):
255
  """วิเคราะห์แยกตามร้าน/สาขา"""
256
 
257
  # 1. สรุปภาพรวมแต่ละร้าน
@@ -294,40 +289,45 @@ def make_shop_analysis(df, shop_col, date_col=None, freq="D"):
294
  height=450
295
  )
296
 
297
- # 3. กราฟแนวโน้มตามเวลาแยกร้าน (ถ้ามี date_col)
298
- fig_trend = None
299
  if date_col and date_col in df.columns:
300
- fig_trend = go.Figure()
 
 
 
 
 
 
 
 
301
 
302
- for shop in shops[:5]: # แสดงแค่ 5 ร้านแรก
303
- shop_df = df[df[shop_col] == shop].copy()
304
- if len(shop_df) == 0:
305
- continue
306
-
307
- # คำนวณ positive ratio ตามเวลา
308
- shop_df['pos_score'] = (shop_df['label'] == 'positive').astype(int)
309
- ts = shop_df.groupby(pd.Grouper(key=date_col, freq=freq))['pos_score'].mean() * 100
310
 
311
- fig_trend.add_scatter(
312
- x=ts.index,
313
  y=ts.values,
314
- mode='lines+markers',
315
- name=shop,
316
- line=dict(width=2),
317
- marker=dict(size=5)
318
  )
319
 
320
  freq_map = {"D": "รายวัน", "W": "รายสัปดาห์", "M": "รายเดือน"}
321
- fig_trend.update_layout(
322
- title=f"📊 แนวโน้ม % รีวิวเชิงบวกแยกตามร้าน ({freq_map[freq]})",
 
323
  template=TEMPLATE,
324
  xaxis_title="วันที่",
325
- yaxis_title="% รีวิวเชิงบวก",
326
  hovermode='x unified',
327
  height=450
328
  )
329
 
330
- return summary_df, fig_compare, fig_trend
331
 
332
  # ================= Core Predict =================
333
  def _predict_batch(texts, model_name, batch_size=32):
@@ -379,9 +379,6 @@ def on_file_change(file_obj):
379
  gr.update(choices=[],value=None),
380
  gr.update(choices=[],value=None),
381
  gr.update(visible=False),
382
- gr.update(visible=False),
383
- gr.update(visible=False),
384
- gr.update(visible=False),
385
  "⚠️ กรุณาอัปโหลดไฟล์ CSV")
386
 
387
  try:
@@ -410,9 +407,6 @@ def on_file_change(file_obj):
410
  gr.update(choices=date_candidates if date_candidates else ["ไม่มี"], value=date_col),
411
  gr.update(choices=shop_candidates if shop_candidates else ["ไม่มี"], value=shop_col),
412
  gr.update(visible=has_date),
413
- gr.update(visible=has_date),
414
- gr.update(visible=has_shop),
415
- gr.update(visible=has_shop),
416
  note)
417
 
418
  except Exception as e:
@@ -420,13 +414,9 @@ def on_file_change(file_obj):
420
  gr.update(choices=[],value=None),
421
  gr.update(choices=[],value=None),
422
  gr.update(visible=False),
423
- gr.update(visible=False),
424
- gr.update(visible=False),
425
- gr.update(visible=False),
426
  f"❌ ไม่สามารถอ่านไฟล์ได้:\n{str(e)}")
427
 
428
- def predict_csv(file_obj, model_choice, text_col, date_col, shop_col,
429
- date_preset, freq, use_smooth, chart_type):
430
  """วิเคราะห์รีวิวจากไฟล์ CSV"""
431
  if file_obj is None:
432
  return (pd.DataFrame(), go.Figure(), go.Figure(),
@@ -436,6 +426,7 @@ def predict_csv(file_obj, model_choice, text_col, date_col, shop_col,
436
 
437
  try:
438
  df_raw = pd.read_csv(file_obj.name)
 
439
  cols = list(df_raw.columns)
440
 
441
  # ตรวจสอบ text column
@@ -444,23 +435,29 @@ def predict_csv(file_obj, model_choice, text_col, date_col, shop_col,
444
 
445
  # ดึงข้อความและทำนาย
446
  texts = [_norm_text(v) for v in df_raw[text_col].tolist()]
447
- texts = [t for t in texts if _is_substantive_text(t)]
 
448
 
449
- if not texts:
450
  return (pd.DataFrame(), go.Figure(), go.Figure(),
451
  gr.update(visible=False), gr.update(visible=False),
452
  pd.DataFrame(), gr.update(visible=False),
453
  "❌ ไม่พบข้อความที่สามารถวิเคราะห์ได้ในไฟ��์", None)
454
 
455
- results = _predict_batch(texts, model_choice)
456
  df_out = pd.DataFrame(results)
457
 
458
  # กราฟสรุปหลัก
459
  fig_main, info = make_summary_chart(df_out, chart_type)
460
 
 
 
 
 
461
  # กราฟตามเวลา
462
  fig_time = go.Figure()
463
  show_time = False
 
464
 
465
  if date_col and date_col in cols and date_col != "ไม่มี":
466
  dts = _to_datetime_safe(df_raw[date_col])
@@ -469,36 +466,35 @@ def predict_csv(file_obj, model_choice, text_col, date_col, shop_col,
469
  df_time["__dt__"] = dts
470
  df_time = df_time.dropna(subset=["__dt__"])
471
 
472
- # ใช้ date preset
473
- df_time = apply_date_preset(df_time, "__dt__", date_preset)
474
 
475
- if len(df_time) > 0:
476
- fig_time = make_time_chart(df_time, "__dt__", freq, use_smooth)
477
  show_time = True
 
 
 
 
478
 
479
  # วิเคราะห์ตาม Shop
480
  shop_summary_df = pd.DataFrame()
481
  fig_shop = go.Figure()
482
- fig_shop_trend = None
483
  show_shop = False
484
 
485
  if shop_col and shop_col in cols and shop_col != "ไม่มี":
486
  df_with_shop = df_out.copy()
487
  df_with_shop[shop_col] = df_raw[shop_col]
488
 
489
- # ถ้ามี date ด้วย ให้ใส่เข้าไป
490
- if date_col and date_col in cols and date_col != "ไม่มี":
491
- dts = _to_datetime_safe(df_raw[date_col])
492
- if dts.notna().any():
493
- df_with_shop["__dt__"] = dts
494
- df_with_shop = df_with_shop.dropna(subset=["__dt__"])
495
- df_with_shop = apply_date_preset(df_with_shop, "__dt__", date_preset)
496
-
497
- shop_summary_df, fig_shop, fig_shop_trend = make_shop_analysis(
498
- df_with_shop, shop_col, "__dt__", freq
499
- )
500
- else:
501
- shop_summary_df, fig_shop, _ = make_shop_analysis(df_with_shop, shop_col)
502
  else:
503
  shop_summary_df, fig_shop, _ = make_shop_analysis(df_with_shop, shop_col)
504
 
@@ -513,7 +509,7 @@ def predict_csv(file_obj, model_choice, text_col, date_col, shop_col,
513
  gr.update(visible=show_time, value=fig_time),
514
  gr.update(visible=show_shop, value=fig_shop),
515
  shop_summary_df,
516
- gr.update(visible=show_shop and fig_shop_trend is not None, value=fig_shop_trend),
517
  info, path)
518
 
519
  except Exception as e:
@@ -616,6 +612,17 @@ with gr.Blocks(title="Thai Sentiment Analysis", theme=gr.themes.Soft()) as demo:
616
  with gr.Row():
617
  date_preset = gr.Radio(
618
  choices=list(DATE_PRESETS.keys()),
 
 
 
 
 
 
 
 
 
 
 
619
  value="ทั้งหมด",
620
  label="📆 ช่วงเวลาที่ต้องการวิเคราะห์",
621
  visible=False
@@ -659,14 +666,11 @@ with gr.Blocks(title="Thai Sentiment Analysis", theme=gr.themes.Soft()) as demo:
659
 
660
  result_time = gr.Plot(label="📈 กราฟแนวโน้มตามเวลา", visible=False)
661
 
662
- with shop_analysis_row:
663
- gr.Markdown("### 🏪 วิเคราะห์แยกตามร้าน/สาขา")
664
 
665
- shop_summary = gr.Dataframe(label="📊 สรุปแต่ละร้าน")
666
  result_shop = gr.Plot(label="🏪 เปรียบเทียบรีวิวแต่ละร้าน", visible=False)
667
-
668
- with shop_trend_row:
669
- result_shop_trend = gr.Plot(label="📈 แนวโน้ม % เชิงบวกแยกตามร้าน", visible=False)
670
 
671
  download_file = gr.File(label="💾 ดาวน์โหลดผลลัพธ์ (CSV)")
672
 
@@ -675,14 +679,13 @@ with gr.Blocks(title="Thai Sentiment Analysis", theme=gr.themes.Soft()) as demo:
675
  on_file_change,
676
  [file_input],
677
  [text_col_dd, date_col_dd, shop_col_dd,
678
- date_preset, freq, use_smooth,
679
- shop_analysis_row, detect_note]
680
  )
681
 
682
  predict_btn_2.click(
683
  predict_csv,
684
  [file_input, model_radio, text_col_dd, date_col_dd, shop_col_dd,
685
- date_preset, freq, use_smooth, chart_type_2],
686
  [result_df_2, result_chart_2, result_time,
687
  result_time, result_shop,
688
  shop_summary, result_shop_trend,
 
28
  TEMPLATE = "plotly_white"
29
  CACHE = {}
30
 
31
+ # ================= Date Presets (แก้ไขให้ทำงานถูกต้อง) =================
32
  DATE_PRESETS = {
33
  "ทั้งหมด": None,
34
  "7 วันล่าสุด": 7,
35
+ "15 วันล่าสุด": 15,
36
  "30 วันล่าสุด": 30,
37
+ "90 วันล่าสุด": 90
 
 
38
  }
39
 
40
  def apply_date_preset(df, date_col, preset_key):
41
  """กรองข้อมูลตาม preset ที่เลือก"""
42
+ if preset_key == "ทั้งหมด" or preset_key not in DATE_PRESETS:
43
  return df
44
 
45
+ days = DATE_PRESETS[preset_key]
46
+ if days is None:
47
+ return df
 
 
 
 
 
 
 
48
 
49
+ now = pd.Timestamp.now()
50
+ cutoff = now - pd.Timedelta(days=days)
 
 
51
 
52
+ return df[df[date_col] >= cutoff]
53
 
54
  # ================= Loader =================
55
  def _import_models():
 
196
 
197
  return fig, info
198
 
199
+ def _resample_counts(df, date_col, freq="auto"):
200
+ """รวมข้อมูลตามช่วงเวลา - auto-detect frequency"""
201
+ if freq == "auto":
202
+ # Auto-detect ตามช่วงเวลาของข้อมูล
203
+ date_range = (df[date_col].max() - df[date_col].min()).days
204
+ if date_range <= 30:
205
+ freq = "D" # รายวัน
206
+ elif date_range <= 90:
207
+ freq = "W" # รายสัปดาห์
208
+ else:
209
+ freq = "M" # รายเดือน
210
+
211
  g = df.groupby([pd.Grouper(key=date_col, freq=freq),"label"]).size().unstack(fill_value=0)
212
  for c in ["negative","positive"]:
213
  if c not in g.columns: g[c]=0
214
+ return g[["negative","positive"]].sort_index(), freq
215
 
216
+ def make_time_chart(df, date_col, freq="auto"):
217
  """กราฟแนวโน้มตามเวลา"""
218
+ ts, actual_freq = _resample_counts(df, date_col, freq)
 
 
 
 
219
 
220
  fig = go.Figure()
221
  fig.add_scatter(
 
234
  )
235
 
236
  freq_map = {"D": "รายวัน", "W": "รายสัปดาห์", "M": "รายเดือน"}
 
237
 
238
  fig.update_layout(
239
+ title=f"📈 แนวโน้มรีวิวตามเวลา ({freq_map[actual_freq]})",
240
  template=TEMPLATE,
241
  xaxis_title="วันที่",
242
  yaxis_title="จำนวนรีวิว",
 
246
 
247
  return fig
248
 
249
+ def make_shop_analysis(df, shop_col, date_col=None, freq="auto"):
250
  """วิเคราะห์แยกตามร้าน/สาขา"""
251
 
252
  # 1. สรุปภาพรวมแต่ละร้าน
 
289
  height=450
290
  )
291
 
292
+ # 3. Stacked bar แสดง Shop ตามช่วงเวลา (ถ้ามี date_col)
293
+ fig_time_shop = None
294
  if date_col and date_col in df.columns:
295
+ # Auto-detect frequency
296
+ if freq == "auto":
297
+ date_range = (df[date_col].max() - df[date_col].min()).days
298
+ if date_range <= 30:
299
+ freq = "D"
300
+ elif date_range <= 90:
301
+ freq = "W"
302
+ else:
303
+ freq = "M"
304
 
305
+ fig_time_shop = go.Figure()
306
+
307
+ # เตรียมข้อมูลแยกตามร้าน
308
+ for shop in shops:
309
+ shop_df = df[df[shop_col] == shop]
310
+ # รวมตามเวลา
311
+ ts = shop_df.groupby(pd.Grouper(key=date_col, freq=freq)).size()
 
312
 
313
+ fig_time_shop.add_bar(
314
+ x=ts.index,
315
  y=ts.values,
316
+ name=shop
 
 
 
317
  )
318
 
319
  freq_map = {"D": "รายวัน", "W": "รายสัปดาห์", "M": "รายเดือน"}
320
+ fig_time_shop.update_layout(
321
+ title=f"📊 จำนวนรีวิวแต่ละร้านตามเวลา ({freq_map[freq]})",
322
+ barmode='stack',
323
  template=TEMPLATE,
324
  xaxis_title="วันที่",
325
+ yaxis_title="จำนวนรีวิว",
326
  hovermode='x unified',
327
  height=450
328
  )
329
 
330
+ return summary_df, fig_compare, fig_time_shop
331
 
332
  # ================= Core Predict =================
333
  def _predict_batch(texts, model_name, batch_size=32):
 
379
  gr.update(choices=[],value=None),
380
  gr.update(choices=[],value=None),
381
  gr.update(visible=False),
 
 
 
382
  "⚠️ กรุณาอัปโหลดไฟล์ CSV")
383
 
384
  try:
 
407
  gr.update(choices=date_candidates if date_candidates else ["ไม่มี"], value=date_col),
408
  gr.update(choices=shop_candidates if shop_candidates else ["ไม่มี"], value=shop_col),
409
  gr.update(visible=has_date),
 
 
 
410
  note)
411
 
412
  except Exception as e:
 
414
  gr.update(choices=[],value=None),
415
  gr.update(choices=[],value=None),
416
  gr.update(visible=False),
 
 
 
417
  f"❌ ไม่สามารถอ่านไฟล์ได้:\n{str(e)}")
418
 
419
+ def predict_csv(file_obj, model_choice, text_col, date_col, shop_col, date_preset, chart_type):
 
420
  """วิเคราะห์รีวิวจากไฟล์ CSV"""
421
  if file_obj is None:
422
  return (pd.DataFrame(), go.Figure(), go.Figure(),
 
426
 
427
  try:
428
  df_raw = pd.read_csv(file_obj.name)
429
+ total_rows = len(df_raw)
430
  cols = list(df_raw.columns)
431
 
432
  # ตรวจสอบ text column
 
435
 
436
  # ดึงข้อความและทำนาย
437
  texts = [_norm_text(v) for v in df_raw[text_col].tolist()]
438
+ texts_clean = [t for t in texts if _is_substantive_text(t)]
439
+ skipped = total_rows - len(texts_clean)
440
 
441
+ if not texts_clean:
442
  return (pd.DataFrame(), go.Figure(), go.Figure(),
443
  gr.update(visible=False), gr.update(visible=False),
444
  pd.DataFrame(), gr.update(visible=False),
445
  "❌ ไม่พบข้อความที่สามารถวิเคราะห์ได้ในไฟ��์", None)
446
 
447
+ results = _predict_batch(texts_clean, model_choice)
448
  df_out = pd.DataFrame(results)
449
 
450
  # กราฟสรุปหลัก
451
  fig_main, info = make_summary_chart(df_out, chart_type)
452
 
453
+ # เพิ่มข้อมูลแถวที่ข้าม
454
+ if skipped > 0:
455
+ info += f"\n\n⚠️ **ข้ามแถวที่ไม่มีข้อความ:** {skipped} แถว (ใช้ {len(texts_clean)}/{total_rows} แถว)"
456
+
457
  # กราฟตามเวลา
458
  fig_time = go.Figure()
459
  show_time = False
460
+ df_time_filtered = None
461
 
462
  if date_col and date_col in cols and date_col != "ไม่มี":
463
  dts = _to_datetime_safe(df_raw[date_col])
 
466
  df_time["__dt__"] = dts
467
  df_time = df_time.dropna(subset=["__dt__"])
468
 
469
+ # ใช้ date preset - แก้ bug ตรงนี้!
470
+ df_time_filtered = apply_date_preset(df_time, "__dt__", date_preset)
471
 
472
+ if len(df_time_filtered) > 0:
473
+ fig_time = make_time_chart(df_time_filtered, "__dt__")
474
  show_time = True
475
+
476
+ # แสดงข้อมูลช่วงเวลาที่กรอง
477
+ if date_preset != "ทั้งหมด":
478
+ info += f"\n\n📅 **ช่วงเวลาที่แสดง:** {date_preset} ({len(df_time_filtered)} รีวิว)"
479
 
480
  # วิเคราะห์ตาม Shop
481
  shop_summary_df = pd.DataFrame()
482
  fig_shop = go.Figure()
483
+ fig_shop_time = None
484
  show_shop = False
485
 
486
  if shop_col and shop_col in cols and shop_col != "ไม่มี":
487
  df_with_shop = df_out.copy()
488
  df_with_shop[shop_col] = df_raw[shop_col]
489
 
490
+ # ถ้ามี date ใช้ข้อมูลที่ filter แล้ว
491
+ if df_time_filtered is not None and len(df_time_filtered) > 0:
492
+ df_with_shop["__dt__"] = df_time_filtered["__dt__"]
493
+ df_with_shop = df_with_shop.dropna(subset=["__dt__"])
494
+
495
+ shop_summary_df, fig_shop, fig_shop_time = make_shop_analysis(
496
+ df_with_shop, shop_col, "__dt__"
497
+ )
 
 
 
 
 
498
  else:
499
  shop_summary_df, fig_shop, _ = make_shop_analysis(df_with_shop, shop_col)
500
 
 
509
  gr.update(visible=show_time, value=fig_time),
510
  gr.update(visible=show_shop, value=fig_shop),
511
  shop_summary_df,
512
+ gr.update(visible=show_shop and fig_shop_time is not None, value=fig_shop_time),
513
  info, path)
514
 
515
  except Exception as e:
 
612
  with gr.Row():
613
  date_preset = gr.Radio(
614
  choices=list(DATE_PRESETS.keys()),
615
+ value="ทั้งหมด",
616
+ label="📆 ช่วงเวลาที่ต้องการวิเคราะห์",
617
+ info="เลือกช่วงเวลาที่ต้องการดูข้อมูล",
618
+ visible=False
619
+ )
620
+
621
+ chart_type_2 = gr.Radio(
622
+ choices=[("วงกลม", "pie"), ("แท่ง", "bar")],
623
+ value="pie",
624
+ label="📊 รูปแบบกราฟสรุป"
625
+ )(DATE_PRESETS.keys()),
626
  value="ทั้งหมด",
627
  label="📆 ช่วงเวลาที่ต้องการวิเคราะห์",
628
  visible=False
 
666
 
667
  result_time = gr.Plot(label="📈 กราฟแนวโน้มตามเวลา", visible=False)
668
 
669
+ gr.Markdown("### 🏪 วิเคราะห์แยกตามร้าน/สาขา")
 
670
 
671
+ shop_summary = gr.Dataframe(label="📊 สรุปแต่ละร้าน", visible=False)
672
  result_shop = gr.Plot(label="🏪 เปรียบเทียบรีวิวแต่ละร้าน", visible=False)
673
+ result_shop_trend = gr.Plot(label="📊 รีวิวแต่ละร้านตามช่วงเวลา (Stacked Bar)", visible=False)
 
 
674
 
675
  download_file = gr.File(label="💾 ดาวน์โหลดผลลัพธ์ (CSV)")
676
 
 
679
  on_file_change,
680
  [file_input],
681
  [text_col_dd, date_col_dd, shop_col_dd,
682
+ date_preset, detect_note]
 
683
  )
684
 
685
  predict_btn_2.click(
686
  predict_csv,
687
  [file_input, model_radio, text_col_dd, date_col_dd, shop_col_dd,
688
+ date_preset, chart_type_2],
689
  [result_df_2, result_chart_2, result_time,
690
  result_time, result_shop,
691
  shop_summary, result_shop_trend,