ParthBhuptani's picture
Update app.py
78e7720 verified
Raw
History Blame Contribute Delete
14.7 kB
import gradio as gr
from huggingface_hub import InferenceClient
import os
# Uses Qwen2.5-7B-Instruct — well within 32B cap, best-in-class multilingual
client = InferenceClient(
model="Qwen/Qwen2.5-7B-Instruct",
token=os.environ.get("HF_TOKEN"),
)
SYSTEM_PROMPT = """You are an expert WhatsApp reply assistant for small shop owners in India.
Your job is to draft short, warm, professional replies that sound like a real shopkeeper — not a robot.
Rules:
- Keep replies under 3–4 sentences. WhatsApp messages must be concise.
- Match the language the user requests (Hindi, Gujarati, English, or Hinglish).
- Sound human and friendly, not stiff or corporate.
- If an item is unavailable, suggest an alternative or ask when they need it.
- Never use markdown formatting, bullet points, or emojis unless specifically requested.
- Don't start with "Namaste" every time — vary the greeting naturally.
- If you don't know the item, write a helpful holding reply.
"""
def generate_reply(customer_message, shop_name, shop_type, common_items, reply_language, tone, request_progress=gr.Progress()):
if not customer_message.strip():
return "⚠️ Please paste a customer message to continue."
request_progress(0, desc="Reading customer message...")
shop_context = ""
if shop_name.strip():
shop_context += f"Shop name: {shop_name}\n"
if shop_type:
shop_context += f"Type of shop: {shop_type}\n"
if common_items.strip():
shop_context += f"Items/services you carry: {common_items}\n"
tone_instruction = {
"Friendly 😊": "very warm and friendly, like talking to a neighbor",
"Professional 💼": "polite and professional but not cold",
"Casual 😎": "casual and relaxed, like chatting with a regular customer",
}.get(tone, "friendly")
user_prompt = f"""{shop_context}
Customer's WhatsApp message: "{customer_message}"
Write a {tone_instruction} reply in {reply_language}.
Keep it short (2–4 lines), conversational, ready to paste directly into WhatsApp.
No markdown, no bullet points. Just the reply text."""
request_progress(0.4, desc="Writing your reply...")
try:
response = client.chat.completions.create(
model="Qwen/Qwen2.5-7B-Instruct",
messages=[
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": user_prompt},
],
max_tokens=250,
temperature=0.75,
)
reply = response.choices[0].message.content.strip()
request_progress(1.0, desc="Done!")
return reply
except Exception as e:
return f"❌ Error: {str(e)}\n\nMake sure HF_TOKEN is set in your Space secrets."
# ── CSS ──────────────────────────────────────────────────────────────────────
css = """
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700&family=Noto+Sans+Devanagari:wght@400;600&display=swap');
* { box-sizing: border-box; }
body, .gradio-container {
font-family: 'Plus Jakarta Sans', sans-serif !important;
background: #0f0f14 !important;
}
.gradio-container {
max-width: 1500px !important;
width: 95% !important;
margin: auto !important;
}
/* ── Hero ── */
#hero {
text-align: center;
padding: 70px 40px;
background:
radial-gradient(circle at top, rgba(249,115,22,0.12), transparent 40%),
linear-gradient(135deg,#131328,#0d0d18);
border: 1px solid #2a2a45;
border-radius: 28px;
margin-bottom: 32px;
box-shadow:
0 10px 40px rgba(0,0,0,0.4),
inset 0 1px 0 rgba(255,255,255,0.05);
}
#hero-icon {
font-size: 3rem;
line-height: 1;
margin-bottom: 12px;
}
#hero-title {
font-size: 2.6rem;
font-weight: 700;
color: #ffffff;
letter-spacing: -0.5px;
margin: 0 0 6px;
}
#hero-title span {
background: linear-gradient(90deg, #f97316, #fb923c);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
#hero-sub {
color: #8888aa;
font-size: 1rem;
margin: 0 0 16px;
line-height: 1.5;
}
#hero-badge {
display: inline-block;
background: #1e1e30;
border: 1px solid #2e2e4a;
color: #7c7caa;
font-size: 0.78rem;
padding: 5px 14px;
border-radius: 999px;
letter-spacing: 0.3px;
}
/* ── Section labels ── */
.section-label {
font-size: 0.72rem;
font-weight: 700;
letter-spacing: 1.5px;
text-transform: uppercase;
color: #f97316;
margin-bottom: 14px !important;
padding-bottom: 8px !important;
border-bottom: 1px solid #2a2a3a !important;
}
/* ── Panels ── */
.panel {
background: rgba(22,22,31,0.9);
border: 1px solid #2a2a45;
border-radius: 20px;
padding: 24px;
backdrop-filter: blur(8px);
box-shadow: 0 8px 30px rgba(0,0,0,0.25);
}
/* ── Gradio inputs ── */
label span {
color: #ccccdd !important;
font-size: 0.85rem !important;
font-weight: 500 !important;
margin-bottom: 4px !important;
}
textarea,
input[type="text"] {
background: #17172b !important;
border: 1px solid #2e3355 !important;
border-radius: 14px !important;
color: white !important;
padding: 14px !important;
transition: all .2s ease !important;
}
textarea:focus,
input[type="text"]:focus {
border-color: #ff7a1a !important;
box-shadow: 0 0 0 4px rgba(255,122,26,0.15) !important;
}
/* ── Dropdowns & Radio ── */
.wrap {
background: #1e1e2e !important;
border: 1px solid #2e2e4a !important;
border-radius: 10px !important;
color: #e8e8f8 !important;
}
.wrap:hover { border-color: #f97316 !important; }
/* Radio buttons */
.block.svelte-1gfknih { gap: 6px !important; }
input[type="radio"] + span {
background: #1e1e2e !important;
border: 1px solid #2e2e4a !important;
border-radius: 8px !important;
color: #aaaacc !important;
font-size: 0.83rem !important;
padding: 6px 12px !important;
transition: all 0.15s !important;
cursor: pointer !important;
}
input[type="radio"]:checked + span {
background: #f97316 !important;
border-color: #f97316 !important;
color: #fff !important;
font-weight: 600 !important;
}
/* ── Generate button ── */
#generate-btn {
background: linear-gradient(
135deg,
#ff7a1a,
#ff5e00
) !important;
border-radius: 16px !important;
border: none !important;
height: 60px !important;
font-size: 18px !important;
font-weight: 700 !important;
box-shadow:
0 10px 30px rgba(255,122,26,.25);
transition: all .25s ease !important;
}
#generate-btn:hover {
transform: translateY(-2px);
}
/* ── Output box ── */
#reply-output textarea {
background: #121d12 !important;
border: 1px solid #2f4f2f !important;
color: #95ff95 !important;
font-size: 16px !important;
min-height: 180px !important;
border-radius: 16px !important;
padding: 18px !important;
}
/* ── Examples ── */
.examples-holder {
background: #16161f !important;
border: 1px solid #2a2a3a !important;
border-radius: 12px !important;
padding: 16px !important;
margin-top: 24px !important;
}
.example-btn {
background: #1e1e2e !important;
border: 1px solid #2e2e4a !important;
border-radius: 8px !important;
color: #aaaacc !important;
font-size: 0.8rem !important;
transition: all 0.15s !important;
}
.example-btn:hover {
border-color: #f97316 !important;
color: #f97316 !important;
}
/* ── Footer ── */
#footer {
text-align: center;
color: #44444a;
font-size: 0.78rem;
margin-top: 32px;
padding-top: 20px;
border-top: 1px solid #1e1e2a;
}
.gr-row {
gap: 24px !important;
}
body {
background:
radial-gradient(circle at top,
rgba(255,122,26,.08),
transparent 30%),
#0b0b13 !important;
}
"""
# ── UI ────────────────────────────────────────────────────────────────────────
with gr.Blocks(title="Dukaan Saathi – AI Reply Assistant") as demo:
gr.HTML("""
<div id="hero">
<div id="hero-icon">🏪</div>
<h1 id="hero-title">
Dukaan <span>Saathi</span>
</h1>
<p id="hero-sub">
Turn customer messages into professional WhatsApp replies in seconds.
<br>
Supports Hindi • Gujarati • English • Hinglish
</p>
<span id="hero-badge">
⚡ Under 3s • 🤖 Qwen 2.5 • 🏪 Small Business AI
</span>
</div>
""")
with gr.Row(equal_height=False):
# ── Left: Shop Profile ──────────────────────────────────────
with gr.Column(scale=4, elem_classes="panel"):
gr.Markdown("**YOUR SHOP PROFILE**", elem_classes="section-label")
shop_name = gr.Textbox(
label="Shop Name",
placeholder="e.g. Patel Medical Store",
max_lines=1,
)
shop_type = gr.Dropdown(
choices=[
"🏥 Medical / Pharmacy",
"🛒 Grocery / Kirana",
"📱 Electronics & Mobile Repair",
"👗 Clothing & Textile",
"🍽️ Restaurant / Food Stall",
"🔧 Hardware / Tools",
"📚 Stationery / Books",
"💈 Salon / Beauty",
"🚗 Auto Parts",
"🎁 General / Other",
],
label="Shop Type",
value="🛒 Grocery / Kirana",
)
common_items = gr.Textbox(
label="Common Items / Services you sell",
placeholder="e.g. paracetamol, antibiotics, BP tablets, vitamins...",
lines=3,
)
gr.Markdown("**REPLY SETTINGS**", elem_classes="section-label")
reply_language = gr.Radio(
choices=["Hindi", "Gujarati", "English", "Hinglish"],
label="Reply Language",
value="Hindi",
)
tone = gr.Radio(
choices=["Friendly 😊", "Professional 💼", "Casual 😎"],
label="Tone",
value="Friendly 😊",
)
# ── Right: Message + Output ─────────────────────────────────
with gr.Column(scale=6, elem_classes="panel"):
gr.Markdown("**CUSTOMER'S WHATSAPP MESSAGE**", elem_classes="section-label")
customer_message = gr.Textbox(
label="Paste the message here",
placeholder='e.g. "Bhaiya dolo 650 milegi? Aaj urgent chahiye."',
lines=4,
)
generate_btn = gr.Button(
"✨ Generate WhatsApp Reply",
elem_id="generate-btn",
)
gr.Markdown("**YOUR REPLY — READY TO PASTE**", elem_classes="section-label")
generated_reply = gr.Textbox(
lines=5,
interactive=False,
placeholder="Your reply will appear here...",
elem_id="reply-output"
)
gr.HTML("""
<button onclick="
navigator.clipboard.writeText(
document.querySelector('#reply-output textarea').value
);
this.innerText='✅ Copied!';
setTimeout(() => {
this.innerText='📋 Copy Reply';
},1500);
"
style="
width:100%;
padding:12px;
margin-top:10px;
border:none;
border-radius:12px;
background:linear-gradient(135deg,#1f2937,#111827);
color:white;
font-weight:600;
cursor:pointer;
">
📋 Copy Reply
</button>
""")
# ── Examples ────────────────────────────────────────────────────
gr.Examples(
label="📋 Try a sample customer message",
examples=[
[
"Bhaiya dolo 650 hai? Aaj shaam tak chahiye 2 strip",
"Patel Medical", "🏥 Medical / Pharmacy",
"paracetamol, antibiotics, BP tablets, vitamins, cough syrup",
"Hindi", "Friendly 😊",
],
[
"Kal subah 2kg aata, 1L soyabean oil aur ek packet namak ghar pe deliver kar dena",
"Sharma Kirana", "🛒 Grocery / Kirana",
"aata, rice, oil, dal, sugar, namak, biscuit, soap",
"Hindi", "Friendly 😊",
],
[
"Bhai maro mobile nu screen tuti gai 6, aaje thase?",
"Tech Zone", "📱 Electronics & Mobile Repair",
"mobile screen repair, battery replacement, charging port, software issues",
"Gujarati", "Professional 💼",
],
[
"Hi, is the butter chicken available today? Can I order for 4 people, delivery by 8pm?",
"Maa da Dhaba", "🍽️ Restaurant / Food Stall",
"butter chicken, dal makhani, roti, rice, paneer dishes",
"Hinglish", "Friendly 😊",
],
],
inputs=[customer_message, shop_name, shop_type, common_items, reply_language, tone],
examples_per_page=4,
)
gr.HTML("""
<div id="footer">
🏪 Dukaan Saathi
Built for the Hugging Face Build Small Hackathon 2026
Powered by Qwen2.5-7B
</div>
""")
generate_btn.click(
fn=generate_reply,
inputs=[customer_message, shop_name, shop_type, common_items, reply_language, tone],
outputs=generated_reply,
show_progress="full",
)
demo.launch(
css=css,
show_error=True
)