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
This commit is contained in:
@@ -0,0 +1,205 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
quiXzoom Academy — Direkt Gemini Integration
|
||||
Använder Gemini API direkt (via AAMOS nyckel) för att generera bildbeskrivningar
|
||||
"""
|
||||
|
||||
import requests
|
||||
import json
|
||||
import os
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
# Gemini API-konfiguration (från AAMOS)
|
||||
GEMINI_API_KEY = "AIzaSyANo7g3-EZTuH_VAw1ZRzW7n-A39ewIhqo"
|
||||
GEMINI_ENDPOINT = "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent"
|
||||
|
||||
# Lektionsbilder som ska genereras
|
||||
LESSON_IMAGES = {
|
||||
"m1l1": {
|
||||
"title": "Välkommen till quiXzoom",
|
||||
"prompt": "Beskriv en pedagogisk illustration: En glad person med smartphone fotograferar en bro i solnedgång. Modern, ren illustration med blå och gröna färger. 16:9 format."
|
||||
},
|
||||
"m2l1": {
|
||||
"title": "AI-granskning av bilder",
|
||||
"prompt": "Beskriv en teknisk illustration: En bild delad 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. Futuristisk men pedagogisk stil."
|
||||
},
|
||||
"m2l2": {
|
||||
"title": "Ljus och exponering",
|
||||
"prompt": "Beskriv en pedagogisk jämförelse: Tre bilder i rad som visar samma bro. 1. Underexponerad (för mörk), 2. Perfekt exponerad (gyllene timmen), 3. Överexponerad (för ljus). Fotorealistisk stil."
|
||||
},
|
||||
"m2l3": {
|
||||
"title": "Fokus och skärpa",
|
||||
"prompt": "Beskriv en pedagogisk bild: Två bilder som visar en vägskylt. Vänster: Suddig, oskarp. Höger: Knivskarp med förstoringsglas-effekt som visar detaljer. Fotorealistisk med grafiska element."
|
||||
},
|
||||
"m2l4": {
|
||||
"title": "Framing och komposition",
|
||||
"prompt": "Beskriv en pedagogisk diagram-bild: En bro fotograferad med korrekt komposition. Overlay med rule of thirds grid, pil som pekar på huvudobjektet, grön markering för bra komposition."
|
||||
},
|
||||
"m3l1": {
|
||||
"title": "GPS-accuracy",
|
||||
"prompt": "Beskriv en teknisk illustration: En karta över en stad med en smartphone i mitten. 4 GPS-satelliter ovanför skickar signaler till telefonen. Färgkodade accuracy-cirklar: grön (noggrann), gul (medel), röd (låg)."
|
||||
},
|
||||
"m4l1": {
|
||||
"title": "Personlig säkerhet",
|
||||
"prompt": "Beskriv en illustration: En person med reflexväst och smartphone fotograferar en bro från säkert avstånd. Trafikkegel, varselväst, säkerhetsavstånd markerat. Modern, vänlig stil."
|
||||
},
|
||||
"m5l1": {
|
||||
"title": "Batch-fotografering",
|
||||
"prompt": "Beskriv en karta-baserad illustration: En stiliserad karta med fotopunkter (A, B, C, D, E) kopplade med en optimerad grön rutt. En person med smartphone följer rutten effektivt."
|
||||
},
|
||||
"m6l1": {
|
||||
"title": "Utbetalningsflöde",
|
||||
"prompt": "Beskriv ett flödesdiagram: Horisontellt flöde som visar 1. Godkänd fotografi → 2. AI-granskning → 3. Godkännande → 4. Utbetalning → 5. Pengar på kontot. Modern, ren illustration med ikoner."
|
||||
}
|
||||
}
|
||||
|
||||
def generate_with_gemini(prompt: str) -> str:
|
||||
"""Generera text med Gemini API"""
|
||||
|
||||
url = f"{GEMINI_ENDPOINT}?key={GEMINI_API_KEY}"
|
||||
|
||||
payload = {
|
||||
"contents": [{
|
||||
"parts": [{
|
||||
"text": prompt
|
||||
}]
|
||||
}],
|
||||
"generationConfig": {
|
||||
"temperature": 0.7,
|
||||
"maxOutputTokens": 1000
|
||||
}
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(url, json=payload, timeout=30)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
|
||||
# Extrahera text från response
|
||||
if 'candidates' in data and len(data['candidates']) > 0:
|
||||
candidate = data['candidates'][0]
|
||||
if 'content' in candidate and 'parts' in candidate['content']:
|
||||
parts = candidate['content']['parts']
|
||||
if len(parts) > 0 and 'text' in parts[0]:
|
||||
return parts[0]['text']
|
||||
|
||||
return None
|
||||
else:
|
||||
print(f" ⚠️ Gemini API fel: {response.status_code}")
|
||||
print(f" {response.text[:200]}")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
print(f" ⚠️ Fel: {e}")
|
||||
return None
|
||||
|
||||
def generate_image_description(lesson_id: str) -> dict:
|
||||
"""Generera bildbeskrivning för en lektion"""
|
||||
|
||||
lesson = LESSON_IMAGES.get(lesson_id)
|
||||
if not lesson:
|
||||
return None
|
||||
|
||||
print(f"🎨 {lesson['title']}")
|
||||
|
||||
# Generera detaljerad bildbeskrivning
|
||||
prompt = f"""Du är en expert på pedagogiska illustrationer för online-utbildningar.
|
||||
|
||||
Beskriv i detalj en illustration för följande lektion:
|
||||
Titel: {lesson['title']}
|
||||
Beskrivning: {lesson['prompt']}
|
||||
|
||||
Ge en detaljerad beskrivning som kan användas för att:
|
||||
1. Generera en bild med AI
|
||||
2. Förstå vad som ska visas i lektionen
|
||||
|
||||
Beskrivningen ska vara på svenska och inkludera:
|
||||
- Huvudobjekt och deras placering
|
||||
- Färger och stil
|
||||
- Viktiga detaljer som måste synas
|
||||
- Pedagogiska element"""
|
||||
|
||||
description = generate_with_gemini(prompt)
|
||||
|
||||
if description:
|
||||
return {
|
||||
"lesson_id": lesson_id,
|
||||
"title": lesson['title'],
|
||||
"description": description,
|
||||
"generated_at": datetime.utcnow().isoformat(),
|
||||
"status": "ready"
|
||||
}
|
||||
else:
|
||||
return None
|
||||
|
||||
def generate_all_images():
|
||||
"""Generera alla bildbeskrivningar"""
|
||||
|
||||
print("🚀 quiXzoom Academy — Gemini Bildgenerering")
|
||||
print("=" * 60)
|
||||
print(f"Använder Gemini API med nyckel: {GEMINI_API_KEY[:15]}...")
|
||||
print("")
|
||||
|
||||
results = []
|
||||
output_dir = Path("academy-generated")
|
||||
output_dir.mkdir(exist_ok=True)
|
||||
|
||||
for lesson_id, lesson in LESSON_IMAGES.items():
|
||||
result = generate_image_description(lesson_id)
|
||||
|
||||
if result:
|
||||
results.append(result)
|
||||
|
||||
# Spara till fil
|
||||
with open(output_dir / f"{lesson_id}.json", "w", encoding="utf-8") as f:
|
||||
json.dump(result, f, indent=2, ensure_ascii=False)
|
||||
|
||||
print(f" ✅ Sparad till academy-generated/{lesson_id}.json")
|
||||
else:
|
||||
print(f" ❌ Kunde inte generera")
|
||||
|
||||
print("")
|
||||
|
||||
# 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(output_dir / "summary.json", "w", encoding="utf-8") as f:
|
||||
json.dump(summary, f, indent=2, ensure_ascii=False)
|
||||
|
||||
print("=" * 60)
|
||||
print(f"✅ {len(results)}/{len(LESSON_IMAGES)} bildbeskrivningar genererade")
|
||||
print(f"📄 Sparade i academy-generated/")
|
||||
|
||||
return summary
|
||||
|
||||
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-direct.py --generate")
|
||||
print("")
|
||||
print("Detta kommer att:")
|
||||
print(" 1. Ansluta till Gemini API")
|
||||
print(" 2. Generera bildbeskrivningar för alla lektioner")
|
||||
print(" 3. Spara resultat i academy-generated/")
|
||||
print("")
|
||||
print("Testar anslutning...")
|
||||
|
||||
# Testa anslutning
|
||||
test = generate_with_gemini("Svara bara: Gemini fungerar!")
|
||||
if test:
|
||||
print(f"✅ Gemini är tillgänglig!")
|
||||
print(f" Svar: {test[:100]}")
|
||||
else:
|
||||
print("❌ Kunde inte ansluta till Gemini")
|
||||
Reference in New Issue
Block a user