Spaces:
Sleeping
Sleeping
import os | |
import gradio as gr | |
import whisper | |
import requests | |
import json, uuid, re | |
from datetime import datetime | |
from pydub import AudioSegment | |
import emoji | |
# Keys and model | |
GROQ_KEY = os.getenv("GROQ_API_KEY") | |
MODEL = whisper.load_model("base") | |
# Emoji filter | |
ALLOWED = {"π", "π", "π", "π€", "β¨", "π", "π¬", "π", "π", "π’", "π§ ", "β "} | |
def filter_emojis(text): | |
return "".join(c if c not in emoji.EMOJI_DATA or c in ALLOWED else "" for c in text) | |
# Save system | |
CHAT_DIR = "saved_chats" | |
os.makedirs(CHAT_DIR, exist_ok=True) | |
def save_chat_manual(history): | |
if not history: return | |
prompt = re.sub(r"[^\w\s]", "", history[-2]["content"])[:30] or "Chat" | |
timestamp = datetime.now().strftime("%b %d %Y %H-%M-%S") | |
fname = f"{prompt} - {timestamp} - {uuid.uuid4().hex[:6]}.json" | |
with open(os.path.join(CHAT_DIR, fname), "w", encoding="utf-8") as f: | |
json.dump(history, f, indent=2, ensure_ascii=False) | |
def list_saved_chats(): | |
return sorted(os.listdir(CHAT_DIR)) | |
def load_chat(fname): | |
try: | |
with open(os.path.join(CHAT_DIR, fname), "r", encoding="utf-8") as f: | |
hist = json.load(f) | |
return hist, hist | |
except: | |
return [], [] | |
# LLM chat | |
def chat_with_groq(user_input, history): | |
try: | |
messages = [{"role": "system", "content": "You are Neobot, a helpful assistant."}] | |
messages += history + [{"role": "user", "content": user_input}] | |
res = requests.post( | |
"https://api.groq.com/openai/v1/chat/completions", | |
headers={"Authorization": f"Bearer {GROQ_KEY}", "Content-Type": "application/json"}, | |
json={"model": "llama3-70b-8192", "messages": messages} | |
) | |
reply = res.json()["choices"][0]["message"]["content"] | |
reply = filter_emojis(reply) | |
history += [{"role": "user", "content": user_input}, {"role": "assistant", "content": reply}] | |
return "", history, history | |
except Exception as e: | |
error = f"β Error: {e}" | |
history += [{"role": "assistant", "content": error}] | |
return "", history, history | |
# Transcribe audio | |
def transcribe(audio_path): | |
if not audio_path: return "" | |
try: | |
temp_wav = f"{uuid.uuid4()}.wav" | |
AudioSegment.from_file(audio_path).export(temp_wav, format="wav") | |
result = MODEL.transcribe(temp_wav) | |
os.remove(temp_wav) | |
return result["text"] | |
except: | |
return "β Transcription failed" | |
# UI | |
with gr.Blocks(css=""" | |
body { background-color: white; font-family: 'Segoe UI', sans-serif; } | |
.gr-button { background-color: #f7f7f7; border-radius: 8px; } | |
.gr-chatbot { border: 1px solid #ccc; border-radius: 12px; } | |
.scroll-sidebar button { margin: 2px 0; width: 100%; text-align: left; border-radius: 6px; background: white; transition: background 0.2s; } | |
.scroll-sidebar button:hover { background: #eee; } | |
""") as demo: | |
state = gr.State([]) | |
with gr.Row(): | |
with gr.Column(scale=1): | |
gr.Markdown("### π Saved Chats") | |
chat_list = gr.Column(elem_id="scroll-sidebar") # Without 'scroll' | |
save_btn = gr.Button("πΎ Save Chat") | |
refresh_btn = gr.Button("π Refresh") | |
with gr.Column(scale=3): | |
gr.Markdown("## π€ Neobot Chat") | |
bot = gr.Chatbot(height=400) | |
with gr.Row(): | |
input_box = gr.Textbox(placeholder="Type a message or record one...", scale=6, show_label=False) | |
send_btn = gr.Button("π Send") | |
voice_input = gr.Audio(label="ποΈ Record Voice", type="filepath") | |
# Chat actions | |
send_btn.click(chat_with_groq, inputs=[input_box, state], outputs=[input_box, bot, state]) | |
input_box.submit(chat_with_groq, inputs=[input_box, state], outputs=[input_box, bot, state]) | |
voice_input.change(transcribe, inputs=voice_input, outputs=[input_box]) | |
save_btn.click(lambda hist: save_chat_manual(hist), inputs=[state], outputs=[]) | |
# Sidebar buttons | |
def render_chat_buttons(): | |
btns = [] | |
for f in list_saved_chats(): | |
def load_fn(fname=f): return load_chat(fname) | |
btn = gr.Button(f[:-5]) | |
btn.click(load_fn, outputs=[bot, state]) | |
btns.append(btn) | |
return btns | |
refresh_btn.click(render_chat_buttons, outputs=[chat_list]) | |
demo.load(render_chat_buttons, outputs=[chat_list]) | |
demo.launch() |