- 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
77 lines
3.7 KiB
HTML
77 lines
3.7 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}ThinkStorm - Throw Your Ideas At Us{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="hero-intake">
|
|
<h1 class="hero-title">Got an idea?<br>Throw it at us.</h1>
|
|
<p class="hero-subtitle">Anonymous intake with zero friction. We preserve your raw thought, research the landscape, and incubate it with self-hosted AI.</p>
|
|
|
|
<div class="intake-box">
|
|
<form id="intake-form">
|
|
<div class="form-group" style="margin-bottom:0.75rem;">
|
|
<label for="submission-text" class="form-label" style="display:flex; justify-content:space-between;">
|
|
<span>Describe your idea...</span>
|
|
<span id="detected-urls" style="color:var(--accent-primary); font-family:var(--font-mono); font-size:0.8rem;">No URLs detected</span>
|
|
</label>
|
|
<textarea
|
|
id="submission-text"
|
|
class="form-textarea"
|
|
placeholder="Describe your idea in free-form text. URLs can be included directly in the text (e.g. https://github.com/... or https://example.com). No title or categorization needed."
|
|
rows="7"
|
|
required
|
|
></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
|
|
</div>
|
|
<button type="submit" class="btn btn-primary" style="padding:0.75rem 2rem; font-size:1.05rem;">
|
|
⚡ Submit Idea
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div style="margin-top: 2.5rem;">
|
|
{% if user and user.role.value != 'ANONYMOUS' %}
|
|
<a href="/ideas" class="btn btn-secondary">
|
|
🔍 Browse Unclaimed & Incubating Ideas →
|
|
</a>
|
|
{% else %}
|
|
<a href="/login" class="btn btn-secondary">
|
|
🔐 Sign In to Browse Ideas →
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|