Kenan023214 commited on
Commit
9734897
·
verified ·
1 Parent(s): 346570b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +46 -74
app.py CHANGED
@@ -7,7 +7,7 @@ import time
7
  # --- Конфигурация Hugging Face Space ---
8
  MODEL_NAME = "Kenan023214/PyroNet-mini"
9
  DEVICE = "cpu" # Используем CPU, как указано для Basic Space
10
- MAX_NEW_TOKENS = 1024 # Увеличим для "хода мыслей"
11
  MAX_CONTEXT_TOKENS = 2048
12
 
13
  # Словарь с встроенным содержимым шаблонов чата
@@ -102,18 +102,14 @@ def trim_history_to_max_tokens(messages, max_tokens):
102
  total = 0
103
  kept = []
104
  for m in rev:
105
- if len(m) == 2:
106
- approx = num_tokens_of_text(m[0]) + num_tokens_of_text(m[1] if m[1] else "") + 10
107
- else:
108
- approx = num_tokens_of_text(m[0]) + 10
109
-
110
  if total + approx > max_tokens:
111
  break
112
  kept.append(m)
113
  total += approx
114
  return list(reversed(kept))
115
 
116
- def build_messages_for_template(history, reasoning: bool, language: str):
117
  """Подготавливает сообщения для шаблона, включая системное сообщение."""
118
  full_template_content = CHAT_TEMPLATES.get(language, CHAT_TEMPLATES["en"])
119
 
@@ -121,12 +117,7 @@ def build_messages_for_template(history, reasoning: bool, language: str):
121
  system_end_tag = "<|end|>"
122
  system_message_raw = full_template_content.split(system_start_tag)[1].split(system_end_tag)[0].strip()
123
 
124
- messages = [{"role": "system", "content": system_message_raw}]
125
-
126
- for user_msg, assistant_msg in history:
127
- messages.append({"role": "user", "content": user_msg})
128
- if assistant_msg is not None:
129
- messages.append({"role": "assistant", "content": assistant_msg})
130
 
131
  if reasoning:
132
  messages.append({"role": "user", "content": f"Режим рассуждения: покажи свои шаги, а затем окончательный ответ, начиная с '{REASONING_SEPARATOR}'"})
@@ -136,91 +127,72 @@ def build_messages_for_template(history, reasoning: bool, language: str):
136
  def extract_assistant_reply_and_reasoning(raw_generated_text: str) -> tuple[str, str]:
137
  """Убирает лишние токены и разделяет ответ на ход мыслей и окончательный ответ."""
138
  text = raw_generated_text
139
-
140
- # Remove the chat template tags
141
  if "<|assistant|>" in text:
142
  text = text.split("<|assistant|>")[-1]
143
 
144
- # Remove end tokens
145
  for tag in ["<|end|>", "<|end_of_text|>", "<|end|>"]:
146
  text = text.replace(tag, "")
147
 
148
  text = text.strip()
149
 
150
- # Check for the reasoning separator to prevent IndexError
151
  if REASONING_SEPARATOR in text:
152
  parts = text.split(REASONING_SEPARATOR, 1)
153
  reasoning = parts[0].strip()
154
  reply = parts[1].strip()
155
  return reply, reasoning
156
  else:
157
- # If separator is not found, the whole text is the reply, and there's no reasoning.
158
- return text, "Ход мыслей не предоставлен."
159
-
160
 
161
  # --- Основная функция для Gradio ---
162
  def generate_response(user_text: str, history, reasoning: bool, language: str):
163
  """
164
  Обрабатывает пользовательский запрос, генерирует ответ и возвращает его
165
- с эффектом печати и отдельным отображением хода мыслей.
166
  """
167
- try:
168
- # Добавляем user-сообщение в историю Gradio
169
- history.append([user_text, None])
170
-
171
- # 1. Первый yield: очищаем поле ввода и показываем, что модель думает
172
- yield "", history, "Модель обдумывает ваш запрос..."
173
-
174
- # Приводим историю к формату, который нужен для шаблона
175
- trimmed_history = trim_history_to_max_tokens(history, MAX_CONTEXT_TOKENS)
176
- messages_for_template = build_messages_for_template(trimmed_history, reasoning, language)
177
- template_content = CHAT_TEMPLATES.get(language, CHAT_TEMPLATES["en"])
178
-
179
- # Применяем шаблон и токенизируем
180
- text = tokenizer.apply_chat_template(
181
- messages_for_template,
182
- chat_template=template_content,
183
- tokenize=False,
184
- add_generation_prompt=True
 
 
 
 
 
 
 
 
 
 
185
  )
186
-
187
- inputs = tokenizer(text, return_tensors="pt").to(DEVICE)
188
 
189
- with torch.no_grad():
190
- outputs = model.generate(
191
- **inputs,
192
- max_new_tokens=MAX_NEW_TOKENS,
193
- do_sample=True,
194
- top_p=0.9,
195
- temperature=0.8,
196
- pad_token_id=tokenizer.eos_token_id
197
- )
198
 
199
- raw = tokenizer.decode(outputs[0], skip_special_tokens=False)
200
-
201
- # Извлекаем финальный ответ и ход мыслей
202
- reply, reasoning_text = extract_assistant_reply_and_reasoning(raw)
203
-
204
- # 2. Второй yield: обновляем поле рассуждений
205
- # и начинаем "печатать" в чат. Это гарантирует, что поле рассуждений
206
- # обновится сразу, до начала анимации в чате.
207
- history[-1][1] = ""
208
  yield "", history, reasoning_text
209
-
210
- # 3. Последующие yield-ы для анимации печати
211
- full_response = ""
212
- for chunk in reply.split():
213
- full_response += chunk + " "
214
- history[-1][1] = full_response
215
- time.sleep(0.05)
216
- yield "", history, reasoning_text
217
-
218
- except Exception as e:
219
- error_message = f"Произошла ошибка: {e}"
220
- history.append([None, error_message])
221
- yield "", history, gr.Textbox.update(value=error_message)
222
-
223
-
224
  # --- Интерфейс Gradio ---
225
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
226
  gr.Markdown("# PyroNet-mini Chat")
 
7
  # --- Конфигурация Hugging Face Space ---
8
  MODEL_NAME = "Kenan023214/PyroNet-mini"
9
  DEVICE = "cpu" # Используем CPU, как указано для Basic Space
10
+ MAX_NEW_TOKENS = 512 # Увеличим для "хода мыслей"
11
  MAX_CONTEXT_TOKENS = 2048
12
 
13
  # Словарь с встроенным содержимым шаблонов чата
 
102
  total = 0
103
  kept = []
104
  for m in rev:
105
+ approx = num_tokens_of_text(m["content"]) + 8
 
 
 
 
106
  if total + approx > max_tokens:
107
  break
108
  kept.append(m)
109
  total += approx
110
  return list(reversed(kept))
111
 
112
+ def build_messages_for_template(history_messages, reasoning: bool, language: str):
113
  """Подготавливает сообщения для шаблона, включая системное сообщение."""
114
  full_template_content = CHAT_TEMPLATES.get(language, CHAT_TEMPLATES["en"])
115
 
 
117
  system_end_tag = "<|end|>"
118
  system_message_raw = full_template_content.split(system_start_tag)[1].split(system_end_tag)[0].strip()
119
 
120
+ messages = [{"role": "system", "content": system_message_raw}] + list(history_messages)
 
 
 
 
 
121
 
122
  if reasoning:
123
  messages.append({"role": "user", "content": f"Режим рассуждения: покажи свои шаги, а затем окончательный ответ, начиная с '{REASONING_SEPARATOR}'"})
 
127
  def extract_assistant_reply_and_reasoning(raw_generated_text: str) -> tuple[str, str]:
128
  """Убирает лишние токены и разделяет ответ на ход мыслей и окончательный ответ."""
129
  text = raw_generated_text
 
 
130
  if "<|assistant|>" in text:
131
  text = text.split("<|assistant|>")[-1]
132
 
 
133
  for tag in ["<|end|>", "<|end_of_text|>", "<|end|>"]:
134
  text = text.replace(tag, "")
135
 
136
  text = text.strip()
137
 
 
138
  if REASONING_SEPARATOR in text:
139
  parts = text.split(REASONING_SEPARATOR, 1)
140
  reasoning = parts[0].strip()
141
  reply = parts[1].strip()
142
  return reply, reasoning
143
  else:
144
+ return text, "" # Если разделитель не найден, возвращаем все как ответ
 
 
145
 
146
  # --- Основная функция для Gradio ---
147
  def generate_response(user_text: str, history, reasoning: bool, language: str):
148
  """
149
  Обрабатывает пользовательский запрос, генерирует ответ и возвращает его
150
+ с эффектом печати.
151
  """
152
+ # Добавляем user-сообщение во внутреннюю историю
153
+ history.append([user_text, None])
154
+
155
+ # Конвертируем Gradio-историю в наш внутренний формат
156
+ internal_history = [{"role": "user", "content": h[0]} for h in history if h[0] is not None]
157
+
158
+ trimmed_history = trim_history_to_max_tokens(internal_history, MAX_CONTEXT_TOKENS)
159
+ messages_for_template = build_messages_for_template(trimmed_history, reasoning, language)
160
+ template_content = CHAT_TEMPLATES.get(language, CHAT_TEMPLATES["en"])
161
+
162
+ # Применяем шаблон и токенизируем
163
+ text = tokenizer.apply_chat_template(
164
+ messages_for_template,
165
+ chat_template=template_content,
166
+ tokenize=False,
167
+ add_generation_prompt=True
168
+ )
169
+
170
+ inputs = tokenizer(text, return_tensors="pt").to(DEVICE)
171
+
172
+ with torch.no_grad():
173
+ outputs = model.generate(
174
+ **inputs,
175
+ max_new_tokens=MAX_NEW_TOKENS,
176
+ do_sample=True,
177
+ top_p=0.9,
178
+ temperature=0.8,
179
+ pad_token_id=tokenizer.eos_token_id
180
  )
 
 
181
 
182
+ raw = tokenizer.decode(outputs[0], skip_special_tokens=False)
183
+
184
+ # Извлекаем финальный ответ и ход мыслей
185
+ reply, reasoning_text = extract_assistant_reply_and_reasoning(raw)
 
 
 
 
 
186
 
187
+ # Обновляем историю Gradio с финальным ответом
188
+ history[-1][1] = ""
189
+
190
+ # Используем генератор для создания эффекта печати
191
+ for chunk in reply.split():
192
+ history[-1][1] += chunk + " "
193
+ time.sleep(0.05) # Небольшая задержка для анимации
 
 
194
  yield "", history, reasoning_text
195
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
  # --- Интерфейс Gradio ---
197
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
198
  gr.Markdown("# PyroNet-mini Chat")