Spaces:
Sleeping
Sleeping
| # providers.py | |
| from typing import List | |
| import os | |
| import numpy as np | |
| import torch | |
| from functools import lru_cache | |
| from sentence_transformers import SentenceTransformer, CrossEncoder | |
| from dotenv import load_dotenv | |
| # .env dosyasını oku | |
| load_dotenv() | |
| # API anahtarını al | |
| GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY") | |
| if not GOOGLE_API_KEY: | |
| print("⚠️ Uyarı: GOOGLE_API_KEY .env dosyasında bulunamadı!") | |
| # ========================= | |
| # CONFIG (env ile override) | |
| # ========================= | |
| EMB_MODEL_NAME = os.getenv("EMB_MODEL", "intfloat/multilingual-e5-small") | |
| # Hız için default MiniLM; Jina kullanmak istersen RERANKER_MODEL=jinaai/jina-reranker-v2-base-multilingual | |
| RERANKER_NAME = os.getenv("RERANKER_MODEL", "cross-encoder/ms-marco-MiniLM-L-6-v2") | |
| GEMINI_MODEL = os.getenv("GEMINI_MODEL", "gemini-1.5-flash") | |
| # ========================= | |
| # Embedding (E5) | |
| # ========================= | |
| _emb_model: SentenceTransformer | None = None | |
| def _get_emb_model() -> SentenceTransformer: | |
| global _emb_model | |
| if _emb_model is None: | |
| # CPU'da stabil ve hızlı çalışması için | |
| torch.set_num_threads(max(1, (os.cpu_count() or 4) // 2)) | |
| _emb_model = SentenceTransformer(EMB_MODEL_NAME) | |
| return _emb_model | |
| def embed(texts: List[str]) -> np.ndarray: | |
| """E5 embedding üretir (normalize etmez).""" | |
| model = _get_emb_model() | |
| vecs = model.encode( | |
| texts, | |
| batch_size=32, | |
| show_progress_bar=False, | |
| convert_to_numpy=True, | |
| normalize_embeddings=False, | |
| ) | |
| return vecs | |
| # ========================= | |
| # Reranker (Cross-Encoder) | |
| # ========================= | |
| _reranker: CrossEncoder | None = None | |
| def _get_reranker() -> CrossEncoder: | |
| global _reranker | |
| if _reranker is None: | |
| trust = "jina" in RERANKER_NAME.lower() | |
| _reranker = CrossEncoder( | |
| RERANKER_NAME, | |
| max_length=384, | |
| trust_remote_code=trust, | |
| ) | |
| return _reranker | |
| def rerank(query: str, candidates: List[str]) -> List[float]: | |
| """Sorgu + aday pasajlar için alaka skorları döndürür (yüksek skor = daha alakalı).""" | |
| model = _get_reranker() | |
| pairs = [[query, c] for c in candidates] | |
| scores = model.predict(pairs, convert_to_numpy=True, show_progress_bar=False) | |
| return scores.tolist() | |
| # ========================= | |
| # (Opsiyonel) Ekstraktif QA – TR SQuAD | |
| # ========================= | |
| _QA_MODEL = os.getenv("QA_MODEL", "savasy/bert-base-turkish-squad") | |
| _qa_pipe = None # lazy load | |
| def qa_extract(question: str, context: str) -> dict: | |
| """ | |
| Pasajdan doğrudan cevap span'ı çıkarır. | |
| Dönen örnek: {'answer': '1907', 'score': 0.93, 'start': 123, 'end': 127} | |
| Kullanmazsan çağırma; yüklenmez ve hız etkisi olmaz. | |
| """ | |
| global _qa_pipe | |
| if _qa_pipe is None: | |
| from transformers import pipeline # import burada ki ihtiyaca göre yüklensin | |
| _qa_pipe = pipeline("question-answering", model=_QA_MODEL, tokenizer=_QA_MODEL) | |
| res = _qa_pipe(question=question, context=context) | |
| return dict(res) | |
| # ========================= | |
| # LLM: Google Gemini | |
| # ========================= | |
| def generate(prompt: str) -> str: | |
| """ | |
| Gemini ile üretken cevap. GOOGLE_API_KEY yoksa 'LLM yapılandırılmadı.' döner. | |
| """ | |
| api_key = os.getenv("GOOGLE_API_KEY") | |
| if not api_key: | |
| return "LLM yapılandırılmadı." | |
| try: | |
| import google.generativeai as genai | |
| genai.configure(api_key=api_key) | |
| model = genai.GenerativeModel(GEMINI_MODEL) | |
| response = model.generate_content( | |
| prompt, | |
| generation_config=genai.types.GenerationConfig( | |
| temperature=0.1, max_output_tokens=300, top_p=0.8 | |
| ), | |
| ) | |
| return response.text.strip() if hasattr(response, "text") else "Cevap oluşturulamadı." | |
| except Exception as e: | |
| return f"LLM hata: {e}" | |