KoDer123 commited on
Commit
7ebf4ab
·
verified ·
1 Parent(s): 39de865

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +320 -49
app.py CHANGED
@@ -1,11 +1,173 @@
1
  import gradio as gr
2
- from huggingface_hub import InferenceClient
 
 
 
 
 
3
 
4
- """
5
- For more information on `huggingface_hub` Inference API support, please check the docs: https://huggingface.co/docs/huggingface_hub/v0.22.2/en/guides/inference
6
- """
7
- client = InferenceClient("HuggingFaceH4/zephyr-7b-beta")
8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
  def respond(
11
  message,
@@ -15,50 +177,159 @@ def respond(
15
  temperature,
16
  top_p,
17
  ):
18
- messages = [{"role": "system", "content": system_message}]
19
-
20
- for val in history:
21
- if val[0]:
22
- messages.append({"role": "user", "content": val[0]})
23
- if val[1]:
24
- messages.append({"role": "assistant", "content": val[1]})
25
-
26
- messages.append({"role": "user", "content": message})
27
-
28
- response = ""
29
-
30
- for message in client.chat_completion(
31
- messages,
32
- max_tokens=max_tokens,
33
- stream=True,
34
- temperature=temperature,
35
- top_p=top_p,
36
- ):
37
- token = message.choices[0].delta.content
38
-
39
- response += token
40
- yield response
41
-
42
-
43
- """
44
- For information on how to customize the ChatInterface, peruse the gradio docs: https://www.gradio.app/docs/chatinterface
45
- """
46
- demo = gr.ChatInterface(
47
- respond,
48
- additional_inputs=[
49
- gr.Textbox(value="You are a friendly Chatbot.", label="System message"),
50
- gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"),
51
- gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"),
52
- gr.Slider(
53
- minimum=0.1,
54
- maximum=1.0,
55
- value=0.95,
56
- step=0.05,
57
- label="Top-p (nucleus sampling)",
58
- ),
59
- ],
60
- )
 
 
 
 
 
 
 
 
61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
 
63
  if __name__ == "__main__":
64
- demo.launch()
 
1
  import gradio as gr
2
+ from transformers import AutoModelForCausalLM, AutoTokenizer
3
+ import torch
4
+ import os
5
+ import shutil
6
+ import time
7
+ import logging
8
 
9
+ # Настройка логирования
10
+ logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
11
+ logger = logging.getLogger(__name__)
 
12
 
13
+ # Информация о системе и CUDA
14
+ logger.info("===== Запуск приложения =====")
15
+ logger.info(f"PyTorch: {torch.__version__}")
16
+ logger.info(f"CUDA доступен: {torch.cuda.is_available()}")
17
+
18
+ if torch.cuda.is_available():
19
+ try:
20
+ cuda_device_count = torch.cuda.device_count()
21
+ logger.info(f"Количество CUDA устройств: {cuda_device_count}")
22
+ for i in range(cuda_device_count):
23
+ logger.info(f"CUDA устройство {i}: {torch.cuda.get_device_name(i)}")
24
+ logger.info(f"Текущее CUDA устройство: {torch.cuda.current_device()}")
25
+ except Exception as e:
26
+ logger.warning(f"Ошибка при получении информации о CUDA: {e}")
27
+ else:
28
+ logger.info("CUDA недоступен, будет использоваться CPU")
29
+
30
+ # Проверяем наличие общих директорий для хранения данных
31
+ possible_dirs = [
32
+ "/data", # Стандартный путь для Spaces с подключенным диском
33
+ "/mnt/data", # Альтернативный путь для подключенного диска
34
+ "/home/user/data", # Директория пользователя
35
+ "/tmp" # Временная директория (запасной вариант)
36
+ ]
37
+
38
+ # Находим первую доступную директорию
39
+ DISK_DIR = None
40
+ for dir_path in possible_dirs:
41
+ try:
42
+ if not os.path.exists(dir_path):
43
+ os.makedirs(dir_path, exist_ok=True)
44
+
45
+ # Проверяем, можем ли мы писать в эту директорию
46
+ test_file = os.path.join(dir_path, "write_test.txt")
47
+ with open(test_file, "w") as f:
48
+ f.write("test")
49
+ os.remove(test_file)
50
+
51
+ DISK_DIR = dir_path
52
+ logger.info(f"Используем директорию для хранения: {DISK_DIR}")
53
+ break
54
+ except (OSError, PermissionError) as e:
55
+ logger.warning(f"Не удалось использовать директорию {dir_path}: {e}")
56
+
57
+ if DISK_DIR is None:
58
+ DISK_DIR = "." # Используем текущую директорию, если ничего не найдено
59
+ logger.warning(f"Внимание! Используем текущую директорию: {os.path.abspath(DISK_DIR)}")
60
+
61
+ # Настраиваем пути для сохранения моделей
62
+ CACHE_DIR = os.path.join(DISK_DIR, "models_cache")
63
+ TORCH_HOME = os.path.join(DISK_DIR, "torch_home")
64
+ OFFLOAD_DIR = os.path.join(DISK_DIR, "offload")
65
+
66
+ # Создаем директории
67
+ os.makedirs(CACHE_DIR, exist_ok=True)
68
+ os.makedirs(TORCH_HOME, exist_ok=True)
69
+ os.makedirs(OFFLOAD_DIR, exist_ok=True)
70
+
71
+ # Устанавливаем переменные окружения для управления кэшированием
72
+ os.environ["TRANSFORMERS_CACHE"] = CACHE_DIR
73
+ os.environ["HF_HOME"] = CACHE_DIR
74
+ os.environ["TORCH_HOME"] = TORCH_HOME
75
+
76
+ # Функция для проверки свободного места на диске
77
+ def check_disk_space(path):
78
+ try:
79
+ total, used, free = shutil.disk_usage(path)
80
+ logger.info(f"Диск {path}: всего {total // (1024**3)} ГБ, свободно {free // (1024**3)} ГБ")
81
+ return free
82
+ except Exception as e:
83
+ logger.warning(f"Не удалось проверить диск {path}: {e}")
84
+ return None
85
+
86
+ # Выводим информацию о диске перед загрузкой
87
+ logger.info("Информация о дисках перед загрузкой:")
88
+ check_disk_space("/")
89
+ check_disk_space(DISK_DIR)
90
+
91
+ # Загрузка модели и токенизатора
92
+ model_name = " KoDer123/Nerealnost_8M"
93
+
94
+ # Глобальные переменные для модели
95
+ model = None
96
+ tokenizer = None
97
+ is_model_loaded = False
98
+
99
+ # Функция для загрузки модели
100
+ def load_model():
101
+ global model, tokenizer, is_model_loaded
102
+
103
+ try:
104
+ logger.info("Загружаем токенизатор...")
105
+ tokenizer = AutoTokenizer.from_pretrained(
106
+ model_name,
107
+ cache_dir=CACHE_DIR,
108
+ local_files_only=False
109
+ )
110
+
111
+ # Устанавливаем pad_token, если его нет
112
+ if tokenizer.pad_token is None:
113
+ tokenizer.pad_token = tokenizer.eos_token
114
+
115
+ logger.info("Загружаем модель...")
116
+ # Определяем оптимальный режим загрузки
117
+ model_kwargs = {
118
+ "cache_dir": CACHE_DIR,
119
+ "local_files_only": False,
120
+ "trust_remote_code": True
121
+ }
122
+
123
+ # Проверяем доступность CUDA
124
+ if torch.cuda.is_available():
125
+ logger.info("Загружаем модель в режиме GPU...")
126
+ model_kwargs.update({
127
+ "device_map": "auto",
128
+ "torch_dtype": torch.float16,
129
+ })
130
+ else:
131
+ logger.info("Загружаем модель в режиме CPU...")
132
+ model_kwargs.update({
133
+ "device_map": "cpu",
134
+ "torch_dtype": torch.float32,
135
+ "low_cpu_mem_usage": True,
136
+ "offload_folder": OFFLOAD_DIR
137
+ })
138
+
139
+ # Загружаем модель
140
+ model = AutoModelForCausalLM.from_pretrained(
141
+ model_name,
142
+ **model_kwargs
143
+ )
144
+
145
+ # Проверяем, на каком устройстве размещена модель
146
+ device_info = next(model.parameters()).device
147
+ logger.info(f"Модель успешно загружена на устройство: {device_info}")
148
+
149
+ is_model_loaded = True
150
+ return "Модель успешно загружена"
151
+ except Exception as e:
152
+ error_msg = str(e)
153
+ logger.error(f"Ошибка загрузки модели: {error_msg}")
154
+ is_model_loaded = False
155
+ return f"Ошибка загрузки модели: {error_msg}"
156
+
157
+ # Загружаем модель
158
+ start_time = time.time()
159
+ load_result = load_model()
160
+ end_time = time.time()
161
+ logger.info(f"Загрузка модели заняла {end_time - start_time:.2f} секунд. Результат: {load_result}")
162
+
163
+ # Выводим информацию о диске после загрузки
164
+ logger.info("Информация о дисках после загрузки:")
165
+ check_disk_space("/")
166
+ check_disk_space(DISK_DIR)
167
+
168
+ # Определяем шаблон Q&A, как при обучении
169
+ qa_prompt = "<s>Пользователь: {}\nАссистент: {}"
170
+ EOS_TOKEN = tokenizer.eos_token if tokenizer.eos_token else "</s>"
171
 
172
  def respond(
173
  message,
 
177
  temperature,
178
  top_p,
179
  ):
180
+ global model, tokenizer, is_model_loaded
181
+
182
+ # Проверяем, загружена ли модель
183
+ if not is_model_loaded or model is None:
184
+ return "Модель не загружена или произошла ошибка при загрузке."
185
+
186
+ # Замеряем время
187
+ start_time = time.time()
188
+
189
+ # Формируем историю в текстовом формате
190
+ full_prompt = ""
191
+ if system_message:
192
+ full_prompt += qa_prompt.format(system_message, "") + "\n"
193
+
194
+ for user_msg, assistant_msg in history:
195
+ if user_msg and assistant_msg:
196
+ full_prompt += qa_prompt.format(user_msg, assistant_msg) + EOS_TOKEN + "\n"
197
+
198
+ full_prompt += qa_prompt.format(message, "")
199
+
200
+ logger.info(f"Генерируем ответ на запрос: '{message[:50]}...' (длина промпта: {len(full_prompt)})")
201
+
202
+ try:
203
+ # Токенизация входных данных
204
+ inputs = tokenizer(full_prompt, return_tensors="pt").to(model.device)
205
+
206
+ # Генерация ответа
207
+ outputs = model.generate(
208
+ **inputs,
209
+ max_new_tokens=max_tokens,
210
+ temperature=temperature,
211
+ top_p=top_p,
212
+ do_sample=True,
213
+ pad_token_id=tokenizer.pad_token_id,
214
+ )
215
+
216
+ # Декодирование полного вывода
217
+ generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
218
+
219
+ # Извлекаем только часть после "Ассистент: "
220
+ response_start = generated_text.rfind("Ассистент: ") + len("Ассистент: ")
221
+ response = generated_text[response_start:].strip()
222
+
223
+ end_time = time.time()
224
+ generation_time = end_time - start_time
225
+ logger.info(f"Генерация заняла {generation_time:.2f} секунд. Получен ответ длиной {len(response)} символов")
226
+
227
+ return response
228
+ except Exception as e:
229
+ logger.error(f"Ошибка при генерации ответа: {str(e)}")
230
+ return f"Произошла ошибка при генерации ответа: {str(e)}"
231
 
232
+ # Настройка интерфейса Gradio
233
+ with gr.Blocks(theme=gr.themes.Soft()) as demo:
234
+ gr.Markdown("# НереальностьQA - Чат с экспертом по эзотерике")
235
+
236
+ with gr.Row():
237
+ with gr.Column(scale=4):
238
+ chatbot = gr.Chatbot(label="Диалог")
239
+ user_input = gr.Textbox(
240
+ placeholder="Введите ваш вопрос здесь...",
241
+ label="Ваш вопрос",
242
+ lines=2
243
+ )
244
+
245
+ with gr.Row():
246
+ submit_btn = gr.Button("Отправить", variant="primary")
247
+ clear_btn = gr.Button("Очистить историю")
248
+
249
+ with gr.Column(scale=1):
250
+ with gr.Accordion("Настройки генерации", open=False):
251
+ system_msg = gr.Textbox(
252
+ value="Ты - эксперт по эзотерике, специализирующийся на энергетике человека, мире отшедших душ и метафизических знаниях. Отвечай подробно, опираясь на свои знания.",
253
+ label="Системное сообщение",
254
+ lines=4
255
+ )
256
+ max_tokens = gr.Slider(
257
+ minimum=1,
258
+ maximum=2048,
259
+ value=512,
260
+ step=1,
261
+ label="Максимальное число токенов"
262
+ )
263
+ temperature = gr.Slider(
264
+ minimum=0.1,
265
+ maximum=4.0,
266
+ value=0.7,
267
+ step=0.1,
268
+ label="Температура"
269
+ )
270
+ top_p = gr.Slider(
271
+ minimum=0.1,
272
+ maximum=1.0,
273
+ value=0.95,
274
+ step=0.05,
275
+ label="Top-p"
276
+ )
277
+
278
+ with gr.Accordion("Информация", open=True):
279
+ info_text = gr.Markdown(f"""
280
+ * **Модель**: {model_name}
281
+ * **Режим работы**: {"GPU" if torch.cuda.is_available() else "CPU"}
282
+ * **Директория для кэша**: {CACHE_DIR}
283
+ """)
284
+
285
+ # Примеры вопросов
286
+ with gr.Accordion("Примеры вопросов", open=True):
287
+ examples = gr.Examples(
288
+ examples=[
289
+ "Что известно о мире отшедших душ и их взаимодействии с нашим миром?",
290
+ "Что такое энергетическая ось человека и как она связана с его биополем?",
291
+ "Расскажи о роли энергии мысли и желания в мире отшедших."
292
+ ],
293
+ inputs=user_input
294
+ )
295
+
296
+ # Функция обработки отправки сообщения
297
+ def chat(message, history):
298
+ if message == "":
299
+ return history, ""
300
+
301
+ # Генерируем ответ
302
+ bot_message = respond(
303
+ message,
304
+ history,
305
+ system_msg.value,
306
+ max_tokens.value,
307
+ temperature.value,
308
+ top_p.value
309
+ )
310
+
311
+ # Добавляем в историю и возвращаем
312
+ history = history + [(message, bot_message)]
313
+ return history, ""
314
+
315
+ # Обработчики событий
316
+ submit_btn.click(
317
+ chat,
318
+ inputs=[user_input, chatbot],
319
+ outputs=[chatbot, user_input]
320
+ )
321
+
322
+ user_input.submit(
323
+ chat,
324
+ inputs=[user_input, chatbot],
325
+ outputs=[chatbot, user_input]
326
+ )
327
+
328
+ clear_btn.click(
329
+ lambda: ([], ""),
330
+ outputs=[chatbot, user_input]
331
+ )
332
 
333
+ # Запуск приложения
334
  if __name__ == "__main__":
335
+ demo.launch()