lamgamepro1 commited on
Commit
91de618
·
verified ·
1 Parent(s): e687e78

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +75 -52
app.py CHANGED
@@ -16,19 +16,19 @@ 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 = {
@@ -38,27 +38,29 @@ def save_to_db(session_id, title, history, profile: gr.OAuthProfile | None):
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"]})
@@ -67,8 +69,8 @@ def chat_engine(message, history, session_id, profile: gr.OAuthProfile | None):
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
 
@@ -76,63 +78,84 @@ def chat_engine(message, history, session_id, profile: gr.OAuthProfile | None):
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)
 
16
 
17
  client = InferenceClient(model="Qwen/Qwen2.5-7B-Instruct", token=HF_TOKEN)
18
 
19
+ # 2. HỆ THỐNG MEMORY (Xử lý theo từng User)
20
  def get_db_history(profile: gr.OAuthProfile | None):
21
+ if not supabase or not profile or not profile.username:
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 Exception as e:
27
+ print(f"Lỗi DB: {e}")
28
  return []
29
 
30
  def save_to_db(session_id, title, history, profile: gr.OAuthProfile | None):
31
+ if not supabase or not profile or not profile.username:
 
32
  return
33
  try:
34
  data = {
 
38
  "history": history
39
  }
40
  supabase.table("chats").upsert(data, on_conflict="session_id").execute()
41
+ except Exception as e:
42
+ print(f"Lỗi lưu: {e}")
43
 
44
+ # 3. GIAO DIỆN GLASSMORPHISM
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; font-family: 'Plus Jakarta Sans', sans-serif !important; }
48
+ .sidebar-node { background: rgba(15, 23, 42, 0.8) !important; backdrop-filter: blur(15px); border-right: 1px solid #38bdf833; padding: 20px; height: 100vh; overflow-y: auto; }
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: 25px; text-align: center; font-weight: bold; }
50
+ .status-tag { font-size: 0.85em; padding: 8px; border-radius: 12px; text-align: center; margin-bottom: 15px; border: 1px solid rgba(255,255,255,0.1); }
51
+ .history-btn { margin-bottom: 5px !important; text-align: left !important; justify-content: flex-start !important; }
 
52
  """
53
 
54
+ # 4. LOGIC XỬ LÝ CHAT
55
  def chat_engine(message, history, session_id, profile: gr.OAuthProfile | None):
56
+ text = message.get("text", "").strip()
57
+ if not text:
58
+ yield gr.update(value={"text": "", "files": []}), history, session_id
59
+ return
60
 
61
+ # Xác định danh tính
62
  user_name = profile.username if profile else "Guest"
63
+ messages = [{"role": "system", "content": f"Bạn là NodeAI Genesis. Master: {user_name}. Phản hồi bằng tiếng Việt chuyên nghiệp."}]
64
 
65
  for msg in history:
66
  messages.append({"role": msg["role"], "content": msg["content"]})
 
69
  new_history = history + [{"role": "user", "content": text}]
70
  ans = ""
71
 
72
+ # Thông báo nếu không lưu được
73
+ save_info = "" if profile else "\n\n*(Lưu ý: Bạn đang ở chế độ Guest, lịch sử sẽ không được lưu)*"
74
 
75
  yield gr.update(value={"text": "", "files": []}), new_history + [{"role": "assistant", "content": "..."}], session_id
76
 
 
78
  for token in client.chat_completion(messages=messages, max_tokens=2048, stream=True):
79
  if token.choices[0].delta.content:
80
  ans += token.choices[0].delta.content
81
+ yield gr.update(), new_history + [{"role": "assistant", "content": ans}], session_id
82
 
83
+ # Chỉ lưu khi đã có profile
84
  if profile:
85
  save_to_db(session_id, text[:25], new_history + [{"role": "assistant", "content": ans}], profile)
86
 
87
  except Exception as e:
88
+ yield gr.update(), new_history + [{"role": "assistant", "content": f"Lỗi kết nối: {str(e)}"}], session_id
89
 
90
+ # 5. UI GIAO DIỆN
91
+ with gr.Blocks(title="NodeAI Genesis Pro") as demo:
92
  session_id = gr.State(str(uuid.uuid4()))
93
  db_state = gr.State([])
94
 
95
  with gr.Row():
96
+ # SIDEBAR
97
  with gr.Column(scale=1, elem_classes="sidebar-node"):
98
  gr.HTML("<div class='logo-area'>NODEAI GENESIS</div>")
99
 
100
+ gr.LoginButton(value="Đăng nhập Hugging Face", size="sm")
101
 
102
+ status_display = gr.HTML("<div class='status-tag'>🔴 Chưa đăng nhập</div>")
 
 
103
 
104
  new_chat_btn = gr.Button("+ CHAT MỚI", variant="primary")
105
+
106
  gr.Markdown("### 🗄️ Database Memory")
107
 
108
+ # Sử dụng gr.render để cập nhật danh sách lịch sử mà không gây lỗi Key
 
109
  @gr.render(inputs=[db_state])
110
+ def render_history_list(items):
111
  with gr.Column():
112
+ if not items:
113
+ gr.Markdown("*Không có dữ liệu*")
114
  for item in items:
115
+ # Dùng hàm lambda bọc kín để tránh lỗi truyền tham số trong vòng lặp
116
+ btn = gr.Button(f"◈ {item['title']}", variant="ghost", elem_classes="history-btn")
117
+ btn.click(
118
+ fn=lambda h=item['history'], s=item['session_id']: (h, s),
119
+ outputs=[chatbot, session_id]
120
+ )
121
+
122
+ # MAIN CHAT
123
  with gr.Column(scale=4):
124
+ chatbot = gr.Chatbot(show_label=False, height="82vh")
125
+
126
+ with gr.Row():
127
+ msg_input = gr.MultimodalTextbox(
128
+ show_label=False,
129
+ placeholder="Hỏi NodeAI hoặc dán code Roblox tại đây...",
130
+ container=False,
131
+ scale=7
132
+ )
133
+
134
+ # XỬ LÝ SỰ KIỆN
135
+ def on_load(profile: gr.OAuthProfile | None):
136
  if profile:
137
+ status = f"<div class='status-tag' style='color:#4ade80'>🟢 Master: {profile.username}</div>"
138
+ history = get_db_history(profile)
139
+ return status, history
140
+ return "<div class='status-tag'>🔴 Chế độ Guest (Không lưu)</div>", []
141
+
142
+ # Tải dữ liệu khi mở trang
143
+ demo.load(on_load, None, [status_display, db_state])
144
+
145
+ # Gửi tin nhắn
146
+ msg_input.submit(
147
+ chat_engine,
148
+ [msg_input, chatbot, session_id],
149
+ [msg_input, chatbot, session_id]
150
+ ).then(
151
+ fn=on_load, outputs=[status_display, db_state]
152
  )
153
 
154
+ # Tạo chat mới
155
+ new_chat_btn.click(
156
+ fn=lambda: ([], str(uuid.uuid4())),
157
+ outputs=[chatbot, session_id]
158
+ )
159
 
160
  if __name__ == "__main__":
161
  demo.launch(css=custom_css)