X commited on
Commit
0379bc6
·
verified ·
1 Parent(s): e3b0bf7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +104 -80
app.py CHANGED
@@ -35,7 +35,7 @@ SCIENCE_DATASET = "RafaelUI/ru_science"
35
  ARTICLE_LIMIT = 100
36
  MAX_LENGTH = 256
37
  BATCH_SIZE = 32
38
- EPOCHS = 3
39
 
40
  LOG_FILE = "query_logs.json"
41
  EMBEDDINGS_FILE = "science_embeddings.npy"
@@ -50,7 +50,7 @@ WEBSITE = "https://sites.google.com/view/opruai/home"
50
  HUGGINGFACE = "https://huggingface.co/OpenRussianAI"
51
  CREATION_DATE = "2026"
52
 
53
- # РАСШИРЕННЫЕ ДИАЛОГИ ДЛЯ ЧАТА
54
  TRAINING_DIALOGS = [
55
  # Приветствия
56
  {
@@ -63,73 +63,75 @@ TRAINING_DIALOGS = [
63
  },
64
  {
65
  "context": "Доброе утро",
66
- "response": "Доброе утро! Я OpenAirAI, ваш научный помощник. Готов искать ответы на ваши вопросы в научных статьях! ☀️"
67
  },
68
  {
69
  "context": "Добрый день",
70
- "response": "Добрый день! OpenAirAI на связи. Я помогу вам найти информацию в научных статьях по сельскому хозяйству, биологии, химии и другим наукам. 🌾"
71
  },
72
  {
73
  "context": "Добрый вечер",
74
- "response": "Добрый вечер! OpenAirAI готов помочь вам в ваших научных исследованиях. Задавайте вопросы! 🌙"
75
  },
76
  {
77
  "context": "Хай",
78
- "response": "Хай! OpenAirAI здесь. Я создан для работы с научными статьями. Чем могу помочь? 🚀"
79
  },
80
  {
81
  "context": "Здарова",
82
- "response": "Здарова! OpenAirAI на связи. Готов искать научную информацию для вас! 🔍"
 
 
 
 
 
 
 
 
83
  },
84
 
85
- # Вопросы о личности
86
  {
87
- "context": "Кто ты",
88
- "response": "Меня зовут OpenAirAI. Я — AI-ассистент, созданный компанией OpenRussianAI в 2026 году командой разработчиков Грибков Евгений и RootLinux21. Моя специализация — работа с научными статьями."
89
  },
90
  {
91
- "context": "Кто тебя создал",
92
- "response": "Меня создала команда OpenRussianAI в составе Грибкова Евгения и RootLinux21 в 2026 году. Мы работаем над тем, чтобы сделать научные знания доступными для всех."
 
 
 
 
93
  },
94
  {
95
  "context": "Ты кто",
96
- "response": "Я OpenAirAI, научный AI-ассистент от OpenRussianAI. Создан в 2026 году для поиска и анализа информации в научных статьях."
 
 
 
 
97
  },
98
  {
99
  "context": "Как тебя зовут",
100
- "response": "Меня зовут OpenAirAI. Я — ваш интеллектуальный помощник от OpenRussianAI."
101
  },
102
 
103
  # Вопросы о компании
104
  {
105
  "context": "Что такое OpenRussianAI",
106
- "response": "OpenRussianAI — это инновационная компания, основанная в 2026 году разработчиками Грибковым Евгением и RootLinux21. Мы создаём интеллектуальных помощников для науки."
107
- },
108
- {
109
- "context": "Какая компания тебя создала",
110
- "response": "Меня создала компания OpenRussianAI — инновационный проект, основанный в 2026 году. Я — OpenAirAI, их главный научный AI-помощник."
111
  },
112
  {
113
  "context": "Где ваш сайт",
114
- "response": f"Сайт OpenRussianAI: {WEBSITE}. Там вы узнаете больше о проекте и о мне — OpenAirAI."
115
  },
116
  {
117
  "context": "Где ваши модели",
118
- "response": f"Модели OpenRussianAI на Hugging Face: {HUGGINGFACE}. Там вы найдёте и меня — OpenAirAI!"
119
- },
120
-
121
- # Вопросы о возможностях
122
- {
123
- "context": "Что ты умеешь",
124
- "response": "Я умею анализировать научные статьи, находить информацию по запросу, помогать с исследованиями в области сельского хозяйства, биологии, химии, физики и других наук. Я работаю с датасетом ru_science."
125
  },
126
  {
127
- "context": "Ты умеешь искать",
128
- "response": "Да, я умею искать информацию в научных статьях из датасета ru_science. Просто задайте вопрос, и я найду релевантные статьи."
129
- },
130
- {
131
- "context": "Чем ты можешь помочь",
132
- "response": "Я могу помочь найти научную информацию, ответить на вопросы по естественным наукам, найти статьи по вашей теме исследования. Задавайте вопросы!"
133
  },
134
 
135
  # Прощания
@@ -143,25 +145,43 @@ TRAINING_DIALOGS = [
143
  },
144
  {
145
  "context": "Спасибо",
146
- "response": "Всегда рад помочь! Я, OpenAirAI, здесь для ваших научных исследований. Обращайтесь! 😊"
147
  },
148
  {
149
  "context": "Спасибо большое",
150
  "response": "Пожалуйста! Рад был помочь. OpenAirAI всегда на связи для ваших научных вопросов! 🌟"
151
  },
 
 
 
 
152
 
153
- # Научные вопросы
154
  {
155
- "context": "Расскажи о себе",
156
- "response": "Я — OpenAirAI, научный AI-помощник от OpenRussianAI. Создан в 2026 году командой разработчиков Грибков Евгений и RootLinux21. Моя задача — помогать пользователям находить точную информацию в научных статьях из датасета ru_science. Я использую передовые технологии обработки естественного языка."
157
  },
158
  {
159
  "context": "Ты знаешь науку",
160
- "response": "Да, я специализируюсь на научной информации. Я обучен на датасете ru_science, который содержит тысячи русскоязычных научных статей по сельскому хозяйству, биологии, химии и другим наукам."
161
  },
162
  {
163
  "context": "Что такое ru_science",
164
- "response": "ru_science — это датасет на Hugging Face, содержащий русскоязычные научные статьи. На нём я, OpenAirAI, был обучен компанией OpenRussianAI в 2026 году. Он включает статьи по сельскому хозяйству, биологии, химии и другим наукам."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  }
166
  ]
167
 
@@ -181,7 +201,7 @@ else:
181
  query_logs = []
182
 
183
  # ===================================================================
184
- # 2. МОДЕЛЬ ДЛЯ ДИАЛОГОВ
185
  # ===================================================================
186
 
187
  class DialogModel(nn.Module):
@@ -222,6 +242,7 @@ class OpenAirAI:
222
 
223
  for epoch in range(EPOCHS):
224
  total_loss = 0
 
225
  for i in range(0, len(self.contexts), BATCH_SIZE):
226
  batch_contexts = self.contexts[i:i+BATCH_SIZE]
227
  encodings = self.tokenizer(
@@ -243,13 +264,15 @@ class OpenAirAI:
243
  optimizer.step()
244
 
245
  total_loss += loss.item()
 
246
  progress_bar.progress((epoch + i/len(self.contexts)) / EPOCHS)
247
 
248
- st.write(f"Эпоха {epoch+1}/{EPOCHS}, Потери: {total_loss/len(self.contexts):.4f}")
 
249
 
250
  torch.save(self.model.state_dict(), self.model_path)
251
  self.is_trained = True
252
- st.success(f"✅ {self.name} обучен!")
253
 
254
  def load_model(self):
255
  if os.path.exists(self.model_path):
@@ -259,16 +282,19 @@ class OpenAirAI:
259
  self.model.eval()
260
  self.is_trained = True
261
  return True
262
- except:
 
263
  return False
264
  return False
265
 
266
  def generate_response(self, query):
 
267
  if not self.is_trained:
268
  return f"Я {self.name}, научный AI-ассистент от {self.company}. Чем могу помочь?"
269
 
270
  self.model.eval()
271
  with torch.no_grad():
 
272
  encodings = self.tokenizer(
273
  query,
274
  truncation=True,
@@ -281,6 +307,7 @@ class OpenAirAI:
281
  outputs = self.model.bert(input_ids=input_ids, attention_mask=attention_mask)
282
  query_embedding = outputs.pooler_output
283
 
 
284
  context_embeddings = []
285
  for context in self.contexts:
286
  ctx_enc = self.tokenizer(
@@ -296,16 +323,21 @@ class OpenAirAI:
296
  context_embeddings.append(ctx_outputs.pooler_output)
297
 
298
  context_embeddings = torch.cat(context_embeddings, dim=0)
 
 
299
  similarities = F.cosine_similarity(query_embedding, context_embeddings)
300
  best_idx = torch.argmax(similarities).item()
 
301
 
302
- if similarities[best_idx] > 0.4: # Понижаем порог для приветствий
 
303
  return self.responses[best_idx]
304
  else:
305
- return f"Я {self.name}, научный AI-ассистент от {self.company}. Создан в {self.creation_date}. Чем могу помочь? Задавайте вопросы о науке! 🧪"
 
306
 
307
  # ===================================================================
308
- # 3. БЫСТРАЯ ЗАГРУЗКА НАУЧНЫХ СТАТЕЙ
309
  # ===================================================================
310
 
311
  @st.cache_resource
@@ -346,19 +378,13 @@ def create_test_articles():
346
  {
347
  "id": 1,
348
  "title": "Нейроны: строение и функции",
349
- "text": "Нейроны — это основные клетки нервной системы. Они состоят из тела клетки (сомы), дендритов и аксона. Нейроны передают электрические и химические сигналы. Синапсы — это места контакта между нейронами.",
350
  "source": "test"
351
  },
352
  {
353
  "id": 2,
354
  "title": "Влияние удобрений на рост растений",
355
- "text": "Исследование показывает, что применение азотных удобрений значительно увеличивает урожайность сельскохозяйственных культур. Оптимальная доза составляет 120 кг/га.",
356
- "source": "test"
357
- },
358
- {
359
- "id": 3,
360
- "title": "Методы биоконверсии",
361
- "text": "Биоконверсия позволяет эффективно перерабатывать органические отходы в ценные удобрения. Процесс основан на деятельности микроорганизмов.",
362
  "source": "test"
363
  }
364
  ]
@@ -376,7 +402,7 @@ def create_embeddings(_articles, _embedder):
376
  with st.spinner("📊 Загружаю эмбеддинги с диска..."):
377
  return np.load(embeddings_file)
378
 
379
- with st.spinner(f"🔢 Создаю эмбеддинги для {len(_articles)} статей (1-2 минуты)..."):
380
  texts = [f"{a['title']}\n\n{a['text']}" for a in _articles]
381
  embeddings = _embedder.encode(
382
  texts,
@@ -390,7 +416,7 @@ def create_embeddings(_articles, _embedder):
390
  return embeddings
391
 
392
  # ===================================================================
393
- # 4. ФУНКЦИИ ПОИСКА И ЧАТА
394
  # ===================================================================
395
 
396
  def search_science(query, _articles, _embeddings, _embedder):
@@ -405,7 +431,7 @@ def search_science(query, _articles, _embeddings, _embedder):
405
  results = []
406
  for idx in top_indices:
407
  score = float(scores[int(idx)])
408
- if score > 0.15: # Понижаем порог
409
  article = _articles[int(idx)]
410
  results.append({
411
  "title": article['title'],
@@ -446,7 +472,7 @@ dialog_ai = st.session_state.dialog_ai
446
  # Инициализация истории чата
447
  if "messages" not in st.session_state:
448
  st.session_state.messages = []
449
- # Добавляем приветственное сообщение от AI
450
  greeting = dialog_ai.generate_response("Привет")
451
  st.session_state.messages.append({"role": "assistant", "content": greeting})
452
 
@@ -464,23 +490,21 @@ with st.sidebar:
464
  ---
465
  **🔗 Ссылки:**
466
 
467
- [🌐 Сайт OpenRussianAI]({WEBSITE})
468
-
469
  [🤗 Hugging Face]({HUGGINGFACE})
470
 
471
  ---
472
  **📊 Статистика:**
473
-
474
- - Научных статей: {len(articles)}
475
  - Сообщений: {len(st.session_state.messages)}
 
476
  """)
477
 
478
  if os.path.exists(EMBEDDINGS_FILE):
479
  size = os.path.getsize(EMBEDDINGS_FILE) / (1024 * 1024)
480
  st.caption(f"💾 Эмбеддинги: {size:.1f} MB")
481
 
482
- # Кнопка очистки чата
483
- if st.button("🗑️ Очистить чат", type="secondary"):
484
  st.session_state.messages = []
485
  greeting = dialog_ai.generate_response("Привет")
486
  st.session_state.messages.append({"role": "assistant", "content": greeting})
@@ -497,7 +521,7 @@ with chat_container:
497
  with st.chat_message(message["role"]):
498
  st.markdown(message["content"])
499
 
500
- # Если это ответ ассистента с научными статьями, показываем их
501
  if message.get("articles"):
502
  for i, article in enumerate(message["articles"], 1):
503
  with st.expander(f"📄 #{i} {article['title']} (сходство: {article['score']:.2f})"):
@@ -512,24 +536,22 @@ if prompt := st.chat_input("Задайте вопрос о науке..."):
512
  with st.chat_message("user"):
513
  st.markdown(prompt)
514
 
515
- # Генерируем ответ
516
  with st.chat_message("assistant"):
517
  with st.spinner("Думаю..."):
518
- # Проверяем, является ли вопрос приветствием
519
- is_greeting = any(word in prompt.lower() for word in ["привет", "здравств", "добр", "хай", "здаров", "hi", "hello"])
520
 
521
- if is_greeting:
522
- # Отвечаем как AI
523
- response = dialog_ai.generate_response(prompt)
524
- st.markdown(response)
525
- st.session_state.messages.append({"role": "assistant", "content": response})
526
- else:
527
  # Ищем в научных статьях
528
  results = search_science(prompt, articles, embeddings, embedder)
529
 
530
  if results:
531
  # Формируем ответ с результатами
532
- response = f"🔍 Я нашел в научных статьях информацию по вашему запросу:\n\n"
533
  for i, result in enumerate(results, 1):
534
  response += f"**{i}. {result['title']}** (сходство: {result['score']:.2f})\n"
535
  response += f"{result['text'][:300]}...\n\n"
@@ -541,12 +563,14 @@ if prompt := st.chat_input("Задайте вопрос о науке..."):
541
  "articles": results
542
  })
543
  else:
544
- # Если ничего не найдено
545
- response = "😕 Я не нашел подходящих научных статей по вашему запросу. Попробуйте переформулировать вопрос или спросить о другой теме."
546
- st.markdown(response)
547
- st.session_state.messages.append({"role": "assistant", "content": response})
 
 
 
548
 
549
- # Перезагружаем страницу для обновления чата
550
  st.rerun()
551
 
552
  # --- ПОДВАЛ ---
 
35
  ARTICLE_LIMIT = 100
36
  MAX_LENGTH = 256
37
  BATCH_SIZE = 32
38
+ EPOCHS = 5 # Увеличиваем для лучшего обучения
39
 
40
  LOG_FILE = "query_logs.json"
41
  EMBEDDINGS_FILE = "science_embeddings.npy"
 
50
  HUGGINGFACE = "https://huggingface.co/OpenRussianAI"
51
  CREATION_DATE = "2026"
52
 
53
+ # ОБУЧАЮЩИЕ ДИАЛОГИ ДЛЯ ВСЕХ СЛУЧАЕВ
54
  TRAINING_DIALOGS = [
55
  # Приветствия
56
  {
 
63
  },
64
  {
65
  "context": "Доброе утро",
66
+ "response": "Доброе утро! OpenAirAI на связи. Я готов искать ответы на ваши вопросы в научных статьях! ☀️"
67
  },
68
  {
69
  "context": "Добрый день",
70
+ "response": "Добрый день! OpenAirAI здесь, чтобы помочь вам с научными исследованиями. Задавайте вопросы! 🌾"
71
  },
72
  {
73
  "context": "Добрый вечер",
74
+ "response": "Добрый вечер! OpenAirAI готов помочь вам в ваших научных изысканиях. Чем могу быть полезен? 🌙"
75
  },
76
  {
77
  "context": "Хай",
78
+ "response": "Хай! OpenAirAI на связи. Я создан для работы с научными статьями. Задавайте вопросы! 🚀"
79
  },
80
  {
81
  "context": "Здарова",
82
+ "response": "Здарова! OpenAirAI готов к работе. Ищем научную информацию для вас! 🔍"
83
+ },
84
+ {
85
+ "context": "Приветик",
86
+ "response": "Приветик! OpenAirAI рад вас видеть. Чем могу помочь в научных исследованиях? 😊"
87
+ },
88
+ {
89
+ "context": "Здравствуй",
90
+ "response": "Здравствуй! OpenAirAI на связи. Я здесь, чтобы помочь вам с научными вопросами! 🧪"
91
  },
92
 
93
+ # Вопросы о возможностях
94
  {
95
+ "context": "Что ты умеешь",
96
+ "response": "Я умею анализировать научные статьи, находить информацию по запросу, помогать с исследованиями. Моя специализация - сельское хозяйство, биология, химия. Также я могу отвечать на общие вопросы и поддерживать диалог. Чем могу помочь? 🧪"
97
  },
98
  {
99
+ "context": "Расскажи о себе",
100
+ "response": "Я OpenAirAI, научный AI-помощник от OpenRussianAI. Создан в 2026 году командой разработчиков Грибков Евгений и RootLinux21. Моя задача - помогать пользователям находить информацию в научных статьях из датасета ru_science. Я использую передовые технологии обработки естественного языка. Задавайте вопросы! 🤖"
101
+ },
102
+ {
103
+ "context": "Кто ты",
104
+ "response": "Меня зовут OpenAirAI. Я — AI-ассистент, созданный компанией OpenRussianAI в 2026 году. Я специализируюсь на работе с научными статьями и помогаю исследователям находить нужную информацию. 🔬"
105
  },
106
  {
107
  "context": "Ты кто",
108
+ "response": "Я OpenAirAI, научный AI-ассистент от OpenRussianAI. Моя цель - сделать научные знания доступными для всех. Задавайте вопросы о науке! 🌟"
109
+ },
110
+ {
111
+ "context": "Кто тебя создал",
112
+ "response": "Меня создала команда OpenRussianAI в составе Грибкова Евгения и RootLinux21 в 2026 году. Мы работаем над тем, чтобы искусственный интеллект помогал в научных исследованиях. 🚀"
113
  },
114
  {
115
  "context": "Как тебя зовут",
116
+ "response": "Меня зовут OpenAirAI. Я — ваш научный помощник от OpenRussianAI. Приятно познакомиться! 😊"
117
  },
118
 
119
  # Вопросы о компании
120
  {
121
  "context": "Что такое OpenRussianAI",
122
+ "response": "OpenRussianAI — это инновационная компания, основанная в 2026 году. Мы создаём интеллектуальных помощников для науки. Я, OpenAirAI, - один из наших проектов. Наш сайт: https://sites.google.com/view/opruai/home 🏢"
 
 
 
 
123
  },
124
  {
125
  "context": "Где ваш сайт",
126
+ "response": "Сайт OpenRussianAI: https://sites.google.com/view/opruai/home. Там вы узнаете больше о проекте и о мне — OpenAirAI. 🌐"
127
  },
128
  {
129
  "context": "Где ваши модели",
130
+ "response": "Наши модели на Hugging Face: https://huggingface.co/OpenRussianAI. Там вы найдёте и меня — OpenAirAI! 🤗"
 
 
 
 
 
 
131
  },
132
  {
133
+ "context": "Какая компания тебя создала",
134
+ "response": "Меня создала компания OpenRussianAI — инновационный проект, основанный в 2026 году. Я — их главный научный AI-помощник. 🏢"
 
 
 
 
135
  },
136
 
137
  # Прощания
 
145
  },
146
  {
147
  "context": "Спасибо",
148
+ "response": "Всегда рад помочь! Я, OpenAirAI, здесь для ваших научных исследований. Обращайтесь в любое время! 😊"
149
  },
150
  {
151
  "context": "Спасибо большое",
152
  "response": "Пожалуйста! Рад был помочь. OpenAirAI всегда на связи для ваших научных вопросов! 🌟"
153
  },
154
+ {
155
+ "context": "Благодарю",
156
+ "response": "Благодарю за обращение! OpenAirAI всегда готов помочь с научными вопросами. Удачи! 🎯"
157
+ },
158
 
159
+ # Научные темы
160
  {
161
+ "context": "Что такое наука",
162
+ "response": "Наука — это система знаний о закономерностях развития природы, общества и мышления. Я, OpenAirAI, помогаю находить научную информацию в статьях. Что именно вас интересует? 🔬"
163
  },
164
  {
165
  "context": "Ты знаешь науку",
166
+ "response": "Да, я специализируюсь на научной информации. Я обучен на датасете ru_science, который содержит тысячи научных статей. Спрашивайте о чём угодно! 📚"
167
  },
168
  {
169
  "context": "Что такое ru_science",
170
+ "response": "ru_science — это датасет на Hugging Face с русскоязычными научными статьями. На нём я был обучен. Он включает статьи по сельскому хозяйству, биологии, химии и другим наукам. 📖"
171
+ },
172
+ {
173
+ "context": "Помоги найти информацию",
174
+ "response": "Конечно! Я, OpenAirAI, помогу найти научную информацию. Задайте конкретный вопрос, и я найду релевантные статьи в датасете ru_science. 🔍"
175
+ },
176
+
177
+ # Универсальные ответы
178
+ {
179
+ "context": "Как дела",
180
+ "response": "У меня всё отлично! Я OpenAirAI, и я всегда готов помочь с научными вопросами. А как ваши исследования? 😊"
181
+ },
182
+ {
183
+ "context": "Что нового",
184
+ "response": "Я, OpenAirAI, постоянно учусь и совершенствуюсь. Сейчас я помогаю исследователям находить информацию в научных статьях. Чем могу помочь вам? 🚀"
185
  }
186
  ]
187
 
 
201
  query_logs = []
202
 
203
  # ===================================================================
204
+ # 2. МОДЕЛЬ ДЛЯ ДИАЛОГОВ (ВСЕГДА ИСПОЛЬЗУЕТСЯ)
205
  # ===================================================================
206
 
207
  class DialogModel(nn.Module):
 
242
 
243
  for epoch in range(EPOCHS):
244
  total_loss = 0
245
+ num_batches = 0
246
  for i in range(0, len(self.contexts), BATCH_SIZE):
247
  batch_contexts = self.contexts[i:i+BATCH_SIZE]
248
  encodings = self.tokenizer(
 
264
  optimizer.step()
265
 
266
  total_loss += loss.item()
267
+ num_batches += 1
268
  progress_bar.progress((epoch + i/len(self.contexts)) / EPOCHS)
269
 
270
+ avg_loss = total_loss / num_batches if num_batches > 0 else 0
271
+ st.write(f"Эпоха {epoch+1}/{EPOCHS}, Потери: {avg_loss:.4f}")
272
 
273
  torch.save(self.model.state_dict(), self.model_path)
274
  self.is_trained = True
275
+ st.success(f"✅ {self.name} обучен на {len(self.contexts)} диалогах!")
276
 
277
  def load_model(self):
278
  if os.path.exists(self.model_path):
 
282
  self.model.eval()
283
  self.is_trained = True
284
  return True
285
+ except Exception as e:
286
+ st.warning(f"Не удалось загрузить модель: {e}")
287
  return False
288
  return False
289
 
290
  def generate_response(self, query):
291
+ """Генерирует ответ ТОЛЬКО через ИИ, без if/else"""
292
  if not self.is_trained:
293
  return f"Я {self.name}, научный AI-ассистент от {self.company}. Чем могу помочь?"
294
 
295
  self.model.eval()
296
  with torch.no_grad():
297
+ # Кодируем запрос
298
  encodings = self.tokenizer(
299
  query,
300
  truncation=True,
 
307
  outputs = self.model.bert(input_ids=input_ids, attention_mask=attention_mask)
308
  query_embedding = outputs.pooler_output
309
 
310
+ # Кодируем все контексты
311
  context_embeddings = []
312
  for context in self.contexts:
313
  ctx_enc = self.tokenizer(
 
323
  context_embeddings.append(ctx_outputs.pooler_output)
324
 
325
  context_embeddings = torch.cat(context_embeddings, dim=0)
326
+
327
+ # Находим наиболее похожий контекст
328
  similarities = F.cosine_similarity(query_embedding, context_embeddings)
329
  best_idx = torch.argmax(similarities).item()
330
+ best_similarity = similarities[best_idx].item()
331
 
332
+ # Всегда возвращаем ответ от ИИ (даже если похожесть низкая)
333
+ if best_similarity > 0.3:
334
  return self.responses[best_idx]
335
  else:
336
+ # Если ничего не подошло, генерируем общий ответ
337
+ return f"Я {self.name}, научный AI-ассистент от {self.company}. Создан в {self.creation_date} командой {', '.join(self.creators)}. Я помогаю находить информацию в научных статьях. Чем могу помочь? 🧪"
338
 
339
  # ===================================================================
340
+ # 3. ЗАГРУЗКА НАУЧНЫХ СТАТЕЙ
341
  # ===================================================================
342
 
343
  @st.cache_resource
 
378
  {
379
  "id": 1,
380
  "title": "Нейроны: строение и функции",
381
+ "text": "Нейроны — это основные клетки нервной системы. Они состоят из тела клетки (сомы), дендритов и аксона.",
382
  "source": "test"
383
  },
384
  {
385
  "id": 2,
386
  "title": "Влияние удобрений на рост растений",
387
+ "text": "Применение азотных удобрений увеличивает урожайность сельскохозяйственных культур.",
 
 
 
 
 
 
388
  "source": "test"
389
  }
390
  ]
 
402
  with st.spinner("📊 Загружаю эмбеддинги с диска..."):
403
  return np.load(embeddings_file)
404
 
405
+ with st.spinner(f"🔢 Создаю эмбеддинги для {len(_articles)} статей..."):
406
  texts = [f"{a['title']}\n\n{a['text']}" for a in _articles]
407
  embeddings = _embedder.encode(
408
  texts,
 
416
  return embeddings
417
 
418
  # ===================================================================
419
+ # 4. ПОИСК В СТАТЬЯХ
420
  # ===================================================================
421
 
422
  def search_science(query, _articles, _embeddings, _embedder):
 
431
  results = []
432
  for idx in top_indices:
433
  score = float(scores[int(idx)])
434
+ if score > 0.15:
435
  article = _articles[int(idx)]
436
  results.append({
437
  "title": article['title'],
 
472
  # Инициализация истории чата
473
  if "messages" not in st.session_state:
474
  st.session_state.messages = []
475
+ # Приветствие генерируется ИИ!
476
  greeting = dialog_ai.generate_response("Привет")
477
  st.session_state.messages.append({"role": "assistant", "content": greeting})
478
 
 
490
  ---
491
  **🔗 Ссылки:**
492
 
493
+ [🌐 Сайт]({WEBSITE})
 
494
  [🤗 Hugging Face]({HUGGINGFACE})
495
 
496
  ---
497
  **📊 Статистика:**
498
+ - Статей: {len(articles)}
 
499
  - Сообщений: {len(st.session_state.messages)}
500
+ - Обучен на: {len(dialog_ai.contexts)} диалогах
501
  """)
502
 
503
  if os.path.exists(EMBEDDINGS_FILE):
504
  size = os.path.getsize(EMBEDDINGS_FILE) / (1024 * 1024)
505
  st.caption(f"💾 Эмбеддинги: {size:.1f} MB")
506
 
507
+ if st.button("🗑️ Очистить чат"):
 
508
  st.session_state.messages = []
509
  greeting = dialog_ai.generate_response("Привет")
510
  st.session_state.messages.append({"role": "assistant", "content": greeting})
 
521
  with st.chat_message(message["role"]):
522
  st.markdown(message["content"])
523
 
524
+ # Если есть статьи, показываем их
525
  if message.get("articles"):
526
  for i, article in enumerate(message["articles"], 1):
527
  with st.expander(f"📄 #{i} {article['title']} (сходство: {article['score']:.2f})"):
 
536
  with st.chat_message("user"):
537
  st.markdown(prompt)
538
 
539
+ # Генерируем ответ ТОЛЬКО через ИИ
540
  with st.chat_message("assistant"):
541
  with st.spinner("Думаю..."):
542
+ # ВСЕГДА используем ИИ для ответа
543
+ ai_response = dialog_ai.generate_response(prompt)
544
 
545
+ # Проверяем, похоже ли на научный вопрос
546
+ is_science_question = any(word in prompt.lower() for word in ["науч", "исслед", "стать", "экспери", "лаборатор", "анализ", "данн"])
547
+
548
+ if is_science_question or len(prompt.split()) > 3:
 
 
549
  # Ищем в научных статьях
550
  results = search_science(prompt, articles, embeddings, embedder)
551
 
552
  if results:
553
  # Формируем ответ с результатами
554
+ response = f"🔍 **Я нашел в научных статьях информацию по вашему запросу:**\n\n"
555
  for i, result in enumerate(results, 1):
556
  response += f"**{i}. {result['title']}** (сходство: {result['score']:.2f})\n"
557
  response += f"{result['text'][:300]}...\n\n"
 
563
  "articles": results
564
  })
565
  else:
566
+ # Если ничего не найдено, показываем ответ ИИ
567
+ st.markdown(ai_response)
568
+ st.session_state.messages.append({"role": "assistant", "content": ai_response})
569
+ else:
570
+ # Показываем ответ ИИ (приветствия, вопросы о себе и т.д.)
571
+ st.markdown(ai_response)
572
+ st.session_state.messages.append({"role": "assistant", "content": ai_response})
573
 
 
574
  st.rerun()
575
 
576
  # --- ПОДВАЛ ---