GeetaAIVisionary commited on
Commit
8dcaee5
·
verified ·
1 Parent(s): cccf139

Update app.py

Browse files

edited to fit for HF

Files changed (1) hide show
  1. app.py +33 -240
app.py CHANGED
@@ -1,243 +1,36 @@
1
- import csv
2
- from types import SimpleNamespace
3
- from nemoguardrails import LLMRails, RailsConfig
 
4
 
5
- # -----------------------------
6
- # Load CSV (ground-truth data)
7
- # -----------------------------
8
- words = []
9
- with open("words.csv", newline="", encoding="utf-8") as f:
10
- for row in csv.DictReader(f):
11
- try:
12
- row["difficulty"] = int(row.get("difficulty", 5))
13
- except Exception:
14
- row["difficulty"] = 5
15
- words.append(row)
16
 
17
- # sort hardest -> easiest
18
- words.sort(key=lambda r: r["difficulty"], reverse=True)
19
-
20
- ROUND_SIZE = 5
21
- state = {"index": 0, "in_round": 0, "current": None, "correct": 0}
22
-
23
-
24
- def _get_row(word: str):
25
- if not word:
26
- return None
27
- wl = word.strip().lower()
28
- for r in words:
29
- if r["word"].strip().lower() == wl:
30
- return r
31
- return None
32
-
33
-
34
- # -----------------------------
35
- # Actions (called from Colang v1)
36
- # -----------------------------
37
- def get_next_word():
38
- """Return next word for the round, or empty string if round finished."""
39
- if state["in_round"] >= ROUND_SIZE or state["index"] >= len(words):
40
- return ""
41
- w = words[state["index"]]["word"]
42
- state["current"] = w
43
- state["index"] += 1
44
- state["in_round"] += 1
45
- return w
46
-
47
-
48
- def get_current():
49
- """Return the current word (or empty string)."""
50
- return state.get("current") or ""
51
-
52
-
53
- def check_spelling(word, attempt):
54
- """Exact (case-insensitive) match check. Returns 'true' or 'false'."""
55
- ok = (attempt or "").strip().lower() == (word or "").strip().lower()
56
- if ok:
57
- state["correct"] += 1
58
- return "true" if ok else "false"
59
-
60
-
61
- def get_definition(word):
62
- r = _get_row(word)
63
- return r["definition"] if r and r.get("definition") else "No definition found."
64
-
65
-
66
- def get_origin(word):
67
- r = _get_row(word)
68
- return r["origin"] if r and r.get("origin") else "No origin found."
69
-
70
-
71
- def get_sentence(word):
72
- r = _get_row(word)
73
- return r["sentence"] if r and r.get("sentence") else "No example available."
74
-
75
-
76
- def get_progress():
77
- return f"Score this round: {state['correct']}/{state['in_round']}."
78
-
79
-
80
- # -----------------------------
81
- # Fully compatible Dummy LLM for NeMo Guardrails 0.15
82
- # -----------------------------
83
- class DummyLLM:
84
- """Return a LangChain-like LLMResult with generations + llm_output."""
85
- def __init__(self, text: str = ""):
86
- self._text = text
87
-
88
- def _result(self):
89
- gen = SimpleNamespace(text=self._text)
90
- # Guardrails expects these fields to exist
91
- return SimpleNamespace(generations=[[gen]], llm_output={})
92
-
93
- # async APIs Guardrails may use
94
- async def agenerate_prompt(self, *args, **kwargs):
95
- return self._result()
96
-
97
- async def agenerate(self, *args, **kwargs):
98
- return self._result()
99
-
100
- # sync fallbacks
101
- def generate_prompt(self, *args, **kwargs):
102
- return self._result()
103
-
104
- def generate(self, *args, **kwargs):
105
- return self._result()
106
-
107
-
108
- # -----------------------------
109
- # Wire up NeMo Guardrails (v1)
110
- # -----------------------------
111
- config = RailsConfig.from_path("rails")
112
- rails = LLMRails(config, llm=DummyLLM()) # keep everything offline
113
-
114
- for fn in [
115
- get_next_word,
116
- get_current,
117
- check_spelling,
118
- get_definition,
119
- get_origin,
120
- get_sentence,
121
- get_progress,
122
- ]:
123
- rails.register_action(fn)
124
-
125
-
126
- # -----------------------------
127
- # Response helpers
128
- # -----------------------------
129
- def extract_assistant_text(resp) -> str:
130
- """Try to pull assistant/bot text from various Guardrails return shapes."""
131
- if isinstance(resp, dict):
132
- # Common path
133
- if resp.get("content"):
134
- return resp["content"]
135
-
136
- # Messages list
137
- msgs = resp.get("messages") or resp.get("output", {}).get("messages", [])
138
- if isinstance(msgs, list) and msgs:
139
- parts = []
140
- for m in msgs:
141
- if isinstance(m, dict) and m.get("role") in ("assistant", "bot"):
142
- txt = m.get("content") or m.get("text") or ""
143
- if txt:
144
- parts.append(txt)
145
- if parts:
146
- return "\n".join(parts)
147
-
148
- # Some builds emit a single message-like dict
149
- if resp.get("role") in ("assistant", "bot") and resp.get("content"):
150
- return resp["content"]
151
-
152
- # Fallback
153
- return ""
154
-
155
-
156
- def run_local_engine(user: str) -> str:
157
- """Deterministic, no-LLM fallback that mirrors our flows."""
158
- u = (user or "").strip().lower()
159
-
160
- if u in ("start", "start quiz", "begin", "quiz me"):
161
- w = get_next_word()
162
- if not w:
163
- p = get_progress()
164
- return f"Round complete. {p}"
165
- return f"Okay! We'll do 5 words this round, hardest to easiest. Ready?\nSpell this word: {w}"
166
-
167
- if u == "definition":
168
- c = get_current()
169
- d = get_definition(c)
170
- return f"Definition: {d}"
171
-
172
- if u == "origin":
173
- c = get_current()
174
- o = get_origin(c)
175
- return f"Origin: {o}"
176
-
177
- if u == "sentence":
178
- c = get_current()
179
- s = get_sentence(c)
180
- return f"Example: {s}"
181
-
182
- if u == "next":
183
- n = get_next_word()
184
- if not n:
185
- p = get_progress()
186
- return f"Round complete. {p}"
187
- return f"Next word: {n}"
188
-
189
- if u in ("stop", "end", "finish"):
190
- p = get_progress()
191
- return f"Stopping the quiz. {p}"
192
-
193
- # Otherwise treat as spelling attempt
194
- c = get_current()
195
- if not c:
196
- # If user types a word before starting
197
- w = get_next_word()
198
- if not w:
199
- p = get_progress()
200
- return f"Round complete. {p}"
201
- # Re-run attempt logic on new word
202
- c = w
203
-
204
- ok = check_spelling(c, user)
205
- if ok == "true":
206
- n = get_next_word()
207
- if not n:
208
- p = get_progress()
209
- return f"✅ Correct!\nRound complete. {p}"
210
- return f"✅ Correct!\nNext word: {n}"
211
- else:
212
- return "❌ Not quite. Try again or ask for definition/origin/sentence."
213
-
214
-
215
- # -----------------------------
216
- # Tiny CLI loop
217
- # -----------------------------
218
- print(
219
- "Type: 'start' (or 'start quiz'), then 'definition'/'origin'/'sentence', "
220
- "type your spelling attempt, 'next', or 'stop'."
221
- )
222
-
223
- while True:
224
- user_in = input("You: ").strip()
225
- if not user_in:
226
- continue
227
-
228
- # Try Guardrails first
229
  try:
230
- resp = rails.generate(messages=[{"role": "user", "content": user_in}])
231
- tutor_text = extract_assistant_text(resp)
232
- except Exception:
233
- tutor_text = ""
234
-
235
- # Fallback to our local engine if Guardrails produced nothing visible
236
- if not tutor_text:
237
- tutor_text = run_local_engine(user_in)
238
-
239
- print("Tutor:", tutor_text or "[no response]")
240
-
241
- if ("Round complete" in tutor_text) or ("Stopping the quiz" in tutor_text):
242
- break
243
-
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+ import gradio as gr
3
+ import pandas as pd
4
+ from pathlib import Path
5
 
6
+ WORDS_PATH = Path("words.csv")
 
 
 
 
 
 
 
 
 
 
7
 
8
+ def lookup(prefix: str):
9
+ if not WORDS_PATH.exists():
10
+ return "words.csv not found in repo."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  try:
12
+ df = pd.read_csv(WORDS_PATH)
13
+ except Exception as e:
14
+ return f"Failed to read words.csv: {e}"
15
+
16
+ # Expecting a column named 'word'. Fallback to first column if not present.
17
+ col = "word" if "word" in df.columns else df.columns[0]
18
+ s = df[col].astype(str)
19
+
20
+ prefix = (prefix or "").strip()
21
+ if not prefix:
22
+ return "Type a prefix to see matches."
23
+
24
+ matches = s[s.str.lower().str.startswith(prefix.lower())].head(20)
25
+ if matches.empty:
26
+ return "No matches."
27
+ return "\n".join(matches.tolist())
28
+
29
+ with gr.Blocks() as demo:
30
+ gr.Markdown("# NeMo Guardrails Demo (starter UI)\nType a prefix to see matching words from **words.csv**.")
31
+ inp = gr.Textbox(label="Prefix")
32
+ out = gr.Textbox(label="Matches", lines=12)
33
+ inp.change(fn=lookup, inputs=inp, outputs=out)
34
+
35
+ if __name__ == "__main__":
36
+ demo.launch()