valluvar-or-ai / app.py
NaveenKumar Namachivayam
fix: increase Thiruvalluvar stamp column min-width from 100px to 150px
d31601a
Raw
History Blame Contribute Delete
7.93 kB
"""Gradio UI for ValluvarAI."""
# Patch Jinja2 LRUCache to handle unhashable keys (gradio 4.44.0 bug).
try:
from jinja2.utils import LRUCache
def _make_hashable(key):
if isinstance(key, dict):
return tuple(sorted((k, _make_hashable(v)) for k, v in key.items()))
if isinstance(key, list):
return tuple(_make_hashable(i) for i in key)
return key
_original_getitem = LRUCache.__getitem__
_original_get = LRUCache.get
_original_setitem = LRUCache.__setitem__
def _safe_getitem(self, key):
return _original_getitem(self, _make_hashable(key))
def _safe_get(self, key, default=None):
return _original_get(self, _make_hashable(key), default)
def _safe_setitem(self, key, value):
return _original_setitem(self, _make_hashable(key), value)
LRUCache.__getitem__ = _safe_getitem
LRUCache.get = _safe_get
LRUCache.__setitem__ = _safe_setitem
except Exception:
pass
import huggingface_hub
if not hasattr(huggingface_hub, "HfFolder"):
class _HfFolder:
path = None
@staticmethod
def get_token():
return None
huggingface_hub.HfFolder = _HfFolder
import gradio as gr
from model_engine import model, stoi, itos
from kural_engine import generate_kural
from game_engine import new_round, check_guess
with gr.Blocks(title="ValluvarAI") as demo:
gr.Markdown("# 🕉️ ValluvarAI")
gr.Markdown(
"An AI that writes new Thirukkurals in the style of Thiruvalluvar. "
"Enter a Tamil theme to generate bilingual wisdom."
)
with gr.Row():
with gr.Column(scale=1):
pass
with gr.Column(scale=1, min_width=150):
gr.Image(
"image/thiruvalluvar_stamp.jpeg",
label="Thiruvalluvar",
show_label=False,
height=150,
width=150,
)
with gr.Column(scale=1):
pass
with gr.Accordion("Model Card", open=False):
gr.Markdown(
f"""
**Architecture:** GPT ({model.config.n_layer}L/{model.config.n_head}H/{model.config.n_embd}D)
**Parameters:** {sum(p.numel() for p in model.parameters()) / 1e6:.1f}M
**Vocabulary:** {len(stoi)} characters (Tamil + English)
**Tokenization:** Character-level
**Training Steps:** 10,000
**Device:** Apple MPS (Mac Mini)
**Training Time:** ~5 hours
**Final Loss:** ~1.5
"""
)
with gr.Accordion("Training Details", open=False):
gr.Markdown(
f"""
**Steps:** 10,000
**Device:** Apple MPS (Mac Mini)
**Time:** ~5 hours
**Final Loss:** ~1.5
"""
)
with gr.Tab("✨ Generate Kural"):
with gr.Row():
with gr.Column():
prompt = gr.Textbox(
label="Theme (Tamil)",
placeholder="e.g., கடவுள் வாழ்த்து, நட்பு, அரசியல்",
value="கடவுள் வாழ்த்து",
)
temperature = gr.Slider(
minimum=0.1,
maximum=2.0,
value=0.8,
step=0.1,
label="Temperature (Creativity)",
)
max_tokens = gr.Slider(
minimum=50,
maximum=400,
value=200,
step=50,
label="Max Tokens",
)
generate_btn = gr.Button("Generate", variant="primary")
with gr.Column():
output = gr.Textbox(label="Generated Kural", lines=10)
source = gr.Textbox(label="Source")
generate_btn.click(
fn=generate_kural,
inputs=[prompt, temperature, max_tokens],
outputs=[output, source],
)
gr.Markdown("### Quick Themes")
with gr.Row():
themes = [
"கடவுள் வாழ்த்து",
"வான் சிறப்பு",
"நட்பு",
"அரசியல்",
"அறன் வலியுறுத்தல்",
"கல்வி",
"காதல்",
"பொருள்",
"அறம்",
"வீரம்",
"வாய்மை",
"அன்பு",
]
for theme in themes:
btn = gr.Button(theme)
btn.click(lambda t=theme: t, outputs=prompt)
with gr.Tab("🎯 Valluvar or AI?"):
gr.Markdown(
"### Can you tell the difference?\n"
"Read the Tamil couplet and guess whether it was written by "
"Thiruvalluvar or generated by the AI."
)
couplet_display = gr.Textbox(
label="குறள்",
lines=3,
interactive=False,
value="Click **Next Couplet** to begin!",
)
game_state = gr.State(value=None)
with gr.Row():
valluvar_btn = gr.Button("📖 Valluvar", variant="secondary", scale=1)
ai_btn = gr.Button("🤖 AI", variant="secondary", scale=1)
reveal_display = gr.Markdown()
next_btn = gr.Button("Next Couplet", variant="primary")
def safe_new_round():
try:
return new_round()
except Exception as e:
print(f"[ERROR] Round generation failed: {e}")
fallback = "அகர முதல் எழுத்தெல்லாம் ஆதி\nபகவன் முதற்றே உலகு"
return fallback, None, "⚠️ Error loading round. Try again."
next_btn.click(
fn=safe_new_round,
outputs=[couplet_display, game_state, reveal_display],
)
valluvar_btn.click(
fn=lambda s: check_guess("valluvar", s),
inputs=[game_state],
outputs=[reveal_display],
)
ai_btn.click(
fn=lambda s: check_guess("ai", s),
inputs=[game_state],
outputs=[reveal_display],
)
with gr.Tab("📊 About"):
gr.Markdown(
f"""
ValluvarAI is a GPT model trained on the **only** Thirukkural dataset.
## Capabilities
- ✅ Generate authentic Tamil couplets (2 lines × 4 words)
- ✅ Produce coherent English translations
- ✅ Handle traditional themes (virtue, politics, love)
- ❌ Modern topics (science, technology) - not in training data
- ❌ Contemporary language - only classical Tamil
- ⚠️ May contain inaccuracies or repetitions
## Examples of AI vs Original
The model sometimes generates exact memorized kurals from the 1330,
and sometimes creates entirely new ones in Thiruvalluvar's style.
## About Me
**NaveenKumar Namachivayam**
- [QAInsights.com](https://www.qainsights.com)
- [Dosa.Dev](https://dosa.dev)
- [JMeter.AI](https://jmeter.ai)
- [LinkedIn](https://www.linkedin.com/in/naveenkumarn/)
## Acknowledgements
- Special thanks to [Project Madurai](https://www.projectmadurai.org/pm_etexts/utf8/pmuni0153.html) for making the Thirukkural text and translations available.
- Built with Tamil ❤️ using PyTorch and Gradio.
"""
)
import os
port = int(os.environ.get("PORT", "7860"))
demo.launch(server_name="0.0.0.0", server_port=port)