lamgamepro1 commited on
Commit
604537c
·
verified ·
1 Parent(s): 0327e31

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +78 -75
app.py CHANGED
@@ -4,13 +4,11 @@ from supabase import create_client, Client
4
  import os
5
  import uuid
6
 
7
- # 1. CẤU HÌNH CORE & SUPABASE
8
  URL = os.environ.get("SUPABASE_URL")
9
  KEY = os.environ.get("SUPABASE_KEY")
10
  HF_TOKEN = os.environ.get("HUGGINGFACE_HUB_TOKEN")
11
 
12
- MASTER_ID = "lamgamepro"
13
-
14
  try:
15
  supabase: Client = create_client(URL, KEY) if URL and KEY else None
16
  except:
@@ -18,118 +16,123 @@ except:
18
 
19
  client = InferenceClient(model="Qwen/Qwen2.5-7B-Instruct", token=HF_TOKEN)
20
 
21
- # 2. HỆ THỐNG MEMORY
22
- def get_db_history():
23
- if not supabase: return []
 
24
  try:
25
- res = supabase.table("chats").select("*").eq("username", MASTER_ID).order("created_at", desc=True).execute()
26
  return res.data
27
- except Exception as e:
28
- print(f"Lỗi tải DB: {e}")
29
  return []
30
 
31
- def save_to_db(session_id, title, history):
32
- if not supabase: return
 
 
33
  try:
34
- data = {"username": MASTER_ID, "session_id": session_id, "title": title, "history": history}
 
 
 
 
 
35
  supabase.table("chats").upsert(data, on_conflict="session_id").execute()
36
- except Exception as e:
37
- print(f"Lỗi lưu DB: {e}")
38
 
39
- # 3. GIAO DIỆN GLASSMORPHISM
40
  custom_css = """
41
  @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@700&family=Plus+Jakarta+Sans:wght@400;600&display=swap');
42
- :root { --primary: #38bdf8; --accent: #f97316; }
43
- .gradio-container { background: radial-gradient(circle at 50% 0%, #0f172a 0%, #020617 100%) !important; color: #e2e8f0 !important; font-family: 'Plus Jakarta Sans', sans-serif !important; }
44
- .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; padding: 20px; overflow-y: auto; }
45
- .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: 10px 0 30px 0; font-size: 24px; }
46
- .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; margin-top: 15px; }
47
- .orange-btn { background: linear-gradient(135deg, #f97316 0%, #fb923c 100%) !important; color: white !important; font-weight: bold !important; border: none !important; border-radius: 12px !important; margin-bottom: 20px; }
48
- footer { display: none !important; }
49
  """
50
 
51
- # 4. LOGIC XỬ LÝ
52
- def process_content(message):
53
  text = message.get("text", "")
54
- files = message.get("files", [])
55
- combined_prompt = text
56
- for f in files:
57
- name = os.path.basename(f)
58
- if f.lower().endswith(('.lua', '.py', '.txt', '.js', '.html', '.css')):
59
- try:
60
- with open(f, "r", encoding="utf-8") as file:
61
- combined_prompt += f"\n\n[FILE: {name}]\n{file.read()}"
62
- except: pass
63
- return combined_prompt
64
-
65
- def chat_engine(message, history, session_id):
66
- full_prompt = process_content(message)
67
- if not full_prompt.strip():
68
- yield gr.update(value={"text": "", "files": []}), history, session_id
69
- return
70
-
71
- messages = [{"role": "system", "content": "Bạn là NodeAI Genesis. Chuyên gia Roblox Studio và Web Development."}]
72
  for msg in history:
73
  messages.append({"role": msg["role"], "content": msg["content"]})
74
-
75
- messages.append({"role": "user", "content": full_prompt})
76
-
77
- # Gradio 6 dùng list of dicts mặc định
78
- new_history = history + [{"role": "user", "content": message.get("text") or "Đã gửi tệp tin"}]
79
  ans = ""
80
 
 
 
 
81
  yield gr.update(value={"text": "", "files": []}), new_history + [{"role": "assistant", "content": "..."}], session_id
82
 
83
  try:
84
  for token in client.chat_completion(messages=messages, max_tokens=2048, stream=True):
85
  if token.choices[0].delta.content:
86
  ans += token.choices[0].delta.content
87
- yield gr.update(), new_history + [{"role": "assistant", "content": ans}], session_id
88
 
89
- save_to_db(session_id, (message.get("text") or "Code Analysis")[:25], new_history + [{"role": "assistant", "content": ans}])
 
 
 
90
  except Exception as e:
91
  yield gr.update(), new_history + [{"role": "assistant", "content": f"Lỗi: {str(e)}"}], session_id
92
 
93
- # 5. UI GIAO DIỆN (Đã sửa lỗi gr.Chatbot và gr.Blocks)
94
- with gr.Blocks(title="NodeAI Genesis Pro") as demo:
95
  session_id = gr.State(str(uuid.uuid4()))
96
  db_state = gr.State([])
97
 
98
  with gr.Row():
99
  with gr.Column(scale=1, elem_classes="sidebar-node"):
100
  gr.HTML("<div class='logo-area'>NODEAI GENESIS</div>")
101
- new_chat_btn = gr.Button("+ WORKSPACE MỚI", elem_classes="orange-btn")
 
 
 
 
 
 
 
102
  gr.Markdown("### 🗄️ Database Memory")
103
 
 
 
104
  @gr.render(inputs=[db_state])
105
- def render_history(items):
106
  with gr.Column():
107
- for item in items or []:
108
- b = gr.Button(f"◈ {item['title']}", variant="ghost")
109
- b.click(lambda h=item['history'], s=item['session_id']: (h, s), None, [chatbot, session_id])
110
 
111
  with gr.Column(scale=4):
112
- # FIX: Bỏ tham số 'type="messages"' vì bản 6.0 đã mặc định cấu trúc này
113
- chatbot = gr.Chatbot(show_label=False, height="80vh")
114
-
115
- with gr.Row(elem_classes="input-area"):
116
- msg_input = gr.MultimodalTextbox(
117
- show_label=False,
118
- placeholder="Hỏi đáp hoặc gửi code Lua tại đây...",
119
- file_types=["image", ".lua", ".py", ".js", ".html"],
120
- container=False
121
- )
122
-
123
- demo.load(lambda: get_db_history(), None, db_state)
124
-
125
- msg_input.submit(
126
- chat_engine,
127
- [msg_input, chatbot, session_id],
128
- [msg_input, chatbot, session_id]
129
- ).then(lambda: get_db_history(), None, db_state)
130
 
 
131
  new_chat_btn.click(lambda: ([], str(uuid.uuid4())), None, [chatbot, session_id])
132
 
133
  if __name__ == "__main__":
134
- # FIX: Chuyển css xuống launch()
135
  demo.launch(css=custom_css)
 
4
  import os
5
  import uuid
6
 
7
+ # 1. CẤU HÌNH CORE
8
  URL = os.environ.get("SUPABASE_URL")
9
  KEY = os.environ.get("SUPABASE_KEY")
10
  HF_TOKEN = os.environ.get("HUGGINGFACE_HUB_TOKEN")
11
 
 
 
12
  try:
13
  supabase: Client = create_client(URL, KEY) if URL and KEY else None
14
  except:
 
16
 
17
  client = InferenceClient(model="Qwen/Qwen2.5-7B-Instruct", token=HF_TOKEN)
18
 
19
+ # 2. HỆ THỐNG MEMORY (Chỉ chạy khi có Profile)
20
+ def get_db_history(profile: gr.OAuthProfile | None):
21
+ if not supabase or not profile:
22
+ return []
23
  try:
24
+ res = supabase.table("chats").select("*").eq("username", profile.username).order("created_at", desc=True).execute()
25
  return res.data
26
+ except:
 
27
  return []
28
 
29
+ def save_to_db(session_id, title, history, profile: gr.OAuthProfile | None):
30
+ # CHẶN LƯU: Nếu không có profile (chưa đăng nhập) thì thoát luôn
31
+ if not supabase or not profile or profile.username is None:
32
+ return
33
  try:
34
+ data = {
35
+ "username": profile.username,
36
+ "session_id": session_id,
37
+ "title": title,
38
+ "history": history
39
+ }
40
  supabase.table("chats").upsert(data, on_conflict="session_id").execute()
41
+ except:
42
+ pass
43
 
44
+ # 3. GIAO DIỆN
45
  custom_css = """
46
  @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@700&family=Plus+Jakarta+Sans:wght@400;600&display=swap');
47
+ .gradio-container { background: radial-gradient(circle at 50% 0%, #0f172a 0%, #020617 100%) !important; color: #e2e8f0 !important; }
48
+ .sidebar-node { background: rgba(15, 23, 42, 0.8) !important; backdrop-filter: blur(15px); border-right: 1px solid #38bdf833; padding: 20px; overflow-y: auto; height: 100vh; }
49
+ .logo-area { font-family: 'Orbitron'; background: linear-gradient(90deg, #38bdf8, #818cf8); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-size: 22px; margin-bottom: 20px; text-align: center; }
50
+ .status-tag { font-size: 0.8em; padding: 5px 10px; border-radius: 20px; text-align: center; margin-bottom: 15px; }
51
+ .status-online { background: rgba(34, 197, 94, 0.2); color: #4ade80; border: 1px solid #22c55e44; }
52
+ .status-offline { background: rgba(239, 68, 68, 0.2); color: #f87171; border: 1px solid #ef444444; }
 
53
  """
54
 
55
+ def chat_engine(message, history, session_id, profile: gr.OAuthProfile | None):
 
56
  text = message.get("text", "")
57
+ if not text.strip(): return gr.update(value={"text": "", "files": []}), history, session_id
58
+
59
+ # Xác định Master hay Khách
60
+ user_name = profile.username if profile else "Guest"
61
+ messages = [{"role": "system", "content": f"Bạn là NodeAI Genesis. Đang hỗ trợ: {user_name}."}]
62
+
 
 
 
 
 
 
 
 
 
 
 
 
63
  for msg in history:
64
  messages.append({"role": msg["role"], "content": msg["content"]})
65
+ messages.append({"role": "user", "content": text})
66
+
67
+ new_history = history + [{"role": "user", "content": text}]
 
 
68
  ans = ""
69
 
70
+ # Hiển thị trạng thái lưu
71
+ save_status = "" if profile else "\n\n*(Lưu ý: Bạn chưa đăng nhập, lịch sử này sẽ mất khi tải lại trang)*"
72
+
73
  yield gr.update(value={"text": "", "files": []}), new_history + [{"role": "assistant", "content": "..."}], session_id
74
 
75
  try:
76
  for token in client.chat_completion(messages=messages, max_tokens=2048, stream=True):
77
  if token.choices[0].delta.content:
78
  ans += token.choices[0].delta.content
79
+ yield gr.update(), new_history + [{"role": "assistant", "content": ans + (save_status if not token.choices[0].delta.content else "")}], session_id
80
 
81
+ # CHỈ LƯU VÀO DB KHI CÓ PROFILE
82
+ if profile:
83
+ save_to_db(session_id, text[:25], new_history + [{"role": "assistant", "content": ans}], profile)
84
+
85
  except Exception as e:
86
  yield gr.update(), new_history + [{"role": "assistant", "content": f"Lỗi: {str(e)}"}], session_id
87
 
88
+ # 4. UI
89
+ with gr.Blocks() as demo:
90
  session_id = gr.State(str(uuid.uuid4()))
91
  db_state = gr.State([])
92
 
93
  with gr.Row():
94
  with gr.Column(scale=1, elem_classes="sidebar-node"):
95
  gr.HTML("<div class='logo-area'>NODEAI GENESIS</div>")
96
+
97
+ gr.LoginButton(value="Sign in with Hugging Face", size="sm")
98
+
99
+ # Hiển thị trạng thái đăng nhập trực quan
100
+ with gr.Group():
101
+ status_html = gr.HTML()
102
+
103
+ new_chat_btn = gr.Button("+ CHAT MỚI", variant="primary")
104
  gr.Markdown("### 🗄️ Database Memory")
105
 
106
+ # Render danh sách lịch sử
107
+ history_box = gr.Column()
108
  @gr.render(inputs=[db_state])
109
+ def show_history(items):
110
  with gr.Column():
111
+ for item in items:
112
+ btn = gr.Button(f"◈ {item['title']}", variant="ghost")
113
+ btn.click(lambda h=item['history'], s=item['session_id']: (h, s), None, [chatbot, session_id])
114
 
115
  with gr.Column(scale=4):
116
+ chatbot = gr.Chatbot(show_label=False, height="85vh")
117
+ msg_input = gr.MultimodalTextbox(show_label=False, placeholder="Hỏi NodeAI...", container=False)
118
+
119
+ # Logic khi tải trang / Đăng nhập
120
+ def check_user(profile: gr.OAuthProfile | None):
121
+ if profile:
122
+ msg = f"<div class='status-tag status-online'>● Online: {profile.username}</div>"
123
+ return msg, get_db_history(profile)
124
+ msg = "<div class='status-tag status-offline'>● Guest Mode (No Save)</div>"
125
+ return msg, []
126
+
127
+ demo.load(check_user, None, [status_html, db_state])
128
+
129
+ # Sự kiện chat
130
+ msg_input.submit(chat_engine, [msg_input, chatbot, session_id], [msg_input, chatbot, session_id]).then(
131
+ lambda profile: get_db_history(profile) if profile else [], None, db_state
132
+ )
 
133
 
134
+ # Nút chat mới
135
  new_chat_btn.click(lambda: ([], str(uuid.uuid4())), None, [chatbot, session_id])
136
 
137
  if __name__ == "__main__":
 
138
  demo.launch(css=custom_css)