Add project files

This commit is contained in:
Suman
2026-08-04 17:09:29 +05:30
parent 464a68cceb
commit ac76cc86bc
372 changed files with 12221 additions and 0 deletions

76
pipeline/verify.py Normal file
View File

@@ -0,0 +1,76 @@
"""
Optional third-party AI verification, layered on top of the core
feature-matching pipeline: sends the winning template's original photo and
the user's original upload to an external vision-LLM endpoint that runs a
detailed QC-style comparison (flowers, vase, ribbon, composition) and
returns a MATCH/DISCREPANCIES/CONFIDENCE verdict plus free-text description.
This never affects the core match result -- if the endpoint is slow, down,
or unreachable (it's a Cloudflare tunnel, which can go stale), the caller
is expected to treat any exception here as a soft failure.
"""
import logging
import os
import re
import requests
import config
logger = logging.getLogger(__name__)
_VERDICT_RE = re.compile(
# DISCREP\w* rather than a literal "DISCREPANCIES" -- the LLM behind
# the endpoint doesn't reliably spell it the same way every time
# ("DISCREPANCIES" vs "DISCREPENCIES" have both been observed), and a
# missed match here silently dumps the whole raw block into the UI.
r"MATCH:\s*\[?\s*(?P<match>YES|NO|PARTIAL)\s*\]?\s*"
r"DISCREP\w*:\s*\[?\s*(?P<discrepancies>.*?)\s*\]?\s*"
r"CONFIDENCE:\s*\[?\s*(?P<confidence>High|Medium|Low)\s*\]?",
re.IGNORECASE | re.DOTALL,
)
def _parse_result_text(text: str) -> dict:
"""The endpoint's `result` field is free text with an embedded
MATCH/DISCREPANCIES/CONFIDENCE block, sometimes followed by a prose
description, sometimes not. Pull out the structured bits; whatever's
left over (if anything) is the description."""
text = text or ""
m = _VERDICT_RE.search(text)
if not m:
return {"match": None, "confidence": None, "discrepancies": None,
"description": text.strip()}
return {
"match": m.group("match").upper(),
"confidence": m.group("confidence").capitalize(),
"discrepancies": m.group("discrepancies").strip() or "None",
"description": text[m.end():].strip(),
}
def verify_images(reference_path: str, actual_path: str) -> dict:
"""reference_path = the matched template's original photo (IMAGE 1),
actual_path = the user's original upload (IMAGE 2)."""
with open(reference_path, "rb") as f1, open(actual_path, "rb") as f2:
files = {
"image1": (os.path.basename(reference_path), f1, "image/png"),
"image2": (os.path.basename(actual_path), f2, "image/jpeg"),
}
response = requests.post(config.VERIFY_ENDPOINT_URL, files=files,
timeout=config.VERIFY_TIMEOUT_SECONDS)
response.raise_for_status()
data = response.json()
parsed = _parse_result_text(data.get("result", ""))
return {
"match": parsed["match"],
"confidence": parsed["confidence"],
"discrepancies": parsed["discrepancies"],
"description": parsed["description"],
"raw_result": data.get("result"),
"pixel_precheck": data.get("pixel_precheck"),
}