Spaces:
Sleeping
Sleeping
File size: 6,528 Bytes
b7f3dcc 4718250 b7f3dcc 4718250 b7f3dcc 4718250 b7f3dcc 4718250 b7f3dcc 4718250 058ae1e 932d1ec b7f3dcc 4718250 b7f3dcc 524e7b6 b7f3dcc 4718250 b7f3dcc 524e7b6 b7f3dcc 524e7b6 b7f3dcc 524e7b6 b7f3dcc 4718250 b7f3dcc 4718250 b7f3dcc 4718250 058ae1e 4718250 524e7b6 932d1ec 524e7b6 b7f3dcc 058ae1e b7f3dcc 058ae1e b7f3dcc | 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 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 | import gradio as gr
import uuid
import logging
import re
import json
import os
import tempfile
from agent_module import chat_agent_stream
from translation_module import localize_init
logger = logging.getLogger("app.ui")
PREMIUM_CSS = """
body, .gradio-container { background-color: #0b0f19 !important; color: #e0e6ed !important; font-family: 'Inter', sans-serif !important; }
.main-container { max-width: 900px !important; margin: 0 auto !important; min-height: 600px !important; max-height: 90vh !important; display: flex !important; flex-direction: column !important; padding: 10px !important; background: #0b0f19 !important; }
.header-row { display: flex !important; align-items: center !important; justify-content: space-between !important; gap: 10px !important; margin-bottom: 10px !important; padding: 10px !important; background: rgba(255, 255, 255, 0.05) !important; border-radius: 12px !important; }
.chat-window { flex-grow: 1 !important; border-radius: 12px !important; border: 1px solid rgba(255, 255, 255, 0.1) !important; background: rgba(0, 0, 0, 0.2) !important; overflow-y: auto !important; }
.input-area { margin-top: 10px !important; background: rgba(255, 255, 255, 0.05) !important; padding: 10px !important; border-radius: 12px !important; flex-shrink: 0 !important; }
footer { display: none !important; }
@media (max-width: 768px) { .main-container { padding: 5px !important; height: auto !important; max-height: none !important; } .header-row { padding: 5px !important; flex-wrap: wrap !important; } }
"""
def save_and_clear(msg):
return "", msg
def export_chat(history):
if not history: return None
with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as tf:
json.dump(history, tf, indent=2)
return tf.name
def import_chat(file):
if file is None: return gr.update(), []
try:
with open(file.name, 'r') as f:
data = json.load(f)
if isinstance(data, list):
return data, data
except Exception as e:
logger.error(f"Import error: {e}")
return gr.update(), gr.update()
def clear_messages(lang_name="English"):
name_map = {"German": "de", "French": "fr", "Spanish": "es", "Italian": "it",
"Portuguese": "pt", "Russian": "ru", "Japanese": "ja", "Chinese": "zh"}
code = name_map.get(lang_name, "en")
loc = localize_init(code)
welcome = [{"role": "assistant", "content": loc["welcome"]}]
return welcome, welcome
def chat_wrapper(message, history, short_answers=False, lang="English"):
if history is None: history = []
history.append({"role": "user", "content": message})
history.append({"role": "assistant", "content": ""})
# Intent detection is now handled internally by chat_agent_stream
for part in chat_agent_stream(message, history[:-2], user_lang=lang, short_answers=short_answers):
if part == "__TURN_END__":
history.append({"role": "assistant", "content": ""})
yield history, history
else:
history[-1]["content"] = part
yield history, history
yield history, history
def on_load(request: gr.Request):
headers = dict(request.headers)
lang_code = "en"
try:
if "accept-language" in headers:
lang_code = headers.get("accept-language").split(",")[0].split("-")[0]
except: pass
loc = localize_init(lang_code)
welcome = [{"role": "assistant", "content": loc["welcome"]}]
return welcome, loc["lang"], gr.update(label=loc["label_short"]), gr.update(placeholder=loc["placeholder"])
def build_demo(enable_reload=True):
with gr.Blocks(css=PREMIUM_CSS, title="Sage 6.5 - Oracle Intermediary") as demo:
history_state = gr.State([])
lang_state = gr.State("English")
saved_msg = gr.State("")
# Default Static Localization for Immediate Render
default_loc = localize_init("en")
default_welcome = [{"role": "assistant", "content": default_loc["welcome"]}]
with gr.Column(elem_classes="main-container"):
with gr.Row(elem_classes="header-row"):
gr.Markdown("## 🔮 Sage 6.5")
with gr.Row():
import_btn = gr.UploadButton("📥 Import", file_types=[".json"], size="sm")
export_btn = gr.DownloadButton("📤 Export", size="sm")
# BEST PRACTICE: Init with value, don't wait for load
chatbot = gr.Chatbot(value=default_welcome, elem_classes="chat-window", type="messages", bubble_full_width=False, show_label=False)
with gr.Row(elem_classes="input-area"):
msg_input = gr.Textbox(placeholder=default_loc["placeholder"], show_label=False, container=False, scale=4)
submit_btn = gr.Button("➤", scale=1, variant="primary")
short_answers = gr.Checkbox(label=default_loc["label_short"], value=False)
# Wire Events
msg_input.submit(save_and_clear, [msg_input], [msg_input, saved_msg], queue=False).then(
chat_wrapper, [saved_msg, history_state, short_answers, lang_state], [chatbot, history_state]
)
submit_btn.click(save_and_clear, [msg_input], [msg_input, saved_msg], queue=False).then(
chat_wrapper, [saved_msg, history_state, short_answers, lang_state], [chatbot, history_state]
)
export_btn.click(export_chat, [history_state], [export_btn])
import_btn.upload(import_chat, [import_btn], [chatbot, history_state])
chatbot.clear(clear_messages, [lang_state], [chatbot, history_state])
# State Sync must happen after init
# We manually sync state with the default value so backend has it
def sync_init():
return default_welcome, default_welcome
# If reload is enabled (client-side), we still try to localize dynamically, but we have a safe fallback now.
if enable_reload:
demo.load(on_load, None, [chatbot, lang_state, short_answers, msg_input])
else:
# If no reload, ensure history state matches visual init
demo.load(sync_init, None, [history_state, chatbot]) # Sync state
api_history = gr.Chatbot(visible=False, type="messages")
api_chat_btn = gr.Button("API CHAT", visible=False)
api_chat_btn.click(chat_wrapper, [msg_input, api_history, short_answers, lang_state], [chatbot, history_state], api_name="chat")
return demo
|