lamgamepro1 commited on
Commit
5ae4eec
·
verified ·
1 Parent(s): b65decc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +119 -66
app.py CHANGED
@@ -10,11 +10,12 @@ except: DDGS = None
10
  try: from gtts import gTTS
11
  except: gTTS = None
12
 
13
- # 1. CẤU HÌNH
14
  HF_TOKEN = os.getenv("HUGGINGFACE_HUB_TOKEN")
15
  client = InferenceClient(model="Qwen/Qwen2.5-7B-Instruct", token=HF_TOKEN)
16
- DB_FILE = "nodeai_platinum_v31.json"
17
 
 
18
  def load_db():
19
  if os.path.exists(DB_FILE):
20
  try:
@@ -26,81 +27,129 @@ def save_db(data):
26
  with open(DB_FILE, "w", encoding="utf-8") as f:
27
  json.dump(data, f, ensure_ascii=False, indent=4)
28
 
29
- # 2. GUI DESIGN (FIX TRÀN MÀN HÌNH)
30
  custom_css = """
31
- @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@700&family=Plus+Jakarta+Sans:wght@400;600&display=swap');
32
 
 
33
  .gradio-container {
34
- background: #08080c !important;
35
  font-family: 'Plus Jakarta Sans', sans-serif !important;
 
36
  overflow-x: hidden !important;
37
  }
38
 
39
- /* Sidebar linh hoạt */
40
  .sidebar-node {
41
  position: fixed !important;
42
  left: 0 !important; top: 0 !important;
43
- width: 260px !important; height: 100vh !important;
44
- background: #0d0d12 !important;
 
 
45
  border-right: 1px solid rgba(255, 255, 255, 0.05) !important;
46
  z-index: 1000 !important;
47
- padding: 20px !important;
 
48
  }
49
 
 
50
  .logo-text {
51
  font-family: 'Orbitron', sans-serif !important;
52
- background: linear-gradient(90deg, #00f2fe, #4facfe);
 
53
  -webkit-background-clip: text;
54
  -webkit-text-fill-color: transparent;
55
- font-size: 20px; text-align: center; margin-bottom: 20px;
 
56
  }
 
57
 
 
58
  .orange-btn {
59
- background: linear-gradient(90deg, #ff7e5f, #feb47b) !important;
60
- border: none !important; color: white !important; font-weight: bold !important;
 
 
 
 
 
 
 
 
61
  }
62
 
63
- /* Chat Area - Sửa lỗi tràn màn hình */
 
 
 
 
 
 
 
 
 
 
 
 
64
  .chat-main {
65
- margin-left: 260px !important;
66
- width: calc(100% - 260px) !important;
67
  min-height: 100vh !important;
68
- padding: 10px 20px !important;
69
- box-sizing: border-box !important;
 
 
70
  }
71
 
 
72
  .gr-chatbot {
73
  background: transparent !important;
74
  border: none !important;
75
- height: 75vh !important;
76
- margin-bottom: 120px !important;
 
 
77
  }
78
 
79
- /* Thanh nhập liệu - Tự động co giãn theo màn hình */
80
  .input-fixed-bottom {
81
  position: fixed !important;
82
- bottom: 20px !important;
83
- left: 280px !important; /* Cách sidebar */
84
- right: 20px !important; /* Cách lề phải */
85
- background: #16161e !important;
86
- border: 1px solid rgba(0, 242, 254, 0.3) !important;
87
- border-radius: 15px !important;
88
- padding: 5px 15px !important;
 
 
 
89
  z-index: 2000 !important;
90
- box-sizing: border-box !important;
 
 
 
 
 
91
  }
92
 
93
- /* Responsive cho điện thoại */
 
 
 
94
  @media screen and (max-width: 768px) {
95
  .sidebar-node { display: none !important; }
96
  .chat-main { margin-left: 0 !important; width: 100% !important; }
97
- .input-fixed-bottom { left: 15px !important; right: 15px !important; }
 
 
 
 
98
  }
99
-
100
- footer { display: none !important; }
101
  """
102
 
103
- # 3. CORE LOGIC
104
  def chat_fn(message, history, session_id, store):
105
  user_text = message.get("text", "")
106
  if not user_text and not message.get("files", []):
@@ -108,7 +157,7 @@ def chat_fn(message, history, session_id, store):
108
  return
109
 
110
  if session_id not in store:
111
- store[session_id] = {"title": user_text[:20] if user_text else "New Workspace", "history": []}
112
 
113
  api_messages = [{"role": "system", "content": "Bạn là NodeAI Genesis. Master: Trần Đình Phúc."}]
114
  for msg in history: api_messages.append({"role": msg["role"], "content": msg["content"]})
@@ -120,13 +169,14 @@ def chat_fn(message, history, session_id, store):
120
  for token in client.chat_completion(messages=api_messages, max_tokens=2000, stream=True):
121
  if token.choices[0].delta.content:
122
  ans += token.choices[0].delta.content
123
- # Chỉ gửi text về chatbot, không gửi về audio_out ở đây
124
  yield {"text": ""}, new_h + [{"role": "assistant", "content": ans}], session_id, store, ""
125
 
126
  final_h = new_h + [{"role": "assistant", "content": ans}]
127
  store[session_id]["history"] = final_h
128
  save_db(store)
129
- # Khi xong hẳn, gửi văn bản cuối cùng vào tts_buffer (một Textbox ẩn)
 
130
  yield {"text": ""}, final_h, session_id, store, ans
131
  except Exception as e:
132
  yield {"text": ""}, history + [{"role": "assistant", "content": str(e)}], session_id, store, ""
@@ -139,42 +189,45 @@ def tts_engine(text):
139
  return "voice.mp3"
140
  except: return None
141
 
142
- # 4. INTERFACE
143
- with gr.Blocks(title="NodeAI Genesis") as demo:
144
  chat_store = gr.State(load_db())
145
  session_id = gr.State(str(uuid.uuid4()))
146
- tts_buffer = gr.Textbox(visible=False) # Dùng làm trung gian để fix lỗi audio
147
 
148
- with gr.Column(elem_classes="sidebar-node"):
149
- gr.HTML("<div class='logo-text'>NODEAI GENESIS</div>")
150
- gr.LoginButton(value="Đăng nhập")
151
- new_btn = gr.Button("+ NEW WORKSPACE", variant="primary", elem_classes="orange-btn")
152
-
153
- with gr.Column():
154
- @gr.render(inputs=chat_store)
155
- def render_history(store):
156
- for sid in reversed(list(store.keys())):
157
- btn = gr.Button(f"◈ {store[sid]['title']}", variant="ghost")
158
- btn.click(lambda s=sid: (store[s]["history"], s), None, [chatbot, session_id])
159
-
160
- with gr.Column(elem_classes="chat-main"):
161
- chatbot = gr.Chatbot(show_label=False)
162
- audio_out = gr.Audio(autoplay=True, visible=False)
163
-
164
- with gr.Row(elem_classes="input-fixed-bottom"):
165
- msg_input = gr.MultimodalTextbox(
166
- show_label=False,
167
- placeholder="Hỏi Master Phúc bất cứ điều gì...",
168
- container=False
169
- )
170
-
171
- # LUỒNG XỬ LÝ (QUAN TRỌNG ĐỂ FIX LỖI)
 
 
 
172
  msg_input.submit(
173
  chat_fn,
174
  [msg_input, chatbot, session_id, chat_store],
175
- [msg_input, chatbot, session_id, chat_store, tts_buffer] # Trả kết quả TTS vào buffer
176
  ).then(
177
- tts_engine, tts_buffer, audio_out # TTS chỉ đọc từ buffer, không đọc từ Chatbot
178
  )
179
 
180
  new_btn.click(lambda: ([], str(uuid.uuid4())), None, [chatbot, session_id])
 
10
  try: from gtts import gTTS
11
  except: gTTS = None
12
 
13
+ # 1. CẤU HÌNH HỆ THỐNG & MODEL
14
  HF_TOKEN = os.getenv("HUGGINGFACE_HUB_TOKEN")
15
  client = InferenceClient(model="Qwen/Qwen2.5-7B-Instruct", token=HF_TOKEN)
16
+ DB_FILE = "nodeai_pro_memory.json"
17
 
18
+ # 2. HỆ THỐNG TRÍ NHỚ (MEMORY CACHE)
19
  def load_db():
20
  if os.path.exists(DB_FILE):
21
  try:
 
27
  with open(DB_FILE, "w", encoding="utf-8") as f:
28
  json.dump(data, f, ensure_ascii=False, indent=4)
29
 
30
+ # 3. GIAO DIỆN SIÊU ĐẸP (GLASSMORPHISM & ORANGE GLOW)
31
  custom_css = """
32
+ @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@800&family=Plus+Jakarta+Sans:wght@400;500;600&display=swap');
33
 
34
+ /* Nền vũ trụ tối */
35
  .gradio-container {
36
+ background: radial-gradient(circle at 50% 0%, #151522 0%, #050508 100%) !important;
37
  font-family: 'Plus Jakarta Sans', sans-serif !important;
38
+ color: #e2e8f0 !important;
39
  overflow-x: hidden !important;
40
  }
41
 
42
+ /* Sidebar Kính mờ (Glassmorphism) */
43
  .sidebar-node {
44
  position: fixed !important;
45
  left: 0 !important; top: 0 !important;
46
+ width: 280px !important; height: 100vh !important;
47
+ background: rgba(15, 15, 20, 0.4) !important;
48
+ backdrop-filter: blur(20px) !important;
49
+ -webkit-backdrop-filter: blur(20px) !important;
50
  border-right: 1px solid rgba(255, 255, 255, 0.05) !important;
51
  z-index: 1000 !important;
52
+ padding: 25px 20px !important;
53
+ box-shadow: 5px 0 30px rgba(0,0,0,0.5) !important;
54
  }
55
 
56
+ /* Logo Cyberpunk */
57
  .logo-text {
58
  font-family: 'Orbitron', sans-serif !important;
59
+ background: linear-gradient(90deg, #00f2fe, #4facfe, #00f2fe);
60
+ background-size: 200% auto;
61
  -webkit-background-clip: text;
62
  -webkit-text-fill-color: transparent;
63
+ font-size: 26px; text-align: center; margin-bottom: 30px;
64
+ animation: shine 3s linear infinite;
65
  }
66
+ @keyframes shine { to { background-position: 200% center; } }
67
 
68
+ /* Nút New Workspace Màu Cam Rực Rỡ */
69
  .orange-btn {
70
+ background: linear-gradient(135deg, #FF6B6B 0%, #FF8E53 100%) !important;
71
+ border: none !important; color: white !important; font-weight: 600 !important;
72
+ border-radius: 12px !important; padding: 10px !important;
73
+ transition: all 0.3s ease !important;
74
+ box-shadow: 0 4px 15px rgba(255, 107, 107, 0.3) !important;
75
+ margin-bottom: 20px !important;
76
+ }
77
+ .orange-btn:hover {
78
+ transform: translateY(-2px) !important;
79
+ box-shadow: 0 6px 20px rgba(255, 107, 107, 0.5) !important;
80
  }
81
 
82
+ /* Nút Lịch sử Chat */
83
+ .hist-btn {
84
+ background: transparent !important; border: 1px solid transparent !important;
85
+ color: #a0aec0 !important; text-align: left !important;
86
+ border-radius: 8px !important; transition: 0.2s !important;
87
+ }
88
+ .hist-btn:hover {
89
+ background: rgba(255, 255, 255, 0.05) !important;
90
+ border: 1px solid rgba(255, 255, 255, 0.1) !important;
91
+ color: #fff !important;
92
+ }
93
+
94
+ /* Khu vực Chat Chính */
95
  .chat-main {
96
+ margin-left: 280px !important;
97
+ width: calc(100% - 280px) !important;
98
  min-height: 100vh !important;
99
+ padding: 20px 0 !important;
100
+ display: flex !important;
101
+ flex-direction: column !important;
102
+ align-items: center !important;
103
  }
104
 
105
+ /* Chatbot Box */
106
  .gr-chatbot {
107
  background: transparent !important;
108
  border: none !important;
109
+ width: 100% !important;
110
+ max-width: 900px !important;
111
+ height: 78vh !important;
112
+ margin-bottom: 100px !important;
113
  }
114
 
115
+ /* Thanh Nhập Liệu Cố Định Chống Tràn */
116
  .input-fixed-bottom {
117
  position: fixed !important;
118
+ bottom: 30px !important;
119
+ left: 50% !important;
120
+ transform: translateX(calc(-50% + 140px)) !important; /* Cân bằng với sidebar */
121
+ width: 100% !important;
122
+ max-width: 850px !important;
123
+ background: rgba(20, 20, 28, 0.8) !important;
124
+ backdrop-filter: blur(15px) !important;
125
+ border: 1px solid rgba(0, 242, 254, 0.2) !important;
126
+ border-radius: 20px !important;
127
+ padding: 8px 15px !important;
128
  z-index: 2000 !important;
129
+ box-shadow: 0 10px 40px rgba(0,0,0,0.5) !important;
130
+ transition: 0.3s !important;
131
+ }
132
+ .input-fixed-bottom:focus-within {
133
+ border-color: rgba(0, 242, 254, 0.6) !important;
134
+ box-shadow: 0 10px 40px rgba(0, 242, 254, 0.15) !important;
135
  }
136
 
137
+ /* Ẩn các thành phần thừa */
138
+ footer, .gr-button-secondary { display: none !important; }
139
+
140
+ /* Responsive Mobile */
141
  @media screen and (max-width: 768px) {
142
  .sidebar-node { display: none !important; }
143
  .chat-main { margin-left: 0 !important; width: 100% !important; }
144
+ .input-fixed-bottom {
145
+ transform: translateX(-50%) !important;
146
+ width: 90% !important;
147
+ bottom: 15px !important;
148
+ }
149
  }
 
 
150
  """
151
 
152
+ # 4. CORE LOGIC CHAT
153
  def chat_fn(message, history, session_id, store):
154
  user_text = message.get("text", "")
155
  if not user_text and not message.get("files", []):
 
157
  return
158
 
159
  if session_id not in store:
160
+ store[session_id] = {"title": user_text[:25] if user_text else "Nova Workspace", "history": []}
161
 
162
  api_messages = [{"role": "system", "content": "Bạn là NodeAI Genesis. Master: Trần Đình Phúc."}]
163
  for msg in history: api_messages.append({"role": msg["role"], "content": msg["content"]})
 
169
  for token in client.chat_completion(messages=api_messages, max_tokens=2000, stream=True):
170
  if token.choices[0].delta.content:
171
  ans += token.choices[0].delta.content
172
+ # Yield text rỗng cho tts_buffer trong lúc stream để tránh lỗi
173
  yield {"text": ""}, new_h + [{"role": "assistant", "content": ans}], session_id, store, ""
174
 
175
  final_h = new_h + [{"role": "assistant", "content": ans}]
176
  store[session_id]["history"] = final_h
177
  save_db(store)
178
+
179
+ # Chỉ khi hoàn thành mới gửi ans vào tts_buffer
180
  yield {"text": ""}, final_h, session_id, store, ans
181
  except Exception as e:
182
  yield {"text": ""}, history + [{"role": "assistant", "content": str(e)}], session_id, store, ""
 
189
  return "voice.mp3"
190
  except: return None
191
 
192
+ # 5. DỰNG GIAO DIỆN
193
+ with gr.Blocks(title="NodeAI Genesis", theme=gr.themes.Base()) as demo:
194
  chat_store = gr.State(load_db())
195
  session_id = gr.State(str(uuid.uuid4()))
196
+ tts_buffer = gr.Textbox(visible=False) # Chìa khóa chống lỗi Audio
197
 
198
+ with gr.Row():
199
+ # SIDEBAR
200
+ with gr.Column(elem_classes="sidebar-node"):
201
+ gr.HTML("<div class='logo-text'>NODEAI GENESIS</div>")
202
+ gr.LoginButton(value="Xác thực Hugging Face")
203
+ new_btn = gr.Button("+ TẠO KHÔNG GIAN MỚI", elem_classes="orange-btn")
204
+
205
+ with gr.Column():
206
+ @gr.render(inputs=chat_store)
207
+ def render_history(store):
208
+ for sid in reversed(list(store.keys())):
209
+ btn = gr.Button(f"💬 {store[sid]['title']}", elem_classes="hist-btn")
210
+ btn.click(lambda s=sid: (store[s]["history"], s), None, [chatbot, session_id])
211
+
212
+ # MAIN CHAT
213
+ with gr.Column(elem_classes="chat-main"):
214
+ chatbot = gr.Chatbot(show_label=False, avatar_images=(None, "https://cdn-icons-png.flaticon.com/512/4712/4712139.png"))
215
+ audio_out = gr.Audio(autoplay=True, visible=False)
216
+
217
+ with gr.Row(elem_classes="input-fixed-bottom"):
218
+ msg_input = gr.MultimodalTextbox(
219
+ show_label=False,
220
+ placeholder="Nhập lệnh cho NodeAI...",
221
+ container=False
222
+ )
223
+
224
+ # XỬ LÝ SỰ KIỆN KHÔNG LỖI
225
  msg_input.submit(
226
  chat_fn,
227
  [msg_input, chatbot, session_id, chat_store],
228
+ [msg_input, chatbot, session_id, chat_store, tts_buffer]
229
  ).then(
230
+ tts_engine, tts_buffer, audio_out
231
  )
232
 
233
  new_btn.click(lambda: ([], str(uuid.uuid4())), None, [chatbot, session_id])