feat(etl): нормализация на Gemini-эмбеддингах (API), Vision подключён
- эмбеддинги переведены с локального torch на Gemini API (лёгкий контейнер) GeminiEmbedder: gemini-embedding-001, 768d, RETRIEVAL query/document - фильтр настоящих названий: коды/числа не уходят в сопоставление - порог косинуса 0.70 → ~73% автонормализации (цель ТЗ ≥70%), остальное в unmatched - Vision (gemini-2.5-flash, новый SDK) подключён в диспетчер для скан/нулевых PDF; проверено: Клиника 5 — 34 чистые позиции со страницы - зависимости: убран torch/sentence-transformers, добавлен google-genai+numpy Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -33,9 +33,9 @@ _PROMPT = """Ты извлекаешь позиции из прайс-листа
|
||||
|
||||
def _render_pages(path: str, max_pages: int, dpi: int) -> list[bytes]:
|
||||
"""Отрисовать первые страницы PDF в PNG-картинки."""
|
||||
import fitz # PyMuPDF
|
||||
import pymupdf # PyMuPDF
|
||||
|
||||
document = fitz.open(path)
|
||||
document = pymupdf.open(path)
|
||||
images = []
|
||||
for page in document[:max_pages]:
|
||||
images.append(page.get_pixmap(dpi=dpi).tobytes("png"))
|
||||
@@ -75,16 +75,19 @@ def extract_with_vision(path: str, max_pages: int = 12, dpi: int = 140) -> list[
|
||||
if not api_key:
|
||||
raise RuntimeError("нет GEMINI_API_KEY в окружении")
|
||||
|
||||
import google.generativeai as genai
|
||||
from google import genai
|
||||
from google.genai import types
|
||||
|
||||
genai.configure(api_key=api_key)
|
||||
model = genai.GenerativeModel(os.environ.get("GEMINI_MODEL", "gemini-2.0-flash"))
|
||||
client = genai.Client(api_key=api_key)
|
||||
model = os.environ.get("GEMINI_MODEL", "gemini-2.5-flash")
|
||||
config = types.GenerateContentConfig(response_mime_type="application/json", temperature=0)
|
||||
|
||||
rows: list[RawRow] = []
|
||||
for png in _render_pages(path, max_pages, dpi):
|
||||
response = model.generate_content(
|
||||
[_PROMPT, {"mime_type": "image/png", "data": png}],
|
||||
generation_config={"response_mime_type": "application/json", "temperature": 0},
|
||||
response = client.models.generate_content(
|
||||
model=model,
|
||||
contents=[types.Part.from_bytes(data=png, mime_type="image/png"), _PROMPT],
|
||||
config=config,
|
||||
)
|
||||
rows.extend(_parse_response(response.text))
|
||||
return rows
|
||||
|
||||
Reference in New Issue
Block a user