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,79 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Applicera förenklad infographic på alla branschsidor.
|
||||
Användning: python3 apply-simple-infographic.py [--dry-run]
|
||||
"""
|
||||
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
def apply_infographic(industry_dir, dry_run=False):
|
||||
"""Applicera infographic på en branschsida."""
|
||||
html_file = industry_dir / 'index.html'
|
||||
if not html_file.exists():
|
||||
return False, "index.html saknas"
|
||||
|
||||
# Läs befintlig HTML
|
||||
content = html_file.read_text(encoding='utf-8')
|
||||
|
||||
# Kolla om redan har infographic
|
||||
if 'qi-infographic' in content:
|
||||
return False, "Har redan infographic"
|
||||
|
||||
# Läs infographic-komponent
|
||||
infographic_path = industry_dir.parent / '_components' / 'infographic-industry-simple.html'
|
||||
if not infographic_path.exists():
|
||||
return False, f"Komponent saknas: {infographic_path}"
|
||||
|
||||
infographic = infographic_path.read_text(encoding='utf-8')
|
||||
|
||||
if dry_run:
|
||||
return True, "Skulle applicera"
|
||||
|
||||
# Injicera före </body>
|
||||
body_end = content.rfind('</body>')
|
||||
if body_end == -1:
|
||||
return False, "Ingen </body> hittad"
|
||||
|
||||
injection = f'''
|
||||
<!-- === INFOGRAPHIC === -->
|
||||
<div class="section section-gray">
|
||||
<div class="container">
|
||||
{infographic}
|
||||
</div>
|
||||
</div>
|
||||
<!-- === END INFOGRAPHIC === -->
|
||||
'''
|
||||
|
||||
new_content = content[:body_end] + injection + '\n' + content[body_end:]
|
||||
html_file.write_text(new_content, encoding='utf-8')
|
||||
return True, "Applicerad"
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--dry-run', action='store_true')
|
||||
args = parser.parse_args()
|
||||
|
||||
root = Path(__file__).parent.parent / 'se'
|
||||
|
||||
print("=== Applicera förenklad infographic ===\n")
|
||||
|
||||
count = 0
|
||||
for subdir in sorted(root.iterdir()):
|
||||
if not subdir.is_dir():
|
||||
continue
|
||||
if subdir.name.startswith('_'):
|
||||
continue
|
||||
if not (subdir / 'index.html').exists():
|
||||
continue
|
||||
|
||||
success, msg = apply_infographic(subdir, dry_run=args.dry_run)
|
||||
status = "✅" if success else "⚠️"
|
||||
print(f" {status} {subdir.name}: {msg}")
|
||||
if success:
|
||||
count += 1
|
||||
|
||||
print(f"\n=== {count} sidor uppdaterade ===")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,145 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Anpassa branschspecifika infographics per undersektor.
|
||||
Användning: python3 customize-industry.py [industry-dir]
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
# Branschspecifika konfigurationer
|
||||
INDUSTRIES = {
|
||||
'facade-inspection': {
|
||||
'name': 'Fasadinspektion',
|
||||
'step_1_title': 'Hitta fasader nära dig',
|
||||
'step_1_desc': 'Se tillgängliga fasaduppdrag på kartan. Välj byggnader i ditt område.',
|
||||
'step_2_title': 'Dokumentera skick',
|
||||
'step_2_desc': 'Fotografera fasad, fönster och entré enligt instruktionerna i appen.',
|
||||
'step_3_title': 'Få betalt',
|
||||
'step_3_desc': 'Ladda upp bilderna. Godkännande inom 24h. Betalt varje måndag.',
|
||||
'value_1_title': 'Snabbare än traditionell besiktning',
|
||||
'value_1_desc': 'Få bilddata inom timmar istället för veckor.',
|
||||
'value_2_title': 'Kvalitetssäkrat',
|
||||
'value_2_desc': 'Varje submission granskas av AI och valideras mot GPS.',
|
||||
'cta_subtext': 'Börja tjäna på fasadinspektion idag.',
|
||||
'cta_button_text': 'Bli Zoomer',
|
||||
},
|
||||
'bridge-inspection': {
|
||||
'name': 'Broinspektion',
|
||||
'step_1_title': 'Hitta broar i ditt område',
|
||||
'step_1_desc': 'Se tillgängliga broinspektionsuppdrag. Välj de som passar din rutt.',
|
||||
'step_2_title': 'Dokumentera broskick',
|
||||
'step_2_desc': 'Fotografera brokropp, leder, räcken och fundament enligt spec.',
|
||||
'step_3_title': 'Bidra till säkerhet',
|
||||
'step_3_desc': 'Dina bilder hjälper kommuner att upptäcka skador tidigt. Betalt varje måndag.',
|
||||
'value_1_title': 'Kritisk infrastruktur',
|
||||
'value_1_desc': 'Hjälp till att hålla Sveriges broar säkra.',
|
||||
'value_2_title': 'Högre ersättning',
|
||||
'value_2_desc': 'Broinspektion betalar 200–500 kr per uppdrag.',
|
||||
'cta_subtext': 'Bidra till säkrare infrastruktur och tjäna pengar.',
|
||||
'cta_button_text': 'Bli broinspektör',
|
||||
},
|
||||
'storm-damage': {
|
||||
'name': 'Stormskadebedömning',
|
||||
'step_1_title': 'Få notis vid storm',
|
||||
'step_1_desc': 'quiXzoom skickar push-notiser när stormskadeuppdrag aktiveras i ditt område.',
|
||||
'step_2_title': 'Dokumentera skador',
|
||||
'step_2_desc': 'Fotografera tak, fasader, träd och vägar. Prioritera säkerheten.',
|
||||
'step_3_title': 'Snabbast betalt',
|
||||
'step_3_desc': 'Stormskadeuppdrag har högst prioritet. Godkännande och betalning inom 48h.',
|
||||
'value_1_title': 'Högst ersättning',
|
||||
'value_1_desc': '300–500 kr per uppdrag. Bonus för snabb insamling.',
|
||||
'value_2_title': 'Hjälp samhället',
|
||||
'value_2_desc': 'Dina bilder påskyndar skadebedömning och återställning.',
|
||||
'cta_subtext': 'Bli först på plats efter stormen.',
|
||||
'cta_button_text': 'Registrera dig',
|
||||
},
|
||||
'property-documentation': {
|
||||
'name': 'Fastighetsdokumentation',
|
||||
'step_1_title': 'Hitta fastigheter',
|
||||
'step_1_desc': 'Se tillgängliga fastighetsuppdrag. Välj bostadsrätter, kontor eller butiker.',
|
||||
'step_2_title': 'Dokumentera noggrant',
|
||||
'step_2_desc': 'Fotografera exteriör, interiör och detaljer enligt checklista.',
|
||||
'step_3_title': 'Få betalt veckovis',
|
||||
'step_3_desc': 'Godkända uppdrag betalas ut varje måndag. Ingen väntetid.',
|
||||
'value_1_title': 'Stort utbud',
|
||||
'value_1_desc': 'Många fastighetsbolag behöver löpande dokumentation.',
|
||||
'value_2_title': 'Flexibelt',
|
||||
'value_2_desc': 'Välj uppdrag som passar din dag.',
|
||||
'cta_subtext': 'Dokumentera fastigheter och tjäna pengar.',
|
||||
'cta_button_text': 'Bli Zoomer',
|
||||
},
|
||||
}
|
||||
|
||||
# Default för branscher som inte finns i config
|
||||
DEFAULT_CONFIG = {
|
||||
'name': 'Fältdatainsamling',
|
||||
'step_1_title': 'Hitta uppdrag',
|
||||
'step_1_desc': 'Se tillgängliga uppdrag nära dig i quiXzoom-appen.',
|
||||
'step_2_title': 'Dokumentera',
|
||||
'step_2_desc': 'Följ instruktionerna och ta bilder med din smartphone.',
|
||||
'step_3_title': 'Få betalt',
|
||||
'step_3_desc': 'Betalt varje vecka för godkända uppdrag.',
|
||||
'value_1_title': 'Flexibelt arbete',
|
||||
'value_1_desc': 'Jobba när du vill, där du vill.',
|
||||
'value_2_title': 'Snabb betalning',
|
||||
'value_2_desc': 'Få betalt varje måndag via Stripe.',
|
||||
'cta_subtext': 'Börja tjäna pengar på fältdatainsamling idag.',
|
||||
'cta_button_text': 'Bli Zoomer',
|
||||
}
|
||||
|
||||
def customize_industry_page(industry_dir):
|
||||
"""Anpassa infographic för en specifik bransch."""
|
||||
industry_name = industry_dir.name
|
||||
config = INDUSTRIES.get(industry_name, DEFAULT_CONFIG)
|
||||
|
||||
# Läs template
|
||||
template_path = industry_dir.parent / '_components' / 'infographic-industry.html'
|
||||
if not template_path.exists():
|
||||
print(f" ❌ Template saknas: {template_path}")
|
||||
return False
|
||||
|
||||
template = template_path.read_text(encoding='utf-8')
|
||||
|
||||
# Ersätt placeholders
|
||||
result = template
|
||||
for key, value in config.items():
|
||||
placeholder = '{{' + key.upper() + '}}'
|
||||
result = result.replace(placeholder, value)
|
||||
|
||||
# Ta bort oersatta placeholders (men inte kommentaren)
|
||||
result = re.sub(r'\{\{([A-Z_]+)\}\}', lambda m: '' if m.group(1) != 'PLACEHOLDERS' else m.group(0), result)
|
||||
|
||||
# Skriv till fil
|
||||
output_path = industry_dir / 'infographic-custom.html'
|
||||
output_path.write_text(result, encoding='utf-8')
|
||||
print(f" ✅ {industry_name}/infographic-custom.html skapad")
|
||||
return True
|
||||
|
||||
def main():
|
||||
root = Path(__file__).parent.parent / 'se'
|
||||
|
||||
print("=== Branschanpassade Infographics ===\n")
|
||||
|
||||
count = 0
|
||||
for subdir in sorted(root.iterdir()):
|
||||
if not subdir.is_dir():
|
||||
continue
|
||||
if subdir.name.startswith('_'):
|
||||
continue
|
||||
if not (subdir / 'index.html').exists():
|
||||
continue
|
||||
|
||||
if customize_industry_page(subdir):
|
||||
count += 1
|
||||
|
||||
print(f"\n=== {count} branschspecifika infographics skapade ===")
|
||||
print("\nNästa steg:")
|
||||
print(" 1. Uppdatera integrate.py för att använda custom infographics")
|
||||
print(" 2. Testa lokalt")
|
||||
print(" 3. Deploy till S3")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
#!/bin/bash
|
||||
# Integrera infographic-komponenter på alla quiXzoom landningssidor
|
||||
# Körs från quixzoom-market-pages/ roten
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
COMPONENTS_DIR="$ROOT_DIR/se/_components"
|
||||
|
||||
echo "=== quiXzoom Infographic Integration ==="
|
||||
echo "Root: $ROOT_DIR"
|
||||
echo ""
|
||||
|
||||
# Funktion: injicera zoomer-infographic före footer
|
||||
inject_zoomer_infographic() {
|
||||
local file="$1"
|
||||
local title="$2"
|
||||
|
||||
# Kontrollera om redan integrerad
|
||||
if grep -q "qz-infographic" "$file" 2>/dev/null; then
|
||||
echo " ⚠️ Skippar (redan integrerad): $(basename $(dirname $file))/$(basename $file)"
|
||||
return
|
||||
fi
|
||||
|
||||
# Läs in infographic-komponenten
|
||||
local infographic=$(cat "$COMPONENTS_DIR/infographic-zoomer.html")
|
||||
|
||||
# Skapa temporär fil med infographic injicerad före </body>
|
||||
local tmpfile="${file}.tmp"
|
||||
|
||||
# Extrahera allt före </body>
|
||||
awk '
|
||||
/<\/body>/ {
|
||||
# Skriv ut infographic innan </body>
|
||||
print ""
|
||||
print "<!-- === INFOGRAPHIC: Zoomer Journey === -->"
|
||||
print "<div class=\"section\">"
|
||||
print " <div class=\"container\">"
|
||||
print " <!-- Infographic injicerad automatiskt -->"
|
||||
print infographic_content
|
||||
print " </div>"
|
||||
print "</div>"
|
||||
print "<!-- === END INFOGRAPHIC === -->"
|
||||
print ""
|
||||
}
|
||||
{ print }
|
||||
' infographic_content="$infographic" "$file" > "$tmpfile"
|
||||
|
||||
mv "$tmpfile" "$file"
|
||||
echo " ✅ Integrerad: $(basename $(dirname $file))/$(basename $file)"
|
||||
}
|
||||
|
||||
# Funktion: injicera business-infographic på index-sidan
|
||||
inject_business_infographic() {
|
||||
local file="$1"
|
||||
|
||||
if grep -q "lb-infographic" "$file" 2>/dev/null; then
|
||||
echo " ⚠️ Skippar (redan integrerad): $(basename $file)"
|
||||
return
|
||||
fi
|
||||
|
||||
local infographic=$(cat "$COMPONENTS_DIR/infographic-business.html")
|
||||
local tmpfile="${file}.tmp"
|
||||
|
||||
awk '
|
||||
/<\/body>/ {
|
||||
print ""
|
||||
print "<!-- === INFOGRAPHIC: Business Decision Flow === -->"
|
||||
print "<div class=\"section section-gray\">"
|
||||
print " <div class=\"container\">"
|
||||
print infographic_content
|
||||
print " </div>"
|
||||
print "</div>"
|
||||
print "<!-- === END INFOGRAPHIC === -->"
|
||||
print ""
|
||||
}
|
||||
{ print }
|
||||
' infographic_content="$infographic" "$file" > "$tmpfile"
|
||||
|
||||
mv "$tmpfile" "$file"
|
||||
echo " ✅ Business infographic integrerad: $(basename $file)"
|
||||
}
|
||||
|
||||
# Funktion: injicera combined flow infographic
|
||||
inject_combined_infographic() {
|
||||
local file="$1"
|
||||
|
||||
if grep -q "lv-infographic" "$file" 2>/dev/null; then
|
||||
echo " ⚠️ Skippar (redan integrerad): $(basename $file)"
|
||||
return
|
||||
fi
|
||||
|
||||
local infographic=$(cat "$COMPONENTS_DIR/infographic-flow.html")
|
||||
local tmpfile="${file}.tmp"
|
||||
|
||||
awk '
|
||||
/<\/body>/ {
|
||||
print ""
|
||||
print "<!-- === INFOGRAPHIC: Landvex + quiXzoom Flow === -->"
|
||||
print "<div class=\"section\">"
|
||||
print " <div class=\"container\">"
|
||||
print infographic_content
|
||||
print " </div>"
|
||||
print "</div>"
|
||||
print "<!-- === END INFOGRAPHIC === -->"
|
||||
print ""
|
||||
}
|
||||
{ print }
|
||||
' infographic_content="$infographic" "$file" > "$tmpfile"
|
||||
|
||||
mv "$tmpfile" "$file"
|
||||
echo " ✅ Combined flow integrerad: $(basename $file)"
|
||||
}
|
||||
|
||||
echo "1. Uppdaterar huvudsida (se/index.html)..."
|
||||
inject_combined_infographic "$ROOT_DIR/se/index.html"
|
||||
|
||||
echo ""
|
||||
echo "2. Uppdaterar branschsidor (zoomer-fokus)..."
|
||||
for dir in "$ROOT_DIR/se"/*/; do
|
||||
# Hoppa över _components
|
||||
[[ "$(basename "$dir")" == "_components" ]] && continue
|
||||
|
||||
html_file="${dir}index.html"
|
||||
if [ -f "$html_file" ]; then
|
||||
inject_zoomer_infographic "$html_file"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "=== Integration klar ==="
|
||||
echo ""
|
||||
echo "Manuella steg som krävs:"
|
||||
echo " 1. Ladda upp till S3: aws s3 sync $ROOT_DIR/se/ s3://quixzoom-landing-prod/markets/se/"
|
||||
echo " 2. CloudFront invalidation"
|
||||
echo " 3. Verifiera på https://quixzoom.se"
|
||||
@@ -0,0 +1,138 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Integrera infographic-komponenter på alla quiXzoom landningssidor.
|
||||
Användning: python3 integrate.py [--dry-run]
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).parent.parent
|
||||
COMPONENTS = ROOT / "se" / "_components"
|
||||
|
||||
def read_component(name):
|
||||
"""Läs en komponentfil och returnera innehållet."""
|
||||
path = COMPONENTS / name
|
||||
if not path.exists():
|
||||
print(f"❌ Komponent saknas: {path}")
|
||||
sys.exit(1)
|
||||
return path.read_text(encoding='utf-8')
|
||||
|
||||
def inject_before_body_end(html_path, content_to_inject, wrapper_class="section"):
|
||||
"""Injicera innehåll före </body>."""
|
||||
content = html_path.read_text(encoding='utf-8')
|
||||
|
||||
# Kolla om redan injicerad
|
||||
if 'infographic' in content and 'lv-infographic' in content_to_inject:
|
||||
return False, "Redan integrerad"
|
||||
if 'infographic' in content and 'qz-infographic' in content_to_inject:
|
||||
return False, "Redan integrerad"
|
||||
if 'infographic' in content and 'lb-infographic' in content_to_inject:
|
||||
return False, "Redan integrerad"
|
||||
|
||||
# Hitta </body> och injicera före
|
||||
body_end = content.rfind('</body>')
|
||||
if body_end == -1:
|
||||
return False, "Ingen </body> hittad"
|
||||
|
||||
# Bygg injektion
|
||||
injection = f'''
|
||||
<!-- === INFOGRAPHIC INJECTED === -->
|
||||
<div class="{wrapper_class}">
|
||||
<div class="container">
|
||||
{content_to_inject}
|
||||
</div>
|
||||
</div>
|
||||
<!-- === END INFOGRAPHIC === -->
|
||||
'''
|
||||
|
||||
new_content = content[:body_end] + injection + '\n' + content[body_end:]
|
||||
html_path.write_text(new_content, encoding='utf-8')
|
||||
return True, "Integrerad"
|
||||
|
||||
def process_main_page(dry_run=False):
|
||||
"""Uppdatera huvudsida med combined flow."""
|
||||
path = ROOT / "se" / "index.html"
|
||||
infographic = read_component("infographic-flow.html")
|
||||
|
||||
if dry_run:
|
||||
print(f" [DRY-RUN] Skulle integrera combined flow på: {path}")
|
||||
return
|
||||
|
||||
success, msg = inject_before_body_end(path, infographic, "section")
|
||||
status = "✅" if success else "⚠️"
|
||||
print(f" {status} {path.name}: {msg}")
|
||||
|
||||
def process_industry_pages(dry_run=False):
|
||||
"""Uppdatera alla branschsidor med zoomer-journey."""
|
||||
infographic = read_component("infographic-zoomer.html")
|
||||
se_dir = ROOT / "se"
|
||||
|
||||
count = 0
|
||||
for subdir in sorted(se_dir.iterdir()):
|
||||
if not subdir.is_dir():
|
||||
continue
|
||||
if subdir.name.startswith('_'):
|
||||
continue
|
||||
if subdir.name == 'index.html':
|
||||
continue
|
||||
|
||||
html_file = subdir / "index.html"
|
||||
if not html_file.exists():
|
||||
continue
|
||||
|
||||
if dry_run:
|
||||
print(f" [DRY-RUN] Skulle integrera zoomer-journey på: {subdir.name}/index.html")
|
||||
count += 1
|
||||
continue
|
||||
|
||||
success, msg = inject_before_body_end(html_file, infographic, "section section-gray")
|
||||
status = "✅" if success else "⚠️"
|
||||
print(f" {status} {subdir.name}/index.html: {msg}")
|
||||
if success:
|
||||
count += 1
|
||||
|
||||
return count
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Integrera infographics på quiXzoom landningssidor")
|
||||
parser.add_argument('--dry-run', action='store_true', help='Simulera utan att ändra filer')
|
||||
args = parser.parse_args()
|
||||
|
||||
print("=== quiXzoom Infographic Integration ===\n")
|
||||
|
||||
# Verifiera komponenter finns
|
||||
for comp in ['infographic-flow.html', 'infographic-zoomer.html', 'infographic-business.html']:
|
||||
path = COMPONENTS / comp
|
||||
if not path.exists():
|
||||
print(f"❌ Komponent saknas: {comp}")
|
||||
sys.exit(1)
|
||||
print(f" 📦 {comp} ({path.stat().st_size:,} bytes)")
|
||||
|
||||
print()
|
||||
|
||||
# 1. Huvudsida
|
||||
print("1. Uppdaterar huvudsida (se/index.html)...")
|
||||
process_main_page(dry_run=args.dry_run)
|
||||
|
||||
# 2. Branschsidor
|
||||
print("\n2. Uppdaterar branschsidor...")
|
||||
count = process_industry_pages(dry_run=args.dry_run)
|
||||
|
||||
print(f"\n=== Sammanfattning ===")
|
||||
if args.dry_run:
|
||||
print(f"[DRY-RUN] Skulle uppdatera {count} filer")
|
||||
else:
|
||||
print(f"Uppdaterade {count} filer")
|
||||
|
||||
print("\nNästa steg:")
|
||||
print(" 1. Testa lokalt: öppna filerna i webbläsare")
|
||||
print(" 2. aws s3 sync se/ s3://quixzoom-landing-prod/markets/se/")
|
||||
print(" 3. CloudFront invalidation")
|
||||
print(" 4. Verifiera på https://quixzoom.se")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user