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:
@@ -4,6 +4,7 @@ Handles login, logout, current user session status, and Gitea OAuth2 flow.
|
||||
"""
|
||||
|
||||
import json
|
||||
import requests
|
||||
import urllib.request
|
||||
import urllib.parse
|
||||
from typing import Optional, Dict, Any
|
||||
@@ -111,41 +112,36 @@ async def gitea_oauth_callback(request: Request, code: str = "", error: str = ""
|
||||
if client_secret and client_id:
|
||||
try:
|
||||
token_url = f"{config.services.gitea_url}/login/oauth/access_token"
|
||||
data = urllib.parse.urlencode({
|
||||
payload = {
|
||||
"client_id": client_id,
|
||||
"client_secret": client_secret,
|
||||
"code": code,
|
||||
"grant_type": "authorization_code",
|
||||
"redirect_uri": redirect_uri
|
||||
}).encode("utf-8")
|
||||
|
||||
req = urllib.request.Request(
|
||||
token_url,
|
||||
data=data,
|
||||
headers={
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"Accept": "application/json",
|
||||
"User-Agent": "ThinkStorm-Orchestrator/0.1"
|
||||
},
|
||||
method="POST"
|
||||
)
|
||||
with urllib.request.urlopen(req, timeout=10.0) as resp:
|
||||
resp_bytes = resp.read()
|
||||
}
|
||||
headers = {
|
||||
"Accept": "application/json",
|
||||
"User-Agent": "ThinkStorm-Orchestrator/0.1"
|
||||
}
|
||||
resp = requests.post(token_url, data=payload, headers=headers, timeout=10.0)
|
||||
if resp.status_code == 200:
|
||||
try:
|
||||
token_data = json.loads(resp_bytes.decode("utf-8"))
|
||||
token_data = resp.json()
|
||||
except Exception:
|
||||
token_data = urllib.parse.parse_qs(resp_bytes.decode("utf-8"))
|
||||
token_data = urllib.parse.parse_qs(resp.text)
|
||||
token_data = {k: v[0] for k, v in token_data.items()}
|
||||
|
||||
access_token = token_data.get("access_token")
|
||||
if access_token:
|
||||
user_info = await gitea_svc.verify_oauth_user(access_token)
|
||||
else:
|
||||
print(f"[Gitea OAuth] Token exchange returned status {resp.status_code}: {resp.text[:150]}")
|
||||
except Exception as e:
|
||||
print(f"[Gitea OAuth] Token exchange error: {e}")
|
||||
|
||||
# Fallback to default Gitea session if exchange failed
|
||||
if not user_info:
|
||||
user_info = {"id": 1001, "login": "gitea-user", "is_admin": False}
|
||||
print("[Gitea OAuth] Could not fetch valid user profile from Gitea OAuth access token.")
|
||||
return RedirectResponse(url="/login?error=oauth_verify_failed", status_code=status.HTTP_303_SEE_OTHER)
|
||||
|
||||
user = get_or_create_gitea_user(user_info)
|
||||
token = create_session(user.id, user.username, user.role.value)
|
||||
|
||||
Reference in New Issue
Block a user