Spaces:
Sleeping
Sleeping
Create evo_inference.py
Browse files- evo_inference.py +40 -93
evo_inference.py
CHANGED
@@ -1,96 +1,40 @@
|
|
1 |
"""
|
2 |
-
evo_inference.py
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
-
|
8 |
-
|
9 |
-
|
10 |
-
a) calls the generator (generative mode), or
|
11 |
-
b) returns a clean extractive answer (safe mode).
|
12 |
"""
|
13 |
|
14 |
-
from typing import List, Dict
|
15 |
from utils_lang import L, normalize_lang
|
16 |
|
17 |
-
# Try to load your real Evo plugin first; else example
|
18 |
_GENERATOR = None
|
19 |
try:
|
20 |
-
from evo_plugin import load_model as _load_real
|
21 |
_GENERATOR = _load_real()
|
22 |
except Exception:
|
23 |
try:
|
24 |
from evo_plugin_example import load_model as _load_example
|
25 |
_GENERATOR = _load_example()
|
26 |
except Exception:
|
27 |
-
_GENERATOR = None #
|
28 |
-
|
29 |
-
MAX_SNIPPET_CHARS = 400 # (Objective) keep context concise
|
30 |
|
|
|
31 |
|
32 |
def _snippet(text: str) -> str:
|
33 |
text = " ".join(text.split())
|
34 |
return text[:MAX_SNIPPET_CHARS] + ("..." if len(text) > MAX_SNIPPET_CHARS else "")
|
35 |
|
36 |
-
|
37 |
-
def _build_grounded_prompt(question: str, lang: str, hits: List[Dict]) -> str:
|
38 |
-
"""
|
39 |
-
(Objective) Construct a compact prompt that includes:
|
40 |
-
- role + response style instruction (language-aware),
|
41 |
-
- the user's question,
|
42 |
-
- the top retrieved chunks as "Context #i".
|
43 |
-
"""
|
44 |
-
lang = normalize_lang(lang)
|
45 |
-
if lang == "fr":
|
46 |
-
system = (
|
47 |
-
"Tu es le Copilote Gouvernemental de Maurice. Réponds dans la langue demandée, "
|
48 |
-
"clairement et étape par étape, en te basant STRICTEMENT sur le contexte. "
|
49 |
-
"Inclure: documents requis, frais, où postuler, délais. Si une info manque, dis-le."
|
50 |
-
)
|
51 |
-
elif lang == "mfe":
|
52 |
-
system = (
|
53 |
-
"To enn Copilot Gouv Moris. Reponn dan langaz itilizater, kler ek pas-a-pas, "
|
54 |
-
"bas lor KI SUIVAN. Met: ki dokiman bizin, fre, kot pou al, delai. "
|
55 |
-
"Si pa ase info, dir li."
|
56 |
-
)
|
57 |
-
else:
|
58 |
-
system = (
|
59 |
-
"You are the Mauritius Government Copilot. Answer in the user's language, "
|
60 |
-
"clearly and step-by-step, using ONLY the provided context. Include: required documents, "
|
61 |
-
"fees, where to apply, processing time. If something is missing, say so."
|
62 |
-
)
|
63 |
-
|
64 |
-
ctx_lines = []
|
65 |
-
for i, h in enumerate(hits[:6], 1):
|
66 |
-
ctx_lines.append(f"[Context #{i}] { _snippet(h['text']) }")
|
67 |
-
|
68 |
-
ctx_block = "\n".join(ctx_lines) if ctx_lines else "[Context] (none)"
|
69 |
-
prompt = (
|
70 |
-
f"{system}\n\n"
|
71 |
-
f"[Question]\n{question}\n\n"
|
72 |
-
f"{ctx_block}\n\n"
|
73 |
-
f"[Instructions]\n"
|
74 |
-
f"- Be concise (6–10 lines).\n"
|
75 |
-
f"- Use bullet steps.\n"
|
76 |
-
f"- Do not invent links or fees; mention if unknown.\n"
|
77 |
-
f"- Answer in language code: {lang}.\n"
|
78 |
-
f"[Answer]\n"
|
79 |
-
)
|
80 |
-
return prompt
|
81 |
-
|
82 |
-
|
83 |
def _extractive_answer(user_query: str, lang: str, hits: List[Dict]) -> str:
|
84 |
-
"""
|
85 |
-
(Objective) The safe fallback: bullet points from hits + standard steps.
|
86 |
-
"""
|
87 |
if not hits:
|
88 |
return L(lang, "intro_err")
|
89 |
-
|
90 |
-
bullets = []
|
91 |
-
for h in hits[:4]:
|
92 |
-
bullets.append(f"- {_snippet(h['text'])}")
|
93 |
-
|
94 |
steps = {
|
95 |
"en": [
|
96 |
"• Step 1: Check eligibility & gather required documents.",
|
@@ -111,46 +55,49 @@ def _extractive_answer(user_query: str, lang: str, hits: List[Dict]) -> str:
|
|
111 |
"• Step 4: Gard referans/reso; swiv letan tretman.",
|
112 |
],
|
113 |
}[normalize_lang(lang)]
|
114 |
-
|
115 |
-
md = (
|
116 |
f"**{L(lang, 'intro_ok')}**\n\n"
|
117 |
f"**Q:** {user_query}\n\n"
|
118 |
f"**Key information:**\n" + "\n".join(bullets) + "\n\n"
|
119 |
f"**Suggested steps:**\n" + "\n".join(steps)
|
120 |
)
|
121 |
-
return md
|
122 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
123 |
|
124 |
def synthesize_with_evo(
|
125 |
user_query: str,
|
126 |
lang: str,
|
127 |
hits: List[Dict],
|
128 |
-
mode: str = "extractive",
|
129 |
max_new_tokens: int = 192,
|
130 |
temperature: float = 0.4,
|
131 |
) -> str:
|
132 |
-
"""
|
133 |
-
(Objective)
|
134 |
-
- If mode == 'generative' and a generator is available, build a grounded prompt and generate.
|
135 |
-
- Else, return the safe extractive answer.
|
136 |
-
"""
|
137 |
lang = normalize_lang(lang)
|
138 |
-
|
139 |
if mode != "generative" or _GENERATOR is None:
|
140 |
return _extractive_answer(user_query, lang, hits)
|
141 |
-
|
142 |
prompt = _build_grounded_prompt(user_query, lang, hits)
|
143 |
try:
|
144 |
-
text = _GENERATOR.generate(
|
145 |
-
|
146 |
-
max_new_tokens=int(max_new_tokens),
|
147 |
-
temperature=float(temperature),
|
148 |
-
)
|
149 |
-
# In case the generator echos or misses structure, still return something readable
|
150 |
-
text = text.strip()
|
151 |
-
if not text:
|
152 |
-
return _extractive_answer(user_query, lang, hits)
|
153 |
-
return text
|
154 |
except Exception:
|
155 |
-
# Any runtime issue falls back to safe mode
|
156 |
return _extractive_answer(user_query, lang, hits)
|
|
|
1 |
"""
|
2 |
+
evo_inference.py — Step 8
|
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 |
+
How it works:
|
7 |
+
- We try to import your real evo plugin (evo_plugin.py). If not found, we load
|
8 |
+
evo_plugin_example.py instead. If both fail, we stay in extractive mode.
|
9 |
+
- synthesize_with_evo(...) now accepts mode/temp/max_tokens from the UI.
|
|
|
|
|
10 |
"""
|
11 |
|
12 |
+
from typing import List, Dict
|
13 |
from utils_lang import L, normalize_lang
|
14 |
|
15 |
+
# Try to load your real Evo plugin first; else use the example; else None.
|
16 |
_GENERATOR = None
|
17 |
try:
|
18 |
+
from evo_plugin import load_model as _load_real # <- your future file (optional)
|
19 |
_GENERATOR = _load_real()
|
20 |
except Exception:
|
21 |
try:
|
22 |
from evo_plugin_example import load_model as _load_example
|
23 |
_GENERATOR = _load_example()
|
24 |
except Exception:
|
25 |
+
_GENERATOR = None # no generator available
|
|
|
|
|
26 |
|
27 |
+
MAX_SNIPPET_CHARS = 400
|
28 |
|
29 |
def _snippet(text: str) -> str:
|
30 |
text = " ".join(text.split())
|
31 |
return text[:MAX_SNIPPET_CHARS] + ("..." if len(text) > MAX_SNIPPET_CHARS else "")
|
32 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
def _extractive_answer(user_query: str, lang: str, hits: List[Dict]) -> str:
|
34 |
+
"""Old safe mode: show top snippets + standard steps."""
|
|
|
|
|
35 |
if not hits:
|
36 |
return L(lang, "intro_err")
|
37 |
+
bullets = [f"- {_snippet(h['text'])}" for h in hits[:4]]
|
|
|
|
|
|
|
|
|
38 |
steps = {
|
39 |
"en": [
|
40 |
"• Step 1: Check eligibility & gather required documents.",
|
|
|
55 |
"• Step 4: Gard referans/reso; swiv letan tretman.",
|
56 |
],
|
57 |
}[normalize_lang(lang)]
|
58 |
+
return (
|
|
|
59 |
f"**{L(lang, 'intro_ok')}**\n\n"
|
60 |
f"**Q:** {user_query}\n\n"
|
61 |
f"**Key information:**\n" + "\n".join(bullets) + "\n\n"
|
62 |
f"**Suggested steps:**\n" + "\n".join(steps)
|
63 |
)
|
|
|
64 |
|
65 |
+
def _build_grounded_prompt(question: str, lang: str, hits: List[Dict]) -> str:
|
66 |
+
"""Create a compact prompt that includes the question + top retrieved snippets."""
|
67 |
+
lang = normalize_lang(lang)
|
68 |
+
if lang == "fr":
|
69 |
+
system = ("Tu es le Copilote Gouvernemental de Maurice. Réponds clairement, étape "
|
70 |
+
"par étape, en te basant UNIQUEMENT sur le contexte. Inclure: documents requis, "
|
71 |
+
"frais, où postuler, délais. Dire si une info manque.")
|
72 |
+
elif lang == "mfe":
|
73 |
+
system = ("To enn Copilot Gouv Moris. Reponn kler ek pas-a-pas, servi zis konteks ki donn. "
|
74 |
+
"Met: ki dokiman bizin, fre, kot pou al, delai. Dir si info manke.")
|
75 |
+
else:
|
76 |
+
system = ("You are the Mauritius Government Copilot. Answer clearly and step-by-step using "
|
77 |
+
"ONLY the provided context. Include: required documents, fees, where to apply, "
|
78 |
+
"processing time. State if anything is missing.")
|
79 |
+
ctx = "\n".join([f"[Context #{i+1}] {_snippet(h['text'])}" for i, h in enumerate(hits[:6])]) or "[Context] (none)"
|
80 |
+
return (
|
81 |
+
f"{system}\n\n[Question]\n{question}\n\n{ctx}\n\n"
|
82 |
+
f"[Instructions]\n- Be concise (6–10 lines)\n- Use bullet steps\n"
|
83 |
+
f"- Do not invent links/fees\n- Answer in language code: {lang}\n[Answer]\n"
|
84 |
+
)
|
85 |
|
86 |
def synthesize_with_evo(
|
87 |
user_query: str,
|
88 |
lang: str,
|
89 |
hits: List[Dict],
|
90 |
+
mode: str = "extractive",
|
91 |
max_new_tokens: int = 192,
|
92 |
temperature: float = 0.4,
|
93 |
) -> str:
|
94 |
+
"""If mode=='generative' and a generator exists, generate; else use extractive fallback."""
|
|
|
|
|
|
|
|
|
95 |
lang = normalize_lang(lang)
|
|
|
96 |
if mode != "generative" or _GENERATOR is None:
|
97 |
return _extractive_answer(user_query, lang, hits)
|
|
|
98 |
prompt = _build_grounded_prompt(user_query, lang, hits)
|
99 |
try:
|
100 |
+
text = _GENERATOR.generate(prompt, max_new_tokens=int(max_new_tokens), temperature=float(temperature))
|
101 |
+
return text.strip() or _extractive_answer(user_query, lang, hits)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
except Exception:
|
|
|
103 |
return _extractive_answer(user_query, lang, hits)
|