lamgamepro1 commited on
Commit
8b0e257
·
verified ·
1 Parent(s): 1cec434

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +91 -83
app.py CHANGED
@@ -4,7 +4,7 @@ import os
4
  import uuid
5
  import json
6
 
7
- # Import an toàn
8
  try: from duckduckgo_search import DDGS
9
  except: DDGS = None
10
  try: from gtts import gTTS
@@ -14,7 +14,7 @@ except: gTTS = None
14
  USER_ID, USER_PASS = "admin", "123456"
15
  HF_TOKEN = os.getenv("HUGGINGFACE_HUB_TOKEN")
16
  client = InferenceClient(model="Qwen/Qwen2.5-7B-Instruct", token=HF_TOKEN)
17
- DB_FILE = "nodeai_platinum_v3.json"
18
 
19
  def load_db():
20
  if os.path.exists(DB_FILE):
@@ -27,100 +27,107 @@ def save_db(data):
27
  with open(DB_FILE, "w", encoding="utf-8") as f:
28
  json.dump(data, f, ensure_ascii=False, indent=4)
29
 
30
- # 2. GUI DESIGN (FIX LỖI LAYOUT & MIC RÕ RÀNG)
31
  custom_css = """
32
  @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@700&family=Plus+Jakarta+Sans:wght@400;600&display=swap');
33
 
 
34
  .gradio-container {
35
- background: radial-gradient(circle at top right, #0d0d1a, #050505) !important;
36
  font-family: 'Plus Jakarta Sans', sans-serif !important;
37
  }
38
 
 
39
  .sidebar-pro {
40
  position: fixed !important;
41
- left: 10px !important; top: 10px !important;
42
- width: 280px !important; height: calc(100vh - 20px) !important;
43
- background: rgba(10, 10, 15, 0.9) !important;
44
- backdrop-filter: blur(20px) !important;
45
- border: 1px solid rgba(0, 242, 254, 0.2) !important;
46
- border-radius: 20px !important;
47
  z-index: 1000 !important;
48
  padding: 20px !important;
49
  }
50
 
51
  .nodeai-logo {
52
  font-family: 'Orbitron', sans-serif !important;
53
- background: linear-gradient(90deg, #00f2fe, #7ef2ff);
54
- -webkit-background-clip: text;
55
- -webkit-text-fill-color: transparent;
56
- font-size: 26px !important;
57
- text-align: center; margin-bottom: 25px;
58
  }
59
 
 
60
  .chat-col {
61
- margin-left: 300px !important;
62
- width: calc(100% - 320px) !important;
63
  height: 100vh !important;
 
64
  }
65
 
66
- .gr-chatbot { background: transparent !important; border: none !important; margin-bottom: 150px !important; }
 
 
 
 
 
67
 
68
- /* THANH NHẬP LIỆU CỐ ĐỊNH - ĐÃ FIX LỖI DỊCH CHUYỂN */
69
- .control-panel-fixed {
70
  position: fixed !important;
71
- bottom: 25px !important;
72
- left: 310px !important;
73
- right: 25px !important;
74
- background: rgba(20, 20, 35, 0.9) !important;
75
- backdrop-filter: blur(15px) !important;
76
- border: 1px solid rgba(0, 242, 254, 0.4) !important;
77
- border-radius: 35px !important;
78
- padding: 12px 25px !important;
79
- z-index: 9999 !important;
80
  display: flex !important;
81
- align-items: center !important;
82
- gap: 15px !important;
83
- box-shadow: 0 10px 40px rgba(0,0,0,0.5) !important;
84
  }
85
 
86
- .input-box { flex: 1 !important; border: none !important; background: transparent !important; }
87
-
88
- /* NÚT MIC TO VÀ RÕ RÀNG */
89
- .mic-container {
90
- min-width: 150px !important;
91
- background: rgba(255, 255, 255, 0.05) !important;
92
- border-radius: 20px !important;
93
  padding: 5px !important;
94
  }
95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  footer { display: none !important; }
97
  """
98
 
99
  # 3. CORE LOGIC
100
- def search_web(query):
101
- if not DDGS: return ""
102
- try:
103
- with DDGS() as ddgs:
104
- results = [f"[{r['title']}]({r['href']}): {r['body']}" for r in ddgs.text(query, max_results=2)]
105
- return "\n".join(results)
106
- except: return ""
107
-
108
  def chat_fn(message, history, session_id, store):
109
  user_text = message.get("text", "") if isinstance(message, dict) else message
110
- if not user_text and not message.get("files", []): return {"text": ""}, history, session_id, store, None
111
 
112
- if session_id not in store:
113
- store[session_id] = {"title": (user_text[:20] if user_text else "Audio Task"), "history": []}
114
 
115
- web_info = search_web(user_text) if any(x in user_text.lower() for x in ["tìm", "tra", "web"]) else ""
 
116
 
117
- api_messages = [{"role": "system", "content": f"Bạn là NodeAI Genesis. Master: Trần Đình Phúc. Web: {web_info}"}]
118
  for msg in history: api_messages.append({"role": msg["role"], "content": msg["content"]})
119
- api_messages.append({"role": "user", "content": user_text})
 
 
120
 
121
  try:
122
  ans = ""
123
- new_h = history + [{"role": "user", "content": user_text}]
124
  for token in client.chat_completion(messages=api_messages, max_tokens=2000, stream=True):
125
  if token.choices[0].delta.content:
126
  ans += token.choices[0].delta.content
@@ -131,7 +138,7 @@ def chat_fn(message, history, session_id, store):
131
  save_db(store)
132
  yield {"text": ""}, final_h, session_id, store, ans
133
  except Exception as e:
134
- yield {"text": ""}, history + [{"role": "assistant", "content": str(e)}], session_id, store, None
135
 
136
  def tts_engine(text):
137
  if not text or not gTTS: return None
@@ -146,37 +153,38 @@ with gr.Blocks(title="NodeAI Genesis") as demo:
146
  chat_store = gr.State(load_db())
147
  session_id = gr.State(str(uuid.uuid4()))
148
 
149
- with gr.Row():
150
- # SIDEBAR
151
- with gr.Column(elem_classes="sidebar-pro"):
152
- gr.HTML("<div class='nodeai-logo'>NODEAI</div>")
153
- new_btn = gr.Button("+ NEW WORKSPACE", variant="primary")
154
- with gr.Column():
155
- @gr.render(inputs=chat_store)
156
- def render_history(store):
157
- for sid in reversed(list(store.keys())):
158
- btn = gr.Button(f"◈ {store[sid]['title']}", variant="ghost")
159
- btn.click(lambda s=sid: (store[s]["history"], s), None, [chatbot, session_id])
 
 
 
 
160
 
161
- # MAIN CONTENT
162
- with gr.Column(elem_classes="chat-col"):
163
- chatbot = gr.Chatbot(show_label=False, height="75vh")
164
- audio_out = gr.Audio(autoplay=True, visible=False)
165
-
166
- # THANH ĐIỀU KHIỂN
167
- with gr.Row(elem_classes="control-panel-fixed"):
168
- with gr.Column(scale=7):
169
- msg_input = gr.MultimodalTextbox(
170
- show_label=False, placeholder="Hỏi NodeAI hoặc gửi ảnh...", container=False, elem_classes="input-box"
171
- )
172
- with gr.Column(scale=3, elem_classes="mic-container"):
173
- # ĐÂY LÀ MIC CỦA BẠN: Bấm vào đây để nói!
174
- mic_btn = gr.Audio(sources=["microphone"], type="filepath", label="Ghi âm", show_label=True)
175
-
176
- # Xử lý sự kiện
177
  msg_input.submit(chat_fn, [msg_input, chatbot, session_id, chat_store], [msg_input, chatbot, session_id, chat_store, audio_out]).then(tts_engine, audio_out, audio_out)
178
 
179
- def process_mic(path): return {"text": "Dịch và trả lời âm thanh này", "files": [path]}
180
  mic_btn.stop_recording(process_mic, mic_btn, msg_input)
181
 
182
  new_btn.click(lambda: ([], str(uuid.uuid4())), None, [chatbot, session_id])
 
4
  import uuid
5
  import json
6
 
7
+ # Thư viện bổ trợ
8
  try: from duckduckgo_search import DDGS
9
  except: DDGS = None
10
  try: from gtts import gTTS
 
14
  USER_ID, USER_PASS = "admin", "123456"
15
  HF_TOKEN = os.getenv("HUGGINGFACE_HUB_TOKEN")
16
  client = InferenceClient(model="Qwen/Qwen2.5-7B-Instruct", token=HF_TOKEN)
17
+ DB_FILE = "nodeai_ultimate_memory.json"
18
 
19
  def load_db():
20
  if os.path.exists(DB_FILE):
 
27
  with open(DB_FILE, "w", encoding="utf-8") as f:
28
  json.dump(data, f, ensure_ascii=False, indent=4)
29
 
30
+ # 2. GUI DESIGN (FIX TOÀN DIỆN)
31
  custom_css = """
32
  @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@700&family=Plus+Jakarta+Sans:wght@400;600&display=swap');
33
 
34
+ /* Nền chủ đạo */
35
  .gradio-container {
36
+ background: #050505 !important;
37
  font-family: 'Plus Jakarta Sans', sans-serif !important;
38
  }
39
 
40
+ /* Sidebar Pro */
41
  .sidebar-pro {
42
  position: fixed !important;
43
+ left: 0 !important; top: 0 !important;
44
+ width: 260px !important; height: 100vh !important;
45
+ background: #0a0a0f !important;
46
+ border-right: 1px solid #1a1a20 !important;
 
 
47
  z-index: 1000 !important;
48
  padding: 20px !important;
49
  }
50
 
51
  .nodeai-logo {
52
  font-family: 'Orbitron', sans-serif !important;
53
+ color: #00f2fe; font-size: 24px; text-align: center; margin-bottom: 30px;
 
 
 
 
54
  }
55
 
56
+ /* Vùng Chat */
57
  .chat-col {
58
+ margin-left: 260px !important;
59
+ width: calc(100% - 260px) !important;
60
  height: 100vh !important;
61
+ padding: 20px 40px !important;
62
  }
63
 
64
+ .gr-chatbot {
65
+ background: transparent !important;
66
+ border: none !important;
67
+ height: 70vh !important;
68
+ margin-bottom: 120px !important;
69
+ }
70
 
71
+ /* KHÓA CHẶT THANH ĐIỀU KHIỂN Ở DƯỚI ĐÁY */
72
+ .input-area-fixed {
73
  position: fixed !important;
74
+ bottom: 30px !important;
75
+ left: 300px !important;
76
+ right: 40px !important;
77
+ z-index: 2000 !important;
 
 
 
 
 
78
  display: flex !important;
79
+ align-items: flex-end !important;
80
+ gap: 10px !important;
 
81
  }
82
 
83
+ /* Ô nhập liệu */
84
+ .input-container {
85
+ flex: 1 !important;
86
+ background: #121217 !important;
87
+ border: 1px solid #2a2a35 !important;
88
+ border-radius: 15px !important;
 
89
  padding: 5px !important;
90
  }
91
 
92
+ /* Mic gọn gàng */
93
+ .mic-box {
94
+ width: 60px !important;
95
+ min-width: 60px !important;
96
+ height: 60px !important;
97
+ background: #121217 !important;
98
+ border: 1px solid #2a2a35 !important;
99
+ border-radius: 15px !important;
100
+ overflow: hidden !important;
101
+ display: flex !important;
102
+ justify-content: center !important;
103
+ align-items: center !important;
104
+ }
105
+
106
+ /* Ẩn bớt các nhãn thừa để tránh nhảy layout */
107
+ .mic-box label, .mic-box .gr-block-label { display: none !important; }
108
+
109
  footer { display: none !important; }
110
  """
111
 
112
  # 3. CORE LOGIC
 
 
 
 
 
 
 
 
113
  def chat_fn(message, history, session_id, store):
114
  user_text = message.get("text", "") if isinstance(message, dict) else message
115
+ files = message.get("files", []) if isinstance(message, dict) else []
116
 
117
+ if not user_text and not files: return {"text": ""}, history, session_id, store, None
 
118
 
119
+ if session_id not in store:
120
+ store[session_id] = {"title": user_text[:20] if user_text else "New Workspace", "history": []}
121
 
122
+ api_messages = [{"role": "system", "content": "Bạn là NodeAI Genesis. Master: Trần Đình Phúc."}]
123
  for msg in history: api_messages.append({"role": msg["role"], "content": msg["content"]})
124
+
125
+ # Hỗ trợ gửi text hoặc file/audio
126
+ api_messages.append({"role": "user", "content": user_text if user_text else "Phân tích nội dung này"})
127
 
128
  try:
129
  ans = ""
130
+ new_h = history + [{"role": "user", "content": user_text if user_text else "📎 File/Audio"}]
131
  for token in client.chat_completion(messages=api_messages, max_tokens=2000, stream=True):
132
  if token.choices[0].delta.content:
133
  ans += token.choices[0].delta.content
 
138
  save_db(store)
139
  yield {"text": ""}, final_h, session_id, store, ans
140
  except Exception as e:
141
+ yield {"text": ""}, history + [{"role": "assistant", "content": f"Lỗi: {str(e)}"}], session_id, store, None
142
 
143
  def tts_engine(text):
144
  if not text or not gTTS: return None
 
153
  chat_store = gr.State(load_db())
154
  session_id = gr.State(str(uuid.uuid4()))
155
 
156
+ # Sidebar
157
+ with gr.Column(elem_classes="sidebar-pro"):
158
+ gr.HTML("<div class='nodeai-logo'>NODEAI</div>")
159
+ new_btn = gr.Button("+ NEW CHAT", variant="primary")
160
+ with gr.Column():
161
+ @gr.render(inputs=chat_store)
162
+ def render_history(store):
163
+ for sid in reversed(list(store.keys())):
164
+ btn = gr.Button(f"💬 {store[sid]['title']}", variant="ghost")
165
+ btn.click(lambda s=sid: (store[s]["history"], s), None, [chatbot, session_id])
166
+
167
+ # Main Chat Area
168
+ with gr.Column(elem_classes="chat-col"):
169
+ chatbot = gr.Chatbot(show_label=False)
170
+ audio_out = gr.Audio(autoplay=True, visible=False)
171
 
172
+ # FIXED INPUT AREA (Chống nhảy layout)
173
+ with gr.Row(elem_classes="input-area-fixed"):
174
+ with gr.Column(elem_classes="input-container", scale=10):
175
+ msg_input = gr.MultimodalTextbox(
176
+ show_label=False,
177
+ placeholder="Hỏi Phúc bất cứ điều gì...",
178
+ container=False
179
+ )
180
+ with gr.Column(elem_classes="mic-box", scale=1):
181
+ # Nút Mic thu nhỏ gọn gàng ở bên cạnh
182
+ mic_btn = gr.Audio(sources=["microphone"], type="filepath", container=False)
183
+
184
+ # Trình xử lý sự kiện
 
 
 
185
  msg_input.submit(chat_fn, [msg_input, chatbot, session_id, chat_store], [msg_input, chatbot, session_id, chat_store, audio_out]).then(tts_engine, audio_out, audio_out)
186
 
187
+ def process_mic(path): return {"text": "Dịch âm thanh này", "files": [path]}
188
  mic_btn.stop_recording(process_mic, mic_btn, msg_input)
189
 
190
  new_btn.click(lambda: ([], str(uuid.uuid4())), None, [chatbot, session_id])