root39058 commited on
Commit
906dcf3
·
verified ·
1 Parent(s): e7ce0cf

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +105 -137
app.py CHANGED
@@ -2,9 +2,9 @@ import gradio as gr
2
  from transformers import AutoModelForCausalLM, AutoTokenizer
3
  import torch
4
  import json
5
- import os
6
  from pathlib import Path
7
  from datetime import datetime
 
8
 
9
  # === ЗАГРУЗКА МОДЕЛИ ===
10
  print("🚀 Загрузка модели...")
@@ -23,25 +23,21 @@ def get_history_path(username):
23
  return HISTORY_DIR / f"{username}.json"
24
 
25
  def load_history(username):
26
- """Загружает историю чатов пользователя"""
27
  path = get_history_path(username)
28
  if path.exists():
29
  with open(path, "r", encoding="utf-8") as f:
30
  return json.load(f)
31
- return {} # {chat_id: {"title": str, "messages": [[user, ai], ...]}}
32
 
33
  def save_history(username, history_data):
34
- """Сохраняет историю чатов пользователя"""
35
  path = get_history_path(username)
36
  with open(path, "w", encoding="utf-8") as f:
37
  json.dump(history_data, f, ensure_ascii=False, indent=2)
38
 
39
  def check_if_pro(token):
40
- """Проверяет, является ли пользователь PRO-подписчиком"""
41
  if not token:
42
  return False
43
  try:
44
- import requests
45
  response = requests.get(
46
  "https://huggingface.co/api/whoami-v2",
47
  headers={"Authorization": f"Bearer {token}"},
@@ -58,20 +54,23 @@ def check_if_pro(token):
58
  def generate_response(message, history, username, current_chat_id):
59
  if not username:
60
  gr.Warning("Пожалуйста, войдите через Hugging Face")
61
- return history, history, gr.update(), current_chat_id
62
 
63
  if not message.strip():
64
- return history, history, gr.update(), current_chat_id
65
 
66
- # Добавляем сообщение пользователя
67
- history = history + [[message, None]]
 
 
68
 
69
- # Формируем промпт
70
  prompt = ""
71
- for user_msg, ai_msg in history:
72
- prompt += f"Пользователь: {user_msg}\n"
73
- if ai_msg:
74
- prompt += f"AI: {ai_msg}\n"
 
75
  prompt += "AI:"
76
 
77
  inputs = tokenizer(prompt, return_tensors="pt").to(device)
@@ -88,26 +87,27 @@ def generate_response(message, history, username, current_chat_id):
88
  response = tokenizer.decode(outputs[0], skip_special_tokens=True)
89
  ai_response = response.split("AI:")[-1].strip()
90
 
91
- # Обновляем последнее сообщение
92
- history[-1][1] = ai_response
93
 
94
  # Сохраняем в хранилище
95
- history_data = load_history(username)
96
- if current_chat_id not in history_data:
97
- history_data[current_chat_id] = {
98
- "title": message[:40] + ("..." if len(message) > 40 else ""),
99
- "created": datetime.now().isoformat(),
100
- "messages": []
101
- }
102
- history_data[current_chat_id]["messages"] = history
103
- save_history(username, history_data)
 
104
 
105
- return history, history, gr.update(value=""), current_chat_id
106
 
107
  # === УПРАВЛЕНИЕ ЧАТАМИ ===
108
  def new_chat(username):
109
  if not username:
110
- return [], {}, None
111
  chat_id = datetime.now().strftime("%Y%m%d_%H%M%S")
112
  history_data = load_history(username)
113
  history_data[chat_id] = {
@@ -116,13 +116,12 @@ def new_chat(username):
116
  "messages": []
117
  }
118
  save_history(username, history_data)
119
- return [], history_data, chat_id
120
 
121
  def load_chat(chat_title, username, current_chat_id):
122
  if not username or not chat_title:
123
  return [], current_chat_id
124
  history_data = load_history(username)
125
- # Находим chat_id по заголовку
126
  for cid, data in history_data.items():
127
  if data["title"] == chat_title:
128
  return data["messages"], cid
@@ -132,7 +131,6 @@ def get_chat_list(username):
132
  if not username:
133
  return []
134
  history_data = load_history(username)
135
- # Сортируем по дате (новые сверху)
136
  sorted_chats = sorted(
137
  history_data.items(),
138
  key=lambda x: x[1].get("created", ""),
@@ -144,7 +142,6 @@ def delete_chat(chat_title, username):
144
  if not username or not chat_title:
145
  return [], {}, None, []
146
  history_data = load_history(username)
147
- # Находим и удаляем чат
148
  for cid, data in list(history_data.items()):
149
  if data["title"] == chat_title:
150
  del history_data[cid]
@@ -152,54 +149,6 @@ def delete_chat(chat_title, username):
152
  save_history(username, history_data)
153
  return [], history_data, None, get_chat_list(username)
154
 
155
- # === ВХОД/ВЫХОД ===
156
- def login_event(request: gr.Request):
157
- """Вызывается после успешного входа через OAuth"""
158
- if request.username:
159
- username = request.username
160
- token = request.oauth_token.get("access_token") if request.oauth_token else None
161
- is_pro = check_if_pro(token)
162
- history_data = load_history(username)
163
- chat_list = get_chat_list(username)
164
-
165
- # Создаем новый чат, если история пуста
166
- current_chat_id = None
167
- if not history_data:
168
- chat_id = datetime.now().strftime("%Y%m%d_%H%M%S")
169
- history_data[chat_id] = {
170
- "title": "Новый чат",
171
- "created": datetime.now().isoformat(),
172
- "messages": []
173
- }
174
- save_history(username, history_data)
175
- current_chat_id = chat_id
176
- chat_list = get_chat_list(username)
177
-
178
- pro_badge = "👑 PRO" if is_pro else ""
179
- return (
180
- gr.update(visible=True), # main_interface
181
- gr.update(visible=False), # login_screen
182
- gr.update(value=f"👤 {username} {pro_badge}".strip()), # user_info
183
- [], # chatbot
184
- history_data, # state
185
- current_chat_id,
186
- chat_list, # список чатов
187
- gr.update(visible=is_pro) # PRO бейдж
188
- )
189
- return (gr.update(), gr.update(), gr.update(), [], {}, None, [], gr.update())
190
-
191
- def logout_event():
192
- return (
193
- gr.update(visible=False),
194
- gr.update(visible=True),
195
- "Не авторизован",
196
- [],
197
- {},
198
- None,
199
- [],
200
- gr.update(visible=False)
201
- )
202
-
203
  # === CSS ===
204
  CUSTOM_CSS = """
205
  .main-header {
@@ -210,10 +159,7 @@ CUSTOM_CSS = """
210
  margin-bottom: 20px;
211
  text-align: center;
212
  }
213
- .main-header h1 {
214
- margin: 0;
215
- font-size: 2em;
216
- }
217
  .pro-badge {
218
  background: linear-gradient(135deg, #ffd700 0%, #ffed4e 100%);
219
  color: #333;
@@ -224,21 +170,6 @@ CUSTOM_CSS = """
224
  margin-left: 10px;
225
  box-shadow: 0 2px 8px rgba(255, 215, 0, 0.4);
226
  }
227
- .sidebar {
228
- background: #f7f7f9;
229
- padding: 15px;
230
- border-radius: 12px;
231
- height: calc(100vh - 200px);
232
- overflow-y: auto;
233
- }
234
- .chat-item {
235
- padding: 8px 12px;
236
- margin: 4px 0;
237
- background: white;
238
- border-radius: 8px;
239
- cursor: pointer;
240
- border: 1px solid #e0e0e0;
241
- }
242
  .user-info {
243
  padding: 10px;
244
  background: white;
@@ -250,14 +181,14 @@ CUSTOM_CSS = """
250
  """
251
 
252
  # === ИНТЕРФЕЙС ===
253
- with gr.Blocks(css=CUSTOM_CSS, title="OpenAirAI-X Chat") as demo:
254
 
255
  # Состояния
 
256
  history_state = gr.State({})
257
  current_chat_id_state = gr.State(None)
258
 
259
  with gr.Column(visible=False) as main_interface:
260
- # Шапка
261
  gr.HTML("""
262
  <div class="main-header">
263
  <h1>🤖 OpenAirAI-X Chat</h1>
@@ -266,18 +197,15 @@ with gr.Blocks(css=CUSTOM_CSS, title="OpenAirAI-X Chat") as demo:
266
  """)
267
 
268
  with gr.Row():
269
- # Боковая панель с историей
270
- with gr.Column(scale=1, elem_classes="sidebar"):
271
  user_info = gr.Textbox(
272
  label="Пользователь",
273
  value="Не авторизован",
274
  interactive=False,
275
  elem_classes="user-info"
276
  )
277
- pro_badge = gr.HTML(
278
- '<div class="pro-badge">👑 PRO</div>',
279
- visible=False
280
- )
281
  new_chat_btn = gr.Button("➕ Новый чат", variant="primary")
282
  gr.Markdown("### 📚 История чатов")
283
  chat_list = gr.Radio(
@@ -293,9 +221,8 @@ with gr.Blocks(css=CUSTOM_CSS, title="OpenAirAI-X Chat") as demo:
293
  chatbot = gr.Chatbot(
294
  label="Диалог",
295
  height=500,
296
- type="tuples",
297
  show_copy_button=True,
298
- avatar_images=(None, "https://huggingface.co/datasets/huggingface/badges/resolve/main/model-icon.png")
299
  )
300
  with gr.Row():
301
  msg_input = gr.Textbox(
@@ -326,71 +253,112 @@ with gr.Blocks(css=CUSTOM_CSS, title="OpenAirAI-X Chat") as demo:
326
  """)
327
  gr.LoginButton(value="🔑 Войти через Hugging Face", variant="primary")
328
 
329
- # === ОБРАБОТЧИКИ СОБЫТИЙ ===
330
 
331
- # Вход
332
- main_interface_ref = main_interface
333
- login_screen_ref = login_screen
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
 
335
- # После OAuth
336
  demo.load(
337
- fn=lambda request: login_event(request) if request.username else (gr.update(), gr.update(), gr.update(), [], {}, None, [], gr.update()),
338
  inputs=None,
339
- outputs=[main_interface, login_screen, user_info, chatbot, history_state, current_chat_id_state, chat_list, pro_badge]
 
340
  )
341
 
342
  # Отправка сообщения
343
  send_btn.click(
344
  fn=generate_response,
345
- inputs=[msg_input, chatbot, user_info, current_chat_id_state],
346
- outputs=[chatbot, chatbot, msg_input, current_chat_id_state]
347
  ).then(
348
- fn=lambda username: get_chat_list(username),
349
- inputs=[user_info],
350
  outputs=[chat_list]
351
  )
352
 
353
  msg_input.submit(
354
  fn=generate_response,
355
- inputs=[msg_input, chatbot, user_info, current_chat_id_state],
356
- outputs=[chatbot, chatbot, msg_input, current_chat_id_state]
357
  ).then(
358
- fn=lambda username: get_chat_list(username),
359
- inputs=[user_info],
360
  outputs=[chat_list]
361
  )
362
 
363
  # Новый чат
364
  new_chat_btn.click(
365
- fn=lambda username: new_chat(username),
366
- inputs=[user_info],
367
- outputs=[chatbot, history_state, current_chat_id_state]
368
- ).then(
369
- fn=lambda username: get_chat_list(username),
370
- inputs=[user_info],
371
- outputs=[chat_list]
372
  )
373
 
374
  # Загрузка чата
375
  chat_list.change(
376
  fn=load_chat,
377
- inputs=[chat_list, user_info, current_chat_id_state],
378
  outputs=[chatbot, current_chat_id_state]
379
  )
380
 
381
  # Удаление чата
382
  delete_chat_btn.click(
383
  fn=delete_chat,
384
- inputs=[chat_list, user_info],
385
  outputs=[chatbot, history_state, current_chat_id_state, chat_list]
386
  )
387
 
388
  # Выход
389
  logout_btn.click(
390
- fn=logout_event,
391
  inputs=None,
392
- outputs=[main_interface, login_screen, user_info, chatbot, history_state, current_chat_id_state, chat_list, pro_badge]
 
393
  )
394
 
395
- # Запуск
396
- demo.launch(server_name="0.0.0.0", server_port=7860)
 
2
  from transformers import AutoModelForCausalLM, AutoTokenizer
3
  import torch
4
  import json
 
5
  from pathlib import Path
6
  from datetime import datetime
7
+ import requests
8
 
9
  # === ЗАГРУЗКА МОДЕЛИ ===
10
  print("🚀 Загрузка модели...")
 
23
  return HISTORY_DIR / f"{username}.json"
24
 
25
  def load_history(username):
 
26
  path = get_history_path(username)
27
  if path.exists():
28
  with open(path, "r", encoding="utf-8") as f:
29
  return json.load(f)
30
+ return {}
31
 
32
  def save_history(username, history_data):
 
33
  path = get_history_path(username)
34
  with open(path, "w", encoding="utf-8") as f:
35
  json.dump(history_data, f, ensure_ascii=False, indent=2)
36
 
37
  def check_if_pro(token):
 
38
  if not token:
39
  return False
40
  try:
 
41
  response = requests.get(
42
  "https://huggingface.co/api/whoami-v2",
43
  headers={"Authorization": f"Bearer {token}"},
 
54
  def generate_response(message, history, username, current_chat_id):
55
  if not username:
56
  gr.Warning("Пожалуйста, войдите через Hugging Face")
57
+ return history, gr.update(), current_chat_id
58
 
59
  if not message.strip():
60
+ return history, gr.update(), current_chat_id
61
 
62
+ # Новый формат Gradio 6+: список словарей
63
+ history = history + [
64
+ {"role": "user", "content": message},
65
+ ]
66
 
67
+ # Формируем промпт из всей истории
68
  prompt = ""
69
+ for msg in history:
70
+ if msg["role"] == "user":
71
+ prompt += f"Пользователь: {msg['content']}\n"
72
+ elif msg["role"] == "assistant":
73
+ prompt += f"AI: {msg['content']}\n"
74
  prompt += "AI:"
75
 
76
  inputs = tokenizer(prompt, return_tensors="pt").to(device)
 
87
  response = tokenizer.decode(outputs[0], skip_special_tokens=True)
88
  ai_response = response.split("AI:")[-1].strip()
89
 
90
+ # Добавляем ответ AI
91
+ history = history + [{"role": "assistant", "content": ai_response}]
92
 
93
  # Сохраняем в хранилище
94
+ if username and current_chat_id:
95
+ history_data = load_history(username)
96
+ if current_chat_id not in history_data:
97
+ history_data[current_chat_id] = {
98
+ "title": message[:40] + ("..." if len(message) > 40 else ""),
99
+ "created": datetime.now().isoformat(),
100
+ "messages": []
101
+ }
102
+ history_data[current_chat_id]["messages"] = history
103
+ save_history(username, history_data)
104
 
105
+ return history, gr.update(value=""), current_chat_id
106
 
107
  # === УПРАВЛЕНИЕ ЧАТАМИ ===
108
  def new_chat(username):
109
  if not username:
110
+ return [], None, []
111
  chat_id = datetime.now().strftime("%Y%m%d_%H%M%S")
112
  history_data = load_history(username)
113
  history_data[chat_id] = {
 
116
  "messages": []
117
  }
118
  save_history(username, history_data)
119
+ return [], chat_id, get_chat_list(username)
120
 
121
  def load_chat(chat_title, username, current_chat_id):
122
  if not username or not chat_title:
123
  return [], current_chat_id
124
  history_data = load_history(username)
 
125
  for cid, data in history_data.items():
126
  if data["title"] == chat_title:
127
  return data["messages"], cid
 
131
  if not username:
132
  return []
133
  history_data = load_history(username)
 
134
  sorted_chats = sorted(
135
  history_data.items(),
136
  key=lambda x: x[1].get("created", ""),
 
142
  if not username or not chat_title:
143
  return [], {}, None, []
144
  history_data = load_history(username)
 
145
  for cid, data in list(history_data.items()):
146
  if data["title"] == chat_title:
147
  del history_data[cid]
 
149
  save_history(username, history_data)
150
  return [], history_data, None, get_chat_list(username)
151
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
  # === CSS ===
153
  CUSTOM_CSS = """
154
  .main-header {
 
159
  margin-bottom: 20px;
160
  text-align: center;
161
  }
162
+ .main-header h1 { margin: 0; font-size: 2em; }
 
 
 
163
  .pro-badge {
164
  background: linear-gradient(135deg, #ffd700 0%, #ffed4e 100%);
165
  color: #333;
 
170
  margin-left: 10px;
171
  box-shadow: 0 2px 8px rgba(255, 215, 0, 0.4);
172
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  .user-info {
174
  padding: 10px;
175
  background: white;
 
181
  """
182
 
183
  # === ИНТЕРФЕЙС ===
184
+ with gr.Blocks(title="OpenAirAI-X Chat") as demo:
185
 
186
  # Состояния
187
+ username_state = gr.State("")
188
  history_state = gr.State({})
189
  current_chat_id_state = gr.State(None)
190
 
191
  with gr.Column(visible=False) as main_interface:
 
192
  gr.HTML("""
193
  <div class="main-header">
194
  <h1>🤖 OpenAirAI-X Chat</h1>
 
197
  """)
198
 
199
  with gr.Row():
200
+ # Боковая панель
201
+ with gr.Column(scale=1, min_width=250):
202
  user_info = gr.Textbox(
203
  label="Пользователь",
204
  value="Не авторизован",
205
  interactive=False,
206
  elem_classes="user-info"
207
  )
208
+ pro_badge = gr.HTML('<div class="pro-badge">👑 PRO</div>', visible=False)
 
 
 
209
  new_chat_btn = gr.Button("➕ Новый чат", variant="primary")
210
  gr.Markdown("### 📚 История чатов")
211
  chat_list = gr.Radio(
 
221
  chatbot = gr.Chatbot(
222
  label="Диалог",
223
  height=500,
 
224
  show_copy_button=True,
225
+ type="messages"
226
  )
227
  with gr.Row():
228
  msg_input = gr.Textbox(
 
253
  """)
254
  gr.LoginButton(value="🔑 Войти через Hugging Face", variant="primary")
255
 
256
+ # === ОБРАБОТЧИКИ ===
257
 
258
+ def handle_login(request: gr.Request):
259
+ if request.username:
260
+ username = request.username
261
+ token = request.oauth_token.get("access_token") if request.oauth_token else None
262
+ is_pro = check_if_pro(token)
263
+ history_data = load_history(username)
264
+ chat_list_choices = get_chat_list(username)
265
+
266
+ current_chat_id = None
267
+ if not history_data:
268
+ chat_id = datetime.now().strftime("%Y%m%d_%H%M%S")
269
+ history_data[chat_id] = {
270
+ "title": "Новый чат",
271
+ "created": datetime.now().isoformat(),
272
+ "messages": []
273
+ }
274
+ save_history(username, history_data)
275
+ current_chat_id = chat_id
276
+ chat_list_choices = get_chat_list(username)
277
+
278
+ pro_badge_html = '<div class="pro-badge">👑 PRO</div>'
279
+ display_name = f"👤 {username}"
280
+
281
+ return (
282
+ gr.update(visible=True), # main_interface
283
+ gr.update(visible=False), # login_screen
284
+ display_name, # user_info
285
+ username, # username_state
286
+ history_data, # history_state
287
+ current_chat_id, # current_chat_id_state
288
+ chat_list_choices, # chat_list
289
+ gr.update(visible=is_pro, value=pro_badge_html)
290
+ )
291
+ return (gr.update(), gr.update(), gr.update(), "", {}, None, [], gr.update())
292
+
293
+ def handle_logout():
294
+ return (
295
+ gr.update(visible=False),
296
+ gr.update(visible=True),
297
+ "Не авторизован",
298
+ "",
299
+ {},
300
+ None,
301
+ [],
302
+ gr.update(visible=False)
303
+ )
304
 
305
+ # При загрузке страницы проверяем авторизацию
306
  demo.load(
307
+ fn=handle_login,
308
  inputs=None,
309
+ outputs=[main_interface, login_screen, user_info, username_state,
310
+ history_state, current_chat_id_state, chat_list, pro_badge]
311
  )
312
 
313
  # Отправка сообщения
314
  send_btn.click(
315
  fn=generate_response,
316
+ inputs=[msg_input, chatbot, username_state, current_chat_id_state],
317
+ outputs=[chatbot, msg_input, current_chat_id_state]
318
  ).then(
319
+ fn=lambda u: get_chat_list(u),
320
+ inputs=[username_state],
321
  outputs=[chat_list]
322
  )
323
 
324
  msg_input.submit(
325
  fn=generate_response,
326
+ inputs=[msg_input, chatbot, username_state, current_chat_id_state],
327
+ outputs=[chatbot, msg_input, current_chat_id_state]
328
  ).then(
329
+ fn=lambda u: get_chat_list(u),
330
+ inputs=[username_state],
331
  outputs=[chat_list]
332
  )
333
 
334
  # Новый чат
335
  new_chat_btn.click(
336
+ fn=new_chat,
337
+ inputs=[username_state],
338
+ outputs=[chatbot, current_chat_id_state, chat_list]
 
 
 
 
339
  )
340
 
341
  # Загрузка чата
342
  chat_list.change(
343
  fn=load_chat,
344
+ inputs=[chat_list, username_state, current_chat_id_state],
345
  outputs=[chatbot, current_chat_id_state]
346
  )
347
 
348
  # Удаление чата
349
  delete_chat_btn.click(
350
  fn=delete_chat,
351
+ inputs=[chat_list, username_state],
352
  outputs=[chatbot, history_state, current_chat_id_state, chat_list]
353
  )
354
 
355
  # Выход
356
  logout_btn.click(
357
+ fn=handle_logout,
358
  inputs=None,
359
+ outputs=[main_interface, login_screen, user_info, username_state,
360
+ history_state, current_chat_id_state, chat_list, pro_badge]
361
  )
362
 
363
+ # Запуск с CSS
364
+ demo.launch(server_name="0.0.0.0", server_port=7860, css=CUSTOM_CSS)