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