KwabsHug commited on
Commit
d7698a8
·
verified ·
1 Parent(s): 68e53d2

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +226 -0
app.py ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ NWFWO Practice – Gradio MCP app for ChatGPT
3
+
4
+ This file does two things:
5
+ 1) Runs a normal Gradio web app (for debugging in your browser)
6
+ 2) Exposes an MCP server + HTML UI card for ChatGPT Apps
7
+ """
8
+
9
+ import gradio as gr
10
+ from dataclasses import dataclass
11
+
12
+
13
+ # ---- 1. Data model for the “game state” ----
14
+
15
+ @dataclass
16
+ class NWFWOExample:
17
+ # A short scenario or sentence in the foreign language (transliterated)
18
+ transliteration: str
19
+ # The correct NWFWO answer (what the learner should guess)
20
+ correct_nwfwo: str
21
+ # Optional: explanation to show after checking
22
+ explanation: str | None = None
23
+
24
+
25
+ # ---- 2. Core tool logic: check the learner’s guess ----
26
+
27
+ @gr.mcp.tool() # this exposes the function as an MCP tool to ChatGPT
28
+ def check_nwfwo(
29
+ transliteration: str,
30
+ correct_nwfwo: str,
31
+ user_guess: str,
32
+ explanation: str | None = None,
33
+ ):
34
+ """
35
+ Simple checker for NWFWO practice.
36
+
37
+ Arguments (ChatGPT will send these as JSON):
38
+ - transliteration: the foreign sentence/word in transliteration
39
+ - correct_nwfwo: the correct NWFWO answer
40
+ - user_guess: what the learner typed or selected
41
+ - explanation: optional teacher explanation
42
+
43
+ Returns: a dict that ChatGPT AND the UI card can use.
44
+ """
45
+ norm_correct = correct_nwfwo.strip().lower()
46
+ norm_guess = user_guess.strip().lower()
47
+
48
+ is_correct = norm_guess == norm_correct
49
+
50
+ # Build friendly feedback
51
+ if is_correct:
52
+ feedback = "✅ Correct! Your NWFWO matches the target."
53
+ else:
54
+ feedback = (
55
+ "❌ Not quite. Compare your NWFWO with the correct one "
56
+ "and think about which sounds or letters changed."
57
+ )
58
+
59
+ result = {
60
+ "transliteration": transliteration,
61
+ "correct_nwfwo": correct_nwfwo,
62
+ "user_guess": user_guess,
63
+ "is_correct": is_correct,
64
+ "feedback": feedback,
65
+ "explanation": explanation
66
+ or "This NWFWO shows how the foreign writing maps to the native word.",
67
+ }
68
+
69
+ return result
70
+
71
+
72
+ # ---- 3. Normal Gradio UI (handy while you’re developing) ----
73
+
74
+ def local_check_ui(transliteration, correct_nwfwo, user_guess, explanation):
75
+ res = check_nwfwo(
76
+ transliteration=transliteration,
77
+ correct_nwfwo=correct_nwfwo,
78
+ user_guess=user_guess,
79
+ explanation=explanation,
80
+ )
81
+ return (
82
+ f"Transliteration: {res['transliteration']}\n"
83
+ f"Your NWFWO: {res['user_guess']}\n"
84
+ f"Correct NWFWO: {res['correct_nwfwo']}\n\n"
85
+ f"{res['feedback']}\n\n"
86
+ f"Explanation: {res['explanation']}"
87
+ )
88
+
89
+
90
+ with gr.Blocks() as demo:
91
+ gr.Markdown("## NWFWO Practice – Local Debug UI")
92
+
93
+ with gr.Row():
94
+ with gr.Column():
95
+ transliteration_box = gr.Textbox(
96
+ label="Transliteration (foreign text written in your script)",
97
+ value="salaam",
98
+ )
99
+ correct_nwfwo_box = gr.Textbox(
100
+ label="Correct NWFWO",
101
+ value="salaam",
102
+ )
103
+ user_guess_box = gr.Textbox(
104
+ label="Your guess NWFWO",
105
+ value="salam",
106
+ )
107
+ explanation_box = gr.Textbox(
108
+ label="Explanation (optional)",
109
+ value="This example shows how long vs short vowels work.",
110
+ )
111
+ btn = gr.Button("Check")
112
+
113
+ with gr.Column():
114
+ result_box = gr.Textbox(
115
+ label="Result",
116
+ lines=8,
117
+ )
118
+
119
+ btn.click(
120
+ local_check_ui,
121
+ inputs=[transliteration_box, correct_nwfwo_box, user_guess_box, explanation_box],
122
+ outputs=[result_box],
123
+ )
124
+
125
+
126
+ # ---- 4. HTML UI card resource for ChatGPT App ----
127
+
128
+ @gr.mcp.resource(
129
+ "ui://widget/nwfwo-practice-card.html",
130
+ mime_type="text/html+skybridge",
131
+ )
132
+ def nwfwo_html_card():
133
+ """
134
+ This HTML will appear as a card inside ChatGPT when this tool runs.
135
+
136
+ It can read:
137
+ - window.openai.toolInput (what ChatGPT sent into the tool)
138
+ - window.openai.toolOutput (what our Python tool returned)
139
+ """
140
+ html = r"""
141
+ <div id="nwfwo-card-root"></div>
142
+ <script>
143
+ const root = document.getElementById("nwfwo-card-root");
144
+
145
+ function render() {
146
+ const input = (window.openai && window.openai.toolInput) || {};
147
+ const output = (window.openai && window.openai.toolOutput) || {};
148
+
149
+ const transliteration = input.transliteration || output.transliteration || "salaam";
150
+ const userGuess = input.user_guess || output.user_guess || "salam";
151
+ const correctNwfwo = input.correct_nwfwo || output.correct_nwfwo || "salaam";
152
+
153
+ const isCorrect = output.is_correct;
154
+ const feedback = output.feedback || "";
155
+ const explanation = output.explanation || "";
156
+
157
+ let badge = "";
158
+ if (typeof isCorrect === "boolean") {
159
+ badge = isCorrect
160
+ ? '<span style="padding:4px 8px;border-radius:999px;background:#d4edda;">Correct</span>'
161
+ : '<span style="padding:4px 8px;border-radius:999px;background:#f8d7da;">Try again</span>';
162
+ }
163
+
164
+ root.innerHTML = `
165
+ <div style="
166
+ border-radius:16px;
167
+ border:1px solid #ddd;
168
+ padding:16px;
169
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
170
+ max-width: 500px;
171
+ ">
172
+ <div style="font-size:14px;color:#666;margin-bottom:4px;">
173
+ NWFWO Practice
174
+ </div>
175
+ <div style="font-size:18px;font-weight:600;margin-bottom:12px;">
176
+ Transliteration
177
+ </div>
178
+ <div style="padding:8px 12px;border-radius:12px;background:#f5f5f5;margin-bottom:12px;">
179
+ ${transliteration}
180
+ </div>
181
+
182
+ <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;">
183
+ <div>
184
+ <div style="font-size:14px;color:#666;">Your NWFWO</div>
185
+ <div style="font-size:16px;">${userGuess}</div>
186
+ </div>
187
+ <div>
188
+ <div style="font-size:14px;color:#666;">Target NWFWO</div>
189
+ <div style="font-size:16px;font-weight:600;">${correctNwfwo}</div>
190
+ </div>
191
+ </div>
192
+
193
+ <div style="margin-bottom:8px;">
194
+ ${badge}
195
+ </div>
196
+
197
+ <div style="font-size:14px;margin-top:8px;border-top:1px solid #eee;padding-top:8px;">
198
+ <div style="font-weight:600;margin-bottom:4px;">Feedback</div>
199
+ <div>${feedback}</div>
200
+ </div>
201
+
202
+ <div style="font-size:13px;color:#555;margin-top:8px;">
203
+ <div style="font-weight:600;margin-bottom:4px;">Explanation</div>
204
+ <div>${explanation}</div>
205
+ </div>
206
+ </div>
207
+ `;
208
+ }
209
+
210
+ render();
211
+ </script>
212
+ """
213
+ return html
214
+
215
+
216
+ # ---- 5. Main entrypoint ----
217
+
218
+ if __name__ == "__main__":
219
+ # This launches:
220
+ # - a browser-accessible Gradio UI for local testing
221
+ # - an MCP server (on /mcp) for ChatGPT to connect to
222
+ demo.launch(
223
+ server_name="0.0.0.0",
224
+ server_port=7860,
225
+ mcp_server=True,
226
+ )