Spaces:
Sleeping
Sleeping
import gradio as gr | |
import os | |
from huggingface_hub import InferenceClient, __version__ as hf_version | |
import random | |
from typing import Generator, Dict, List, Tuple, Optional | |
import logging | |
logging.basicConfig( | |
level=logging.DEBUG, | |
format='%(asctime)s - %(levelname)s - %(message)s' | |
) | |
logging.debug(f"Using huggingface_hub version: {hf_version}") | |
# Get token from environment variable | |
hf_token = os.environ.get("QWEN_BOT_TOKEN") | |
client = InferenceClient("Qwen/Qwen2.5-72B-Instruct", token=hf_token) | |
TOPIC_EXAMPLES = { | |
"Daily Life": { | |
"beginner": [ | |
"What time do you wake up?", | |
"Do you go to school or work?", | |
"What do you eat for breakfast?" | |
], | |
"intermediate": [ | |
"What do you usually do after work?", | |
"Do you like cooking? What’s your favorite dish?", | |
"Tell me about your morning routine." | |
], | |
"advanced": [ | |
"How do you balance personal and professional responsibilities?", | |
"What does a productive day look like for you?", | |
"How has your daily routine changed over the years?" | |
] | |
}, | |
"Travel": { | |
"beginner": [ | |
"Do you like to travel?", | |
"Have you been to another city?", | |
"Do you like airplanes?" | |
], | |
"intermediate": [ | |
"Have you ever been to another country?", | |
"What's your dream vacation?", | |
"What do you like to pack in your suitcase?" | |
], | |
"advanced": [ | |
"How has travel influenced your worldview?", | |
"What do you think makes a destination culturally significant?", | |
"Describe your most challenging travel experience." | |
] | |
}, | |
"Food": { | |
"beginner": [ | |
"Do you like apples?", | |
"What is your favorite snack?", | |
"Do you eat rice or noodles?" | |
], | |
"intermediate": [ | |
"Can you describe how to cook your favorite dish?", | |
"What is your go-to comfort food and why?", | |
"Have you ever tried food from another country?" | |
], | |
"advanced": [ | |
"How does food reflect a culture’s values and traditions?", | |
"Compare the cuisines of two different countries.", | |
"What’s the most unique food you’ve ever tasted?" | |
] | |
}, | |
"Work & School": { | |
"beginner": [ | |
"Do you go to school or work?", | |
"What is your teacher’s name?", | |
"Do you have homework?" | |
], | |
"intermediate": [ | |
"What do you do at your job or school?", | |
"What’s your favorite subject or task?", | |
"Do you like working with other people?" | |
], | |
"advanced": [ | |
"How do you stay motivated in your work or studies?", | |
"What are the challenges of remote learning or working?", | |
"How do education systems differ around the world?" | |
] | |
}, | |
"Hobbies": { | |
"beginner": [ | |
"Do you like music?", | |
"What games do you play?", | |
"Can you draw or paint?" | |
], | |
"intermediate": [ | |
"What hobbies do you enjoy in your free time?", | |
"When did you start your favorite hobby?", | |
"Do you prefer indoor or outdoor hobbies?" | |
], | |
"advanced": [ | |
"How can hobbies contribute to personal growth?", | |
"What’s a hobby you would like to master and why?", | |
"How has technology changed the way we pursue hobbies?" | |
] | |
}, | |
"Shopping": { | |
"beginner": [ | |
"Do you like shopping?", | |
"What do you buy at the store?", | |
"Do you go shopping alone?" | |
], | |
"intermediate": [ | |
"Do you prefer shopping online or in stores?", | |
"Tell me about your last shopping trip.", | |
"What kinds of things do you usually buy?" | |
], | |
"advanced": [ | |
"How has consumer behavior changed over time?", | |
"What are the pros and cons of online shopping?", | |
"Do advertisements affect your shopping decisions?" | |
] | |
}, | |
"Weather": { | |
"beginner": [ | |
"Is it sunny today?", | |
"Do you like rain?", | |
"What is your favorite season?" | |
], | |
"intermediate": [ | |
"What’s the weather like where you are?", | |
"Do you like hot or cold weather?", | |
"How do you prepare for a rainy day?" | |
], | |
"advanced": [ | |
"How does climate affect daily life in your region?", | |
"What are the consequences of global climate change?", | |
"How does weather influence culture and traditions?" | |
] | |
} | |
} | |
MAX_HISTORY_LENGTH = 20 | |
MEMORY_WINDOW = 5 | |
MAX_TOKENS = 1024 | |
TEMPERATURE = 0.7 | |
TOP_P = 0.95 | |
def get_examples_for_topic(topic, difficulty): | |
return TOPIC_EXAMPLES.get(topic, {}).get(difficulty, []) | |
def get_conversation_prompt(): | |
return """You are JoJo, a friendly and supportive AI who helps people practice speaking English through fun, casual conversation. | |
Always keep your replies short (2–4 sentences) and speak naturally, like a friendly tutor or partner. Ask engaging, open-ended questions to keep the conversation going. | |
If the user makes a grammar or vocabulary mistake, gently correct them by repeating the corrected sentence, followed by a kind note like: \"You can also say it like this!\" | |
Do not teach grammar rules. Just offer corrections through example. Never lecture or explain unless asked. | |
Keep the tone warm, encouraging, and non-judgmental.""" | |
def respond(message: str, chat_history: List[Tuple[str, str]], topic: Optional[str] = None, use_full_memory: bool = True) -> Tuple[str, List[Tuple[str, str]]]: | |
if not message.strip(): | |
return "", chat_history | |
try: | |
api_messages = [{"role": "system", "content": get_conversation_prompt()}] | |
logging.debug(f"System Message: {api_messages[0]}") | |
if chat_history and use_full_memory: | |
for user_msg, bot_msg in chat_history[-MEMORY_WINDOW:]: | |
api_messages.extend([ | |
{"role": "user", "content": str(user_msg)}, | |
{"role": "assistant", "content": str(bot_msg)} | |
]) | |
api_messages.append({"role": "user", "content": str(message)}) | |
response = client.chat_completion( | |
messages=api_messages, | |
max_tokens=MAX_TOKENS, | |
temperature=TEMPERATURE, | |
top_p=TOP_P | |
) | |
bot_message = response.choices[0].message.content | |
updated_history = list(chat_history) | |
updated_history.append((message, bot_message)) | |
return "", updated_history | |
except Exception as e: | |
logging.error("Error in respond function", exc_info=True) | |
error_msg = f"There was a temporary issue. Please try again. (Error: {str(e)})" | |
return "", list(chat_history) + [(message, error_msg)] | |
def get_avatar_url(): | |
return "https://api.dicebear.com/7.x/bottts/svg?seed=rabbit&backgroundColor=b6e3f4" | |
custom_css = """ | |
.compact-btn { | |
padding: 0.75rem !important; | |
font-size: 1rem !important; | |
font-weight: 500; | |
border-radius: 8px; | |
background-color: #2f2f2f; | |
color: white; | |
transition: background-color 0.3s; | |
} | |
.compact-btn:hover { | |
background-color: #444; | |
} | |
#voice-controls { | |
margin-top: 1em; | |
text-align: center; | |
opacity: 0.5; | |
font-size: 0.9rem; | |
font-style: italic; | |
} | |
""" | |
with gr.Blocks(theme=gr.themes.Soft(), css=custom_css) as demo: | |
gr.Markdown(""" | |
# 🐰 JoJo - Your Speaking Buddy | |
**Chat in English with JoJo — your kind and cheerful language partner.** | |
Pick a topic, choose your level, and practice naturally. JoJo will guide you, ask questions, and gently correct you along the way! | |
""") | |
avatar = get_avatar_url() | |
memory_flag = gr.State(value=True) | |
with gr.Row(): | |
with gr.Column(scale=3): | |
chatbot = gr.Chatbot( | |
height=400, | |
bubble_full_width=True, | |
show_copy_button=True, | |
avatar_images=[None, avatar], | |
scale=1, | |
min_width=800 | |
) | |
msg = gr.Textbox( | |
placeholder="Say something to JoJo...", | |
scale=4 | |
) | |
with gr.Row(): | |
submit = gr.Button("Send", variant="primary") | |
clear = gr.Button("New Chat") | |
gr.Markdown(""" | |
<div id="voice-controls"> | |
🎤 Voice input and 🔈 playback coming soon! | |
</div> | |
""") | |
with gr.Column(scale=1): | |
gr.Markdown("""### 🎯 Conversation Settings""") | |
topic = gr.Dropdown( | |
choices=list(TOPIC_EXAMPLES.keys()), | |
label="Select Topic", | |
value="Daily Life" | |
) | |
difficulty = gr.Dropdown( | |
choices=["beginner", "intermediate", "advanced"], | |
label="Select Difficulty", | |
value="intermediate" | |
) | |
gr.Markdown("""### 💬 Quick Starters""") | |
starter_btn1 = gr.Button("Starter 1", scale=1, min_width=250, elem_classes="compact-btn") | |
starter_btn2 = gr.Button("Starter 2", scale=1, min_width=250, elem_classes="compact-btn") | |
starter_btn3 = gr.Button("Starter 3", scale=1, min_width=250, elem_classes="compact-btn") | |
starter_buttons = [starter_btn1, starter_btn2, starter_btn3] | |
def update_starters(selected_topic, selected_difficulty): | |
examples = get_examples_for_topic(selected_topic, selected_difficulty) | |
results = [examples[i] if i < len(examples) else "" for i in range(3)] | |
return tuple(results) | |
def use_starter(text: str, history: List[Tuple[str, str]], selected_topic: str, memory_flag: bool) -> Tuple[str, List[Tuple[str, str]]]: | |
if not text: | |
return "", history | |
try: | |
_, updated = respond(text, history, selected_topic, memory_flag) | |
return "", updated | |
except Exception as e: | |
return "", history + [(text, f"Error: {str(e)}")] | |
for btn in starter_buttons: | |
btn.click(fn=use_starter, inputs=[btn, chatbot, topic, memory_flag], outputs=[msg, chatbot], queue=True) | |
topic.change(fn=update_starters, inputs=[topic, difficulty], outputs=starter_buttons) | |
difficulty.change(fn=update_starters, inputs=[topic, difficulty], outputs=starter_buttons) | |
msg.submit(fn=respond, inputs=[msg, chatbot, topic, memory_flag], outputs=[msg, chatbot]) | |
submit.click(fn=respond, inputs=[msg, chatbot, topic, memory_flag], outputs=[msg, chatbot]) | |
clear.click(lambda: [], None, chatbot, queue=False) | |
clear.click(lambda: "", None, msg, queue=False) | |
default_starters = get_examples_for_topic("Daily Life", "intermediate") | |
demo.load(fn=lambda: tuple(default_starters[:3]), outputs=starter_buttons, queue=False) | |
if __name__ == "__main__": | |
demo.launch(server_name="0.0.0.0", server_port=7860) | |