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
+27
View File
@@ -23,6 +23,33 @@
></textarea>
</div>
<!-- Optional Reference Image Upload Control -->
<div class="form-group" style="margin-bottom:1rem; border-top:1px solid var(--border-glass); padding-top:0.75rem;">
<label for="submission-image" class="form-label" style="display:flex; justify-content:space-between; align-items:center; margin-bottom:0.4rem;">
<span style="display:flex; align-items:center; gap:0.4rem;">
<span>🖼️ Optional reference image</span>
<span style="font-size:0.75rem; color:var(--text-muted);">(JPEG, PNG, WebP)</span>
</span>
<span id="image-status" style="font-family:var(--font-mono); font-size:0.75rem; color:var(--text-muted);">Max 1 image</span>
</label>
<div class="image-upload-wrapper" style="display:flex; align-items:center; gap:0.75rem; flex-wrap:wrap;">
<input
type="file"
id="submission-image"
name="image"
accept="image/jpeg,image/png,image/webp"
style="display:none;"
>
<button type="button" id="choose-image-btn" class="btn btn-secondary btn-sm" style="display:inline-flex; align-items:center; gap:0.4rem; cursor:pointer;">
<span>📷 Choose Image</span>
</button>
<div id="image-preview-chip" style="display:none; align-items:center; gap:0.5rem; background:rgba(99,102,241,0.15); border:1px solid rgba(99,102,241,0.3); border-radius:var(--radius-sm); padding:0.3rem 0.6rem; font-size:0.82rem;">
<span id="image-file-name" style="font-family:var(--font-mono); color:#a5b4fc; max-width:220px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;"></span>
<button type="button" id="remove-image-btn" style="background:transparent; border:none; color:#f87171; cursor:pointer; font-size:0.9rem; padding:0; line-height:1;" title="Remove image">✕</button>
</div>
</div>
</div>
<div class="intake-footer">
<div class="intake-hints">
<span id="char-count" style="font-family:var(--font-mono);">0 / 10,000</span> • URLs automatically evaluated for safety