HemanM commited on
Commit
ced2a62
·
verified ·
1 Parent(s): 02be56c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +108 -23
app.py CHANGED
@@ -1,24 +1,36 @@
1
  """
2
  app.py
3
- Step 5: Language selector + Evo synthesis hook.
4
 
5
- What changed (Objective):
6
- - Added a language dropdown (EN/FR/Kreol)
7
- - Now we call `synthesize_with_evo()` to build the answer
8
- - Localized labels via utils_lang.L()
9
  """
10
 
 
 
 
 
11
  import gradio as gr
 
12
  from indexer import build_index
13
- from rag_search import RAGSearcher, format_sources
 
 
 
 
 
 
14
  from evo_inference import synthesize_with_evo
15
  from utils_lang import SUPPORTED, normalize_lang, L
16
 
17
- _searcher = None # (Objective) Lazy global searcher
 
 
18
 
19
 
20
  def ensure_searcher():
21
- """(Objective) Create the global RAGSearcher if needed."""
22
  global _searcher
23
  if _searcher is None:
24
  _searcher = RAGSearcher()
@@ -26,53 +38,116 @@ def ensure_searcher():
26
 
27
 
28
  def on_build_index():
29
- """(Objective) Build FAISS index, reset the searcher."""
30
  try:
31
  msg = build_index()
32
  global _searcher
33
- _searcher = None # force reload with fresh index
34
  except Exception as e:
35
  msg = f"Error while building index: {e}"
36
  return msg
37
 
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  def on_ask(question: str, top_k: int, lang_code: str, history: list):
40
  """
41
- (Objective) Handle user question:
42
- - ensure index
43
- - retrieve top-k hits
44
- - synthesize Evo-style answer (templated for now)
45
- - show localized Sources label
 
46
  """
47
  lang = normalize_lang(lang_code)
48
  if not question or len(question.strip()) < 3:
49
- return history, L(lang, "intro_err"), f"{L(lang, 'sources')}: (none)"
50
 
51
  try:
52
  searcher = ensure_searcher()
53
  hits = searcher.search(question, k=int(top_k))
54
  answer = synthesize_with_evo(question, lang, hits)
 
 
55
  srcs = format_sources(hits)
56
- # Localize the "Sources" header by replacing it if needed
57
  if srcs.startswith("Sources:"):
58
  srcs = srcs.replace("Sources:", f"{L(lang, 'sources')}:")
 
 
 
 
 
 
 
59
  except Exception as e:
60
  answer = f"Error: {e}\n\n{L(lang, 'tip_build')}"
61
  srcs = f"{L(lang, 'sources')}: (none)"
 
 
62
 
63
  history = history + [(question, answer)]
64
- return history, answer, srcs
65
 
66
 
67
  with gr.Blocks(title=L("en", "title")) as demo:
68
- # Note: We render static English title in metadata; inside the page we localize fully.
69
- gr.Markdown(f"# 🇲🇺 **{L('en','title')}** — Step 5")
70
 
 
71
  with gr.Row():
72
  build_btn = gr.Button(L("en", "build_btn"))
73
  status = gr.Markdown(L("en", "status_idle"))
74
  build_btn.click(fn=on_build_index, outputs=status)
75
 
 
 
 
 
 
 
 
76
  gr.Markdown("### Language / Langue / Langaz")
77
  lang = gr.Dropdown(choices=list(SUPPORTED.keys()), value="en", label="EN / FR / MFE")
78
 
@@ -85,8 +160,18 @@ with gr.Blocks(title=L("en", "title")) as demo:
85
  chat = gr.Chatbot(label="Assistant", height=360)
86
  answer_md = gr.Markdown()
87
  sources_md = gr.Markdown()
88
-
89
- ask_btn.click(fn=on_ask, inputs=[q, k, lang, chat], outputs=[chat, answer_md, sources_md])
90
- q.submit(fn=on_ask, inputs=[q, k, lang, chat], outputs=[chat, answer_md, sources_md])
 
 
 
 
 
 
 
 
 
 
91
 
92
  demo.launch()
 
1
  """
2
  app.py
3
+ Step 6: Add official links & forms display + Admin upload (TXT) with auto-reindex.
4
 
5
+ New in Step 6 (Objective):
6
+ - After answering, we extract URLs from retrieved chunks, split "forms", and show both as clickable lists.
7
+ - Admin can upload new TXT files from the UI; we save them to data/seed/ and rebuild the index automatically.
 
8
  """
9
 
10
+ import os
11
+ from pathlib import Path
12
+ from typing import List
13
+
14
  import gradio as gr
15
+
16
  from indexer import build_index
17
+ from rag_search import (
18
+ RAGSearcher,
19
+ format_sources,
20
+ extract_links,
21
+ split_form_links,
22
+ links_markdown,
23
+ )
24
  from evo_inference import synthesize_with_evo
25
  from utils_lang import SUPPORTED, normalize_lang, L
26
 
27
+ # Global (Objective) lazy searcher instance
28
+ _searcher = None
29
+ DATA_SEED_DIR = Path("data/seed")
30
 
31
 
32
  def ensure_searcher():
33
+ """(Objective) Create/return a global RAGSearcher bound to the current index."""
34
  global _searcher
35
  if _searcher is None:
36
  _searcher = RAGSearcher()
 
38
 
39
 
40
  def on_build_index():
41
+ """(Objective) Build FAISS index, reset searcher so it reloads next query."""
42
  try:
43
  msg = build_index()
44
  global _searcher
45
+ _searcher = None
46
  except Exception as e:
47
  msg = f"Error while building index: {e}"
48
  return msg
49
 
50
 
51
+ def save_uploaded_txt(files: List[gr.File]) -> List[str]:
52
+ """
53
+ (Objective) Save uploaded .txt files into data/seed/.
54
+ Gradio may pass objects with .name or file paths as strings; support both.
55
+ Returns a list of saved filenames.
56
+ """
57
+ saved = []
58
+ DATA_SEED_DIR.mkdir(parents=True, exist_ok=True)
59
+ if not files:
60
+ return saved
61
+
62
+ for f in files:
63
+ try:
64
+ # Handle both dict-like and path-like objects gracefully
65
+ path = getattr(f, "name", None) or (f if isinstance(f, str) else None)
66
+ # Some gradio versions pass dicts with 'name'
67
+ if isinstance(f, dict) and "name" in f:
68
+ path = f["name"]
69
+ if not path:
70
+ continue
71
+ # Read bytes and write to seed folder using the base filename
72
+ src = Path(path)
73
+ if src.suffix.lower() != ".txt":
74
+ continue # Only .txt for this step
75
+ content = Path(path).read_bytes()
76
+ dest = DATA_SEED_DIR / src.name
77
+ dest.write_bytes(content)
78
+ saved.append(src.name)
79
+ except Exception:
80
+ # Skip problematic files silently for robustness
81
+ continue
82
+ return saved
83
+
84
+
85
+ def on_upload_and_reindex(files) -> str:
86
+ """
87
+ (Objective) Save uploaded .txt files and rebuild the index immediately.
88
+ """
89
+ saved = save_uploaded_txt(files or [])
90
+ if not saved:
91
+ return "No valid .txt uploaded."
92
+ status = on_build_index()
93
+ return f"Uploaded: {', '.join(saved)}\n{status}"
94
+
95
+
96
  def on_ask(question: str, top_k: int, lang_code: str, history: list):
97
  """
98
+ (Objective) Handle user question end-to-end:
99
+ - Ensure index exists
100
+ - Retrieve top-k hits
101
+ - Synthesize grounded answer (templated Evo)
102
+ - Extract and render links & forms
103
+ - Append to chat history
104
  """
105
  lang = normalize_lang(lang_code)
106
  if not question or len(question.strip()) < 3:
107
+ return history, L(lang, "intro_err"), f"{L(lang, 'sources')}: (none)", "", ""
108
 
109
  try:
110
  searcher = ensure_searcher()
111
  hits = searcher.search(question, k=int(top_k))
112
  answer = synthesize_with_evo(question, lang, hits)
113
+
114
+ # Sources (localized header)
115
  srcs = format_sources(hits)
 
116
  if srcs.startswith("Sources:"):
117
  srcs = srcs.replace("Sources:", f"{L(lang, 'sources')}:")
118
+
119
+ # Links & Forms
120
+ all_links = extract_links(hits)
121
+ form_links, other_links = split_form_links(all_links)
122
+ links_md = links_markdown(L(lang, "links"), other_links)
123
+ forms_md = links_markdown(L(lang, "forms"), form_links)
124
+
125
  except Exception as e:
126
  answer = f"Error: {e}\n\n{L(lang, 'tip_build')}"
127
  srcs = f"{L(lang, 'sources')}: (none)"
128
+ links_md = f"**{L(lang, 'links')}:** (none)"
129
+ forms_md = f"**{L(lang, 'forms')}:** (none)"
130
 
131
  history = history + [(question, answer)]
132
+ return history, answer, srcs, links_md, forms_md
133
 
134
 
135
  with gr.Blocks(title=L("en", "title")) as demo:
136
+ gr.Markdown(f"# 🇲🇺 **{L('en','title')}** Step 6")
 
137
 
138
+ # --- Admin controls
139
  with gr.Row():
140
  build_btn = gr.Button(L("en", "build_btn"))
141
  status = gr.Markdown(L("en", "status_idle"))
142
  build_btn.click(fn=on_build_index, outputs=status)
143
 
144
+ with gr.Accordion("Admin: upload TXT and auto-reindex", open=False):
145
+ upload = gr.File(file_count="multiple", file_types=["text"], label="Upload .txt files")
146
+ save_btn = gr.Button("Save & Reindex")
147
+ upload_status = gr.Markdown()
148
+ save_btn.click(fn=on_upload_and_reindex, inputs=upload, outputs=upload_status)
149
+
150
+ # --- User Q&A
151
  gr.Markdown("### Language / Langue / Langaz")
152
  lang = gr.Dropdown(choices=list(SUPPORTED.keys()), value="en", label="EN / FR / MFE")
153
 
 
160
  chat = gr.Chatbot(label="Assistant", height=360)
161
  answer_md = gr.Markdown()
162
  sources_md = gr.Markdown()
163
+ links_md = gr.Markdown()
164
+ forms_md = gr.Markdown()
165
+
166
+ ask_btn.click(
167
+ fn=on_ask,
168
+ inputs=[q, k, lang, chat],
169
+ outputs=[chat, answer_md, sources_md, links_md, forms_md],
170
+ )
171
+ q.submit(
172
+ fn=on_ask,
173
+ inputs=[q, k, lang, chat],
174
+ outputs=[chat, answer_md, sources_md, links_md, forms_md],
175
+ )
176
 
177
  demo.launch()