Files
portal/knowledge/aleksandra/brain/embed.py
T

51 lines
2.0 KiB
Python
Raw Normal View History

"""Эмбеддинги: провайдер AITunnel (по умолчанию) с fallback на локальную модель.
Живой источник инкапсулирован — вся остальная логика получает embed_fn инъекцией."""
import os
import json
import urllib.request
def batch(texts, embed_fn):
return [embed_fn(t) for t in texts]
def _aitunnel_embedder():
key_path = os.environ.get("ALEX_AITUNNEL_KEY", "aitunnel.key")
key = open(key_path, encoding="utf-8").read().strip()
model = os.environ.get("ALEX_EMBED_MODEL", "text-embedding-3-small")
def embed(text):
body = {"model": model, "input": text}
req = urllib.request.Request(
"https://api.aitunnel.ru/v1/embeddings",
data=json.dumps(body).encode(), method="POST")
req.add_header("Authorization", f"Bearer {key}")
req.add_header("Content-Type", "application/json")
r = json.load(urllib.request.urlopen(req, timeout=30))
return r["data"][0]["embedding"]
return embed
def _fake_embedder():
# детерминированный «отпечаток» без сети — для тестов/сухих прогонов
def embed(text):
t = text.lower()
return [
float(sum(ord(c) for c in t) % 97),
float(len(t) % 13),
float(t.count("а") + t.count("о")),
]
return embed
def get_embedder(provider=None):
provider = provider or os.environ.get("ALEX_EMBED", "aitunnel")
if provider == "aitunnel":
return _aitunnel_embedder()
if provider == "local":
# fallback: локальная модель на GPU-сервере (sentence-transformers).
# Реализовать при переключении; сигнатура та же: embed(text) -> list[float].
raise NotImplementedError("local-эмбеддер подключается на GPU-сервере при провале AITunnel")
return _fake_embedder()