File size: 4,415 Bytes
d1b380c
aa9cd89
 
e841288
aa9cd89
f33a336
 
573da01
279522e
e841288
aa9cd89
 
f33a336
aa9cd89
 
573da01
aa9cd89
573da01
e841288
0cab78e
 
f33a336
e841288
 
 
5b4e1f9
e841288
aa9cd89
50e3328
 
e841288
aa9cd89
0cab78e
aa9cd89
0cab78e
aa9cd89
 
 
e841288
0cab78e
 
aa9cd89
 
ec2b48a
aa9cd89
 
 
 
 
 
 
ec2b48a
 
aa9cd89
f2047e9
ec2b48a
aa9cd89
 
 
f33a336
aa9cd89
 
 
f33a336
 
 
aa9cd89
f33a336
 
aa9cd89
40fe208
f33a336
0cab78e
e841288
 
 
 
 
 
 
 
c675b2a
 
 
e841288
eafff78
e841288
 
0cab78e
e841288
aa9cd89
e841288
 
 
 
c675b2a
e841288
 
aa9cd89
e841288
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c675b2a
bea35f9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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()