lamgamepro1 commited on
Commit
5ad2f89
·
verified ·
1 Parent(s): bb0b91b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +97 -80
app.py CHANGED
@@ -1,126 +1,143 @@
1
  import gradio as gr
2
  from huggingface_hub import InferenceClient
 
3
  import os
4
  import uuid
5
  import json
 
6
 
7
- # 1. CẤU HÌNH MODEL (Qwen 2.5 là model ổn định và mạnh nhất hiện tại)
8
- HF_TOKEN = os.getenv("HUGGINGFACE_HUB_TOKEN")
9
- MODEL_ID = "Qwen/Qwen2.5-7B-Instruct"
10
- client = InferenceClient(model=MODEL_ID, token=HF_TOKEN)
11
- DB_FILE = "nodeai_final_vault.json"
12
 
13
- def load_vault():
14
- if os.path.exists(DB_FILE):
15
- try:
16
- with open(DB_FILE, "r", encoding="utf-8") as f: return json.load(f)
17
- except: return {}
18
- return {}
19
 
20
- def save_vault(data):
21
- with open(DB_FILE, "w", encoding="utf-8") as f:
22
- json.dump(data, f, ensure_ascii=False, indent=4)
 
 
 
 
 
 
 
 
 
23
 
24
- # 2. UI GLASSMORPHISM PLATINUM
25
  custom_css = """
26
- @import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;600&family=Orbitron:wght@700&display=swap');
27
- .gradio-container { background: #050508 !important; color: white !important; font-family: 'Plus Jakarta Sans', sans-serif !important; }
28
- .sidebar-node { position: fixed !important; left: 0; top: 0; width: 280px; height: 100vh; background: rgba(10, 10, 20, 0.8); backdrop-filter: blur(20px); border-right: 1px solid rgba(255,255,255,0.1); padding: 20px; z-index: 100; }
29
- .logo-text { font-family: 'Orbitron', sans-serif; background: linear-gradient(90deg, #00d2ff, #3a7bd5); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-size: 20px; font-weight: bold; margin-bottom: 30px; text-align: center; }
30
- .orange-btn { background: linear-gradient(135deg, #ff6b6b, #f093fb) !important; border: none !important; color: white !important; font-weight: bold !important; border-radius: 10px !important; }
31
- .chat-main { margin-left: 300px !important; max-width: calc(100% - 320px) !important; }
32
- .input-fixed-bottom { position: fixed !important; bottom: 20px; left: 50%; transform: translateX(calc(-50% + 140px)); width: 80%; max-width: 800px; background: #1a1a2e; border: 1px solid #3a7bd5; border-radius: 15px; z-index: 1000; }
 
33
  footer { display: none !important; }
34
  """
35
 
36
- # 3. XỬ LÝ NỘI DUNG FILE
37
- def process_message(message):
38
  text = message.get("text", "")
39
  files = message.get("files", [])
40
- file_contents = ""
41
 
42
  for f in files:
43
- # Nếu là file văn bản/code thì đọc nội dung
44
  if f.lower().endswith(('.lua', '.py', '.txt', '.js', '.html', '.css')):
45
  try:
46
  with open(f, "r", encoding="utf-8") as file:
47
- content = file.read()
48
- file_contents += f"\n\n[FILE: {os.path.basename(f)}]\n{content}\n"
49
  except: pass
50
- return text + file_contents
 
 
51
 
52
- # 4. CHAT FUNCTION
53
- def chat_fn(message, history, session_id, profile: gr.OAuthProfile | None):
54
  username = profile.username if profile else "Master_Phuc"
55
- full_text = process_message(message)
56
 
57
- if not full_text.strip():
58
- yield {"text": ""}, history, session_id, ""
59
- return
60
 
61
- vault = load_vault()
62
- if username not in vault: vault[username] = {}
63
- if session_id not in vault[username]:
64
- vault[username][session_id] = {"title": message.get("text", "New Chat")[:20], "history": []}
65
-
66
- # Format chuẩn hội thoại
67
- messages = [{"role": "system", "content": f"Bạn là NodeAI Genesis. Master: {username}. Bạn hỗ trợ chuyên sâu về Roblox Lua và Web."}]
68
- for msg in history:
69
- messages.append({"role": msg["role"], "content": msg["content"]})
70
- messages.append({"role": "user", "content": full_text})
71
 
 
 
 
 
72
  try:
73
- ans = ""
74
- # Cập nhật history cho giao diện (hiển thị thumbnail ảnh nếu có)
75
- new_h = history + [{"role": "user", "content": message.get("text") or "Gửi file"}]
76
-
77
  for token in client.chat_completion(messages=messages, max_tokens=2048, stream=True):
78
  if token.choices[0].delta.content:
79
  ans += token.choices[0].delta.content
80
- yield {"text": ""}, new_h + [{"role": "assistant", "content": ans}], session_id, ""
81
 
82
- final_h = new_h + [{"role": "assistant", "content": ans}]
83
- vault[username][session_id]["history"] = final_h
84
- save_vault(vault)
85
- yield {"text": ""}, final_h, session_id, ans
 
86
  except Exception as e:
87
- yield {"text": ""}, history + [{"role": "assistant", "content": f"Lỗi: {str(e)}"}], session_id, ""
88
 
89
- # 5. GIAO DIỆN
90
- with gr.Blocks(title="NodeAI Genesis Pro") as demo:
91
  session_id = gr.State(str(uuid.uuid4()))
92
  tts_buffer = gr.Textbox(visible=False)
93
- vault_state = gr.State(load_vault())
94
-
95
  with gr.Row():
96
- with gr.Column(elem_classes="sidebar-node"):
97
- gr.HTML("<div class='logo-text'>NODEAI GENESIS</div>")
 
98
  gr.LoginButton()
99
- new_btn = gr.Button("+ NEW WORKSPACE", elem_classes="orange-btn")
100
 
101
- @gr.render(inputs=[vault_state])
102
- def render_history(current_vault, profile: gr.OAuthProfile | None):
103
- username = profile.username if profile else "Master_Phuc"
104
- user_chats = current_vault.get(username, {})
105
  with gr.Column():
106
- for sid in reversed(list(user_chats.keys())):
107
- btn = gr.Button(f"◈ {user_chats[sid]['title']}", variant="ghost")
108
- btn.click(lambda s=sid, u=username: (load_vault()[u][s]["history"], s), None, [chatbot, session_id])
 
109
 
110
- with gr.Column(elem_classes="chat-main"):
111
- chatbot = gr.Chatbot(show_label=False)
112
- audio_out = gr.Audio(autoplay=True, visible=False)
113
- with gr.Row(elem_classes="input-fixed-bottom"):
 
 
114
  msg_input = gr.MultimodalTextbox(
115
- show_label=False, placeholder="Gửi ảnh, file lua hoặc nhắn tin...",
116
- container=False, file_types=["image", ".lua", ".py", ".txt"]
 
 
117
  )
118
 
119
- msg_input.submit(chat_fn, [msg_input, chatbot, session_id], [msg_input, chatbot, session_id, tts_buffer]
120
- ).then(lambda: load_vault(), None, vault_state
121
- ).then(lambda x: f"https://translate.google.com/translate_tts?ie=UTF-8&tl=vi&client=tw-ob&q={x[:200]}" if x else None, tts_buffer, audio_out)
 
 
 
 
 
 
 
 
 
 
 
122
 
123
- new_btn.click(lambda: ([], str(uuid.uuid4())), None, [chatbot, session_id])
124
 
125
  if __name__ == "__main__":
126
- demo.launch(css=custom_css)
 
1
  import gradio as gr
2
  from huggingface_hub import InferenceClient
3
+ from supabase import create_client, Client
4
  import os
5
  import uuid
6
  import json
7
+ import base64
8
 
9
+ # 1. CẤU HÌNH CORE (Lấy từ Secrets của Hugging Face)
10
+ URL = os.environ.get("SUPABASE_URL")
11
+ KEY = os.environ.get("SUPABASE_KEY")
12
+ HF_TOKEN = os.environ.get("HUGGINGFACE_HUB_TOKEN")
 
13
 
14
+ # Khởi tạo siêu máy chủ
15
+ supabase: Client = create_client(URL, KEY)
16
+ client = InferenceClient(model="Qwen/Qwen2.5-7B-Instruct", token=HF_TOKEN)
 
 
 
17
 
18
+ # 2. HÀM XỬ LÝ DATABASE (Supabase Vĩnh Cửu)
19
+ def get_user_history(username):
20
+ try:
21
+ res = supabase.table("chats").select("*").eq("username", username).order("created_at", desc=True).execute()
22
+ return res.data
23
+ except: return []
24
+
25
+ def save_to_db(username, session_id, title, history):
26
+ try:
27
+ data = {"username": username, "session_id": session_id, "title": title, "history": history}
28
+ supabase.table("chats").upsert(data, on_conflict="session_id").execute()
29
+ except Exception as e: print(f"DB Error: {e}")
30
 
31
+ # 3. GIAO DIỆN SIÊU CẤP (GLASSMORPHISM PRO)
32
  custom_css = """
33
+ @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@700&family=Plus+Jakarta+Sans:wght@400;600&display=swap');
34
+ :root { --primary: #38bdf8; --accent: #f97316; }
35
+ .gradio-container { background: radial-gradient(circle at 50% 0%, #0f172a 0%, #020617 100%) !important; color: #e2e8f0 !important; }
36
+ .sidebar-node { background: rgba(15, 23, 42, 0.7) !important; backdrop-filter: blur(20px) !important; border-right: 1px solid rgba(56, 189, 248, 0.2) !important; height: 100vh !important; }
37
+ .logo-area { font-family: 'Orbitron', sans-serif; background: linear-gradient(90deg, var(--primary), #818cf8); -webkit-background-clip: text; -webkit-text-fill-color: transparent; text-align: center; padding: 20px 0; }
38
+ .chat-bubble { border-radius: 15px !important; border: 1px solid rgba(255,255,255,0.1) !important; }
39
+ .input-area { background: rgba(30, 41, 59, 0.9) !important; border: 1px solid var(--primary) !important; border-radius: 20px !important; box-shadow: 0 0 20px rgba(56, 189, 248, 0.2) !important; }
40
+ .orange-btn { background: linear-gradient(135deg, #f97316 0%, #fb923c 100%) !important; color: white !important; font-weight: bold !important; border: none !important; }
41
  footer { display: none !important; }
42
  """
43
 
44
+ # 4. LOGIC XỬ LÝ ĐA PHƯƠNG TIỆN (Multimodal)
45
+ def process_content(message):
46
  text = message.get("text", "")
47
  files = message.get("files", [])
48
+ combined_prompt = text
49
 
50
  for f in files:
51
+ name = os.path.basename(f)
52
  if f.lower().endswith(('.lua', '.py', '.txt', '.js', '.html', '.css')):
53
  try:
54
  with open(f, "r", encoding="utf-8") as file:
55
+ combined_prompt += f"\n\n[FILE: {name}]\n{file.read()}"
 
56
  except: pass
57
+ elif f.lower().endswith(('.png', '.jpg', '.jpeg')):
58
+ combined_prompt += f"\n\n[ Master đã gửi 1 ảnh: {name} ]"
59
+ return combined_prompt
60
 
61
+ def chat_engine(message, history, session_id, profile: gr.OAuthProfile | None):
 
62
  username = profile.username if profile else "Master_Phuc"
63
+ full_prompt = process_content(message)
64
 
65
+ if not full_prompt.strip(): yield "", history, session_id, "" ; return
 
 
66
 
67
+ # Build Prompt
68
+ messages = [{"role": "system", "content": f"Bạn là NodeAI Genesis. Master: {username}. Bạn là chuyên gia Roblox và Web. Hãy phân tích kỹ code Master gửi."}]
69
+ for msg in history: messages.append({"role": msg["role"], "content": msg["content"]})
70
+ messages.append({"role": "user", "content": full_prompt})
 
 
 
 
 
 
71
 
72
+ ans = ""
73
+ # Cập nhật UI ngay lập tức
74
+ display_history = history + [{"role": "user", "content": message.get("text") or "Gửi file"}]
75
+
76
  try:
 
 
 
 
77
  for token in client.chat_completion(messages=messages, max_tokens=2048, stream=True):
78
  if token.choices[0].delta.content:
79
  ans += token.choices[0].delta.content
80
+ yield "", display_history + [{"role": "assistant", "content": ans}], session_id, ""
81
 
82
+ # Lưu vào Supabase sau khi hoàn thành stream
83
+ final_history = display_history + [{"role": "assistant", "content": ans}]
84
+ title = message.get("text", "Workspace Analysis")[:25]
85
+ save_to_db(username, session_id, title, final_history)
86
+ yield "", final_history, session_id, ans
87
  except Exception as e:
88
+ yield "", history + [{"role": "assistant", "content": f"⚠️ Lỗi: {str(e)}"}], session_id, ""
89
 
90
+ # 5. DỰNG WEB APP
91
+ with gr.Blocks(title="NodeAI Diamond Pro", css=custom_css) as demo:
92
  session_id = gr.State(str(uuid.uuid4()))
93
  tts_buffer = gr.Textbox(visible=False)
94
+ db_state = gr.State([])
95
+
96
  with gr.Row():
97
+ # Sidebar History
98
+ with gr.Column(scale=1, elem_classes="sidebar-node"):
99
+ gr.HTML("<div class='logo-area'><h1>NODEAI GENESIS</h1></div>")
100
  gr.LoginButton()
101
+ new_chat = gr.Button("+ NEW WORKSPACE", elem_classes="orange-btn")
102
 
103
+ gr.Markdown("### 🛠 Lịch sử Cloud")
104
+ @gr.render(inputs=[db_state])
105
+ def render_history(items, profile: gr.OAuthProfile | None):
 
106
  with gr.Column():
107
+ for item in items:
108
+ b = gr.Button(f"◈ {item['title']}", variant="ghost")
109
+ b.click(lambda h=item['history'], s=item['session_id']: (h, s),
110
+ None, [chatbot, session_id])
111
 
112
+ # Main Chat Area
113
+ with gr.Column(scale=4):
114
+ chatbot = gr.Chatbot(show_label=False, bubble_full_width=False, height="75vh")
115
+ audio_player = gr.Audio(autoplay=True, visible=False)
116
+
117
+ with gr.Row(elem_classes="input-area"):
118
  msg_input = gr.MultimodalTextbox(
119
+ show_label=False,
120
+ placeholder="Dán script Roblox hoặc hỏi Master Phúc...",
121
+ file_types=["image", ".lua", ".py", ".txt"],
122
+ container=False
123
  )
124
 
125
+ # Khởi tạo dữ liệu
126
+ def refresh(profile: gr.OAuthProfile | None):
127
+ user = profile.username if profile else "Master_Phuc"
128
+ return get_user_history(user)
129
+
130
+ demo.load(refresh, None, db_state)
131
+
132
+ # Event Handlers
133
+ msg_input.submit(
134
+ chat_engine, [msg_input, chatbot, session_id], [msg_input, chatbot, session_id, tts_buffer]
135
+ ).then(refresh, None, db_state).then(
136
+ lambda x: f"https://translate.google.com/translate_tts?ie=UTF-8&tl=vi&client=tw-ob&q={x[:200]}" if x else None,
137
+ tts_buffer, audio_player
138
+ )
139
 
140
+ new_chat.click(lambda: ([], str(uuid.uuid4())), None, [chatbot, session_id])
141
 
142
  if __name__ == "__main__":
143
+ demo.launch()