Rajan Sharma commited on
Commit
aae6699
·
verified ·
1 Parent(s): 325f883

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +33 -19
app.py CHANGED
@@ -1,7 +1,8 @@
 
1
  import os, traceback, regex as re2
2
  import gradio as gr
3
  import pandas as pd
4
- from typing import List, Tuple, Dict
5
 
6
  from settings import HEALTHCARE_SETTINGS, GENERAL_CONVERSATION_PROMPT, USE_SCENARIO_ENGINE
7
  from audit_log import log_event
@@ -12,20 +13,23 @@ from healthcare_analysis import HealthcareAnalyzer
12
  from scenario_planner import parse_to_plan
13
  from scenario_engine import ScenarioEngine
14
  from rag import RAGIndex
15
- from llm_router import generate_narrative, cohere_chat
16
 
17
  def _sanitize_text(s: str) -> str:
18
  if not isinstance(s, str): return s
 
19
  return re2.sub(r'[\p{C}--[\n\t]]+', '', s)
20
 
21
- def _dataset_catalog(results: Dict[str, any]) -> Dict[str, List[str]]:
22
- cat = {}
 
23
  for k, v in results.items():
24
  if isinstance(v, pd.DataFrame):
25
  cat[k] = v.columns.tolist()
26
  return cat
27
 
28
  def is_healthcare_scenario(text: str, has_files: bool) -> bool:
 
29
  t = (text or "").lower()
30
  kws = HEALTHCARE_SETTINGS["healthcare_keywords"]
31
  structured = any(s in t for s in ["background", "situation", "tasks", "deliverables"])
@@ -34,43 +38,47 @@ def is_healthcare_scenario(text: str, has_files: bool) -> bool:
34
  def handle(user_msg: str, history: list, files: list) -> Tuple[list, str]:
35
  try:
36
  safe_in, blocked_in, reason_in = safety_filter(user_msg, mode="input")
37
- if blocked_in: return history + [(user_msg, refusal_reply(reason_in))], ""
 
38
 
39
- # Normalize files -> paths
40
  file_paths = [getattr(f, "name", None) or f for f in (files or [])]
41
 
42
- # Register CSVs
43
  registry = DataRegistry()
44
  for p in file_paths:
45
- try: registry.add_path(p)
46
- except Exception as e: log_event("ingest_error", None, {"file": p, "err": str(e)})
 
 
47
 
48
- # RAG ingest (safe on empty)
49
  rag = RAGIndex()
50
  ing = extract_text_from_files(file_paths)
51
  rag.add(ing.get("chunks", []))
52
 
 
53
  if is_healthcare_scenario(safe_in, bool(file_paths)) and USE_SCENARIO_ENGINE:
54
  analyzer = HealthcareAnalyzer(registry)
55
- datasets = analyzer.comprehensive_analysis(safe_in)
56
  catalog = _dataset_catalog(datasets)
57
 
58
- # LLM plan (no hardcoding)
59
  plan = parse_to_plan(safe_in, catalog)
60
 
61
- # Deterministic execution
62
  structured_md = ScenarioEngine.execute_plan(plan, datasets)
63
 
64
- # Narrative with Canadian grounding
65
  rag_hits = [txt for txt, _ in rag.retrieve(safe_in, k=6)]
66
  narrative = generate_narrative(safe_in, structured_md, rag_hits)
67
 
68
  final = f"{structured_md}\n\n# Narrative & Recommendations\n\n{narrative}"
69
  return history + [(user_msg, _sanitize_text(final))], ""
70
 
71
- # General conversation (Cohere primary, open-model fallback inside cohere_chat if needed)
72
  prompt = f"{GENERAL_CONVERSATION_PROMPT}\n\nUser: {safe_in}\nAssistant:"
73
- ans = cohere_chat(prompt) or "How can I help further?"
74
  return history + [(user_msg, _sanitize_text(ans))], ""
75
 
76
  except Exception as e:
@@ -78,10 +86,16 @@ def handle(user_msg: str, history: list, files: list) -> Tuple[list, str]:
78
  log_event("app_error", None, {"err": str(e), "tb": tb})
79
  return history + [(user_msg, f"Error: {e}\n\n{tb}")], ""
80
 
 
81
  with gr.Blocks(analytics_enabled=False) as demo:
82
  gr.Markdown("## Canadian Healthcare AI • Scenario-Agnostic (Cohere primary • Deterministic analytics)")
83
- chat = gr.Chatbot(type="tuple", height=520) # tuple mode (matches how we store history)
84
- files = gr.Files(file_count="multiple", type="filepath", file_types=HEALTHCARE_SETTINGS["supported_file_types"])
 
 
 
 
 
85
  msg = gr.Textbox(placeholder="Paste any scenario (Background / Situation / Tasks / Deliverables) or just chat.")
86
  send = gr.Button("Send")
87
  clear = gr.Button("Clear")
@@ -95,5 +109,5 @@ with gr.Blocks(analytics_enabled=False) as demo:
95
  clear.click(lambda: ([], ""), outputs=[chat, msg])
96
 
97
  if __name__ == "__main__":
 
98
  demo.launch(server_name="0.0.0.0", server_port=int(os.getenv("PORT", "7860")))
99
-
 
1
+ # app.py
2
  import os, traceback, regex as re2
3
  import gradio as gr
4
  import pandas as pd
5
+ from typing import List, Tuple, Dict, Any
6
 
7
  from settings import HEALTHCARE_SETTINGS, GENERAL_CONVERSATION_PROMPT, USE_SCENARIO_ENGINE
8
  from audit_log import log_event
 
13
  from scenario_planner import parse_to_plan
14
  from scenario_engine import ScenarioEngine
15
  from rag import RAGIndex
16
+ from llm_router import generate_narrative, cohere_chat, open_fallback_chat
17
 
18
  def _sanitize_text(s: str) -> str:
19
  if not isinstance(s, str): return s
20
+ # strip control chars (keep newlines/tabs)
21
  return re2.sub(r'[\p{C}--[\n\t]]+', '', s)
22
 
23
+ def _dataset_catalog(results: Dict[str, Any]) -> Dict[str, List[str]]:
24
+ """Expose available columns per dataset to the planner."""
25
+ cat: Dict[str, List[str]] = {}
26
  for k, v in results.items():
27
  if isinstance(v, pd.DataFrame):
28
  cat[k] = v.columns.tolist()
29
  return cat
30
 
31
  def is_healthcare_scenario(text: str, has_files: bool) -> bool:
32
+ """Heuristic: scenario mode when user provided files + scenario-ish text."""
33
  t = (text or "").lower()
34
  kws = HEALTHCARE_SETTINGS["healthcare_keywords"]
35
  structured = any(s in t for s in ["background", "situation", "tasks", "deliverables"])
 
38
  def handle(user_msg: str, history: list, files: list) -> Tuple[list, str]:
39
  try:
40
  safe_in, blocked_in, reason_in = safety_filter(user_msg, mode="input")
41
+ if blocked_in:
42
+ return history + [(user_msg, refusal_reply(reason_in))], ""
43
 
44
+ # Normalize files -> paths (safe when files is None)
45
  file_paths = [getattr(f, "name", None) or f for f in (files or [])]
46
 
47
+ # Register CSVs into the registry
48
  registry = DataRegistry()
49
  for p in file_paths:
50
+ try:
51
+ registry.add_path(p)
52
+ except Exception as e:
53
+ log_event("ingest_error", None, {"file": p, "err": str(e)})
54
 
55
+ # RAG ingest (best-effort, text only; safe on empty)
56
  rag = RAGIndex()
57
  ing = extract_text_from_files(file_paths)
58
  rag.add(ing.get("chunks", []))
59
 
60
+ # Scenario mode: plan -> deterministic execution -> narrative
61
  if is_healthcare_scenario(safe_in, bool(file_paths)) and USE_SCENARIO_ENGINE:
62
  analyzer = HealthcareAnalyzer(registry)
63
+ datasets = analyzer.comprehensive_analysis(safe_in) # expose dataframes by filename
64
  catalog = _dataset_catalog(datasets)
65
 
66
+ # 1) LLM parses scenario into a plan (scenario-agnostic, no hardcoding)
67
  plan = parse_to_plan(safe_in, catalog)
68
 
69
+ # 2) Deterministic execution of the plan (pandas-based)
70
  structured_md = ScenarioEngine.execute_plan(plan, datasets)
71
 
72
+ # 3) Canadian grounding + narrative (Cohere primary, open-model fallback)
73
  rag_hits = [txt for txt, _ in rag.retrieve(safe_in, k=6)]
74
  narrative = generate_narrative(safe_in, structured_md, rag_hits)
75
 
76
  final = f"{structured_md}\n\n# Narrative & Recommendations\n\n{narrative}"
77
  return history + [(user_msg, _sanitize_text(final))], ""
78
 
79
+ # General conversation mode (no scenario/files required)
80
  prompt = f"{GENERAL_CONVERSATION_PROMPT}\n\nUser: {safe_in}\nAssistant:"
81
+ ans = cohere_chat(prompt) or open_fallback_chat(prompt) or "How can I help further?"
82
  return history + [(user_msg, _sanitize_text(ans))], ""
83
 
84
  except Exception as e:
 
86
  log_event("app_error", None, {"err": str(e), "tb": tb})
87
  return history + [(user_msg, f"Error: {e}\n\n{tb}")], ""
88
 
89
+ # -------- UI --------
90
  with gr.Blocks(analytics_enabled=False) as demo:
91
  gr.Markdown("## Canadian Healthcare AI • Scenario-Agnostic (Cohere primary • Deterministic analytics)")
92
+ # tuple mode matches how we store history as (user, assistant)
93
+ chat = gr.Chatbot(type="tuple", height=520)
94
+ files = gr.Files(
95
+ file_count="multiple",
96
+ type="filepath",
97
+ file_types=HEALTHCARE_SETTINGS["supported_file_types"]
98
+ )
99
  msg = gr.Textbox(placeholder="Paste any scenario (Background / Situation / Tasks / Deliverables) or just chat.")
100
  send = gr.Button("Send")
101
  clear = gr.Button("Clear")
 
109
  clear.click(lambda: ([], ""), outputs=[chat, msg])
110
 
111
  if __name__ == "__main__":
112
+ # You can set share=True if you want a public link in dev.
113
  demo.launch(server_name="0.0.0.0", server_port=int(os.getenv("PORT", "7860")))