vortex123 commited on
Commit
d94d450
·
verified ·
1 Parent(s): 4ed0e73

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +71 -54
app.py CHANGED
@@ -4,25 +4,24 @@ import google.generativeai as genai
4
  import asyncio
5
 
6
  ###############################################################################
7
- # 1. Настройка окружения и инициализация модели
8
  ###############################################################################
9
 
10
- # Задайте свой ключ через переменную окружения, например:
11
- # export GEMINI_API_KEY="ваш-ключ"
12
- GEMINI_API_KEY = "AIzaSyBoqoPX-9uzvXyxzse0gRwH8_P9xO6O3Bc"
13
  if not GEMINI_API_KEY:
14
  print("Error: GEMINI_API_KEY is not set.")
15
  exit()
 
16
  genai.configure(api_key=GEMINI_API_KEY)
17
 
18
- # Список доступных моделей
19
  AVAILABLE_MODELS = [
20
  "gemini-2.0-flash-exp",
21
  "gemini-exp-1206",
22
- "gemini-2.0-flash-thinking-exp-1219"
23
  ]
24
 
25
- # Инициализируем модели и храним их в словаре
26
  MODELS = {}
27
  for model_name in AVAILABLE_MODELS:
28
  try:
@@ -31,30 +30,54 @@ for model_name in AVAILABLE_MODELS:
31
  print(f"[Предупреждение] Не удалось инициализировать модель {model_name}: {e}")
32
 
33
  ###############################################################################
34
- # 2. Утилиты для преобразования истории между Gradio-форматом и Gemini
35
  ###############################################################################
36
 
37
- def _history_gradio_to_genai(history):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  """
39
  Gradio хранит историю как [(user_msg, bot_msg), (user_msg, bot_msg), ...].
40
- Библиотека google.generativeai ждёт [{'role': 'user', 'parts': ...}, {'role': 'assistant', 'parts': ...}, ...].
 
41
  """
42
  genai_history = []
 
 
43
  for user_text, bot_text in history:
 
44
  if user_text:
45
  genai_history.append({"role": "user", "parts": user_text})
 
46
  if bot_text:
47
- genai_history.append({"role": "assistant", "parts": bot_text})
 
48
  return genai_history
49
 
50
 
51
  ###############################################################################
52
- # 3. Асинхронные генераторы для получения ответа от моделей
53
  ###############################################################################
54
 
55
  async def _respond_stream(model_name, user_message, history):
56
  """
57
- Генерация ответа (постепенного, stream=True) для обычных моделей (без thinking).
58
  Возвращаем кусочки текста через yield.
59
  """
60
  if model_name not in MODELS:
@@ -62,21 +85,20 @@ async def _respond_stream(model_name, user_message, history):
62
  return
63
 
64
  model = MODELS[model_name]
65
- genai_history = _history_gradio_to_genai(history)
 
 
66
 
67
  try:
68
- # Создаём чат с уже накопленной историей
69
  chat = model.start_chat(history=genai_history)
70
- # Запрашиваем стриминг (постепенный) ответа
71
  response_stream = chat.send_message(user_message, stream=True)
72
 
73
  partial_text = ""
74
  for chunk in response_stream:
75
- chunk_text = chunk.text or ""
76
- partial_text += chunk_text
77
  yield partial_text
78
 
79
- return # Завершить генератор без значения
80
  except Exception as e:
81
  yield f"Ошибка при запросе к API: {e}"
82
  return
@@ -84,23 +106,22 @@ async def _respond_stream(model_name, user_message, history):
84
 
85
  async def _respond_thinking(model_name, user_message, history):
86
  """
87
- Генерация ответа для thinking-модели (gemini-2.0-flash-thinking-exp).
88
- 1) Сначала отдаём "Думаю..."
89
- 2) Затем формируем итоговый ответ + собираем «размышления» part.thought == True.
90
  """
91
  if model_name not in MODELS:
92
  yield "Ошибка: модель не найдена.", ""
93
  return
94
 
95
  model = MODELS[model_name]
96
- genai_history = _history_gradio_to_genai(history)
97
 
98
- # Шаг 1: сообщаем "Думаю..."
99
  yield "Думаю...", ""
100
 
101
  try:
102
  chat = model.start_chat(history=genai_history)
103
- # Без стриминга — дожидаемся полного ответа
104
  response = chat.send_message(user_message, stream=False)
105
 
106
  thinking_process_text = ""
@@ -122,7 +143,7 @@ async def _respond_thinking(model_name, user_message, history):
122
 
123
 
124
  ###############################################################################
125
- # 4. Основная функция для обработки нового пользовательского сообщения в Gradio
126
  ###############################################################################
127
 
128
  async def user_send_message(
@@ -133,31 +154,29 @@ async def user_send_message(
133
  ):
134
  """
135
  Параметры:
136
- user_message : строка, введённая пользователем
137
- history : текущая история [(user, assistant), ...]
138
- model_name : выбранная модель
139
- thinking_text: текущее содержимое поля «Размышления»
140
-
141
- Возвращаем (обновлённую историю, обновлённое thinking_text) пошагово через yield.
142
  """
 
143
  if not user_message.strip():
144
- # Если пользователь не ввёл ничего, не делаем запрос
145
  yield history, thinking_text
146
  return
147
 
148
- # Добавляем новый шаг в историю (ассистент пока None)
149
  history.append((user_message, None))
150
 
151
- # Если модель thinking
152
  if "thinking" in model_name.lower():
153
  async for (assistant_text, thought_text) in _respond_thinking(model_name, user_message, history):
154
- # Обновляем последний элемент истории
155
  history[-1] = (user_message, assistant_text)
156
- # Записываем «размышления» во второе поле
157
  yield history, thought_text
158
  return
159
  else:
160
- # Обычная модель (stream)
161
  partial_answer = ""
162
  async for chunk in _respond_stream(model_name, user_message, history):
163
  partial_answer = chunk
@@ -167,7 +186,7 @@ async def user_send_message(
167
 
168
 
169
  ###############################################################################
170
- # 5. Колбэки для очистки
171
  ###############################################################################
172
 
173
  def clear_all():
@@ -176,50 +195,49 @@ def clear_all():
176
 
177
 
178
  ###############################################################################
179
- # 6. Gradio-интерфейс
180
  ###############################################################################
181
 
182
  with gr.Blocks() as demo:
183
- gr.Markdown("## Chat с Gemini (поддержка разных моделей и «thinking»-режима)")
184
 
185
  with gr.Row():
186
  model_dropdown = gr.Dropdown(
187
  choices=AVAILABLE_MODELS,
188
- value="gemini-1.5-flash",
189
  label="Выберите модель"
190
  )
191
  clear_button = gr.Button("Очистить чат")
192
 
193
- # Состояние для хранения истории и размышлений
194
- history_state = gr.State([]) # [(user, assistant), ...]
195
- thinking_store = gr.State("") # текст размышлений
 
196
 
197
  chatbot = gr.Chatbot(label="Диалог с Gemini")
198
  user_input = gr.Textbox(label="Ваш вопрос", placeholder="Введите текст...")
199
 
200
- # Поле для размышлений
201
  thinking_output = gr.Textbox(
202
- label="Размышления (только для gemini-2.0-flash-thinking-exp)",
203
  interactive=False
204
  )
205
 
206
  send_btn = gr.Button("Отправить")
207
 
208
- # 1) При нажатии «Отправить»
209
  send_chain = send_btn.click(
210
  fn=user_send_message,
211
  inputs=[user_input, history_state, model_dropdown, thinking_store],
212
  outputs=[history_state, thinking_store],
213
  queue=True
214
  )
215
- # Затем обновляем чат
216
  send_chain.then(
217
  fn=lambda h: h,
218
  inputs=[history_state],
219
  outputs=[chatbot],
220
  queue=True
221
  )
222
- # И отображаем размышления
223
  send_chain.then(
224
  fn=lambda t: t,
225
  inputs=[thinking_store],
@@ -227,7 +245,7 @@ with gr.Blocks() as demo:
227
  queue=True
228
  )
229
 
230
- # 2) При нажатии Enter в textbox
231
  submit_chain = user_input.submit(
232
  fn=user_send_message,
233
  inputs=[user_input, history_state, model_dropdown, thinking_store],
@@ -247,7 +265,7 @@ with gr.Blocks() as demo:
247
  queue=True
248
  )
249
 
250
- # 3) Кнопка «Очистить»
251
  clear_chain = clear_button.click(
252
  fn=clear_all,
253
  inputs=[],
@@ -265,6 +283,5 @@ with gr.Blocks() as demo:
265
  outputs=[thinking_output]
266
  )
267
 
268
- # Запуск приложения
269
  if __name__ == "__main__":
270
- demo.launch()
 
4
  import asyncio
5
 
6
  ###############################################################################
7
+ # 1. Настройка окружения и инициализация моделей
8
  ###############################################################################
9
 
10
+ # Ваш ключ. В идеале: os.environ.get("GEMINI_API_KEY")
11
+ GEMINI_API_KEY = "AIzaSyBoqoPX-9uzvXyxzse0gRwH8_P9xO6O3Bc"
 
12
  if not GEMINI_API_KEY:
13
  print("Error: GEMINI_API_KEY is not set.")
14
  exit()
15
+
16
  genai.configure(api_key=GEMINI_API_KEY)
17
 
18
+ # Список доступных моделей (добавьте/уберите при необходимости)
19
  AVAILABLE_MODELS = [
20
  "gemini-2.0-flash-exp",
21
  "gemini-exp-1206",
22
+ "gemini-2.0-flash-thinking-exp-1219",
23
  ]
24
 
 
25
  MODELS = {}
26
  for model_name in AVAILABLE_MODELS:
27
  try:
 
30
  print(f"[Предупреждение] Не удалось инициализировать модель {model_name}: {e}")
31
 
32
  ###############################################################################
33
+ # 2. Функция для определения роли ассистента
34
  ###############################################################################
35
 
36
+ def _assistant_role(model_name: str) -> str:
37
+ """
38
+ Для некоторых моделей ("gemini-exp-1206", "gemini-2.0-flash-thinking-exp-1219")
39
+ требуется role="model", а не "assistant".
40
+ """
41
+ # Примерно так: если видим "flash-exp" без "1206" или явно gemini-2.0-flash-exp,
42
+ # то оставляем role="assistant". Иначе -> "model".
43
+ # Подстройте логику под ваши модели.
44
+
45
+ if model_name in ["gemini-exp-1206", "gemini-2.0-flash-thinking-exp-1219"]:
46
+ return "model"
47
+ # Все остальные — пусть будут "assistant"
48
+ return "assistant"
49
+
50
+ ###############################################################################
51
+ # 3. Утилиты для преобразования истории между Gradio-форматом и Gemini
52
+ ###############################################################################
53
+
54
+ def _history_gradio_to_genai(history, model_name):
55
  """
56
  Gradio хранит историю как [(user_msg, bot_msg), (user_msg, bot_msg), ...].
57
+ Модели требуют [{'role': 'user'|'model'|'assistant', 'parts': ...}, ...].
58
+ Для некоторых моделей вместо 'assistant' нужно 'model'.
59
  """
60
  genai_history = []
61
+ asst_role = _assistant_role(model_name)
62
+
63
  for user_text, bot_text in history:
64
+ # Сообщение от пользователя
65
  if user_text:
66
  genai_history.append({"role": "user", "parts": user_text})
67
+ # Сообщение от ассистента
68
  if bot_text:
69
+ genai_history.append({"role": asst_role, "parts": bot_text})
70
+
71
  return genai_history
72
 
73
 
74
  ###############################################################################
75
+ # 4. Асинхронные генераторы для получения ответа от моделей
76
  ###############################################################################
77
 
78
  async def _respond_stream(model_name, user_message, history):
79
  """
80
+ Генерация ответа (постепенного, stream=True) для обычных моделей.
81
  Возвращаем кусочки текста через yield.
82
  """
83
  if model_name not in MODELS:
 
85
  return
86
 
87
  model = MODELS[model_name]
88
+
89
+ # Конвертируем историю в нужный формат
90
+ genai_history = _history_gradio_to_genai(history, model_name)
91
 
92
  try:
 
93
  chat = model.start_chat(history=genai_history)
 
94
  response_stream = chat.send_message(user_message, stream=True)
95
 
96
  partial_text = ""
97
  for chunk in response_stream:
98
+ partial_text += (chunk.text or "")
 
99
  yield partial_text
100
 
101
+ return
102
  except Exception as e:
103
  yield f"Ошибка при запросе к API: {e}"
104
  return
 
106
 
107
  async def _respond_thinking(model_name, user_message, history):
108
  """
109
+ Генерация ответа для «thinking»-модели (gemini-2.0-flash-thinking-exp и т.п.).
110
+ 1) "Думаю..."
111
+ 2) Затем итоговый ответ + размышления.
112
  """
113
  if model_name not in MODELS:
114
  yield "Ошибка: модель не найдена.", ""
115
  return
116
 
117
  model = MODELS[model_name]
118
+ genai_history = _history_gradio_to_genai(history, model_name)
119
 
120
+ # Сначала "Думаю..."
121
  yield "Думаю...", ""
122
 
123
  try:
124
  chat = model.start_chat(history=genai_history)
 
125
  response = chat.send_message(user_message, stream=False)
126
 
127
  thinking_process_text = ""
 
143
 
144
 
145
  ###############################################################################
146
+ # 5. Основная функция для Gradio
147
  ###############################################################################
148
 
149
  async def user_send_message(
 
154
  ):
155
  """
156
  Параметры:
157
+ user_message : вход от пользователя
158
+ history : [(user, assistant), ...]
159
+ model_name : текущая выбранная модель
160
+ thinking_text: текущее «размышление»
161
+
162
+ Возвращаем (обновлённая_история, новое_thinking_text) пошагово через yield.
163
  """
164
+ # Если пользователь ничего не ввёл
165
  if not user_message.strip():
 
166
  yield history, thinking_text
167
  return
168
 
169
+ # Добавляем новую пару в историю
170
  history.append((user_message, None))
171
 
172
+ # Если в названии модели есть "thinking"
173
  if "thinking" in model_name.lower():
174
  async for (assistant_text, thought_text) in _respond_thinking(model_name, user_message, history):
 
175
  history[-1] = (user_message, assistant_text)
 
176
  yield history, thought_text
177
  return
178
  else:
179
+ # Обычная модель
180
  partial_answer = ""
181
  async for chunk in _respond_stream(model_name, user_message, history):
182
  partial_answer = chunk
 
186
 
187
 
188
  ###############################################################################
189
+ # 6. Колбэки для очистки
190
  ###############################################################################
191
 
192
  def clear_all():
 
195
 
196
 
197
  ###############################################################################
198
+ # 7. Gradio-интерфейс
199
  ###############################################################################
200
 
201
  with gr.Blocks() as demo:
202
+ gr.Markdown("## Chat с Gemini (несколько моделей, «thinking»-режим)")
203
 
204
  with gr.Row():
205
  model_dropdown = gr.Dropdown(
206
  choices=AVAILABLE_MODELS,
207
+ value="gemini-2.0-flash-exp", # Можно выбрать по умолчанию
208
  label="Выберите модель"
209
  )
210
  clear_button = gr.Button("Очистить чат")
211
 
212
+ # Состояние для хранения [(user, assistant), ...]
213
+ history_state = gr.State([])
214
+ # Состояние для размышлений
215
+ thinking_store = gr.State("")
216
 
217
  chatbot = gr.Chatbot(label="Диалог с Gemini")
218
  user_input = gr.Textbox(label="Ваш вопрос", placeholder="Введите текст...")
219
 
220
+ # Поле для размышлений (только для thinking-модели)
221
  thinking_output = gr.Textbox(
222
+ label="Размышления",
223
  interactive=False
224
  )
225
 
226
  send_btn = gr.Button("Отправить")
227
 
228
+ # При нажатии «Отправить»
229
  send_chain = send_btn.click(
230
  fn=user_send_message,
231
  inputs=[user_input, history_state, model_dropdown, thinking_store],
232
  outputs=[history_state, thinking_store],
233
  queue=True
234
  )
 
235
  send_chain.then(
236
  fn=lambda h: h,
237
  inputs=[history_state],
238
  outputs=[chatbot],
239
  queue=True
240
  )
 
241
  send_chain.then(
242
  fn=lambda t: t,
243
  inputs=[thinking_store],
 
245
  queue=True
246
  )
247
 
248
+ # При нажатии Enter
249
  submit_chain = user_input.submit(
250
  fn=user_send_message,
251
  inputs=[user_input, history_state, model_dropdown, thinking_store],
 
265
  queue=True
266
  )
267
 
268
+ # Очистка
269
  clear_chain = clear_button.click(
270
  fn=clear_all,
271
  inputs=[],
 
283
  outputs=[thinking_output]
284
  )
285
 
 
286
  if __name__ == "__main__":
287
+ demo.launch()