Spaces:
Running
Running
| import streamlit as st | |
| from datasets import load_dataset | |
| import numpy as np | |
| import torch | |
| from sentence_transformers import SentenceTransformer | |
| # =================================================================== | |
| # 1. НАСТРОЙКИ | |
| # =================================================================== | |
| MODEL_NAME = "BAAI/bge-large-en-v1.5" | |
| DATASET_NAME = "wikimedia/wikipedia" | |
| LANGUAGE = "20231101.en" # можно заменить на "20231101.ru" для русского | |
| ARTICLE_LIMIT = 1000 # сколько статей загрузить (для экономии памяти) | |
| st.set_page_config( | |
| page_title="Wikipedia Assistant", | |
| page_icon="🌖", | |
| layout="wide" | |
| ) | |
| st.title("🌖 Wikipedia Assistant") | |
| st.markdown("Задай вопрос — я найду ответ в Википедии!") | |
| # =================================================================== | |
| # 2. ЗАГРУЗКА ДАТАСЕТА | |
| # =================================================================== | |
| def load_wikipedia(): | |
| """Загружает датасет Википедии""" | |
| with st.spinner("📚 Загружаю Википедию..."): | |
| dataset = load_dataset( | |
| DATASET_NAME, | |
| LANGUAGE, | |
| split="train", | |
| streaming=True | |
| ) | |
| articles = [] | |
| for i, row in enumerate(dataset): | |
| if i >= ARTICLE_LIMIT: | |
| break | |
| articles.append({ | |
| "id": row.get("id", i), | |
| "title": row.get("title", "Без названия"), | |
| "text": row.get("text", "")[:3000], | |
| "url": row.get("url", "") | |
| }) | |
| return articles | |
| def load_embedder(): | |
| """Загружает модель для эмбеддингов""" | |
| with st.spinner("🧠 Загружаю модель..."): | |
| return SentenceTransformer(MODEL_NAME) | |
| # =================================================================== | |
| # 3. ПОИСК | |
| # =================================================================== | |
| def search_wikipedia(query, articles, embedder): | |
| """Ищет ответ на вопрос в Википедии""" | |
| # Кодируем запрос | |
| query_vector = embedder.encode( | |
| [query], | |
| normalize_embeddings=True | |
| )[0] | |
| # Кодируем все статьи (если ещё не закодированы) | |
| if "embeddings" not in st.session_state: | |
| with st.spinner("🔢 Создаю эмбеддинги статей..."): | |
| texts = [f"{a['title']}\n\n{a['text']}" for a in articles] | |
| embeddings = embedder.encode( | |
| texts, | |
| normalize_embeddings=True | |
| ) | |
| st.session_state.embeddings = embeddings | |
| # Ищем | |
| scores = st.session_state.embeddings @ query_vector | |
| top_indices = np.argsort(-scores)[:3] | |
| results = [] | |
| for idx in top_indices: | |
| results.append({ | |
| "article": articles[int(idx)], | |
| "score": float(scores[int(idx)]) | |
| }) | |
| return results | |
| # =================================================================== | |
| # 4. ИНТЕРФЕЙС | |
| # =================================================================== | |
| # Загружаем данные | |
| articles = load_wikipedia() | |
| embedder = load_embedder() | |
| st.success(f"✅ Загружено {len(articles)} статей") | |
| # Поле ввода | |
| query = st.text_input("🔍 Что хочешь узнать?", placeholder="Например: Как измеряют расстояние до галактик?") | |
| if query: | |
| with st.spinner("🔎 Ищу ответ..."): | |
| results = search_wikipedia(query, articles, embedder) | |
| # Показываем результаты | |
| for i, result in enumerate(results, 1): | |
| score = result["score"] | |
| article = result["article"] | |
| # Только если релевантно | |
| if score > 0.3: | |
| with st.expander(f"#{i} {article['title']} (сходство: {score:.2f})"): | |
| st.write(article["text"][:2000] + "...") | |
| if article["url"]: | |
| st.link_button("🔗 Читать на Википедии", article["url"]) | |
| else: | |
| st.warning("😕 Не нашёл подходящей статьи. Попробуй уточнить вопрос.") | |
| else: | |
| st.info("💡 Напиши вопрос, и я найду ответ в Википедии") |