Initial commit

Photo-based book cataloger with AI identification.
Room → Cabinet → Shelf → Book hierarchy; FastAPI + SQLite backend;
vanilla JS SPA; OpenAI-compatible plugin system for boundary
detection, text recognition, and archive search.
This commit is contained in:
2026-03-09 14:17:13 +03:00
commit 084d1aebd5
64 changed files with 8605 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
"""Book identifier plugin — raw spine text → bibliographic metadata.
Input: raw_text string (from text_recognizer).
Output: {"title": "...", "author": "...", "year": "...", "isbn": "...",
"publisher": "...", "confidence": 0.95}
confidence — float 0-1; results below confidence_threshold are discarded by logic.py.
Result added to books.candidates and books.ai_* fields.
"""
from models import AIConfig, AIIdentifyResult
from ._client import AIClient
class BookIdentifierPlugin:
"""Identifies a book from spine text using a VLM with web-search capability."""
category = "book_identifiers"
OUTPUT_FORMAT = (
'{"title": "...", "author": "...", "year": "...", ' '"isbn": "...", "publisher": "...", "confidence": 0.95}'
)
def __init__(
self,
plugin_id: str,
name: str,
ai_config: AIConfig,
prompt_text: str,
auto_queue: bool,
rate_limit_seconds: float,
):
self.plugin_id = plugin_id
self.name = name
self.auto_queue = auto_queue
self.rate_limit_seconds = rate_limit_seconds
self._client = AIClient(ai_config, self.OUTPUT_FORMAT)
self._prompt_text = prompt_text
def identify(self, raw_text: str) -> AIIdentifyResult:
"""Returns AIIdentifyResult with title/author/year/isbn/publisher/confidence."""
raw = self._client.call(self._prompt_text, [], text_vars={"RAW_TEXT": raw_text})
result = AIIdentifyResult(
title=str(raw.get("title") or ""),
author=str(raw.get("author") or ""),
year=str(raw.get("year") or ""),
isbn=str(raw.get("isbn") or ""),
publisher=str(raw.get("publisher") or ""),
)
conf = raw.get("confidence")
if conf is not None:
result["confidence"] = float(conf)
return result
@property
def confidence_threshold(self) -> float:
return self._client.cfg["confidence_threshold"]