Implement optional single-image intake, Signal ingestion, and multimodal vision analysis

- Add image intake service with format validation (JPEG, PNG, WebP) and EXIF/GPS stripping
- Enforce strict single-image rule across Web and Signal attachment channels
- Implement token-optimized vision downscaling and JPEG compression
- Add IMAGE_CONTEXT pipeline stage with OmniRoute vision routing and resilient failover
- Seed and manage versioned idea-image-interpreter prompt in catalog
- Update Web UI with responsive image picker, preview chip, and Visual Context tab
- Add comprehensive automated test suite in test_image_intake.py
- Update README and Labyricorn devlog
This commit is contained in:
2026-08-23 01:40:22 -07:00
parent 94ff1e4408
commit 41e08611c9
30 changed files with 3784 additions and 278 deletions
+5 -1
View File
@@ -22,6 +22,7 @@ from ..services.perplexica import PerplexicaAdapter
from ..services.opengist import OpenGistAdapter
from ..services.gitea import GiteaAdapter
from ..services.virustotal import VirusTotalAdapter
from ..services.signal_gateway import SignalGatewayAdapter
from ..queue.worker import job_queue
router = APIRouter(prefix="/api/admin", tags=["admin"], dependencies=[Depends(require_admin)])
@@ -32,6 +33,7 @@ perplexica_svc = PerplexicaAdapter()
opengist_svc = OpenGistAdapter()
gitea_svc = GiteaAdapter()
virustotal_svc = VirusTotalAdapter()
signal_gateway_svc = SignalGatewayAdapter()
class PromptUpdateRequest(BaseModel):
name: Optional[str] = None
@@ -151,6 +153,8 @@ async def test_service_connection(service_id: str):
adapter = perplexica_svc
elif service_id == "virustotal":
adapter = virustotal_svc
elif service_id == "signal_gateway":
adapter = signal_gateway_svc
else:
raise HTTPException(status_code=404, detail=f"Service '{service_id}' not found.")
@@ -247,7 +251,7 @@ async def list_jobs():
async def retry_idea_job(idea_id: str):
with get_db() as conn:
conn.execute("UPDATE ideas SET processing_state = 'QUEUED' WHERE id = ?", (idea_id,))
await job_queue.enqueue_foreground("intake", idea_id)
await job_queue.enqueue_foreground("intake", idea_id, {"bypass_duplicate_check": True})
return {"message": f"Idea {idea_id} enqueued for processing retry."}
# ----------------- Moderation & Quarantine -----------------