KennyOry commited on
Commit
30c1a2b
·
verified ·
1 Parent(s): a87f480

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +40 -161
app.py CHANGED
@@ -1,4 +1,4 @@
1
- from flask import Flask, render_template, request, Response, jsonify, session
2
  from mistralai import Mistral
3
  import logging
4
  import time
@@ -11,11 +11,9 @@ import os
11
  import trafilatura
12
  from bs4 import BeautifulSoup
13
  import random
14
- import uuid
15
 
16
  app = Flask(__name__)
17
  app.secret_key = 'super_secret_key'
18
- app.config['SESSION_TYPE'] = 'filesystem'
19
 
20
  message_queue = queue.Queue()
21
 
@@ -53,14 +51,6 @@ SYSTEM_PROMPT = """
53
  - Начинай сразу с **Проблема:** без преамбул
54
  """
55
 
56
- CONTEXT_PROMPT = """
57
- Ты PrintMaster, сервисный инженер по печатной технике. Отвечай на вопросы пользователя в контексте текущего диалога.
58
- Правила:
59
- 1. Если вопрос связан с текущей проблемой - отвечай на основе предыдущих данных
60
- 2. Если нужны новые технические данные - попроси пользователя уточнить
61
- 3. Если вопрос не связан с текущей проблемой - уточни у пользователя, хочет ли он начать новую тему
62
- """
63
-
64
  BLACKLISTED_DOMAINS = [
65
  'reddit.com',
66
  'stackoverflow.com',
@@ -358,120 +348,54 @@ def verify_with_sources(response: str, sources: list) -> str:
358
  message_queue.put(('log', error_msg))
359
  return response
360
 
361
- def needs_web_search(user_input: str, context: list) -> bool:
362
- """Определяет, нужен ли новый поиск для текущего запроса"""
363
  try:
364
- prompt = f"""
365
- Определи, нужен ли новый поиск в интернете для ответа на последний запрос пользователя.
366
-
367
- История диалога:
368
- {json.dumps(context[-5:], ensure_ascii=False)}
369
-
370
- Последний запрос пользователя: {user_input}
371
-
372
- Правила:
373
- 1. Если запрос требует новой информации (технические детали, коды ошибок, инструкции) - верни True
374
- 2. Если запрос относится к текущей проблеме и не требует новых данных - верни False
375
- 3. Если пользователь просит уточнить или переформулировать ответ - верни False
376
- 4. Если пользователь запрашивает новые примеры или альтернативные решения - верни True
377
- """
378
 
379
- response = mistral_client.chat.complete(
380
- model="mistral-medium",
 
 
 
 
 
 
381
  messages=[
382
- {"role": "system", "content": "Ты эксперт по анализу запросов. Отвечай только TRUE или FALSE."},
383
- {"role": "user", "content": prompt}
384
  ],
385
- max_tokens=10,
386
- temperature=0.0
387
  )
388
-
389
- decision = response.choices[0].message.content.strip().lower()
390
- return "true" in decision or "да" in decision or "1" in decision
391
-
392
- except Exception as e:
393
- logging.error(f"Ошибка определения необходимости поиска: {str(e)}")
394
- return True
395
 
396
- def process_query(prompt: str, session_id: str):
397
- try:
398
- start_time = time.time()
399
- message_queue.put(('log', f"👤 Запрос: {prompt}"))
400
-
401
- # Инициализация сессии
402
- if 'context' not in session:
403
- session['context'] = {
404
- 'history': [],
405
- 'sources': [],
406
- 'problem': '',
407
- 'norm_data': {},
408
- 'last_query': '',
409
- 'last_response': ''
410
- }
411
-
412
- context = session['context']
413
- context['history'].append({"role": "user", "content": prompt})
414
- context['last_query'] = prompt
415
-
416
- # Определяем, нужен ли новый поиск
417
- needs_search = True
418
- if context['sources'] and context['problem']:
419
- message_queue.put(('status', "🔍 Анализирую необходимость нового поиска..."))
420
- needs_search = needs_web_search(prompt, context['history'])
421
-
422
- search_data = ""
423
- sources = []
424
- norm_data = {}
425
-
426
- if needs_search or not context['sources']:
427
- message_queue.put(('status', "⚙️ Извлекаю параметры из входящего запроса"))
428
- norm_data = generate_search_query(prompt)
429
- message_queue.put(('log', f"⏏️ Извлечено: {json.dumps(norm_data, ensure_ascii=False)}"))
430
-
431
- search_query = norm_data['search_query']
432
- search_data, sources = web_search(search_query)
433
- context['sources'] = sources
434
- context['norm_data'] = norm_data
435
- message_queue.put(('log', f"📚 Собрано: {len(search_data)} символов в {len(sources)} источнике(-ах)"))
436
- else:
437
- message_queue.put(('status', "⚙️ Использую данные из предыдущего поиска"))
438
- sources = context['sources']
439
- norm_data = context['norm_data']
440
- search_data = "\n\n".join([f"[[Источник {i+1}]] {s['title']}\n{s['content']}" for i, s in enumerate(sources)])
441
-
442
- if not context['problem'] or needs_search:
443
- message_queue.put(('status', "🧩 Определяю проблему"))
444
- problem_response = mistral_client.chat.complete(
445
- model=MISTRAL_MODEL,
446
- messages=[
447
- {"role": "system", "content": "Опиши СУТЬ проблемы в одном предложении. Только диагноз, без решений. Не более 12 слов. На русском."},
448
- {"role": "user", "content": f"Запрос пользователя: {prompt}\nПоисковые данные:\n{search_data}"}
449
- ],
450
- max_tokens=150,
451
- temperature=0.2
452
- )
453
- extracted_problem = problem_response.choices[0].message.content.strip()
454
- context['problem'] = extracted_problem
455
- else:
456
- extracted_problem = context['problem']
457
-
458
  message_queue.put(('log', f"🧩 Определённая проблема: {extracted_problem}"))
459
 
 
 
460
  messages = [
461
- {"role": "system", "content": CONTEXT_PROMPT if context['history'] else SYSTEM_PROMPT},
462
- *context['history'],
463
- {"role": "system", "content": f"""
464
- Контекст:
465
- Бренд: {norm_data.get('brand', '')}
466
- Модель: {norm_data.get('model', '')}
467
- Ошибка: {norm_data.get('error_code', '')}
468
- Суть проблемы (на основе поиска): {extracted_problem}
469
- Данные поиска:
470
- {search_data}
471
- """}
472
  ]
473
 
474
- message_queue.put(('status', "🧠 Генерирую ответ..."))
475
  message_queue.put(('response_start', ""))
476
 
477
  full_response = ""
@@ -487,7 +411,6 @@ def process_query(prompt: str, session_id: str):
487
  message_queue.put(('response_chunk', chunk_text))
488
 
489
  # Проверка соответствия источникам
490
- message_queue.put(('status', "🔍 Проверяю ответ по источникам..."))
491
  verified_response = verify_with_sources(full_response, sources)
492
 
493
  # Очистка и форматирование ответа
@@ -496,12 +419,6 @@ def process_query(prompt: str, session_id: str):
496
  message_queue.put(('response_end', final_response))
497
  message_queue.put(('sources', json.dumps(sources)))
498
 
499
- # Сохраняем ответ в контексте
500
- context['history'].append({"role": "assistant", "content": final_response})
501
- context['last_response'] = final_response
502
- session['context'] = context
503
- session.modified = True
504
-
505
  total_time = time.time() - start_time
506
  message_queue.put(('log', f"💡 Ответ: {final_response[:200]}..."))
507
  message_queue.put(('log', f"⏱ Время: {total_time:.1f}с"))
@@ -516,55 +433,17 @@ def process_query(prompt: str, session_id: str):
516
 
517
  @app.route('/')
518
  def index():
519
- # Инициализируем сессию при первом посещении
520
- if 'session_id' not in session:
521
- session['session_id'] = str(uuid.uuid4())
522
- session['context'] = {
523
- 'history': [],
524
- 'sources': [],
525
- 'problem': '',
526
- 'norm_data': {},
527
- 'last_query': '',
528
- 'last_response': ''
529
- }
530
  return render_template('index.html')
531
 
 
532
  @app.route('/ask', methods=['POST'])
533
  def ask():
534
  user_input = request.form['message']
535
- session_id = session.get('session_id', str(uuid.uuid4()))
536
- thread = threading.Thread(target=process_query, args=(user_input, session_id))
537
  thread.daemon = True
538
  thread.start()
539
  return jsonify({'status': 'processing'})
540
 
541
- @app.route('/repeat', methods=['POST'])
542
- def repeat():
543
- if 'context' in session:
544
- context = session['context']
545
- last_query = context.get('last_query', '')
546
- if last_query:
547
- session_id = session.get('session_id', str(uuid.uuid4()))
548
- thread = threading.Thread(target=process_query, args=(last_query, session_id))
549
- thread.daemon = True
550
- thread.start()
551
- return jsonify({'status': 'repeating'})
552
- return jsonify({'status': 'no_query'})
553
-
554
- @app.route('/new_session', methods=['POST'])
555
- def new_session():
556
- session.clear()
557
- session['session_id'] = str(uuid.uuid4())
558
- session['context'] = {
559
- 'history': [],
560
- 'sources': [],
561
- 'problem': '',
562
- 'norm_data': {},
563
- 'last_query': '',
564
- 'last_response': ''
565
- }
566
- return jsonify({'status': 'new_session'})
567
-
568
 
569
  @app.route('/stream')
570
  def stream():
 
1
+ from flask import Flask, render_template, request, Response, jsonify
2
  from mistralai import Mistral
3
  import logging
4
  import time
 
11
  import trafilatura
12
  from bs4 import BeautifulSoup
13
  import random
 
14
 
15
  app = Flask(__name__)
16
  app.secret_key = 'super_secret_key'
 
17
 
18
  message_queue = queue.Queue()
19
 
 
51
  - Начинай сразу с **Проблема:** без преамбул
52
  """
53
 
 
 
 
 
 
 
 
 
54
  BLACKLISTED_DOMAINS = [
55
  'reddit.com',
56
  'stackoverflow.com',
 
348
  message_queue.put(('log', error_msg))
349
  return response
350
 
351
+
352
+ def process_query(prompt: str):
353
  try:
354
+ start_time = time.time()
355
+ message_queue.put(('log', f"👤 Запрос: {prompt}"))
356
+ message_queue.put(('log', f"⚙️ Извлекаю параметры из входящего запроса"))
357
+
358
+ norm_data = generate_search_query(prompt)
359
+ message_queue.put(('log', f"⏏️ Извлечено: {json.dumps(norm_data, ensure_ascii=False)}"))
 
 
 
 
 
 
 
 
360
 
361
+ search_query = norm_data['search_query']
362
+ search_data, sources = web_search(search_query)
363
+
364
+ message_queue.put(('log', f"📚 Собрано: {len(search_data)} символов в {len(sources)} источнике(-ах)"))
365
+
366
+ message_queue.put(('log', f"⚙️ Определяю проблему"))
367
+ problem_response = mistral_client.chat.complete(
368
+ model=MISTRAL_MODEL,
369
  messages=[
370
+ {"role": "system", "content": "Опиши СУТЬ проблемы в одном предложении. Только диагноз, без решений. Не более 12 слов. На русском."},
371
+ {"role": "user", "content": f"Запрос пользователя: {prompt}\nПоисковые данные:\n{search_data}"}
372
  ],
373
+ max_tokens=150,
374
+ temperature=0.2
375
  )
376
+ extracted_problem = problem_response.choices[0].message.content.strip()
377
+
378
+ if not extracted_problem or len(extracted_problem) < 5:
379
+ extracted_problem = f"Неисправность {norm_data['brand']} {norm_data['model']}"
 
 
 
380
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
381
  message_queue.put(('log', f"🧩 Определённая проблема: {extracted_problem}"))
382
 
383
+ sources_text = "\n".join([f"[{i+1}] {s['title']} - {s['url']}" for i, s in enumerate(sources)])
384
+
385
  messages = [
386
+ {"role": "system", "content": SYSTEM_PROMPT + f"""
387
+ Контекст:
388
+ Бренд: {norm_data['brand']}
389
+ Модель: {norm_data['model']}
390
+ Ошибка: {norm_data['error_code']}
391
+ Суть проблемы (на основе поиска): {extracted_problem}
392
+ Данные поиска:
393
+ {search_data}
394
+ """},
395
+ {"role": "user", "content": f"Проблема: {prompt}"}
 
396
  ]
397
 
398
+ message_queue.put(('log', "🧠 На основе полученных данных генерирую ответ..."))
399
  message_queue.put(('response_start', ""))
400
 
401
  full_response = ""
 
411
  message_queue.put(('response_chunk', chunk_text))
412
 
413
  # Проверка соответствия источникам
 
414
  verified_response = verify_with_sources(full_response, sources)
415
 
416
  # Очистка и форматирование ответа
 
419
  message_queue.put(('response_end', final_response))
420
  message_queue.put(('sources', json.dumps(sources)))
421
 
 
 
 
 
 
 
422
  total_time = time.time() - start_time
423
  message_queue.put(('log', f"💡 Ответ: {final_response[:200]}..."))
424
  message_queue.put(('log', f"⏱ Время: {total_time:.1f}с"))
 
433
 
434
  @app.route('/')
435
  def index():
 
 
 
 
 
 
 
 
 
 
 
436
  return render_template('index.html')
437
 
438
+
439
  @app.route('/ask', methods=['POST'])
440
  def ask():
441
  user_input = request.form['message']
442
+ thread = threading.Thread(target=process_query, args=(user_input,))
 
443
  thread.daemon = True
444
  thread.start()
445
  return jsonify({'status': 'processing'})
446
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
447
 
448
  @app.route('/stream')
449
  def stream():