Исправь ошибки
import aiohttp
import asyncio
import json
import logging
import os
import time
import torch
from flask import Flask, request, jsonify, render_template
from bs4 import BeautifulSoup
from sentence_transformers import SentenceTransformer, util
from transformers import pipeline
from razdel import sentenize

# Настройка логирования
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')

app = Flask(__name__)

# Инициализация моделей
logging.info("Загрузка моделей...")
# Модель для семантического поиска
search_model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
qa_pipeline = pipeline("question-answering", model="deepset/roberta-base-squad2")
logging.info("Модели загружены.")

# Пути к файлам
ARTICLES_FILE = 'articles.json'
EMBEDDINGS_FILE = 'embeddings.pt'

# Асинхронные функции для загрузки статей
async def fetch_random_wiki_title(session):
    try:
        async with session.get('https://ru.wikipedia.org/wiki/Special:Random') as response:
            await asyncio.sleep(0.05)  # Пауза между запросами
            return str(response.url)
    except Exception as e:
        logging.error(f"Ошибка при запросе случайной статьи: {e}")
        return None

async def fetch_wiki_article(session, url):
    try:
        async with session.get(url) as response:
            content = await response.text()
            soup = BeautifulSoup(content, 'html.parser')

            title = soup.find(id="firstHeading").text.strip()
            paragraphs = [p.get_text() for p in soup.find_all('p') if len(p.get_text()) > 50]

            article = ' '.join(paragraphs)
            return {'url': url, 'title': title, 'article': article}
    except Exception as e:
        logging.error(f"Ошибка при запросе статьи: {e}")
        return None

async def get_wiki_articles(count, concurrency=10):
    semaphore = asyncio.Semaphore(concurrency)
    articles = []
    logging.info(f"Загружается {count} статей с Википедии...")

    async with aiohttp.ClientSession(connector=aiohttp.TCPConnector(limit=concurrency)) as session:
        tasks = [fetch_random_wiki_title(session) for _ in range(count)]
        urls = await asyncio.gather(*tasks)

        fetch_tasks = [fetch_wiki_article(session, url) for url in urls if url]
        articles_data = await asyncio.gather(*fetch_tasks)

    articles = [article for article in articles_data if article]
    with open(ARTICLES_FILE, 'w', encoding='utf-8') as f:
        json.dump(articles, f, ensure_ascii=False, indent=2)

    logging.info(f"Загрузка завершена. Статьи сохранены в '{ARTICLES_FILE}'.")
    return articles

# Загрузка и подготовка статей
def load_articles():
    try:
        with open(ARTICLES_FILE, 'r', encoding='utf-8') as f:
            articles = json.load(f)
            return articles
    except Exception as e:
        logging.error(f"Ошибка при загрузке '{ARTICLES_FILE}': {e}")
        return []

def split_into_chunks(article_text, max_length=512):
    sentences = [sentence.text for sentence in sentenize(article_text)]
    chunks = []
    current_chunk = ""
    for sentence in sentences:
        if len(current_chunk) + len(sentence) + 1 <= max_length:
            current_chunk += " " + sentence
        else:
            chunks.append(current_chunk.strip())
            current_chunk = sentence
    if current_chunk:
        chunks.append(current_chunk.strip())
    return chunks

def process_articles(articles):
    processed = []
    for article in articles:
        chunks = split_into_chunks(article['article'])
        for chunk in chunks:
            processed.append({
                'url': article['url'],
                'title': article['title'],
                'chunk': chunk
            })
    return processed

def generate_article_embeddings(processed_articles):
    chunks = [article['chunk'] for article in processed_articles]
    embeddings = search_model.encode(chunks, convert_to_tensor=True)
    return embeddings

def save_embeddings(embeddings, processed_articles):
    torch.save({
        'embeddings': embeddings,
        'data': processed_articles
    }, EMBEDDINGS_FILE)
    logging.info(f"Эмбеддинги сохранены в '{EMBEDDINGS_FILE}'.")

def load_or_generate_embeddings():
    if os.path.exists(EMBEDDINGS_FILE):
        logging.info("Загрузка эмбеддингов из файла...")
        data = torch.load(EMBEDDINGS_FILE)
        embeddings = data['embeddings']
        processed_articles = data['data']
        logging.info("Эмбеддинги загружены.")
    else:
        logging.info("Генерация и сохранение эмбеддингов...")
        articles = load_articles()
        if not articles:
            logging.error("Нет статей для генерации эмбеддингов.")
            return None, None
        processed_articles = process_articles(articles)
        embeddings = generate_article_embeddings(processed_articles)
        save_embeddings(embeddings, processed_articles)
    return embeddings, processed_articles

# Поиск релевантных статей на основе вопроса
def find_relevant_articles(question, embeddings, processed_articles, top_k=5):
    question_embedding = search_model.encode(question, convert_to_tensor=True)
    cos_scores = util.cos_sim(question_embedding, embeddings)[0]
    top_results = torch.topk(cos_scores, k=top_k)

    relevant_articles = []
    for score, idx in zip(top_results.values, top_results.indices):
        if score > 0.1:  # Порог релевантности
            relevant_articles.append(processed_articles[idx])
    return relevant_articles

# Генерация ответа на основе релевантных статей
def generate_answer(question, relevant_articles):
    answers = []
    for article in relevant_articles:
        answer = qa_pipeline({
            'question': question,
            'context': article['chunk']
        })
        answers.append((answer['score'], answer['answer']))

    if not answers:
        return "Ответ не найден."

    # Выбор ответа с наивысшим доверием
    best_answer = max(answers, key=lambda x: x[0])
    if best_answer[0] > 0.1:
        return best_answer[1]
    else:
        return "Ответ не найден."

# Маршрут главной страницы
@app.route('/')
def index():
    return render_template('index.html')

# Маршрут для загрузки статей
@app.route('/getwiki', methods=['POST'])
def get_wiki():
    data = request.get_json()
    count = data.get('count', 1)

    if not isinstance(count, int) or count <= 0:
        return jsonify({"error": "Параметр 'count' должен быть положительным целым числом."}), 400

    # Замер времени начала
    start_time = time.time()

    # Запуск асинхронной загрузки статей
    try:
        asyncio.run(get_wiki_articles(count))
    except Exception as e:
        logging.error(f"Ошибка при загрузке статей: {e}")
        return jsonify({"error": "Ошибка при загрузке статей."}), 500

    # Замер времени окончания
    duration = time.time() - start_time

    # После загрузки обновить эмбеддинги
    embeddings, processed_articles = load_or_generate_embeddings()
    if embeddings is None:
        return jsonify({"error": "Не удалось загрузить или сгенерировать эмбеддинги."}), 500

    return jsonify({
        "message": f"Загружено {count} статей.",
        "execution_time": f"{duration:.2f} секунд"
    })

# Маршрут для обработки вопросов
@app.route('/ask', methods=['POST'])
def ask():
    data = request.get_json()
    question = data.get('question', '').strip()

    if not question:
        return jsonify({"error": "Введите вопрос."}), 400

    # Загрузка эмбеддингов и обработанных статей
    embeddings, processed_articles = load_or_generate_embeddings()
    if embeddings is None or processed_articles is None:
        return jsonify({"error": "Нет эмбеддингов. Сначала загрузите статьи."}), 400

    # Поиск релевантных статей
    relevant_articles = find_relevant_articles(question, embeddings, processed_articles, top_k=5)

    if not relevant_articles:
        return jsonify({"answer": "Не найдено подходящих статей.", "execution_time": "0.00 секунд"})

    # Замер времени генерации ответа
    start_time = time.time()

    # Генерация ответа
    answer = generate_answer(question, relevant_articles)

    # Замер времени окончания
    duration = time.time() - start_time

    return jsonify({
        "answer": answer,
        "execution_time": f"{duration:.2f} секунд"
    })

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)