HemanM commited on
Commit
8c4d10e
·
verified ·
1 Parent(s): ffe2489

Update evo_inference.py

Browse files
Files changed (1) hide show
  1. evo_inference.py +91 -36
evo_inference.py CHANGED
@@ -1,25 +1,19 @@
1
  """
2
- evo_inference.py — Step 8 (refined)
3
- Adds a GENERATIVE path using a small plugin (FLAN-T5 stand-in) while keeping the
4
- old EXTRACTIVE fallback (bullet points) if generation isn't available.
5
-
6
- What's new in this refinement:
7
- - Answers are explicitly labeled **[Generative]** or **[Extractive]** so you
8
- can tell which path ran at a glance.
9
-
10
- How it works:
11
- - We try to import your real evo plugin (evo_plugin.py). If not found, we load
12
- evo_plugin_example.py instead. If both fail, we stay in extractive mode.
13
- - synthesize_with_evo(...) accepts mode/temp/max_tokens from the UI.
14
  """
15
 
16
  from typing import List, Dict
 
17
  from utils_lang import L, normalize_lang
18
 
19
  # Try to load your real Evo plugin first; else use the example; else None.
20
  _GENERATOR = None
21
  try:
22
- from evo_plugin import load_model as _load_real # <- your future file (optional)
23
  _GENERATOR = _load_real()
24
  except Exception:
25
  try:
@@ -72,27 +66,90 @@ def _extractive_answer(user_query: str, lang: str, hits: List[Dict]) -> str:
72
  )
73
 
74
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  def _build_grounded_prompt(question: str, lang: str, hits: List[Dict]) -> str:
76
- """Create a compact prompt that includes the question + top retrieved snippets."""
 
 
 
 
 
 
 
 
77
  lang = normalize_lang(lang)
 
 
 
 
 
 
 
 
78
  if lang == "fr":
79
- system = ("Tu es le Copilote Gouvernemental de Maurice. Réponds clairement, étape "
80
- "par étape, en te basant UNIQUEMENT sur le contexte. Inclure: documents requis, "
81
- "frais, postuler, délais. Dire si une info manque.")
 
 
 
82
  elif lang == "mfe":
83
- system = ("To enn Copilot Gouv Moris. Reponn kler ek pas-a-pas, servi zis konteks ki donn. "
84
- "Met: ki dokiman bizin, fre, kot pou al, delai. Dir si info manke.")
85
- else:
86
- system = ("You are the Mauritius Government Copilot. Answer clearly and step-by-step using "
87
- "ONLY the provided context. Include: required documents, fees, where to apply, "
88
- "processing time. State if anything is missing.")
89
-
90
- ctx = "\n".join([f"[Context #{i+1}] {_snippet(h['text'])}" for i, h in enumerate(hits[:6])]) or "[Context] (none)"
91
- return (
92
- f"{system}\n\n[Question]\n{question}\n\n{ctx}\n\n"
93
- f"[Instructions]\n- Be concise (6–10 lines)\n- Use bullet steps\n"
94
- f"- Do not invent links/fees\n- Answer in language code: {lang}\n[Answer]\n"
 
 
 
 
95
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
 
98
  def synthesize_with_evo(
@@ -105,7 +162,7 @@ def synthesize_with_evo(
105
  ) -> str:
106
  """
107
  If mode=='generative' and a generator exists, generate a grounded answer
108
- and label it **[Generative]**. Otherwise, return the labeled extractive fallback.
109
  """
110
  lang = normalize_lang(lang)
111
 
@@ -122,13 +179,11 @@ def synthesize_with_evo(
122
  prompt,
123
  max_new_tokens=int(max_new_tokens),
124
  temperature=float(temperature),
125
- ).strip()
126
-
127
- if not text:
 
128
  return _extractive_answer(user_query, lang, hits)
129
-
130
  return "**[Generative]**\n\n" + text
131
-
132
  except Exception:
133
- # Any runtime issue falls back to safe mode
134
  return _extractive_answer(user_query, lang, hits)
 
1
  """
2
+ evo_inference.py — Step 8 (FLAN-optimized)
3
+ - Generative path uses a FLAN-friendly prompt: Instruction / Context / Question / Answer
4
+ - Filters placeholder chunks
5
+ - Cleans common prompt-echo lines
6
+ - Keeps labeled [Generative] / [Extractive] outputs with safe fallback
 
 
 
 
 
 
 
7
  """
8
 
9
  from typing import List, Dict
10
+ import re
11
  from utils_lang import L, normalize_lang
12
 
13
  # Try to load your real Evo plugin first; else use the example; else None.
14
  _GENERATOR = None
15
  try:
16
+ from evo_plugin import load_model as _load_real # your future file (optional)
17
  _GENERATOR = _load_real()
18
  except Exception:
19
  try:
 
66
  )
67
 
68
 
69
+ def _lang_name(code: str) -> str:
70
+ return {"en": "English", "fr": "French", "mfe": "Kreol Morisien"}.get(code, "English")
71
+
72
+
73
+ def _filter_hits(hits: List[Dict], keep: int = 6) -> List[Dict]:
74
+ """
75
+ Prefer non-placeholder chunks; if all are placeholders, return originals.
76
+ """
77
+ filtered = [
78
+ h for h in hits
79
+ if "placeholder" not in h["text"].lower() and "disclaimer" not in h["text"].lower()
80
+ ]
81
+ if not filtered:
82
+ filtered = hits
83
+ return filtered[:keep]
84
+
85
+
86
  def _build_grounded_prompt(question: str, lang: str, hits: List[Dict]) -> str:
87
+ """
88
+ FLAN-style prompt:
89
+ Instruction: ...
90
+ Context:
91
+ 1) ...
92
+ 2) ...
93
+ Question: ...
94
+ Answer:
95
+ """
96
  lang = normalize_lang(lang)
97
+ lang_readable = _lang_name(lang)
98
+
99
+ instruction = (
100
+ "You are the Mauritius Government Copilot. Answer ONLY using the provided context. "
101
+ "If a detail is missing (fees, required docs, office or processing time), say so clearly. "
102
+ "Structure the answer as short bullet points with: Required documents, Fees, Where to apply, "
103
+ "Processing time, and Steps. Keep it concise (6–10 lines)."
104
+ )
105
  if lang == "fr":
106
+ instruction = (
107
+ "Tu es le Copilote Gouvernemental de Maurice. Réponds UNIQUEMENT à partir du contexte fourni. "
108
+ "Si une information manque (frais, documents requis, bureau ou délai), dis-le clairement. "
109
+ "Structure en puces courtes : Documents requis, Frais, Où postuler, Délai de traitement, Étapes. "
110
+ "Reste concis (6–10 lignes)."
111
+ )
112
  elif lang == "mfe":
113
+ instruction = (
114
+ "To enn Copilot Gouv Moris. Reponn zis lor konteks ki donn. "
115
+ "Si enn detay manke (fre, dokiman, biro, letan tretman), dir li kler. "
116
+ "Servi pwen kout: Dokiman, Fre, Kot pou al, Letan tretman, Steps. "
117
+ "Reste kout (6–10 ligner)."
118
+ )
119
+
120
+ chosen = _filter_hits(hits, keep=6)
121
+ ctx_lines = [f"{i+1}) {_snippet(h['text'])}" for i, h in enumerate(chosen)]
122
+ ctx_block = "\n".join(ctx_lines) if ctx_lines else "(none)"
123
+
124
+ prompt = (
125
+ f"Instruction ({lang_readable}): {instruction}\n\n"
126
+ f"Context:\n{ctx_block}\n\n"
127
+ f"Question: {question}\n\n"
128
+ f"Answer ({lang_readable}):"
129
  )
130
+ return prompt
131
+
132
+
133
+ _ECHO_PATTERNS = [
134
+ r"^\s*Instruction.*$", r"^\s*Context:.*$", r"^\s*Question:.*$", r"^\s*Answer.*$",
135
+ r"^\s*\[Instructions?\].*$", r"^\s*Be concise.*$", r"^\s*Do not invent.*$",
136
+ r"^\s*(en|fr|mfe)\s*$",
137
+ ]
138
+
139
+ def _clean_generated(text: str) -> str:
140
+ """
141
+ Remove common echoed lines from the model output.
142
+ """
143
+ lines = [ln.strip() for ln in text.strip().splitlines()]
144
+ out = []
145
+ for ln in lines:
146
+ if any(re.match(pat, ln, flags=re.IGNORECASE) for pat in _ECHO_PATTERNS):
147
+ continue
148
+ out.append(ln)
149
+ cleaned = "\n".join(out).strip()
150
+ # extra guard: collapse repeated blank lines
151
+ cleaned = re.sub(r"\n{3,}", "\n\n", cleaned)
152
+ return cleaned
153
 
154
 
155
  def synthesize_with_evo(
 
162
  ) -> str:
163
  """
164
  If mode=='generative' and a generator exists, generate a grounded answer
165
+ (labeled [Generative]). Otherwise, return the labeled extractive fallback.
166
  """
167
  lang = normalize_lang(lang)
168
 
 
179
  prompt,
180
  max_new_tokens=int(max_new_tokens),
181
  temperature=float(temperature),
182
+ )
183
+ text = _clean_generated(text)
184
+ # Fallback if empty or suspiciously short
185
+ if not text or len(text) < 20:
186
  return _extractive_answer(user_query, lang, hits)
 
187
  return "**[Generative]**\n\n" + text
 
188
  except Exception:
 
189
  return _extractive_answer(user_query, lang, hits)