archivartaunik commited on
Commit
ef83ec8
·
verified ·
1 Parent(s): 91a7fce

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +156 -0
app.py CHANGED
@@ -18,6 +18,7 @@ import os
18
  import json
19
  import datetime as _dt
20
  from typing import List, Tuple, Optional
 
21
 
22
  import requests
23
  import pandas as pd
@@ -180,6 +181,11 @@ def _system_instruction(lang_code: str) -> str:
180
  return "Reply in English."
181
  return "Reply in the caller's language; if unclear, use concise professional English."
182
 
 
 
 
 
 
183
 
184
  # ─────────────────────────────────────────────────────────────────────────────
185
  # Gradio handlers
@@ -309,6 +315,131 @@ def ui_analyze(selected_idx: Optional[int], df: pd.DataFrame,
309
  except Exception:
310
  pass
311
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312
  # ─────────────────────────────────────────────────────────────────────────────
313
  # Password / gating helpers
314
  # ─────────────────────────────────────────────────────────────────────────────
@@ -391,6 +522,23 @@ with gr.Blocks(title="Vochi CRM Call Logs (Gradio)") as demo:
391
  analyze_btn = gr.Button("🧠 Analyze", variant="primary")
392
  analysis_md = gr.Markdown()
393
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
394
  # Wire events
395
  # 1) Fetch button: gate by password
396
  fetch_btn.click(
@@ -415,6 +563,14 @@ with gr.Blocks(title="Vochi CRM Call Logs (Gradio)") as demo:
415
  outputs=[analysis_md],
416
  )
417
 
 
 
 
 
 
 
 
 
418
 
419
  if __name__ == "__main__":
420
  # On HF Spaces, just running this file is enough; launch() is fine for local dev, too.
 
18
  import json
19
  import datetime as _dt
20
  from typing import List, Tuple, Optional
21
+ import time # ← ДАДАНА
22
 
23
  import requests
24
  import pandas as pd
 
181
  return "Reply in English."
182
  return "Reply in the caller's language; if unclear, use concise professional English."
183
 
184
+ # ← ДАДАНА: невялікі хелпер для выбару прампту
185
+ def _prepare_prompt(template_key: str, custom_prompt: str) -> str:
186
+ if template_key == "custom":
187
+ return (custom_prompt or "").strip() or PROMPT_TEMPLATES["simple"]
188
+ return PROMPT_TEMPLATES.get(template_key, PROMPT_TEMPLATES["simple"])
189
 
190
  # ─────────────────────────────────────────────────────────────────────────────
191
  # Gradio handlers
 
315
  except Exception:
316
  pass
317
 
318
+ # ← ДАДАНА: Пакетны аналіз званкоў за дзень/час
319
+ def ui_analyze_calls_by_date(
320
+ authed: bool,
321
+ date_str: str,
322
+ template_key: str,
323
+ custom_prompt: str,
324
+ lang_code: str,
325
+ model_pref: str,
326
+ ):
327
+ """
328
+ Fetch calls for the given date and analyze them one-by-one with the same
329
+ settings/fields as the single-call AI Analysis tab. Save a .txt file and
330
+ show results on screen.
331
+ """
332
+ # Гейт па паролі
333
+ if not authed:
334
+ return (
335
+ "🔒 Увядзіце пароль, каб запусціць аналіз.", # results_md
336
+ None, # file
337
+ "Доступ закрыты.", # status
338
+ gr.update(visible=True), # show pwd group
339
+ )
340
+
341
+ date_str = (date_str or "").strip()
342
+ if not date_str:
343
+ date_str = _today_str()
344
+
345
+ # 1) Атрымаць спіс званкоў за дату
346
+ try:
347
+ calls = fetch_calllogs(date_str)
348
+ df = pd.DataFrame(calls)
349
+ except Exception as e:
350
+ return (f"Не ўдалося загрузіць спіс: {e}", None, "", gr.update())
351
+
352
+ if df.empty:
353
+ return ("За гэты дзень званкоў не знойдзена.", None, "", gr.update())
354
+
355
+ # 2) Падрыхтоўка кліента мадэлі і прампту
356
+ if not _HAS_GENAI:
357
+ return ("❌ google-genai library not found.", None, "", gr.update())
358
+
359
+ api_key = os.environ.get("GOOGLE_API_KEY", "").strip()
360
+ if not api_key:
361
+ return ("GOOGLE_API_KEY не зададзены ў Secrets.", None, "", gr.update())
362
+
363
+ try:
364
+ client = genai.Client(api_key=api_key)
365
+ model_name = _resolve_model(client, model_pref)
366
+ except Exception as e:
367
+ return (f"Не ўдалося ініцыялізаваць кліента: {e}", None, "", gr.update())
368
+
369
+ sys_inst = _system_instruction(lang_code)
370
+ prompt = _prepare_prompt(template_key, custom_prompt)
371
+
372
+ # 3) Пакетны праход: па адным выкліку
373
+ results_blocks: List[str] = []
374
+ analyzed = 0
375
+
376
+ for i, row in df.iterrows():
377
+ unique_id = str(row.get("UniqueId", ""))
378
+ if not unique_id:
379
+ continue
380
+
381
+ # Скачваем/кэшынгуем mp3
382
+ try:
383
+ mp3_path = f"/tmp/call_{unique_id}.mp3"
384
+ if not os.path.exists(mp3_path) or os.path.getsize(mp3_path) == 0:
385
+ mp3_path, _ = fetch_mp3_by_unique_id(unique_id)
386
+ except Exception as e:
387
+ results_blocks.append(
388
+ f"### Call {i+1}\n"
389
+ f"- UniqueId: {unique_id}\n"
390
+ f"- Start: {row.get('Start','')}\n"
391
+ f"- CallerId: {row.get('CallerId','')}\n"
392
+ f"- Destination: {row.get('Destination','')}\n"
393
+ f"- Duration: {row.get('Duration','')}\n\n"
394
+ f"**Памылка загрузкі аўдыё:** {e}\n"
395
+ "---"
396
+ )
397
+ continue
398
+
399
+ # Upload + generate
400
+ try:
401
+ uploaded_file = client.files.upload(file=mp3_path)
402
+ merged = f"[SYSTEM INSTRUCTION: {sys_inst}]\n\n{prompt}"
403
+ resp = client.models.generate_content(
404
+ model=model_name,
405
+ contents=[uploaded_file, merged],
406
+ )
407
+ text = getattr(resp, "text", "") or "(пусты адказ)"
408
+ except Exception as e:
409
+ text = f"Памылка аналізу: {e}"
410
+ finally:
411
+ try:
412
+ if 'uploaded_file' in locals() and hasattr(uploaded_file, 'name'):
413
+ client.files.delete(name=uploaded_file.name)
414
+ except Exception:
415
+ pass
416
+
417
+ # Сфармаваць блок выніку для гэтага званка
418
+ block = (
419
+ f"### Call {i+1}\n"
420
+ f"- UniqueId: {unique_id}\n"
421
+ f"- Start: {row.get('Start','')}\n"
422
+ f"- CallerId: {row.get('CallerId','')}\n"
423
+ f"- Destination: {row.get('Destination','')}\n"
424
+ f"- Duration: {row.get('Duration','')}\n\n"
425
+ f"**Analysis:**\n\n{text}\n"
426
+ "---"
427
+ )
428
+ results_blocks.append(block)
429
+ analyzed += 1
430
+
431
+ if analyzed == 0:
432
+ return ("Не атрымалася прааналізаваць ніводнага званка.", None, "", gr.update())
433
+
434
+ # 4) Захаваць у .txt і вярнуць
435
+ results_text = "\n\n".join(results_blocks)
436
+ fname = f"/tmp/batch_analysis_{date_str}_{int(time.time())}.txt"
437
+ with open(fname, "w", encoding="utf-8") as f:
438
+ f.write(results_text)
439
+
440
+ status = f"Гатова ✅. Прааналізавана званкоў: {analyzed}."
441
+ return (results_text, fname, status, gr.update(visible=False))
442
+
443
  # ─────────────────────────────────────────────────────────────────────────────
444
  # Password / gating helpers
445
  # ─────────────────────────────────────────────────────────────────────────────
 
522
  analyze_btn = gr.Button("🧠 Analyze", variant="primary")
523
  analysis_md = gr.Markdown()
524
 
525
+ # ← ДАДАНА: новая ўкладка пакетнага аналізу
526
+ with gr.Tab("Аналіз званкоў за дзень/час"):
527
+ batch_date_inp = gr.Textbox(label="Date", value=_today_str(), scale=1)
528
+
529
+ with gr.Row():
530
+ tpl_batch_dd = gr.Dropdown(choices=TPL_OPTIONS, value="simple", label="Template")
531
+ lang_batch_dd = gr.Dropdown(choices=LANG_OPTIONS, value="default", label="Language")
532
+ model_batch_dd = gr.Dropdown(choices=MODEL_OPTIONS, value="models/gemini-2.5-flash", label="Model")
533
+
534
+ custom_batch_tb = gr.Textbox(label="Custom prompt", lines=8, visible=False)
535
+
536
+ batch_btn = gr.Button("прааналізаваць", variant="primary")
537
+
538
+ batch_status_md = gr.Markdown()
539
+ batch_results_md = gr.Markdown()
540
+ batch_file_out = gr.File(label="Вынікі (.txt)")
541
+
542
  # Wire events
543
  # 1) Fetch button: gate by password
544
  fetch_btn.click(
 
563
  outputs=[analysis_md],
564
  )
565
 
566
+ # ← ДАДАНА: падзеі для новай укладкі
567
+ tpl_batch_dd.change(ui_toggle_custom_prompt, inputs=[tpl_batch_dd], outputs=[custom_batch_tb])
568
+ batch_btn.click(
569
+ ui_analyze_calls_by_date,
570
+ inputs=[authed, batch_date_inp, tpl_batch_dd, custom_batch_tb, lang_batch_dd, model_batch_dd],
571
+ outputs=[batch_results_md, batch_file_out, batch_status_md, pwd_group],
572
+ )
573
+
574
 
575
  if __name__ == "__main__":
576
  # On HF Spaces, just running this file is enough; launch() is fine for local dev, too.