Files
boc/academy-gemini-bridge.py
T
Bernt aee0f09db8 landvex: Fixar och tester klara för alla komponenter
- Datafabrik: Dockerfile fix, agentorkestrering fungerar
- Vision: Identify-modell, FAISS, OCR alla testade
- API: Alla 7 integrationstester passerade
- Upplösare: Entitetsupplösning verifierad
2026-07-05 06:41:32 +00:00

280 lines
9.3 KiB
Python

#!/usr/bin/env python3
"""
quiXzoom Academy — Gemini Bridge via AAMOS
Använder AAMOS Academy API för att generera bilder med Gemini
"""
import requests
import json
import os
import base64
from datetime import datetime
from pathlib import Path
# AAMOS API-konfiguration
AAMOS_BASE_URL = "http://localhost:3100"
ACADEMY_API = f"{AAMOS_BASE_URL}/api/aamos/academy"
# S3-konfiguration
S3_BUCKET = "quixzoom-landing-prod"
ACADEMY_IMAGES_PATH = "academy/images"
# Lektionsbilder som ska genereras
LESSON_IMAGES = {
"m1l1": {
"title": "Välkommen till quiXzoom",
"prompt": """Generera en vänlig illustration för en online-utbildning om crowdsourcing-fotografering.
Scen: En person med smartphone fotograferar en bro i solnedgång. Personen ser glad och professionell ut.
Stil: Modern, ren illustration (inte fotorealistisk)
Färger: Blå (#0066FF), grön (#00C853), svart (#0A0A0A), vita accenter
Format: 16:9 bredbild
Ingen text i bilden
Pedagogisk och inspirerande känsla"""
},
"m2l1": {
"title": "AI-granskning av bilder",
"prompt": """Generera en teknisk illustration som visar AI-analys av en fotografi.
Scen: Dela bilden i två delar. Vänster: Originalbild på en bro. Höger: Samma bild med AI-analys-overlay som markerar skärpa, ljus, komposition med färgkodade indikatorer.
Stil: Futuristisk men pedagogisk
Färger: Blå (#0066FF), grön (#00C853), orange (#FF6B35) för markeringar
Format: 16:9
Ingen text"""
},
"m2l2": {
"title": "Ljus och exponering",
"prompt": """Generera en pedagogisk jämförelsebild för fotoutbildning.
Scen: Tre bilder i rad som visar samma bro från samma vinkel:
1. Vänster: Underexponerad (för mörk)
2. Mitten: Perfekt exponerad (gyllene timmen, varmt ljus)
3. Höger: Överexponerad (för ljus, utbrända detaljer)
Stil: Fotorealistisk
Format: 16:9 (tre paneler)
Ingen text, men tydlig visuell skillnad"""
},
"m2l3": {
"title": "Fokus och skärpa",
"prompt": """Generera en pedagogisk bild som visar skillnaden mellan oskarp och skarp fotografi.
Scen: Två bilder som visar en vägskylt:
1. Vänster: Suddig, oskarp bild
2. Höger: Knivskarp bild med tydliga detaljer
Lägg till ett förstoringsglas-effekt som visar detaljerna tydligare på den skarpa bilden.
Stil: Fotorealistisk med grafiska element
Format: 16:9
Ingen text"""
},
"m2l4": {
"title": "Framing och komposition",
"prompt": """Generera en pedagogisk diagram-bild för fotokomposition.
Scen: En bro fotograferad med korrekt komposition. Overlay som visar:
- Rule of thirds grid (3x3 linjer)
- Huvudobjektet centrerat vid skärningspunkter
- Pil som pekar på huvudobjektet
- Grön markering för "bra" komposition
Stil: Fotorealistisk med pedagogiska overlay-element
Format: 16:9
Ingen text"""
},
"m3l1": {
"title": "GPS-accuracy",
"prompt": """Generera en teknisk illustration om GPS-teknik.
Scen: En karta över en stad sett uppifrån. En smartphone i mitten som tar emot signaler från 4 GPS-satelliter ovanför (visa som linjer från satelliter till telefon). Färgkodad accuracy-cirkel runt telefonen:
- Grön cirkel: Noggrann position (liten cirkel)
- Gul cirkel: Medel (större cirkel)
- Röd cirkel: Låg accuracy (stor cirkel)
Stil: Modern, teknisk illustration
Format: 16:9
Ingen text"""
},
"m4l1": {
"title": "Personlig säkerhet i fält",
"prompt": """Generera en illustration om säker fotografering.
Scen: En person (Zoomer) med reflexväst och smartphone fotograferar en bro från ett säkert avstånd. Visa:
- Reflexväst på personen
- Trafikkegel som markerar säker zon
- Säkerhetsavstånd markerat med streckad linje
- Bil som passerar på håll
Stil: Modern, vänlig illustration
Färger: Orange varselväst, blå (#0066FF), grön (#00C853)
Format: 16:9
Ingen text"""
},
"m5l1": {
"title": "Batch-fotografering",
"prompt": """Generera en karta-baserad illustration för effektiv fotografering.
Scen: En stiliserad karta med flera fotopunkter (A, B, C, D, E) som är kopplade med en optimerad rutt (grön linje). En person med smartphone och cykel/bil följer rutten. Visa att personen fotograferar flera platser effektivt.
Stil: Modern karta/illustration
Färger: Grön rutt (#00C853), blå punkter (#0066FF), neutral bakgrund
Format: 16:9
Ingen text"""
},
"m6l1": {
"title": "Utbetalningsflöde",
"prompt": """Generera ett flödesdiagram för utbetalningsprocess.
Scen: Ett horisontellt flöde som visar:
1. Godkänd fotografi (grön bock)
2. AI-granskning (robot-ikon)
3. Godkännande (stämpel)
4. Utbetalning (pengar/bank)
5. Pengar på kontot (glad person)
Stil: Modern, ren illustration med ikoner
Färger: Grön (#00C853) för framsteg, blå (#0066FF) för process
Format: 16:9
Ingen text, bara ikoner och pilar"""
}
}
def generate_with_aamos(prompt: str, provider: str = "gemini") -> dict:
"""Generera innehåll via AAMOS Academy API"""
url = f"{ACADEMY_API}/ai/generate"
payload = {
"prompt": prompt,
"provider": provider,
"maxTokens": 2000
}
try:
response = requests.post(url, json=payload, timeout=30)
if response.status_code == 200:
return response.json()
else:
print(f" ⚠️ AAMOS API fel: {response.status_code}")
return {"error": f"HTTP {response.status_code}"}
except requests.exceptions.ConnectionError:
print(f" ⚠️ Kunde inte ansluta till AAMOS på {AAMOS_BASE_URL}")
return {"error": "Connection failed"}
except Exception as e:
print(f" ⚠️ Fel: {e}")
return {"error": str(e)}
def generate_image_description(lesson_id: str) -> str:
"""Generera bildbeskrivning via AAMOS Gemini"""
lesson = LESSON_IMAGES.get(lesson_id)
if not lesson:
return None
print(f"🎨 Genererar bild för: {lesson['title']}")
# Använd AAMOS för att generera en detaljerad bildbeskrivning
# (Gemini text-generering, inte bildgenerering ännu)
result = generate_with_aamos(lesson['prompt'], "gemini")
if 'text' in result:
return result['text']
else:
return None
def save_image_metadata(lesson_id: str, description: str):
"""Spara bild-metadata för senare generering"""
metadata = {
"lesson_id": lesson_id,
"title": LESSON_IMAGES[lesson_id]['title'],
"description": description,
"prompt": LESSON_IMAGES[lesson_id]['prompt'],
"generated_at": datetime.utcnow().isoformat(),
"status": "description_ready",
"image_url": None
}
# Spara till lokal fil
output_dir = Path("academy-generated")
output_dir.mkdir(exist_ok=True)
with open(output_dir / f"{lesson_id}.json", "w") as f:
json.dump(metadata, f, indent=2, ensure_ascii=False)
return metadata
def generate_all_images():
"""Generera alla bildbeskrivningar för Academy"""
print("🚀 quiXzoom Academy — Bildgenerering via AAMOS Gemini")
print("=" * 60)
results = []
for lesson_id, lesson in LESSON_IMAGES.items():
print(f"\n📚 {lesson['title']}")
# Generera beskrivning via AAMOS
description = generate_image_description(lesson_id)
if description:
# Spara metadata
metadata = save_image_metadata(lesson_id, description)
results.append(metadata)
print(f" ✅ Beskrivning genererad")
else:
print(f" ❌ Kunde inte generera")
# Spara sammanfattning
summary = {
"generated_at": datetime.utcnow().isoformat(),
"total_images": len(LESSON_IMAGES),
"successful": len(results),
"failed": len(LESSON_IMAGES) - len(results),
"images": results
}
with open("academy-generated/summary.json", "w") as f:
json.dump(summary, f, indent=2, ensure_ascii=False)
print(f"\n{'=' * 60}")
print(f"{len(results)}/{len(LESSON_IMAGES)} bildbeskrivningar genererade")
print(f"📄 Sparade i academy-generated/")
return summary
def upload_to_s3(image_path: str, s3_key: str) -> str:
"""Ladda upp bild till S3"""
import subprocess
cmd = [
"aws", "s3", "cp", image_path,
f"s3://{S3_BUCKET}/{s3_key}",
"--acl", "public-read",
"--content-type", "image/png"
]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
url = f"https://{S3_BUCKET}.s3.eu-north-1.amazonaws.com/{s3_key}"
print(f" ✅ Uppladdad: {url}")
return url
else:
print(f" ❌ Fel: {result.stderr}")
return None
if __name__ == "__main__":
import sys
if len(sys.argv) > 1 and sys.argv[1] == "--generate":
generate_all_images()
else:
print("Användning:")
print(" python academy-gemini-bridge.py --generate")
print("")
print("Detta kommer att:")
print(" 1. Ansluta till AAMOS Academy API (localhost:3100)")
print(" 2. Generera bildbeskrivningar med Gemini")
print(" 3. Spara metadata för varje bild")
print("")
print("När bildbeskrivningarna är klara kan du:")
print(" - Använda dem för att generera riktiga bilder")
print(" - Kopiera in dem i Academy-lektionerna")