Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -13,12 +13,12 @@ import emoji
|
|
13 |
groq_key = os.getenv("GROQ_API_KEY")
|
14 |
whisper_model = whisper.load_model("base")
|
15 |
|
16 |
-
#
|
17 |
allowed_emojis = {"π", "π", "π", "π€", "β¨", "π", "π¬", "π", "π", "π’", "π§ ", "β
"}
|
18 |
def filter_emojis(text):
|
19 |
return "".join(char if char not in emoji.EMOJI_DATA or char in allowed_emojis else "" for char in text)
|
20 |
|
21 |
-
#
|
22 |
CHAT_DIR = "saved_chats"
|
23 |
os.makedirs(CHAT_DIR, exist_ok=True)
|
24 |
|
@@ -28,38 +28,38 @@ def save_chat_auto(history):
|
|
28 |
title = " ".join(title.split()[:5]) or "Chat"
|
29 |
timestamp = datetime.now().strftime("%b %d %Y %H-%M-%S")
|
30 |
filename = f"{title} - {timestamp}.json"
|
31 |
-
|
32 |
-
with open(path, "w", encoding="utf-8") as f:
|
33 |
json.dump(history, f, indent=2, ensure_ascii=False)
|
34 |
return filename
|
35 |
|
36 |
def list_saved_chats():
|
37 |
-
return sorted([f
|
38 |
|
39 |
-
def
|
40 |
try:
|
41 |
-
with open(os.path.join(CHAT_DIR,
|
42 |
history = json.load(f)
|
43 |
chat_display = [(m["content"], None) if m["role"] == "user" else (None, m["content"]) for m in history]
|
44 |
return chat_display, history
|
45 |
except:
|
46 |
return [], []
|
47 |
|
48 |
-
# Chat
|
49 |
def chat_with_groq(message, history):
|
50 |
messages = [{"role": "system", "content": "You are Neobot β a helpful, professional assistant."}]
|
51 |
messages += history + [{"role": "user", "content": message}]
|
52 |
-
|
53 |
headers = {"Authorization": f"Bearer {groq_key}", "Content-Type": "application/json"}
|
54 |
payload = {"model": "llama3-70b-8192", "messages": messages}
|
55 |
-
|
56 |
res = requests.post("https://api.groq.com/openai/v1/chat/completions", headers=headers, json=payload)
|
57 |
reply = res.json()["choices"][0]["message"]["content"]
|
58 |
reply = filter_emojis(reply)
|
59 |
-
|
60 |
history += [{"role": "user", "content": message}, {"role": "assistant", "content": reply}]
|
61 |
save_chat_auto(history)
|
62 |
-
|
|
|
63 |
|
64 |
# Transcribe audio
|
65 |
def transcribe_audio(audio_path):
|
@@ -71,14 +71,15 @@ def transcribe_audio(audio_path):
|
|
71 |
os.remove(temp_wav)
|
72 |
return result["text"]
|
73 |
except Exception:
|
74 |
-
return "β
|
75 |
|
76 |
# UI
|
77 |
with gr.Blocks(css="""
|
78 |
-
body { background
|
79 |
-
.gr-button, .gr-textbox
|
80 |
-
textarea, input[type='text'] { border-radius: 20px; padding: 10px
|
81 |
-
.
|
|
|
82 |
""") as demo:
|
83 |
|
84 |
state = gr.State([])
|
@@ -88,7 +89,7 @@ textarea, input[type='text'] { border-radius: 20px; padding: 10px 15px; border:
|
|
88 |
with gr.Column(scale=1):
|
89 |
gr.Markdown("<h2 style='text-align:center;'>Chats</h2>")
|
90 |
new_chat = gr.Button("π New Chat")
|
91 |
-
|
92 |
|
93 |
with gr.Column(scale=3):
|
94 |
gr.Markdown("<h1 style='text-align:center;'>Neobot</h1>")
|
@@ -97,31 +98,35 @@ textarea, input[type='text'] { border-radius: 20px; padding: 10px 15px; border:
|
|
97 |
chat_input = gr.Textbox(placeholder="Type or speak here...", scale=8, show_label=False)
|
98 |
plus = gr.Button("β")
|
99 |
mic = gr.Button("ποΈ")
|
100 |
-
|
101 |
-
|
102 |
|
103 |
send = gr.Button("Send π")
|
104 |
-
send.click(chat_with_groq, inputs=[chat_input, state], outputs=[chat_input, chatbot, state,
|
105 |
-
chat_input.submit(chat_with_groq, inputs=[chat_input, state], outputs=[chat_input, chatbot, state,
|
106 |
|
107 |
-
|
108 |
-
|
|
|
109 |
|
110 |
-
|
|
|
111 |
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
def toggle_recording(state):
|
116 |
-
if not state:
|
117 |
-
return gr.update(value="Recording..."), True, gr.update(visible=True)
|
118 |
else:
|
119 |
return "", False, gr.update(visible=False)
|
120 |
|
121 |
-
def
|
122 |
-
return transcribe_audio(
|
|
|
|
|
|
|
|
|
|
|
|
|
123 |
|
124 |
-
|
125 |
-
audio.change(handle_transcription, inputs=[audio], outputs=[chat_input, audio])
|
126 |
|
127 |
demo.launch()
|
|
|
13 |
groq_key = os.getenv("GROQ_API_KEY")
|
14 |
whisper_model = whisper.load_model("base")
|
15 |
|
16 |
+
# Emoji filtering
|
17 |
allowed_emojis = {"π", "π", "π", "π€", "β¨", "π", "π¬", "π", "π", "π’", "π§ ", "β
"}
|
18 |
def filter_emojis(text):
|
19 |
return "".join(char if char not in emoji.EMOJI_DATA or char in allowed_emojis else "" for char in text)
|
20 |
|
21 |
+
# Save/load
|
22 |
CHAT_DIR = "saved_chats"
|
23 |
os.makedirs(CHAT_DIR, exist_ok=True)
|
24 |
|
|
|
28 |
title = " ".join(title.split()[:5]) or "Chat"
|
29 |
timestamp = datetime.now().strftime("%b %d %Y %H-%M-%S")
|
30 |
filename = f"{title} - {timestamp}.json"
|
31 |
+
with open(os.path.join(CHAT_DIR, filename), "w", encoding="utf-8") as f:
|
|
|
32 |
json.dump(history, f, indent=2, ensure_ascii=False)
|
33 |
return filename
|
34 |
|
35 |
def list_saved_chats():
|
36 |
+
return sorted([f for f in os.listdir(CHAT_DIR) if f.endswith(".json")])
|
37 |
|
38 |
+
def load_chat_file(filename):
|
39 |
try:
|
40 |
+
with open(os.path.join(CHAT_DIR, filename), "r", encoding="utf-8") as f:
|
41 |
history = json.load(f)
|
42 |
chat_display = [(m["content"], None) if m["role"] == "user" else (None, m["content"]) for m in history]
|
43 |
return chat_display, history
|
44 |
except:
|
45 |
return [], []
|
46 |
|
47 |
+
# Chat handler
|
48 |
def chat_with_groq(message, history):
|
49 |
messages = [{"role": "system", "content": "You are Neobot β a helpful, professional assistant."}]
|
50 |
messages += history + [{"role": "user", "content": message}]
|
51 |
+
|
52 |
headers = {"Authorization": f"Bearer {groq_key}", "Content-Type": "application/json"}
|
53 |
payload = {"model": "llama3-70b-8192", "messages": messages}
|
54 |
+
|
55 |
res = requests.post("https://api.groq.com/openai/v1/chat/completions", headers=headers, json=payload)
|
56 |
reply = res.json()["choices"][0]["message"]["content"]
|
57 |
reply = filter_emojis(reply)
|
58 |
+
|
59 |
history += [{"role": "user", "content": message}, {"role": "assistant", "content": reply}]
|
60 |
save_chat_auto(history)
|
61 |
+
chat_display = [(m["content"], None) if m["role"] == "user" else (None, m["content"]) for m in history]
|
62 |
+
return "", chat_display, history, list_saved_chats()
|
63 |
|
64 |
# Transcribe audio
|
65 |
def transcribe_audio(audio_path):
|
|
|
71 |
os.remove(temp_wav)
|
72 |
return result["text"]
|
73 |
except Exception:
|
74 |
+
return "β Transcription failed"
|
75 |
|
76 |
# UI
|
77 |
with gr.Blocks(css="""
|
78 |
+
body { background: white; font-family: 'Segoe UI', sans-serif; }
|
79 |
+
.gr-button, .gr-textbox { background: #fff; color: #000; }
|
80 |
+
textarea, input[type='text'] { border: 1px solid #ccc; border-radius: 20px; padding: 10px; height: 48px; }
|
81 |
+
.sidebar { background: #f5f5f5; height: 100%; overflow-y: auto; padding: 10px; }
|
82 |
+
.sidebar button { width: 100%; margin: 5px 0; text-align: left; border: 1px solid #ccc; border-radius: 5px; background: white; }
|
83 |
""") as demo:
|
84 |
|
85 |
state = gr.State([])
|
|
|
89 |
with gr.Column(scale=1):
|
90 |
gr.Markdown("<h2 style='text-align:center;'>Chats</h2>")
|
91 |
new_chat = gr.Button("π New Chat")
|
92 |
+
saved_chats_list = gr.Column(elem_id="chat_list")
|
93 |
|
94 |
with gr.Column(scale=3):
|
95 |
gr.Markdown("<h1 style='text-align:center;'>Neobot</h1>")
|
|
|
98 |
chat_input = gr.Textbox(placeholder="Type or speak here...", scale=8, show_label=False)
|
99 |
plus = gr.Button("β")
|
100 |
mic = gr.Button("ποΈ")
|
101 |
+
hidden_audio = gr.Audio(type="filepath", visible=False)
|
102 |
+
file_input = gr.File(file_types=[".mp3", ".wav"], visible=False)
|
103 |
|
104 |
send = gr.Button("Send π")
|
105 |
+
send.click(chat_with_groq, inputs=[chat_input, state], outputs=[chat_input, chatbot, state, saved_chats_list])
|
106 |
+
chat_input.submit(chat_with_groq, inputs=[chat_input, state], outputs=[chat_input, chatbot, state, saved_chats_list])
|
107 |
|
108 |
+
def refresh_chat_list():
|
109 |
+
chats = list_saved_chats()
|
110 |
+
return [gr.Button(value=chat, scale=1) for chat in chats]
|
111 |
|
112 |
+
def load_chat_btn(filename):
|
113 |
+
return load_chat_file(filename)
|
114 |
|
115 |
+
def start_stop_recording(is_recording):
|
116 |
+
if not is_recording:
|
117 |
+
return "Recording...", True, gr.update(visible=True)
|
|
|
|
|
|
|
118 |
else:
|
119 |
return "", False, gr.update(visible=False)
|
120 |
|
121 |
+
def handle_audio(audio):
|
122 |
+
return transcribe_audio(audio), gr.update(visible=False)
|
123 |
+
|
124 |
+
new_chat.click(lambda: ("", [], []), outputs=[chat_input, chatbot, state])
|
125 |
+
plus.click(lambda: gr.update(visible=True), outputs=[file_input])
|
126 |
+
file_input.change(transcribe_audio, inputs=file_input, outputs=chat_input)
|
127 |
+
mic.click(start_stop_recording, inputs=recording, outputs=[chat_input, recording, hidden_audio])
|
128 |
+
hidden_audio.change(handle_audio, inputs=hidden_audio, outputs=[chat_input, hidden_audio])
|
129 |
|
130 |
+
demo.load(refresh_chat_list, outputs=[saved_chats_list])
|
|
|
131 |
|
132 |
demo.launch()
|