Initial import: Carteasy Shop (Dev-Stand)
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,270 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
🎛️ Intelectra AI Control Center - Flask Dashboard
|
||||
Trackt KI-Besucher und steuert FAQ/Schema System
|
||||
"""
|
||||
|
||||
from flask import Flask, render_template, request, jsonify, redirect, url_for, flash
|
||||
import mysql.connector
|
||||
import json
|
||||
import re
|
||||
from datetime import datetime, timedelta
|
||||
import os
|
||||
from config import DB_CONFIG
|
||||
|
||||
app = Flask(__name__)
|
||||
app.secret_key = 'intelectra_ai_dashboard_secret_2025'
|
||||
|
||||
class AIAdminDashboard:
|
||||
def __init__(self):
|
||||
self.db_config = DB_CONFIG
|
||||
|
||||
# KI-Detection Patterns
|
||||
self.ai_signatures = {
|
||||
'ChatGPT': ['GPTBot', 'ChatGPT-User', 'OpenAI', 'gpt-crawler'],
|
||||
'Claude': ['Claude-Web', 'Anthropic', 'Claude', 'anthropic'],
|
||||
'Gemini': ['Google-Extended', 'Bard', 'Gemini', 'GoogleOther'],
|
||||
'Perplexity': ['PerplexityBot', 'perplexity'],
|
||||
'Bing AI': ['BingBot', 'EdgeBot', 'msnbot'],
|
||||
'Meta AI': ['FacebookBot', 'Meta', 'facebookexternalhit'],
|
||||
'You.com': ['YouBot', 'you.com'],
|
||||
'SearchGPT': ['SearchGPT', 'OpenAI-SearchBot']
|
||||
}
|
||||
|
||||
def get_db_connection(self):
|
||||
"""Sichere DB-Verbindung"""
|
||||
try:
|
||||
return mysql.connector.connect(**self.db_config)
|
||||
except Exception as e:
|
||||
print(f"DB Connection failed: {e}")
|
||||
return None
|
||||
|
||||
def detect_ai_visitor(self, user_agent, referer=''):
|
||||
"""Erkennt KI-Besucher anhand User-Agent & Referer"""
|
||||
user_agent = user_agent.lower()
|
||||
referer = referer.lower()
|
||||
|
||||
for ai_name, signatures in self.ai_signatures.items():
|
||||
for signature in signatures:
|
||||
if signature.lower() in user_agent or signature.lower() in referer:
|
||||
return ai_name
|
||||
|
||||
return None
|
||||
|
||||
def log_ai_visit(self, ai_name, url, user_agent, ip_address, referer=''):
|
||||
"""Loggt KI-Besuch in Datenbank"""
|
||||
try:
|
||||
conn = self.get_db_connection()
|
||||
if not conn:
|
||||
return False
|
||||
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Artikel-ID aus URL extrahieren
|
||||
article_id = None
|
||||
url_match = re.search(r'/artikel/(\d+)', url)
|
||||
if url_match:
|
||||
article_id = int(url_match.group(1))
|
||||
|
||||
query = """
|
||||
INSERT INTO ai_visitor_log
|
||||
(ai_name, url, article_id, user_agent, ip_address, referer, visited_at)
|
||||
VALUES (%s, %s, %s, %s, %s, %s, %s)
|
||||
"""
|
||||
|
||||
cursor.execute(query, (ai_name, url, article_id, user_agent, ip_address, referer, datetime.now()))
|
||||
conn.commit()
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"AI visit logging failed: {e}")
|
||||
return False
|
||||
|
||||
def get_ai_stats(self, days=7):
|
||||
"""Holt KI-Statistiken der letzten N Tage"""
|
||||
try:
|
||||
conn = self.get_db_connection()
|
||||
if not conn:
|
||||
return {}
|
||||
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
|
||||
# Basis-Statistiken
|
||||
since_date = datetime.now() - timedelta(days=days)
|
||||
|
||||
# KI-Besuche pro AI
|
||||
cursor.execute("""
|
||||
SELECT ai_name, COUNT(*) as visit_count,
|
||||
COUNT(DISTINCT ip_address) as unique_visitors
|
||||
FROM ai_visitor_log
|
||||
WHERE visited_at >= %s
|
||||
GROUP BY ai_name
|
||||
ORDER BY visit_count DESC
|
||||
""", (since_date,))
|
||||
|
||||
ai_visits = cursor.fetchall()
|
||||
|
||||
# Top besuchte Artikel
|
||||
cursor.execute("""
|
||||
SELECT avl.article_id, COUNT(*) as visit_count,
|
||||
GROUP_CONCAT(DISTINCT avl.ai_name) as visiting_ais
|
||||
FROM ai_visitor_log avl
|
||||
WHERE avl.visited_at >= %s AND avl.article_id IS NOT NULL
|
||||
GROUP BY avl.article_id
|
||||
ORDER BY visit_count DESC
|
||||
LIMIT 10
|
||||
""", (since_date,))
|
||||
|
||||
top_articles = cursor.fetchall()
|
||||
|
||||
# Zeitverteilung (Stunden)
|
||||
cursor.execute("""
|
||||
SELECT HOUR(visited_at) as hour, COUNT(*) as visits
|
||||
FROM ai_visitor_log
|
||||
WHERE visited_at >= %s
|
||||
GROUP BY HOUR(visited_at)
|
||||
ORDER BY hour
|
||||
""", (since_date,))
|
||||
|
||||
hourly_distribution = cursor.fetchall()
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
return {
|
||||
'ai_visits': ai_visits,
|
||||
'top_articles': top_articles,
|
||||
'hourly_distribution': hourly_distribution,
|
||||
'period_days': days
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
print(f"Stats retrieval failed: {e}")
|
||||
return {}
|
||||
|
||||
# Flask Dashboard Routes
|
||||
dashboard = AIAdminDashboard()
|
||||
|
||||
@app.route('/')
|
||||
def dashboard_home():
|
||||
"""Hauptdashboard mit KI-Statistiken"""
|
||||
stats = dashboard.get_ai_stats(days=7)
|
||||
return render_template('dashboard.html', stats=stats)
|
||||
|
||||
@app.route('/faq-management')
|
||||
def faq_management():
|
||||
"""FAQ/Problem Management Interface"""
|
||||
try:
|
||||
conn = dashboard.get_db_connection()
|
||||
cursor = conn.cursor(dictionary=True)
|
||||
|
||||
# Alle Probleme laden
|
||||
cursor.execute("""
|
||||
SELECT * FROM problem_solutions
|
||||
WHERE active = TRUE
|
||||
ORDER BY frequency_score DESC
|
||||
""")
|
||||
problems = cursor.fetchall()
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
return render_template('faq_management.html', problems=problems)
|
||||
|
||||
except Exception as e:
|
||||
flash(f'Error loading problems: {e}', 'error')
|
||||
return redirect(url_for('dashboard_home'))
|
||||
|
||||
@app.route('/add-problem', methods=['GET', 'POST'])
|
||||
def add_problem():
|
||||
"""Neues Problem hinzufügen"""
|
||||
if request.method == 'POST':
|
||||
try:
|
||||
conn = dashboard.get_db_connection()
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Form-Daten extrahieren
|
||||
data = {
|
||||
'problem_category': request.form['category'],
|
||||
'problem_title': request.form['title'],
|
||||
'problem_description': request.form['description'],
|
||||
'symptoms': json.dumps(request.form['symptoms'].split('\n')),
|
||||
'keywords': json.dumps(request.form['keywords'].split(',')),
|
||||
'urgency_level': request.form['urgency'],
|
||||
'repair_complexity': request.form['complexity'],
|
||||
'frequency_score': int(request.form.get('frequency', 50))
|
||||
}
|
||||
|
||||
query = """
|
||||
INSERT INTO problem_solutions
|
||||
(problem_category, problem_title, problem_description, symptoms,
|
||||
keywords, urgency_level, repair_complexity, frequency_score)
|
||||
VALUES (%(problem_category)s, %(problem_title)s, %(problem_description)s,
|
||||
%(symptoms)s, %(keywords)s, %(urgency_level)s,
|
||||
%(repair_complexity)s, %(frequency_score)s)
|
||||
"""
|
||||
|
||||
cursor.execute(query, data)
|
||||
conn.commit()
|
||||
|
||||
cursor.close()
|
||||
conn.close()
|
||||
|
||||
flash('Problem erfolgreich hinzugefügt!', 'success')
|
||||
return redirect(url_for('faq_management'))
|
||||
|
||||
except Exception as e:
|
||||
flash(f'Error adding problem: {e}', 'error')
|
||||
|
||||
return render_template('add_problem.html')
|
||||
|
||||
@app.route('/api/ai-visits')
|
||||
def api_ai_visits():
|
||||
"""API Endpoint für Live AI-Visit Updates"""
|
||||
stats = dashboard.get_ai_stats(days=1)
|
||||
return jsonify(stats)
|
||||
|
||||
@app.route('/api/detect-visitor', methods=['POST'])
|
||||
def api_detect_visitor():
|
||||
"""API Endpoint für KI-Visitor Detection (wird vom PHP Shop aufgerufen)"""
|
||||
try:
|
||||
data = request.json
|
||||
user_agent = data.get('user_agent', '')
|
||||
url = data.get('url', '')
|
||||
ip_address = data.get('ip_address', '')
|
||||
referer = data.get('referer', '')
|
||||
|
||||
# KI erkennen
|
||||
ai_name = dashboard.detect_ai_visitor(user_agent, referer)
|
||||
|
||||
if ai_name:
|
||||
# In DB loggen
|
||||
dashboard.log_ai_visit(ai_name, url, user_agent, ip_address, referer)
|
||||
|
||||
return jsonify({
|
||||
'ai_detected': True,
|
||||
'ai_name': ai_name,
|
||||
'logged': True
|
||||
})
|
||||
else:
|
||||
return jsonify({
|
||||
'ai_detected': False,
|
||||
'ai_name': None,
|
||||
'logged': False
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/schema-preview/<int:article_id>')
|
||||
def schema_preview(article_id):
|
||||
"""Live Preview des generierten AI Schemas für einen Artikel"""
|
||||
# Hier würde das AI Schema für den Artikel generiert und angezeigt
|
||||
return render_template('schema_preview.html', article_id=article_id)
|
||||
|
||||
if __name__ == '__main__':
|
||||
# Development Server - NUR für Testing!
|
||||
app.run(host='127.0.0.1', port=5000, debug=True)
|
||||
Executable
+346
@@ -0,0 +1,346 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
🤖 AI Shopping Schema Generator - Intelectra
|
||||
Erzeugt KI-optimierte JSON-LD Schemas für bessere AI-Findbarkeit
|
||||
|
||||
SICHER: Läuft komplett isoliert, keine Live-Shop Auswirkungen!
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import re
|
||||
from datetime import datetime
|
||||
import os
|
||||
|
||||
class AIShoppingSchemaGenerator:
|
||||
def __init__(self):
|
||||
self.base_url = "https://intelectra.de"
|
||||
self.safety_icon_base = "/themes/theme2/media/images/safety/"
|
||||
|
||||
def generate_schema(self, item_data):
|
||||
"""Erzeugt KI-optimiertes Schema für einen Artikel"""
|
||||
try:
|
||||
schema = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Product",
|
||||
"name": item_data.get('name', ''),
|
||||
"identifier": f"intelectra-{item_data.get('item_id', '')}",
|
||||
"category": "Elektro-Ersatzteil",
|
||||
"url": f"{self.base_url}/artikel/{item_data.get('item_id', '')}",
|
||||
|
||||
# Timestamp für Monitoring
|
||||
"_meta": {
|
||||
"generated": datetime.now().isoformat(),
|
||||
"generator": "AI Shopping Schema v1.0",
|
||||
"source": "intelectra_live_shop"
|
||||
}
|
||||
}
|
||||
|
||||
# Sicherheitshinweise hinzufügen (wenn vorhanden)
|
||||
if item_data.get('warnings'):
|
||||
schema["safetyConsiderations"] = self.build_safety_schema(item_data['warnings'])
|
||||
|
||||
# Problem-Solution-Mapping (Smart Feature!)
|
||||
schema["solves"] = self.build_problem_solutions(item_data)
|
||||
|
||||
# Kompatibilitäts-Informationen
|
||||
if item_data.get('attributes'):
|
||||
schema["compatibleWith"] = self.build_compatibility_schema(item_data['attributes'])
|
||||
|
||||
# Installations-Hinweise
|
||||
schema["installationHints"] = self.generate_installation_hints(item_data)
|
||||
|
||||
return schema
|
||||
|
||||
except Exception as e:
|
||||
self.log_error(f"Schema generation failed: {str(e)}")
|
||||
return None
|
||||
|
||||
def build_safety_schema(self, warnings):
|
||||
"""Konvertiert Sicherheitshinweise in KI-optimiertes Format"""
|
||||
safety_considerations = []
|
||||
|
||||
for warning in warnings:
|
||||
consideration = {
|
||||
"@type": "SafetyConsideration",
|
||||
"name": warning.get('name', ''),
|
||||
"description": warning.get('beschreibung', ''),
|
||||
"warningLevel": self.detect_warning_level(warning.get('name', '')),
|
||||
"iconPath": f"{self.safety_icon_base}{warning.get('image_filename', '')}"
|
||||
}
|
||||
|
||||
# Intelligente Kategorisierung
|
||||
if "elektrisch" in warning.get('name', '').lower():
|
||||
consideration["category"] = "electrical_hazard"
|
||||
consideration["preventiveMeasures"] = ["Netzstecker ziehen", "Spannungsfreiheit prüfen"]
|
||||
elif "quetsch" in warning.get('name', '').lower():
|
||||
consideration["category"] = "mechanical_hazard"
|
||||
consideration["preventiveMeasures"] = ["Schutzhandschuhe tragen", "Vorsichtig arbeiten"]
|
||||
|
||||
safety_considerations.append(consideration)
|
||||
|
||||
return safety_considerations
|
||||
|
||||
def build_problem_solutions(self, item_data):
|
||||
"""🚀 UNIVERSAL PROBLEM-SOLUTION ENGINE - Der komplette Motor!"""
|
||||
name = item_data.get('name', '').lower()
|
||||
solutions = []
|
||||
|
||||
# 🚰 WASSERSYSTEM - Pumpen, Schläuche, Ventile
|
||||
if any(word in name for word in ['pumpe', 'pump', 'ablaufpumpe', 'laugenpumpe']):
|
||||
solutions.append({
|
||||
"@type": "ProblemSolution",
|
||||
"problem": "Wasser läuft nicht ab / Pumpe defekt",
|
||||
"symptoms": ["Gerät pumpt nicht", "Wasser steht", "Ablauf verstopft", "Pumpe brummt", "E20 Fehler", "E03 Fehler", "F03 Fehler", "OE Fehler", "5E Fehler"],
|
||||
"urgencyLevel": "HIGH",
|
||||
"repairComplexity": "MEDIUM",
|
||||
"problemKeywords": ["pumpe defekt", "wasser läuft nicht ab", "ablauf verstopft", "e20 fehler", "pumpe brummt", "f03 fehler"]
|
||||
})
|
||||
|
||||
if any(word in name for word in ['schlauch', 'aquastop', 'zulaufschlauch', 'ablaufschlauch']):
|
||||
solutions.append({
|
||||
"@type": "ProblemSolution",
|
||||
"problem": "Wasserschlauch defekt / Undichtigkeit",
|
||||
"symptoms": ["Wasser tropft", "Schlauch porös", "Undichtigkeit", "Aquastop löst aus", "E10 Fehler", "F17 Fehler"],
|
||||
"urgencyLevel": "HIGH",
|
||||
"repairComplexity": "EASY",
|
||||
"problemKeywords": ["schlauch kaputt", "wasser tropft", "undicht", "aquastop piepst", "e10 fehler"]
|
||||
})
|
||||
|
||||
# 🔥 HEIZSYSTEM - Heizstäbe, Thermostate, NTC
|
||||
if any(word in name for word in ['heizstab', 'heizung', 'thermostat', 'ntc', 'temperaturfühler']):
|
||||
solutions.append({
|
||||
"@type": "ProblemSolution",
|
||||
"problem": "Gerät heizt nicht / Temperaturproblem",
|
||||
"symptoms": ["Kein warmes Wasser", "Geschirr bleibt kalt", "Heizung defekt", "E15 Fehler", "F25 Fehler", "E01 Fehler"],
|
||||
"urgencyLevel": "MEDIUM",
|
||||
"repairComplexity": "MEDIUM",
|
||||
"problemKeywords": ["heizt nicht", "kein warmes wasser", "heizstab defekt", "e15 fehler", "f25 fehler"]
|
||||
})
|
||||
|
||||
# ⚡ MOTOREN - Antriebsmotoren, Umwälzpumpen
|
||||
if any(word in name for word in ['motor', 'antrieb', 'antriebsmotor', 'umwälzpumpe']):
|
||||
solutions.append({
|
||||
"@type": "ProblemSolution",
|
||||
"problem": "Motor dreht nicht / Antrieb defekt",
|
||||
"symptoms": ["Trommel dreht nicht", "Motor brummt", "Gerät startet nicht", "F21 Fehler", "E02 Fehler", "F34 Fehler"],
|
||||
"urgencyLevel": "HIGH",
|
||||
"repairComplexity": "HARD",
|
||||
"problemKeywords": ["motor defekt", "trommel dreht nicht", "motor brummt", "f21 fehler", "antrieb kaputt"]
|
||||
})
|
||||
|
||||
# 🚪 TÜRSYSTEM - Türschloss, Türdichtung, Türgriff
|
||||
if any(word in name for word in ['türschloss', 'türgriff', 'türdichtung', 'door lock', 'handle']):
|
||||
solutions.append({
|
||||
"@type": "ProblemSolution",
|
||||
"problem": "Tür schließt nicht / Türproblem",
|
||||
"symptoms": ["Tür geht nicht zu", "Türschloss defekt", "Wasser tropft aus Tür", "E01 Fehler", "F16 Fehler"],
|
||||
"urgencyLevel": "MEDIUM",
|
||||
"repairComplexity": "EASY",
|
||||
"problemKeywords": ["tür geht nicht zu", "türschloss defekt", "türgriff kaputt", "e01 fehler"]
|
||||
})
|
||||
|
||||
# ⚙️ MECHANIK - Stoßdämpfer, Federn, Lager, Riemen
|
||||
if any(word in name for word in ['stoßdämpfer', 'feder', 'lager', 'riemen', 'keilriemen']):
|
||||
solutions.append({
|
||||
"@type": "ProblemSolution",
|
||||
"problem": "Mechanik defekt / Geräusche beim Betrieb",
|
||||
"symptoms": ["Komische Geräusche", "Gerät wackelt", "Vibrationen", "Quietschen", "Schleifen"],
|
||||
"urgencyLevel": "MEDIUM",
|
||||
"repairComplexity": "MEDIUM",
|
||||
"problemKeywords": ["komische geräusche", "gerät wackelt", "quietscht", "schleift", "vibriert"]
|
||||
})
|
||||
|
||||
# 🔌 ELEKTRONIK - Platinen, Sensoren, Timer
|
||||
if any(word in name for word in ['platine', 'steuerung', 'elektronik', 'sensor', 'timer', 'display']):
|
||||
solutions.append({
|
||||
"@type": "ProblemSolution",
|
||||
"problem": "Elektronik defekt / Steuerungsproblem",
|
||||
"symptoms": ["Display zeigt Fehler", "Programm startet nicht", "Tasten reagieren nicht", "F-Fehler", "E-Fehler"],
|
||||
"urgencyLevel": "HIGH",
|
||||
"repairComplexity": "HARD",
|
||||
"problemKeywords": ["display defekt", "steuerung kaputt", "f fehler", "e fehler", "platine defekt"]
|
||||
})
|
||||
|
||||
# 🧽 FILTER & REINIGUNG
|
||||
if any(word in name for word in ['filter', 'sieb', 'flusensieb', 'wasserfilter']):
|
||||
solutions.append({
|
||||
"@type": "ProblemSolution",
|
||||
"problem": "Filter verstopft / Reinigungsproblem",
|
||||
"symptoms": ["Schlechte Waschleistung", "Filter verstopft", "Geruch", "Wasser trüb"],
|
||||
"urgencyLevel": "LOW",
|
||||
"repairComplexity": "EASY",
|
||||
"problemKeywords": ["filter verstopft", "schlechte waschleistung", "geruch", "flusensieb"]
|
||||
})
|
||||
|
||||
# 💡 BELEUCHTUNG - Lampen, LEDs
|
||||
if any(word in name for word in ['lampe', 'led', 'birne', 'leuchte', 'beleuchtung']):
|
||||
solutions.append({
|
||||
"@type": "ProblemSolution",
|
||||
"problem": "Beleuchtung defekt / Licht geht nicht",
|
||||
"symptoms": ["Licht geht nicht an", "LED defekt", "Birne kaputt", "Dunkel im Gerät"],
|
||||
"urgencyLevel": "LOW",
|
||||
"repairComplexity": "EASY",
|
||||
"problemKeywords": ["licht geht nicht", "led defekt", "birne kaputt", "beleuchtung aus"]
|
||||
})
|
||||
|
||||
return solutions
|
||||
|
||||
def build_compatibility_schema(self, attributes):
|
||||
"""Extrahiert Kompatibilitäts-Informationen aus Attributen"""
|
||||
compatible_brands = []
|
||||
|
||||
# Pattern für bekannte Marken (Intelectra-optimiert)
|
||||
brand_patterns = {
|
||||
'bsh': ['siemens', 'bosch', 'neff', 'gaggenau', 'constructa'],
|
||||
'whirlpool': ['whirlpool', 'bauknecht', 'privileg', 'ignis'],
|
||||
'electrolux': ['electrolux', 'aeg', 'zanussi'],
|
||||
'miele': ['miele'],
|
||||
'liebherr': ['liebherr'],
|
||||
'amica': ['amica', 'hansa']
|
||||
}
|
||||
|
||||
# Suche nach Marken in Attributen
|
||||
for attr_key, attr_value in attributes.items():
|
||||
if isinstance(attr_value, str):
|
||||
for brand_group, brands in brand_patterns.items():
|
||||
if any(brand in attr_value.lower() for brand in brands):
|
||||
compatible_brands.extend(brands)
|
||||
|
||||
return {
|
||||
"brands": list(set(compatible_brands)),
|
||||
"applianceTypes": self.detect_appliance_types(attributes)
|
||||
}
|
||||
|
||||
def detect_appliance_types(self, attributes):
|
||||
"""Erkennt Gerätetypen aus Attributen"""
|
||||
types = []
|
||||
|
||||
# Pattern Recognition für Gerätetypen
|
||||
type_keywords = {
|
||||
"Waschmaschine": ["waschmaschine", "washing", "wäsche"],
|
||||
"Geschirrspüler": ["geschirrspüler", "dishwasher", "spülmaschine"],
|
||||
"Kühlschrank": ["kühlschrank", "refrigerator", "kühl"],
|
||||
"Backofen": ["backofen", "oven", "herd"],
|
||||
"Trockner": ["trockner", "wäschetrockner", "dryer"]
|
||||
}
|
||||
|
||||
for attr_value in attributes.values():
|
||||
if isinstance(attr_value, str):
|
||||
for appliance, keywords in type_keywords.items():
|
||||
if any(keyword in attr_value.lower() for keyword in keywords):
|
||||
types.append(appliance)
|
||||
|
||||
return list(set(types))
|
||||
|
||||
def generate_installation_hints(self, item_data):
|
||||
"""Generiert intelligente Installations-Hinweise"""
|
||||
name = item_data.get('name', '').lower()
|
||||
|
||||
if 'schlauch' in name:
|
||||
return {
|
||||
"difficulty": "Einfach - ohne Fachmann machbar",
|
||||
"timeRequired": "5-10 Minuten",
|
||||
"toolsNeeded": ["Zange", "Schraubendreher"],
|
||||
"safetyNote": "Wasser abstellen vor Montage"
|
||||
}
|
||||
elif 'pumpe' in name:
|
||||
return {
|
||||
"difficulty": "Mittel - handwerkliches Geschick nötig",
|
||||
"timeRequired": "30-45 Minuten",
|
||||
"toolsNeeded": ["Schraubendreher", "Zange", "Multimeter"],
|
||||
"safetyNote": "Strom abstellen! Gerät vom Netz trennen"
|
||||
}
|
||||
elif 'heizstab' in name:
|
||||
return {
|
||||
"difficulty": "Schwer - Fachmann empfohlen",
|
||||
"timeRequired": "60-90 Minuten",
|
||||
"toolsNeeded": ["Multimeter", "Spezialwerkzeug"],
|
||||
"safetyNote": "⚠️ HOCHSPANNUNG! Strom komplett abschalten"
|
||||
}
|
||||
|
||||
return {
|
||||
"difficulty": "Mittlere Schwierigkeit",
|
||||
"timeRequired": "15-30 Minuten",
|
||||
"safetyNote": "Sicherheitshinweise beachten"
|
||||
}
|
||||
|
||||
def detect_warning_level(self, warning_name):
|
||||
"""Intelligente Warnstufen-Erkennung"""
|
||||
name_lower = warning_name.lower()
|
||||
|
||||
if any(word in name_lower for word in ['elektrisch', 'strom', 'spannung']):
|
||||
return "CRITICAL"
|
||||
elif any(word in name_lower for word in ['heiß', 'temperatur', 'verbrennung']):
|
||||
return "HIGH"
|
||||
elif any(word in name_lower for word in ['quetsch', 'verletzung']):
|
||||
return "MEDIUM"
|
||||
else:
|
||||
return "LOW"
|
||||
|
||||
def save_schema(self, schema, item_id):
|
||||
"""Speichert Schema für späteren Abruf (optional)"""
|
||||
try:
|
||||
schema_dir = "/var/www/vhosts/intelectra.de/httpdocs/core/python/logs"
|
||||
os.makedirs(schema_dir, exist_ok=True)
|
||||
schema_file = f"{schema_dir}/schema_{item_id}.json"
|
||||
|
||||
with open(schema_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(schema, f, indent=2, ensure_ascii=False)
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
self.log_error(f"Schema save failed: {str(e)}")
|
||||
return False
|
||||
|
||||
def log_error(self, message):
|
||||
"""Fehler-Logging"""
|
||||
try:
|
||||
log_dir = "/var/www/vhosts/intelectra.de/httpdocs/core/python/logs"
|
||||
os.makedirs(log_dir, exist_ok=True)
|
||||
log_file = f"{log_dir}/ai_schema.log"
|
||||
timestamp = datetime.now().isoformat()
|
||||
with open(log_file, 'a', encoding='utf-8') as f:
|
||||
f.write(f"{timestamp} ERROR: {message}\n")
|
||||
except:
|
||||
pass # Silent fail für Live-Shop
|
||||
|
||||
def main():
|
||||
"""Hauptfunktion - wird von PHP aufgerufen"""
|
||||
if len(sys.argv) < 2:
|
||||
print(json.dumps({"error": "No input data provided"}))
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
# Input von PHP parsen
|
||||
input_data = json.loads(sys.argv[1])
|
||||
|
||||
# Schema Generator initialisieren
|
||||
generator = AIShoppingSchemaGenerator()
|
||||
|
||||
# Schema erzeugen
|
||||
schema = generator.generate_schema(input_data)
|
||||
|
||||
if schema:
|
||||
# Optional: Schema speichern
|
||||
generator.save_schema(schema, input_data.get('item_id', 'unknown'))
|
||||
|
||||
# Erfolg zurückgeben
|
||||
result = {
|
||||
"success": True,
|
||||
"schema_generated": True,
|
||||
"item_id": input_data.get('item_id'),
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
else:
|
||||
result = {"success": False, "error": "Schema generation failed"}
|
||||
|
||||
print(json.dumps(result))
|
||||
|
||||
except Exception as e:
|
||||
error_result = {"success": False, "error": str(e)}
|
||||
print(json.dumps(error_result))
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
/**
|
||||
* 🕵️ AI Visitor Tracker Integration für Intelectra Shop
|
||||
* Erkennt KI-Besucher und loggt sie automatisch
|
||||
*
|
||||
* USAGE: Include in item.class.php oder header.php
|
||||
*/
|
||||
|
||||
class AIVisitorTracker {
|
||||
|
||||
private $flask_dashboard_url = 'http://127.0.0.1:5000';
|
||||
|
||||
public function trackVisitor() {
|
||||
// Visitor-Daten sammeln
|
||||
$visitor_data = [
|
||||
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
|
||||
'url' => $_SERVER['REQUEST_URI'] ?? '',
|
||||
'ip_address' => $this->getRealIPAddress(),
|
||||
'referer' => $_SERVER['HTTP_REFERER'] ?? '',
|
||||
'timestamp' => date('Y-m-d H:i:s')
|
||||
];
|
||||
|
||||
// Async call zum Flask Dashboard (non-blocking)
|
||||
$this->sendToFlaskDashboard($visitor_data);
|
||||
}
|
||||
|
||||
private function getRealIPAddress() {
|
||||
// Echte IP ermitteln (auch hinter Proxies)
|
||||
$ip_headers = [
|
||||
'HTTP_CF_CONNECTING_IP', // Cloudflare
|
||||
'HTTP_CLIENT_IP', // Proxy
|
||||
'HTTP_X_FORWARDED_FOR', // Load Balancer
|
||||
'HTTP_X_FORWARDED',
|
||||
'HTTP_X_CLUSTER_CLIENT_IP',
|
||||
'HTTP_FORWARDED_FOR',
|
||||
'HTTP_FORWARDED',
|
||||
'REMOTE_ADDR' // Standard
|
||||
];
|
||||
|
||||
foreach ($ip_headers as $header) {
|
||||
if (!empty($_SERVER[$header])) {
|
||||
$ip = $_SERVER[$header];
|
||||
// Bei mehreren IPs die erste nehmen
|
||||
if (strpos($ip, ',') !== false) {
|
||||
$ip = trim(explode(',', $ip)[0]);
|
||||
}
|
||||
// IP validieren
|
||||
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
|
||||
return $ip;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $_SERVER['REMOTE_ADDR'] ?? 'unknown';
|
||||
}
|
||||
|
||||
private function sendToFlaskDashboard($data) {
|
||||
// Non-blocking cURL request zum Flask Dashboard
|
||||
$ch = curl_init();
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_URL => $this->flask_dashboard_url . '/api/detect-visitor',
|
||||
CURLOPT_POST => true,
|
||||
CURLOPT_POSTFIELDS => json_encode($data),
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Content-Type: application/json',
|
||||
'User-Agent: Intelectra-AI-Tracker/1.0'
|
||||
],
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => 2, // Max 2 Sekunden warten
|
||||
CURLOPT_CONNECTTIMEOUT => 1, // Max 1 Sekunde für Verbindung
|
||||
CURLOPT_FOLLOWLOCATION => false,
|
||||
CURLOPT_SSL_VERIFYPEER => false
|
||||
]);
|
||||
|
||||
// Async ausführen (non-blocking)
|
||||
$this->execInBackground($ch);
|
||||
}
|
||||
|
||||
private function execInBackground($ch) {
|
||||
// cURL im Hintergrund ausführen ohne auf Antwort zu warten
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT_MS, 100); // Sehr kurzer Timeout
|
||||
@curl_exec($ch); // @ um Fehler zu unterdrücken
|
||||
curl_close($ch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Intelligente KI-Erkennung (falls Flask nicht verfügbar)
|
||||
*/
|
||||
public function detectAILocally($user_agent) {
|
||||
$ai_patterns = [
|
||||
'ChatGPT' => ['GPTBot', 'ChatGPT-User', 'OpenAI', 'gpt-crawler'],
|
||||
'Claude' => ['Claude-Web', 'Anthropic', 'claude.ai'],
|
||||
'Gemini' => ['Google-Extended', 'Bard', 'Gemini', 'GoogleOther'],
|
||||
'Perplexity' => ['PerplexityBot', 'perplexity.ai'],
|
||||
'Bing AI' => ['BingBot', 'EdgeBot', 'bing.com/chat'],
|
||||
'Meta AI' => ['FacebookBot', 'facebookexternalhit'],
|
||||
'You.com' => ['YouBot'],
|
||||
'SearchGPT' => ['SearchGPT', 'OpenAI-SearchBot']
|
||||
];
|
||||
|
||||
$user_agent_lower = strtolower($user_agent);
|
||||
|
||||
foreach ($ai_patterns as $ai_name => $patterns) {
|
||||
foreach ($patterns as $pattern) {
|
||||
if (strpos($user_agent_lower, strtolower($pattern)) !== false) {
|
||||
return $ai_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log AI-Besuch direkt in MySQL (Fallback)
|
||||
*/
|
||||
public function logAIVisitDirectly($ai_name, $visitor_data) {
|
||||
try {
|
||||
// DB-Verbindung (hier deine DB-Credentials einsetzen)
|
||||
$pdo = new PDO(
|
||||
'mysql:host=localhost;dbname=intelectra_problems;charset=utf8mb4',
|
||||
'ai_schema_user',
|
||||
'your_password_here'
|
||||
);
|
||||
|
||||
// Artikel-ID aus URL extrahieren
|
||||
$article_id = null;
|
||||
if (preg_match('/\/artikel\/(\d+)/', $visitor_data['url'], $matches)) {
|
||||
$article_id = intval($matches[1]);
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO ai_visitor_log
|
||||
(ai_name, url, article_id, user_agent, ip_address, referer, visited_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, NOW())
|
||||
");
|
||||
|
||||
$stmt->execute([
|
||||
$ai_name,
|
||||
$visitor_data['url'],
|
||||
$article_id,
|
||||
$visitor_data['user_agent'],
|
||||
$visitor_data['ip_address'],
|
||||
$visitor_data['referer']
|
||||
]);
|
||||
|
||||
return true;
|
||||
|
||||
} catch (Exception $e) {
|
||||
// Silent fail - Live Shop darf nicht gestört werden
|
||||
error_log("AI Tracking failed: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Public API für Integration in Shop
|
||||
*/
|
||||
public static function track() {
|
||||
$tracker = new self();
|
||||
$tracker->trackVisitor();
|
||||
}
|
||||
|
||||
public static function isAI($user_agent) {
|
||||
$tracker = new self();
|
||||
return $tracker->detectAILocally($user_agent);
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-Track wenn direkt aufgerufen
|
||||
if (basename(__FILE__) == basename($_SERVER['SCRIPT_NAME'])) {
|
||||
AIVisitorTracker::track();
|
||||
}
|
||||
|
||||
/**
|
||||
* INTEGRATION BEISPIELE:
|
||||
*
|
||||
* 1. In item.class.php am Ende von buildSingleItem():
|
||||
* require_once 'ai_tracker_integration.php';
|
||||
* AIVisitorTracker::track();
|
||||
*
|
||||
* 2. In header.php/index.php:
|
||||
* include_once 'core/python/ai_tracker_integration.php';
|
||||
* AIVisitorTracker::track();
|
||||
*
|
||||
* 3. Als separater Tracker:
|
||||
* $ai_name = AIVisitorTracker::isAI($_SERVER['HTTP_USER_AGENT']);
|
||||
* if ($ai_name) {
|
||||
* echo "<!-- AI erkannt: $ai_name -->";
|
||||
* }
|
||||
*/
|
||||
?>
|
||||
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
🔧 Configuration für Enhanced AI Schema Generator
|
||||
Sichere DB-Konfiguration für Live-Shop
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
# Database Configuration
|
||||
# Diese Werte sollten in einer sicheren Umgebung gesetzt werden
|
||||
DB_CONFIG = {
|
||||
'host': os.getenv('DB_HOST', 'localhost'),
|
||||
'database': os.getenv('DB_NAME', 'intelectra_problems'), # Separate DB für Probleme
|
||||
'user': os.getenv('DB_USER', 'ai_schema_user'),
|
||||
'password': os.getenv('DB_PASSWORD', ''),
|
||||
'charset': 'utf8mb4',
|
||||
'use_unicode': True,
|
||||
'autocommit': True
|
||||
}
|
||||
|
||||
# Fallback-Modus aktivieren falls DB nicht verfügbar
|
||||
ENABLE_FALLBACK = True
|
||||
|
||||
# Logging Configuration
|
||||
LOG_DIR = "/var/www/vhosts/intelectra.de/httpdocs/core/python/logs"
|
||||
SCHEMA_SAVE_DIR = "/var/www/vhosts/intelectra.de/httpdocs/core/python/logs"
|
||||
|
||||
# API Configuration
|
||||
BASE_URL = "https://intelectra.de"
|
||||
SAFETY_ICON_BASE = "/web/intelectra_shop/themes/theme2/media/images/safety/"
|
||||
@@ -0,0 +1,148 @@
|
||||
-- 🕵️ AI Visitor Tracking Database Schema
|
||||
-- Trackt welche KI wann welche Artikel besucht
|
||||
|
||||
-- Haupt-Tabelle: AI Visitor Log
|
||||
CREATE TABLE ai_visitor_log (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
ai_name VARCHAR(50) NOT NULL, -- 'ChatGPT', 'Claude', 'Gemini', etc.
|
||||
url VARCHAR(500) NOT NULL, -- Besuchte URL
|
||||
article_id INT NULL, -- Extrahierte Artikel-ID (falls Artikel-Seite)
|
||||
user_agent TEXT, -- Kompletter User-Agent String
|
||||
ip_address VARCHAR(45), -- IP (IPv4/IPv6)
|
||||
referer VARCHAR(500), -- Referer URL
|
||||
visited_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
-- Indizes für Performance
|
||||
INDEX idx_ai_name (ai_name),
|
||||
INDEX idx_article_id (article_id),
|
||||
INDEX idx_visited_at (visited_at),
|
||||
INDEX idx_ai_article (ai_name, article_id)
|
||||
);
|
||||
|
||||
-- AI Performance Stats (aggregierte Daten)
|
||||
CREATE TABLE ai_performance_stats (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
ai_name VARCHAR(50) NOT NULL,
|
||||
article_id INT NOT NULL,
|
||||
visit_count INT DEFAULT 1,
|
||||
first_visit TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
last_visit TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
conversion_count INT DEFAULT 0, -- Spätere Erweiterung für Kaufabschlüsse
|
||||
|
||||
UNIQUE KEY unique_ai_article (ai_name, article_id),
|
||||
INDEX idx_ai_performance (ai_name, visit_count DESC)
|
||||
);
|
||||
|
||||
-- AI Schema Generation Log
|
||||
CREATE TABLE ai_schema_generation_log (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
article_id INT NOT NULL,
|
||||
schema_type ENUM('product', 'problem_solution', 'safety') NOT NULL,
|
||||
generated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
generation_time_ms INT, -- Performance Monitoring
|
||||
problems_found INT DEFAULT 0, -- Anzahl gefundener Probleme
|
||||
schema_size_kb DECIMAL(6,2), -- Schema-Größe in KB
|
||||
success BOOLEAN DEFAULT TRUE,
|
||||
error_message TEXT NULL,
|
||||
|
||||
INDEX idx_article_generation (article_id, generated_at),
|
||||
INDEX idx_performance (generation_time_ms, generated_at)
|
||||
);
|
||||
|
||||
-- User-Agent Patterns für bessere KI-Erkennung
|
||||
CREATE TABLE ai_detection_patterns (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
ai_name VARCHAR(50) NOT NULL,
|
||||
pattern VARCHAR(200) NOT NULL,
|
||||
pattern_type ENUM('user_agent', 'referer', 'ip_range') DEFAULT 'user_agent',
|
||||
confidence_score DECIMAL(3,2) DEFAULT 1.0, -- 0.0 - 1.0 Wahrscheinlichkeit
|
||||
active BOOLEAN DEFAULT TRUE,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
last_matched TIMESTAMP NULL,
|
||||
match_count INT DEFAULT 0,
|
||||
|
||||
INDEX idx_ai_patterns (ai_name, active),
|
||||
INDEX idx_pattern_type (pattern_type)
|
||||
);
|
||||
|
||||
-- Initial AI Detection Patterns
|
||||
INSERT INTO ai_detection_patterns (ai_name, pattern, pattern_type, confidence_score) VALUES
|
||||
-- ChatGPT/OpenAI
|
||||
('ChatGPT', 'GPTBot', 'user_agent', 1.0),
|
||||
('ChatGPT', 'ChatGPT-User', 'user_agent', 1.0),
|
||||
('ChatGPT', 'OpenAI', 'user_agent', 0.9),
|
||||
('ChatGPT', 'gpt-crawler', 'user_agent', 0.8),
|
||||
|
||||
-- Claude/Anthropic
|
||||
('Claude', 'Claude-Web', 'user_agent', 1.0),
|
||||
('Claude', 'Anthropic', 'user_agent', 0.9),
|
||||
('Claude', 'claude.ai', 'referer', 1.0),
|
||||
|
||||
-- Google Gemini/Bard
|
||||
('Gemini', 'Google-Extended', 'user_agent', 1.0),
|
||||
('Gemini', 'Bard', 'user_agent', 1.0),
|
||||
('Gemini', 'Gemini', 'user_agent', 1.0),
|
||||
('Gemini', 'GoogleOther', 'user_agent', 0.7),
|
||||
('Gemini', 'bard.google.com', 'referer', 1.0),
|
||||
|
||||
-- Perplexity
|
||||
('Perplexity', 'PerplexityBot', 'user_agent', 1.0),
|
||||
('Perplexity', 'perplexity.ai', 'referer', 1.0),
|
||||
|
||||
-- Microsoft Bing AI
|
||||
('Bing AI', 'BingBot', 'user_agent', 0.8),
|
||||
('Bing AI', 'EdgeBot', 'user_agent', 0.9),
|
||||
('Bing AI', 'bing.com/chat', 'referer', 1.0),
|
||||
|
||||
-- Meta AI
|
||||
('Meta AI', 'FacebookBot', 'user_agent', 0.7),
|
||||
('Meta AI', 'facebookexternalhit', 'user_agent', 0.8),
|
||||
|
||||
-- Weitere aufkommende KIs
|
||||
('You.com', 'YouBot', 'user_agent', 1.0),
|
||||
('SearchGPT', 'SearchGPT', 'user_agent', 1.0),
|
||||
('SearchGPT', 'OpenAI-SearchBot', 'user_agent', 1.0);
|
||||
|
||||
-- Trigger für automatische Performance Stats Update
|
||||
DELIMITER $$
|
||||
CREATE TRIGGER update_ai_performance_stats
|
||||
AFTER INSERT ON ai_visitor_log
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
IF NEW.article_id IS NOT NULL THEN
|
||||
INSERT INTO ai_performance_stats (ai_name, article_id, visit_count, first_visit, last_visit)
|
||||
VALUES (NEW.ai_name, NEW.article_id, 1, NEW.visited_at, NEW.visited_at)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
visit_count = visit_count + 1,
|
||||
last_visit = NEW.visited_at;
|
||||
END IF;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
-- View für Dashboard: Tägliche AI Stats
|
||||
CREATE VIEW daily_ai_stats AS
|
||||
SELECT
|
||||
DATE(visited_at) as visit_date,
|
||||
ai_name,
|
||||
COUNT(*) as total_visits,
|
||||
COUNT(DISTINCT ip_address) as unique_visitors,
|
||||
COUNT(DISTINCT article_id) as articles_visited,
|
||||
AVG(CASE WHEN article_id IS NOT NULL THEN 1 ELSE 0 END) as article_visit_rate
|
||||
FROM ai_visitor_log
|
||||
WHERE visited_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)
|
||||
GROUP BY DATE(visited_at), ai_name
|
||||
ORDER BY visit_date DESC, total_visits DESC;
|
||||
|
||||
-- View für Top AI-besuchte Artikel
|
||||
CREATE VIEW top_ai_articles AS
|
||||
SELECT
|
||||
article_id,
|
||||
SUM(visit_count) as total_ai_visits,
|
||||
COUNT(DISTINCT ai_name) as different_ais,
|
||||
GROUP_CONCAT(DISTINCT ai_name ORDER BY visit_count DESC) as top_ais,
|
||||
MAX(last_visit) as latest_ai_visit
|
||||
FROM ai_performance_stats
|
||||
WHERE article_id IS NOT NULL
|
||||
GROUP BY article_id
|
||||
ORDER BY total_ai_visits DESC
|
||||
LIMIT 50;
|
||||
@@ -0,0 +1,274 @@
|
||||
-- 🗄️ Problem-FAQ-Database Creation Script - Intelectra AI Schema System
|
||||
-- Erzeugt dynamische Problem-Solution-Datenbank für KI-Optimierung
|
||||
|
||||
-- Haupt-Tabelle: problem_solutions
|
||||
CREATE TABLE problem_solutions (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
|
||||
-- Problem-Kategorisierung
|
||||
problem_category ENUM(
|
||||
'heating', 'pumping', 'door_system', 'motor_drive',
|
||||
'electronics', 'mechanical', 'filters', 'lighting',
|
||||
'water_system', 'drainage'
|
||||
) NOT NULL,
|
||||
|
||||
-- Problem-Definition
|
||||
problem_title VARCHAR(200) NOT NULL,
|
||||
problem_description TEXT,
|
||||
|
||||
-- Symptome & Erkennungsmerkmale
|
||||
symptoms JSON NOT NULL, -- ["Geschirr bleibt kalt", "Kein warmes Wasser"]
|
||||
error_codes JSON, -- ["E15", "F25", "F21"]
|
||||
keywords JSON NOT NULL, -- ["heizt nicht", "kein warmes wasser", "heizstab"]
|
||||
alternative_keywords JSON, -- ["temperatur", "warm", "erhitzen"]
|
||||
|
||||
-- Problem-Eigenschaften
|
||||
urgency_level ENUM('LOW', 'MEDIUM', 'HIGH', 'CRITICAL') DEFAULT 'MEDIUM',
|
||||
repair_complexity ENUM('EASY', 'MEDIUM', 'HARD') DEFAULT 'MEDIUM',
|
||||
frequency_score INT DEFAULT 0, -- Häufigkeit des Problems (für Ranking)
|
||||
|
||||
-- Lösungs-Informationen
|
||||
typical_parts JSON, -- [{"category": "heizstab", "keywords": ["heating", "thermostat"]}]
|
||||
installation_time_min INT, -- Minuten
|
||||
installation_time_max INT, -- Minuten
|
||||
tools_needed JSON, -- ["Schraubendreher", "Multimeter", "Zange"]
|
||||
safety_notes TEXT,
|
||||
difficulty_description VARCHAR(100), -- "Mittel - handwerkliches Geschick nötig"
|
||||
|
||||
-- Meta-Daten
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
active BOOLEAN DEFAULT TRUE
|
||||
);
|
||||
|
||||
-- Erweiterte Tabelle: problem_appliance_mapping
|
||||
CREATE TABLE problem_appliance_mapping (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
problem_id INT,
|
||||
appliance_type ENUM(
|
||||
'waschmaschine', 'geschirrspuler', 'kuhlschrank',
|
||||
'backofen', 'dunstabzug', 'mikrowelle', 'trockner'
|
||||
),
|
||||
brand_compatibility JSON, -- ["bosch", "siemens", "miele"]
|
||||
model_patterns JSON, -- ["SMI*", "WM*", "GSV*"]
|
||||
|
||||
FOREIGN KEY (problem_id) REFERENCES problem_solutions(id)
|
||||
);
|
||||
|
||||
-- Keyword-Optimierung: problem_keywords
|
||||
CREATE TABLE problem_keywords (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
problem_id INT,
|
||||
keyword VARCHAR(100),
|
||||
keyword_type ENUM('primary', 'secondary', 'symptom', 'error_code'),
|
||||
weight DECIMAL(3,2) DEFAULT 1.0, -- Gewichtung für Relevanz
|
||||
language CHAR(2) DEFAULT 'de',
|
||||
|
||||
FOREIGN KEY (problem_id) REFERENCES problem_solutions(id),
|
||||
INDEX idx_keyword (keyword),
|
||||
INDEX idx_type (keyword_type)
|
||||
);
|
||||
|
||||
-- Usage Analytics & Learning
|
||||
CREATE TABLE problem_usage_stats (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
problem_id INT,
|
||||
item_id INT,
|
||||
generated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
ai_model VARCHAR(50), -- 'chatgpt', 'gemini', 'claude'
|
||||
user_feedback ENUM('helpful', 'not_helpful', 'partially_helpful'),
|
||||
|
||||
FOREIGN KEY (problem_id) REFERENCES problem_solutions(id)
|
||||
);
|
||||
|
||||
-- Initial Seed Data: Top 20 häufigste Ersatzteil-Probleme
|
||||
|
||||
-- Problem 1: Heizung defekt (Sehr häufig - 85%)
|
||||
INSERT INTO problem_solutions VALUES (
|
||||
1,
|
||||
'heating',
|
||||
'Geschirrspüler heizt nicht',
|
||||
'Das Gerät spült zwar, aber das Wasser wird nicht warm. Geschirr bleibt verschmutzt und kalt.',
|
||||
|
||||
'["Geschirr bleibt kalt", "Kein warmes Wasser", "Schlechtes Spülergebnis", "Wasser lauwarm"]',
|
||||
'["E15", "F25", "Er:15"]',
|
||||
'["heizt nicht", "kein warmes wasser", "heizstab", "thermostat", "ntc"]',
|
||||
'["temperatur", "warm", "erhitzen", "heizelement", "heizpumpe"]',
|
||||
|
||||
'HIGH',
|
||||
'MEDIUM',
|
||||
85, -- Sehr häufiges Problem
|
||||
|
||||
'[{"category": "heizstab", "keywords": ["heizstab", "heating", "thermostat"]},
|
||||
{"category": "ntc", "keywords": ["ntc", "temperaturfühler", "sensor"]}]',
|
||||
45, 90,
|
||||
'["Schraubendreher", "Multimeter", "Zange"]',
|
||||
'⚠️ STROM ABSCHALTEN! Gerät vom Netz trennen vor Reparatur.',
|
||||
'Mittel - handwerkliches Geschick nötig'
|
||||
);
|
||||
|
||||
-- Problem 2: Pumpe defekt (Sehr häufig - 92%)
|
||||
INSERT INTO problem_solutions VALUES (
|
||||
2,
|
||||
'pumping',
|
||||
'Wasser läuft nicht ab / Pumpe defekt',
|
||||
'Das Gerät pumpt das Wasser nicht ab, Wasser steht in der Maschine.',
|
||||
|
||||
'["Wasser steht", "Gerät pumpt nicht", "Ablauf verstopft", "Pumpe brummt", "Seltsame Geräusche"]',
|
||||
'["E20", "E03", "F03", "Er:03"]',
|
||||
'["pumpe defekt", "wasser läuft nicht ab", "ablaufpumpe", "laugenpumpe"]',
|
||||
'["drainage", "pump", "water", "ablauf", "entwässerung"]',
|
||||
|
||||
'HIGH',
|
||||
'MEDIUM',
|
||||
92, -- Sehr häufig
|
||||
|
||||
'[{"category": "pumpe", "keywords": ["pumpe", "pump", "ablaufpumpe", "laugenpumpe"]}]',
|
||||
30, 60,
|
||||
'["Schraubendreher", "Zange", "Eimer", "Handschuhe"]',
|
||||
'Wasser abstellen! Restwasser ablassen vor Ausbau.',
|
||||
'Mittel - Wasserkontakt möglich'
|
||||
);
|
||||
|
||||
-- Problem 3: Türschloss defekt (Häufig - 78%)
|
||||
INSERT INTO problem_solutions VALUES (
|
||||
3,
|
||||
'door_system',
|
||||
'Tür schließt nicht richtig / Türschloss defekt',
|
||||
'Die Gerätetür lässt sich nicht richtig schließen oder das Schloss hakt.',
|
||||
|
||||
'["Tür geht nicht zu", "Türschloss hakt", "Gerät startet nicht", "Türgriff locker"]',
|
||||
'["E01", "Er:01", "F01"]',
|
||||
'["türschloss defekt", "tür geht nicht zu", "türgriff kaputt", "schloss hakt"]',
|
||||
'["door lock", "türschließung", "verschluss", "riegel"]',
|
||||
|
||||
'MEDIUM',
|
||||
'EASY',
|
||||
78,
|
||||
|
||||
'[{"category": "türschloss", "keywords": ["türschloss", "door lock", "türgriff"]}]',
|
||||
15, 30,
|
||||
'["Schraubendreher", "Zange"]',
|
||||
'Gerät ausschalten vor Reparatur.',
|
||||
'Einfach - DIY möglich'
|
||||
);
|
||||
|
||||
-- Problem 4: Motor/Antrieb defekt (Häufig - 65%)
|
||||
INSERT INTO problem_solutions VALUES (
|
||||
4,
|
||||
'motor_drive',
|
||||
'Trommel dreht nicht / Motor defekt',
|
||||
'Der Antriebsmotor funktioniert nicht mehr, Trommel dreht sich nicht.',
|
||||
|
||||
'["Trommel dreht nicht", "Motor brummt nur", "Gerät macht komische Geräusche", "Kein Schleudern"]',
|
||||
'["F21", "E02", "Er:02", "F02"]',
|
||||
'["motor defekt", "trommel dreht nicht", "antrieb kaputt", "motor brummt"]',
|
||||
'["drive motor", "antriebsmotor", "drehmotor", "trommelmotor"]',
|
||||
|
||||
'HIGH',
|
||||
'HARD',
|
||||
65,
|
||||
|
||||
'[{"category": "motor", "keywords": ["motor", "antrieb", "antriebsmotor"]}]',
|
||||
90, 180,
|
||||
'["Multimeter", "Schraubendreher", "Zange", "Spezialwerkzeug"]',
|
||||
'⚠️ STROM ABSCHALTEN! Schweres Teil - Hilfe holen!',
|
||||
'Schwer - Fachmann empfohlen'
|
||||
);
|
||||
|
||||
-- Problem 5: Wasserschlauch undicht (Häufig - 71%)
|
||||
INSERT INTO problem_solutions VALUES (
|
||||
5,
|
||||
'water_system',
|
||||
'Wasserschlauch undicht / Aquastop defekt',
|
||||
'Zulauf- oder Ablaufschlauch ist undicht oder Aquastop löst aus.',
|
||||
|
||||
'["Wasser tropft", "Schlauch undicht", "Aquastop piepst", "Pfütze unter Gerät"]',
|
||||
'["E10", "Er:10", "F10"]',
|
||||
'["schlauch undicht", "wasser tropft", "aquastop defekt", "zulaufschlauch"]',
|
||||
'["water hose", "wasserschlauch", "zulauf", "aquastop"]',
|
||||
|
||||
'HIGH',
|
||||
'EASY',
|
||||
71,
|
||||
|
||||
'[{"category": "schlauch", "keywords": ["schlauch", "hose", "aquastop", "zulauf"]}]',
|
||||
10, 25,
|
||||
'["Zange", "Schraubendreher"]',
|
||||
'Wasserzufuhr abstellen vor Reparatur!',
|
||||
'Einfach - DIY möglich'
|
||||
);
|
||||
|
||||
-- Weitere Top-Probleme...
|
||||
-- Problem 6: Filter verstopft
|
||||
INSERT INTO problem_solutions VALUES (
|
||||
6, 'filters', 'Filter/Flusensieb verstopft',
|
||||
'Filter oder Flusensieb ist verstopft und beeinträchtigt die Leistung.',
|
||||
'["Schlechte Waschleistung", "Geruch", "Wasser läuft schlecht ab", "Filter stinkt"]',
|
||||
'["E18", "Er:18"]',
|
||||
'["filter verstopft", "flusensieb", "sieb verstopft", "schlechte waschleistung"]',
|
||||
'["filter", "lint filter", "sieb", "flusen"]',
|
||||
'MEDIUM', 'EASY', 88,
|
||||
'[{"category": "filter", "keywords": ["filter", "sieb", "flusensieb"]}]',
|
||||
5, 15,
|
||||
'["Handschuhe", "Eimer"]',
|
||||
'Filter regelmäßig reinigen zur Vorbeugung.',
|
||||
'Einfach - regelmäßige Wartung'
|
||||
);
|
||||
|
||||
-- Problem 7: Türdichtung defekt
|
||||
INSERT INTO problem_solutions VALUES (
|
||||
7, 'door_system', 'Türdichtung undicht/beschädigt',
|
||||
'Türdichtung ist porös oder beschädigt, Wasser tritt aus.',
|
||||
'["Wasser läuft aus Tür", "Dichtung porös", "Schimmel an Dichtung", "Gummi rissig"]',
|
||||
NULL,
|
||||
'["türdichtung defekt", "dichtung undicht", "wasser läuft aus", "gummi kaputt"]',
|
||||
'["door seal", "türdichtung", "dichtgummi", "manschette"]',
|
||||
'MEDIUM', 'MEDIUM', 67,
|
||||
'[{"category": "dichtung", "keywords": ["dichtung", "seal", "türdichtung", "manschette"]}]',
|
||||
30, 60,
|
||||
'["Schraubendreher", "Spezialkleber"]',
|
||||
'Gerät komplett trocknen vor Montage.',
|
||||
'Mittel - Geduld erforderlich'
|
||||
);
|
||||
|
||||
-- Problem 8: Thermostat defekt
|
||||
INSERT INTO problem_solutions VALUES (
|
||||
8, 'heating', 'Thermostat/Temperaturfühler defekt',
|
||||
'Temperaturfühler oder Thermostat misst falsche Werte.',
|
||||
'["Falsche Temperatur", "Überhitzung", "Zu kalt", "Temperatur schwankt"]',
|
||||
'["E25", "F25", "Er:25"]',
|
||||
'["thermostat defekt", "temperaturfühler", "ntc defekt", "temperatur falsch"]',
|
||||
'["thermostat", "temperature sensor", "ntc", "fühler"]',
|
||||
'MEDIUM', 'MEDIUM', 58,
|
||||
'[{"category": "thermostat", "keywords": ["thermostat", "ntc", "temperaturfühler"]}]',
|
||||
30, 45,
|
||||
'["Multimeter", "Schraubendreher"]',
|
||||
'Temperatur-Test vor Einbau durchführen.',
|
||||
'Mittel - Messgerät nötig'
|
||||
);
|
||||
|
||||
-- Weitere Keywords für bessere Suche
|
||||
INSERT INTO problem_keywords (problem_id, keyword, keyword_type, weight) VALUES
|
||||
(1, 'heizt nicht', 'primary', 2.0),
|
||||
(1, 'kalt', 'symptom', 1.5),
|
||||
(1, 'e15', 'error_code', 2.0),
|
||||
(2, 'pumpt nicht', 'primary', 2.0),
|
||||
(2, 'wasser steht', 'symptom', 1.8),
|
||||
(2, 'e20', 'error_code', 2.0),
|
||||
(3, 'tür zu', 'primary', 1.8),
|
||||
(3, 'schloss', 'secondary', 1.5),
|
||||
(4, 'dreht nicht', 'primary', 2.0),
|
||||
(4, 'motor', 'primary', 1.9),
|
||||
(5, 'tropft', 'symptom', 1.7),
|
||||
(5, 'aquastop', 'primary', 1.9);
|
||||
|
||||
-- Appliance Mappings für bessere Zuordnung
|
||||
INSERT INTO problem_appliance_mapping (problem_id, appliance_type, brand_compatibility, model_patterns) VALUES
|
||||
(1, 'geschirrspuler', '["bosch", "siemens", "neff", "gaggenau"]', '["SMI*", "SMV*", "SMU*"]'),
|
||||
(2, 'waschmaschine', '["bosch", "siemens", "miele"]', '["WM*", "WA*", "WS*"]'),
|
||||
(2, 'geschirrspuler', '["bosch", "siemens"]', '["SMI*", "SMV*"]'),
|
||||
(3, 'waschmaschine', '["bosch", "siemens", "miele", "amica"]', '["WM*", "WA*"]'),
|
||||
(4, 'waschmaschine', '["bosch", "siemens", "miele"]', '["WM*", "WA*"]'),
|
||||
(5, 'waschmaschine', '["bosch", "siemens", "miele", "amica"]', '["WM*", "WA*"]'),
|
||||
(5, 'geschirrspuler', '["bosch", "siemens"]', '["SMI*", "SMV*"]');
|
||||
@@ -0,0 +1,417 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
🤖 Enhanced AI Shopping Schema Generator - Intelectra
|
||||
Erzeugt KI-optimierte JSON-LD Schemas mit dynamischer Problem-DB-Abfrage
|
||||
|
||||
SICHER: Läuft komplett isoliert, keine Live-Shop Auswirkungen!
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import re
|
||||
import mysql.connector
|
||||
from datetime import datetime
|
||||
import os
|
||||
from config import DB_CONFIG, ENABLE_FALLBACK, BASE_URL, SAFETY_ICON_BASE, LOG_DIR, SCHEMA_SAVE_DIR
|
||||
|
||||
class EnhancedAISchemaGenerator:
|
||||
def __init__(self):
|
||||
self.base_url = BASE_URL
|
||||
self.safety_icon_base = SAFETY_ICON_BASE
|
||||
self.db_connection = None
|
||||
|
||||
# DB-Verbindung herstellen (sichere Fallback-Behandlung)
|
||||
if ENABLE_FALLBACK:
|
||||
try:
|
||||
self.connect_to_database()
|
||||
except Exception as e:
|
||||
self.log_error(f"DB connection failed: {str(e)} - Using fallback mode")
|
||||
|
||||
def connect_to_database(self):
|
||||
"""Sichere DB-Verbindung mit Config-basierter Konfiguration"""
|
||||
try:
|
||||
self.db_connection = mysql.connector.connect(**DB_CONFIG)
|
||||
except mysql.connector.Error as err:
|
||||
self.log_error(f"MySQL connection error: {err}")
|
||||
self.db_connection = None
|
||||
|
||||
def generate_schema(self, item_data):
|
||||
"""Erzeugt KI-optimiertes Schema für einen Artikel"""
|
||||
try:
|
||||
schema = {
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Product",
|
||||
"name": item_data.get('name', ''),
|
||||
"identifier": f"intelectra-{item_data.get('item_id', '')}",
|
||||
"category": "Elektro-Ersatzteil",
|
||||
"url": f"{self.base_url}/artikel/{item_data.get('item_id', '')}",
|
||||
|
||||
# Timestamp für Monitoring
|
||||
"_meta": {
|
||||
"generated": datetime.now().isoformat(),
|
||||
"generator": "Enhanced AI Schema v2.0 - Database Powered",
|
||||
"source": "intelectra_live_shop",
|
||||
"database_enabled": self.db_connection is not None
|
||||
}
|
||||
}
|
||||
|
||||
# Sicherheitshinweise hinzufügen (wenn vorhanden)
|
||||
if item_data.get('warnings'):
|
||||
schema["safetyConsiderations"] = self.build_safety_schema(item_data['warnings'])
|
||||
|
||||
# 🚀 NEUE DATABASE-POWERED Problem-Solution-Mapping!
|
||||
schema["solves"] = self.build_dynamic_problem_solutions(item_data)
|
||||
|
||||
# Kompatibilitäts-Informationen
|
||||
if item_data.get('attributes'):
|
||||
schema["compatibleWith"] = self.build_compatibility_schema(item_data['attributes'])
|
||||
|
||||
# Installations-Hinweise
|
||||
schema["installationHints"] = self.generate_installation_hints(item_data)
|
||||
|
||||
return schema
|
||||
|
||||
except Exception as e:
|
||||
self.log_error(f"Schema generation failed: {str(e)}")
|
||||
return None
|
||||
|
||||
def build_dynamic_problem_solutions(self, item_data):
|
||||
"""🚀 NEUE DATABASE-POWERED Problem-Solution Engine"""
|
||||
if not self.db_connection:
|
||||
# Fallback auf alte hardcoded Methode
|
||||
return self.build_fallback_problem_solutions(item_data)
|
||||
|
||||
try:
|
||||
problems = self.get_problems_for_item(item_data)
|
||||
solutions = []
|
||||
|
||||
for problem in problems:
|
||||
solution = {
|
||||
"@type": "ProblemSolution",
|
||||
"problem": problem['problem_title'],
|
||||
"description": problem['problem_description'],
|
||||
"symptoms": json.loads(problem['symptoms']),
|
||||
"errorCodes": json.loads(problem['error_codes'] or '[]'),
|
||||
"urgencyLevel": problem['urgency_level'],
|
||||
"repairComplexity": problem['repair_complexity'],
|
||||
"estimatedTime": f"{problem['installation_time_min']}-{problem['installation_time_max']} Minuten",
|
||||
"toolsRequired": json.loads(problem['tools_needed'] or '[]'),
|
||||
"safetyInstructions": problem['safety_notes'],
|
||||
"difficultyLevel": problem['difficulty_description'],
|
||||
"problemKeywords": json.loads(problem['keywords']),
|
||||
"frequencyScore": problem['frequency_score'], # Für KI-Ranking
|
||||
"dataSource": "dynamic_database"
|
||||
}
|
||||
solutions.append(solution)
|
||||
|
||||
return solutions
|
||||
|
||||
except Exception as e:
|
||||
self.log_error(f"Database problem query failed: {str(e)}")
|
||||
return self.build_fallback_problem_solutions(item_data)
|
||||
|
||||
def get_problems_for_item(self, item_data):
|
||||
"""Intelligente Problem-Zuordnung basierend auf Item-Daten"""
|
||||
if not self.db_connection:
|
||||
return []
|
||||
|
||||
try:
|
||||
cursor = self.db_connection.cursor(dictionary=True)
|
||||
|
||||
# 1. Kategorie-Erkennung
|
||||
category = self.detect_category(item_data['name'], item_data.get('attributes', {}))
|
||||
|
||||
# 2. Keyword-Matching
|
||||
item_keywords = self.extract_keywords(item_data['name'])
|
||||
|
||||
# 3. DB-Abfrage mit Ranking
|
||||
query = """
|
||||
SELECT ps.*,
|
||||
COALESCE(SUM(pk.weight), 0) as relevance_score
|
||||
FROM problem_solutions ps
|
||||
LEFT JOIN problem_keywords pk ON ps.id = pk.problem_id
|
||||
WHERE (ps.problem_category = %s
|
||||
OR JSON_OVERLAPS(ps.keywords, %s)
|
||||
OR pk.keyword IN ({placeholders}))
|
||||
AND ps.active = TRUE
|
||||
GROUP BY ps.id
|
||||
ORDER BY relevance_score DESC, ps.frequency_score DESC
|
||||
LIMIT 5
|
||||
""".format(placeholders=','.join(['%s'] * len(item_keywords)))
|
||||
|
||||
params = [category, json.dumps(item_keywords)] + item_keywords
|
||||
cursor.execute(query, params)
|
||||
problems = cursor.fetchall()
|
||||
|
||||
cursor.close()
|
||||
return problems
|
||||
|
||||
except Exception as e:
|
||||
self.log_error(f"Database query error: {str(e)}")
|
||||
return []
|
||||
|
||||
def detect_category(self, item_name, attributes):
|
||||
"""Intelligente Kategorie-Erkennung"""
|
||||
name_lower = item_name.lower()
|
||||
|
||||
category_patterns = {
|
||||
'heating': ['heizstab', 'thermostat', 'ntc', 'temperaturfühler', 'heizung'],
|
||||
'pumping': ['pumpe', 'pump', 'ablaufpumpe', 'laugenpumpe', 'umwälzpumpe'],
|
||||
'motor_drive': ['motor', 'antrieb', 'antriebsmotor'],
|
||||
'door_system': ['türschloss', 'türgriff', 'türdichtung', 'door'],
|
||||
'electronics': ['platine', 'steuerung', 'elektronik', 'display', 'timer'],
|
||||
'mechanical': ['stoßdämpfer', 'feder', 'lager', 'riemen'],
|
||||
'water_system': ['schlauch', 'ventil', 'aquastop', 'wasserzulauf'],
|
||||
'filters': ['filter', 'sieb', 'flusensieb'],
|
||||
'lighting': ['lampe', 'led', 'birne', 'leuchte']
|
||||
}
|
||||
|
||||
for category, keywords in category_patterns.items():
|
||||
if any(keyword in name_lower for keyword in keywords):
|
||||
return category
|
||||
|
||||
return 'mechanical' # Default
|
||||
|
||||
def extract_keywords(self, item_name):
|
||||
"""Extrahiert relevante Keywords aus Item-Name"""
|
||||
name_lower = item_name.lower()
|
||||
|
||||
# Basis-Keywords extrahieren
|
||||
keywords = []
|
||||
|
||||
# Wichtige Einzelwörter
|
||||
important_words = ['pumpe', 'motor', 'heizstab', 'schlauch', 'filter',
|
||||
'türschloss', 'dichtung', 'thermostat', 'sensor']
|
||||
|
||||
for word in important_words:
|
||||
if word in name_lower:
|
||||
keywords.append(word)
|
||||
|
||||
# Synonyme und Variationen
|
||||
if 'pump' in name_lower:
|
||||
keywords.extend(['pumpe', 'pump'])
|
||||
if 'heating' in name_lower:
|
||||
keywords.extend(['heizstab', 'heizung'])
|
||||
if 'door' in name_lower:
|
||||
keywords.extend(['tür', 'türschloss'])
|
||||
|
||||
return list(set(keywords))
|
||||
|
||||
def build_fallback_problem_solutions(self, item_data):
|
||||
"""Fallback auf alte hardcoded Methode wenn DB nicht verfügbar"""
|
||||
name = item_data.get('name', '').lower()
|
||||
solutions = []
|
||||
|
||||
# Vereinfachte Fallback-Logic (nur Top-Probleme)
|
||||
if any(word in name for word in ['pumpe', 'pump']):
|
||||
solutions.append({
|
||||
"@type": "ProblemSolution",
|
||||
"problem": "Wasser läuft nicht ab / Pumpe defekt",
|
||||
"symptoms": ["Gerät pumpt nicht", "Wasser steht", "E20 Fehler"],
|
||||
"urgencyLevel": "HIGH",
|
||||
"repairComplexity": "MEDIUM",
|
||||
"dataSource": "fallback_hardcoded"
|
||||
})
|
||||
|
||||
if any(word in name for word in ['heizstab', 'heizung']):
|
||||
solutions.append({
|
||||
"@type": "ProblemSolution",
|
||||
"problem": "Gerät heizt nicht",
|
||||
"symptoms": ["Kein warmes Wasser", "E15 Fehler"],
|
||||
"urgencyLevel": "HIGH",
|
||||
"repairComplexity": "MEDIUM",
|
||||
"dataSource": "fallback_hardcoded"
|
||||
})
|
||||
|
||||
return solutions
|
||||
|
||||
def build_safety_schema(self, warnings):
|
||||
"""Konvertiert Sicherheitshinweise in KI-optimiertes Format"""
|
||||
safety_considerations = []
|
||||
|
||||
for warning in warnings:
|
||||
consideration = {
|
||||
"@type": "SafetyConsideration",
|
||||
"name": warning.get('name', ''),
|
||||
"description": warning.get('beschreibung', ''),
|
||||
"warningLevel": self.detect_warning_level(warning.get('name', '')),
|
||||
"iconPath": f"{self.safety_icon_base}{warning.get('final_bilddateiname', '')}"
|
||||
}
|
||||
|
||||
# Intelligente Kategorisierung
|
||||
if "elektrisch" in warning.get('name', '').lower():
|
||||
consideration["category"] = "electrical_hazard"
|
||||
consideration["preventiveMeasures"] = ["Netzstecker ziehen", "Spannungsfreiheit prüfen"]
|
||||
elif "quetsch" in warning.get('name', '').lower():
|
||||
consideration["category"] = "mechanical_hazard"
|
||||
consideration["preventiveMeasures"] = ["Schutzhandschuhe tragen", "Vorsichtig arbeiten"]
|
||||
|
||||
safety_considerations.append(consideration)
|
||||
|
||||
return safety_considerations
|
||||
|
||||
def build_compatibility_schema(self, attributes):
|
||||
"""Extrahiert Kompatibilitäts-Informationen aus Attributen"""
|
||||
compatible_brands = []
|
||||
|
||||
# Pattern für bekannte Marken
|
||||
brand_patterns = {
|
||||
'siemens': ['siemens', 'bosch', 'neff', 'gaggenau'],
|
||||
'miele': ['miele'],
|
||||
'amica': ['amica', 'whirlpool', 'bauknecht', 'privileg'],
|
||||
'liebherr': ['liebherr']
|
||||
}
|
||||
|
||||
# Suche nach Marken in Attributen
|
||||
for attr_key, attr_value in attributes.items():
|
||||
if isinstance(attr_value, str):
|
||||
for brand_group, brands in brand_patterns.items():
|
||||
if any(brand in attr_value.lower() for brand in brands):
|
||||
compatible_brands.extend(brands)
|
||||
|
||||
return {
|
||||
"brands": list(set(compatible_brands)),
|
||||
"applianceTypes": self.detect_appliance_types(attributes)
|
||||
}
|
||||
|
||||
def detect_appliance_types(self, attributes):
|
||||
"""Erkennt Gerätetypen aus Attributen"""
|
||||
types = []
|
||||
|
||||
type_keywords = {
|
||||
"Waschmaschine": ["waschmaschine", "washing", "wäsche"],
|
||||
"Geschirrspüler": ["geschirrspüler", "dishwasher", "spülmaschine"],
|
||||
"Kühlschrank": ["kühlschrank", "refrigerator", "kühl"],
|
||||
"Backofen": ["backofen", "oven", "herd"]
|
||||
}
|
||||
|
||||
for attr_value in attributes.values():
|
||||
if isinstance(attr_value, str):
|
||||
for appliance, keywords in type_keywords.items():
|
||||
if any(keyword in attr_value.lower() for keyword in keywords):
|
||||
types.append(appliance)
|
||||
|
||||
return list(set(types))
|
||||
|
||||
def generate_installation_hints(self, item_data):
|
||||
"""Generiert intelligente Installations-Hinweise"""
|
||||
name = item_data.get('name', '').lower()
|
||||
|
||||
if 'schlauch' in name:
|
||||
return {
|
||||
"difficulty": "Einfach - ohne Fachmann machbar",
|
||||
"timeRequired": "5-10 Minuten",
|
||||
"toolsNeeded": ["Zange", "Schraubendreher"],
|
||||
"safetyNote": "Wasser abstellen vor Montage"
|
||||
}
|
||||
elif 'pumpe' in name:
|
||||
return {
|
||||
"difficulty": "Mittel - handwerkliches Geschick nötig",
|
||||
"timeRequired": "30-45 Minuten",
|
||||
"toolsNeeded": ["Schraubendreher", "Zange", "Multimeter"],
|
||||
"safetyNote": "Strom abstellen! Gerät vom Netz trennen"
|
||||
}
|
||||
elif 'heizstab' in name:
|
||||
return {
|
||||
"difficulty": "Schwer - Fachmann empfohlen",
|
||||
"timeRequired": "60-90 Minuten",
|
||||
"toolsNeeded": ["Multimeter", "Spezialwerkzeug"],
|
||||
"safetyNote": "⚠️ HOCHSPANNUNG! Strom komplett abschalten"
|
||||
}
|
||||
|
||||
return {
|
||||
"difficulty": "Mittlere Schwierigkeit",
|
||||
"timeRequired": "15-30 Minuten",
|
||||
"safetyNote": "Sicherheitshinweise beachten"
|
||||
}
|
||||
|
||||
def detect_warning_level(self, warning_name):
|
||||
"""Intelligente Warnstufen-Erkennung"""
|
||||
name_lower = warning_name.lower()
|
||||
|
||||
if any(word in name_lower for word in ['elektrisch', 'strom', 'spannung']):
|
||||
return "CRITICAL"
|
||||
elif any(word in name_lower for word in ['heiß', 'temperatur', 'verbrennung']):
|
||||
return "HIGH"
|
||||
elif any(word in name_lower for word in ['quetsch', 'verletzung']):
|
||||
return "MEDIUM"
|
||||
else:
|
||||
return "LOW"
|
||||
|
||||
def save_schema(self, schema, item_id):
|
||||
"""Speichert Schema für späteren Abruf (optional)"""
|
||||
try:
|
||||
schema_file = f"{SCHEMA_SAVE_DIR}/enhanced_schema_{item_id}.json"
|
||||
|
||||
os.makedirs(SCHEMA_SAVE_DIR, exist_ok=True)
|
||||
|
||||
with open(schema_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(schema, f, indent=2, ensure_ascii=False)
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
self.log_error(f"Schema save failed: {str(e)}")
|
||||
return False
|
||||
|
||||
def log_error(self, message):
|
||||
"""Fehler-Logging"""
|
||||
try:
|
||||
log_file = f"{LOG_DIR}/enhanced_ai_schema.log"
|
||||
timestamp = datetime.now().isoformat()
|
||||
|
||||
os.makedirs(LOG_DIR, exist_ok=True)
|
||||
|
||||
with open(log_file, 'a', encoding='utf-8') as f:
|
||||
f.write(f"{timestamp} ERROR: {message}\n")
|
||||
except:
|
||||
pass # Silent fail für Live-Shop
|
||||
|
||||
def __del__(self):
|
||||
"""DB-Verbindung sauber schließen"""
|
||||
if self.db_connection:
|
||||
try:
|
||||
self.db_connection.close()
|
||||
except:
|
||||
pass
|
||||
|
||||
def main():
|
||||
"""Hauptfunktion - wird von PHP aufgerufen"""
|
||||
if len(sys.argv) < 2:
|
||||
print(json.dumps({"error": "No input data provided"}))
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
# Input von PHP parsen
|
||||
input_data = json.loads(sys.argv[1])
|
||||
|
||||
# Enhanced Schema Generator initialisieren
|
||||
generator = EnhancedAISchemaGenerator()
|
||||
|
||||
# Schema erzeugen
|
||||
schema = generator.generate_schema(input_data)
|
||||
|
||||
if schema:
|
||||
# Optional: Schema speichern
|
||||
generator.save_schema(schema, input_data.get('item_id', 'unknown'))
|
||||
|
||||
# Erfolg zurückgeben
|
||||
result = {
|
||||
"success": True,
|
||||
"schema_generated": True,
|
||||
"item_id": input_data.get('item_id'),
|
||||
"timestamp": datetime.now().isoformat(),
|
||||
"database_powered": generator.db_connection is not None,
|
||||
"problems_found": len(schema.get("solves", []))
|
||||
}
|
||||
else:
|
||||
result = {"success": False, "error": "Schema generation failed"}
|
||||
|
||||
print(json.dumps(result))
|
||||
|
||||
except Exception as e:
|
||||
error_result = {"success": False, "error": str(e)}
|
||||
print(json.dumps(error_result))
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
🗄️ Database Setup Utility für Problem-FAQ System
|
||||
ACHTUNG: Nur ausführen wenn DB-Zugang verfügbar!
|
||||
"""
|
||||
|
||||
import mysql.connector
|
||||
import json
|
||||
import sys
|
||||
from config import DB_CONFIG
|
||||
|
||||
def create_problem_database():
|
||||
"""Erstellt die Problem-Datenbank und Tabellen"""
|
||||
try:
|
||||
# Verbindung ohne spezifische Datenbank
|
||||
temp_config = DB_CONFIG.copy()
|
||||
temp_config.pop('database', None)
|
||||
|
||||
connection = mysql.connector.connect(**temp_config)
|
||||
cursor = connection.cursor()
|
||||
|
||||
# Datenbank erstellen
|
||||
cursor.execute(f"CREATE DATABASE IF NOT EXISTS {DB_CONFIG['database']} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci")
|
||||
cursor.execute(f"USE {DB_CONFIG['database']}")
|
||||
|
||||
print(f"✅ Datenbank '{DB_CONFIG['database']}' erstellt/ausgewählt")
|
||||
|
||||
# SQL-Script ausführen
|
||||
with open('/var/www/vhosts/intelectra.de/httpdocs/core/python/create_problem_database.sql', 'r', encoding='utf-8') as f:
|
||||
sql_script = f.read()
|
||||
|
||||
# Script in einzelne Statements aufteilen
|
||||
statements = [stmt.strip() for stmt in sql_script.split(';') if stmt.strip()]
|
||||
|
||||
for statement in statements:
|
||||
if statement.upper().startswith(('CREATE', 'INSERT')):
|
||||
try:
|
||||
cursor.execute(statement)
|
||||
print(f"✅ SQL Statement ausgeführt: {statement[:50]}...")
|
||||
except mysql.connector.Error as err:
|
||||
print(f"⚠️ Warning: {err} für Statement: {statement[:50]}...")
|
||||
|
||||
connection.commit()
|
||||
cursor.close()
|
||||
connection.close()
|
||||
|
||||
print("\n🎉 Database Setup erfolgreich abgeschlossen!")
|
||||
return True
|
||||
|
||||
except mysql.connector.Error as err:
|
||||
print(f"❌ Database Error: {err}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"💥 Setup Error: {str(e)}")
|
||||
return False
|
||||
|
||||
def test_database_connection():
|
||||
"""Testet die Datenbankverbindung"""
|
||||
try:
|
||||
connection = mysql.connector.connect(**DB_CONFIG)
|
||||
cursor = connection.cursor()
|
||||
|
||||
# Test-Query
|
||||
cursor.execute("SELECT COUNT(*) FROM problem_solutions WHERE active = TRUE")
|
||||
count = cursor.fetchone()[0]
|
||||
|
||||
cursor.close()
|
||||
connection.close()
|
||||
|
||||
print(f"✅ Database Connection OK - {count} aktive Probleme gefunden")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Database Connection Failed: {str(e)}")
|
||||
return False
|
||||
|
||||
def show_sample_problems():
|
||||
"""Zeigt Beispiel-Probleme aus der Datenbank"""
|
||||
try:
|
||||
connection = mysql.connector.connect(**DB_CONFIG)
|
||||
cursor = connection.cursor(dictionary=True)
|
||||
|
||||
cursor.execute("""
|
||||
SELECT problem_title, problem_category, urgency_level, frequency_score
|
||||
FROM problem_solutions
|
||||
WHERE active = TRUE
|
||||
ORDER BY frequency_score DESC
|
||||
LIMIT 5
|
||||
""")
|
||||
|
||||
problems = cursor.fetchall()
|
||||
|
||||
print("\n📊 Top 5 Probleme in der Datenbank:")
|
||||
print("-" * 50)
|
||||
for i, problem in enumerate(problems, 1):
|
||||
print(f"{i}. {problem['problem_title']}")
|
||||
print(f" Kategorie: {problem['problem_category']}")
|
||||
print(f" Urgency: {problem['urgency_level']}")
|
||||
print(f" Häufigkeit: {problem['frequency_score']}%")
|
||||
print()
|
||||
|
||||
cursor.close()
|
||||
connection.close()
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ Error showing problems: {str(e)}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("🗄️ Problem-FAQ Database Setup")
|
||||
print("=" * 40)
|
||||
|
||||
if len(sys.argv) > 1 and sys.argv[1] == "--create":
|
||||
print("🔨 Creating database and tables...")
|
||||
if create_problem_database():
|
||||
test_database_connection()
|
||||
show_sample_problems()
|
||||
else:
|
||||
print("🧪 Testing existing database connection...")
|
||||
if test_database_connection():
|
||||
show_sample_problems()
|
||||
else:
|
||||
print("\n💡 Tipp: Verwende --create um die Datenbank zu erstellen")
|
||||
print(" Beispiel: python3 setup_database.py --create")
|
||||
@@ -0,0 +1,329 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>🤖 Intelectra AI Control Center</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: #fff;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.header {
|
||||
background: rgba(0,0,0,0.2);
|
||||
padding: 1rem;
|
||||
text-align: center;
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 2rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: rgba(255,255,255,0.1);
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: 15px;
|
||||
padding: 1.5rem;
|
||||
border: 1px solid rgba(255,255,255,0.2);
|
||||
box-shadow: 0 8px 32px rgba(31, 38, 135, 0.37);
|
||||
}
|
||||
|
||||
.card h3 {
|
||||
margin-bottom: 1rem;
|
||||
font-size: 1.2rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.ai-stat {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.5rem 0;
|
||||
border-bottom: 1px solid rgba(255,255,255,0.1);
|
||||
}
|
||||
|
||||
.ai-stat:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.ai-name {
|
||||
font-weight: bold;
|
||||
color: #4ade80;
|
||||
}
|
||||
|
||||
.ai-count {
|
||||
background: rgba(255,255,255,0.2);
|
||||
padding: 0.2rem 0.8rem;
|
||||
border-radius: 20px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.article-item {
|
||||
background: rgba(0,0,0,0.1);
|
||||
padding: 1rem;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.article-id {
|
||||
font-weight: bold;
|
||||
color: #fbbf24;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
height: 200px;
|
||||
background: rgba(255,255,255,0.05);
|
||||
border-radius: 10px;
|
||||
padding: 1rem;
|
||||
display: flex;
|
||||
align-items: end;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.chart-bar {
|
||||
background: linear-gradient(to top, #4ade80, #22d3ee);
|
||||
border-radius: 4px 4px 0 0;
|
||||
min-width: 20px;
|
||||
position: relative;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.chart-bar:hover {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.chart-bar::after {
|
||||
content: attr(data-value);
|
||||
position: absolute;
|
||||
top: -25px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
font-size: 0.8rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.nav-menu {
|
||||
background: rgba(255,255,255,0.1);
|
||||
padding: 1rem;
|
||||
border-radius: 10px;
|
||||
margin-bottom: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.nav-menu a {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
padding: 0.5rem 1rem;
|
||||
margin: 0 0.5rem;
|
||||
border-radius: 20px;
|
||||
background: rgba(255,255,255,0.1);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.nav-menu a:hover {
|
||||
background: rgba(255,255,255,0.2);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.status-indicator {
|
||||
display: inline-block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 50%;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.status-online { background: #4ade80; }
|
||||
.status-offline { background: #ef4444; }
|
||||
|
||||
.live-counter {
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin: 1rem 0;
|
||||
color: #4ade80;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% { opacity: 1; }
|
||||
50% { opacity: 0.5; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
|
||||
.pulse {
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header">
|
||||
<h1>🤖 Intelectra AI Control Center</h1>
|
||||
<p>KI-Tracking & Schema Management Dashboard</p>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="nav-menu">
|
||||
<a href="/">📊 Dashboard</a>
|
||||
<a href="/faq-management">🗄️ FAQ Management</a>
|
||||
<a href="/add-problem">➕ Problem hinzufügen</a>
|
||||
<a href="/schema-preview/12345">👁️ Schema Preview</a>
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
<!-- Live AI Activity -->
|
||||
<div class="card">
|
||||
<h3>🔥 Live AI Activity</h3>
|
||||
<div class="live-counter pulse" id="live-counter">0</div>
|
||||
<p style="text-align: center; opacity: 0.8;">KI-Besuche heute</p>
|
||||
<div class="status-indicator status-online"></div>
|
||||
<span>Tracking aktiv</span>
|
||||
</div>
|
||||
|
||||
<!-- AI Visits -->
|
||||
<div class="card">
|
||||
<h3>🤖 KI-Besucher (7 Tage)</h3>
|
||||
{% if stats.ai_visits %}
|
||||
{% for ai in stats.ai_visits %}
|
||||
<div class="ai-stat">
|
||||
<span class="ai-name">{{ ai.ai_name }}</span>
|
||||
<div>
|
||||
<span class="ai-count">{{ ai.visit_count }} Besuche</span>
|
||||
<small style="opacity: 0.7; margin-left: 0.5rem;">
|
||||
{{ ai.unique_visitors }} Unique
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p style="opacity: 0.7;">Noch keine KI-Besuche erkannt</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Top Articles -->
|
||||
<div class="card">
|
||||
<h3>📈 Top KI-Artikel</h3>
|
||||
{% if stats.top_articles %}
|
||||
{% for article in stats.top_articles %}
|
||||
<div class="article-item">
|
||||
<div class="article-id">Artikel #{{ article.article_id }}</div>
|
||||
<div style="font-size: 0.9rem; opacity: 0.8;">
|
||||
{{ article.visit_count }} Besuche von: {{ article.visiting_ais }}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p style="opacity: 0.7;">Noch keine Artikel-Besuche</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Hourly Distribution -->
|
||||
<div class="card">
|
||||
<h3>⏰ Tagesverteilung</h3>
|
||||
<div class="chart-container">
|
||||
{% if stats.hourly_distribution %}
|
||||
{% for hour_data in stats.hourly_distribution %}
|
||||
{% set max_visits = stats.hourly_distribution|map(attribute='visits')|max %}
|
||||
{% set bar_height = (hour_data.visits / max_visits * 150)|round|int %}
|
||||
<div class="chart-bar"
|
||||
style="height: {{ bar_height }}px"
|
||||
data-value="{{ hour_data.visits }}"
|
||||
title="{{ hour_data.hour }}:00 - {{ hour_data.visits }} Besuche">
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p style="opacity: 0.7; align-self: center;">Noch keine Daten</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- System Status -->
|
||||
<div class="card">
|
||||
<h3>⚙️ System Status</h3>
|
||||
<div class="ai-stat">
|
||||
<span>AI Schema Generator</span>
|
||||
<span class="ai-count">✅ Aktiv</span>
|
||||
</div>
|
||||
<div class="ai-stat">
|
||||
<span>Problem Database</span>
|
||||
<span class="ai-count">✅ Online</span>
|
||||
</div>
|
||||
<div class="ai-stat">
|
||||
<span>KI Tracking</span>
|
||||
<span class="ai-count">✅ Läuft</span>
|
||||
</div>
|
||||
<div class="ai-stat">
|
||||
<span>Flask Dashboard</span>
|
||||
<span class="ai-count">🟡 Dev Mode</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="card">
|
||||
<h3>⚡ Quick Actions</h3>
|
||||
<div style="display: flex; flex-direction: column; gap: 0.5rem;">
|
||||
<button onclick="refreshStats()" style="background: rgba(255,255,255,0.2); border: none; color: #fff; padding: 0.8rem; border-radius: 8px; cursor: pointer;">
|
||||
🔄 Stats aktualisieren
|
||||
</button>
|
||||
<button onclick="exportData()" style="background: rgba(255,255,255,0.2); border: none; color: #fff; padding: 0.8rem; border-radius: 8px; cursor: pointer;">
|
||||
📥 Daten exportieren
|
||||
</button>
|
||||
<button onclick="clearCache()" style="background: rgba(255,255,255,0.2); border: none; color: #fff; padding: 0.8rem; border-radius: 8px; cursor: pointer;">
|
||||
🗑️ Cache leeren
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Live Updates alle 30 Sekunden
|
||||
setInterval(updateLiveStats, 30000);
|
||||
|
||||
function updateLiveStats() {
|
||||
fetch('/api/ai-visits')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
// Live Counter updaten
|
||||
const totalToday = data.ai_visits.reduce((sum, ai) => sum + ai.visit_count, 0);
|
||||
document.getElementById('live-counter').textContent = totalToday;
|
||||
})
|
||||
.catch(error => console.error('Live update failed:', error));
|
||||
}
|
||||
|
||||
function refreshStats() {
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
function exportData() {
|
||||
window.open('/api/export-stats', '_blank');
|
||||
}
|
||||
|
||||
function clearCache() {
|
||||
if (confirm('Cache wirklich leeren?')) {
|
||||
fetch('/api/clear-cache', { method: 'POST' })
|
||||
.then(() => alert('Cache geleert!'));
|
||||
}
|
||||
}
|
||||
|
||||
// Initial load
|
||||
updateLiveStats();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,176 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
🧪 Test Script für Enhanced AI Schema Generator mit DB-Integration
|
||||
SICHER: Testet ohne Live-Shop zu beeinträchtigen
|
||||
"""
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
import os
|
||||
|
||||
def test_enhanced_schema_generation():
|
||||
"""Testet Enhanced Schema-Generierung mit verschiedenen Artikeltypen"""
|
||||
|
||||
# Test-Daten für verschiedene Problemkategorien
|
||||
test_cases = [
|
||||
{
|
||||
"name": "🚰 PUMPE - Ablaufpumpe Test",
|
||||
"data": {
|
||||
"item_id": "TEST_PUMP_001",
|
||||
"name": "Bosch Ablaufpumpe für Waschmaschine WM14N140",
|
||||
"warnings": [
|
||||
{
|
||||
"name": ".WARNUNG! Gefahr eines elektrischen Schlags",
|
||||
"beschreibung": "Schalten Sie das Gerät aus vor Reparatur.",
|
||||
"final_bilddateiname": "ISO_7010_W012.svg"
|
||||
}
|
||||
],
|
||||
"attributes": {
|
||||
"attribute_1": "Pumpe für Waschmaschine",
|
||||
"attribute_2": "Kompatibel mit Bosch, Siemens",
|
||||
"attribute_3": "Laugenpumpe"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "🔥 HEIZUNG - Heizstab Test",
|
||||
"data": {
|
||||
"item_id": "TEST_HEAT_001",
|
||||
"name": "Siemens Heizstab mit Thermostat für Geschirrspüler",
|
||||
"warnings": [
|
||||
{
|
||||
"name": ".WARNUNG! Gefahr eines elektrischen Schlags",
|
||||
"beschreibung": "Hochspannung! Strom abschalten.",
|
||||
"final_bilddateiname": "ISO_7010_W012.svg"
|
||||
}
|
||||
],
|
||||
"attributes": {
|
||||
"attribute_1": "Heizelement für Spülmaschine",
|
||||
"attribute_2": "Kompatibel mit Siemens, Bosch",
|
||||
"attribute_3": "Mit NTC-Sensor"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "🚪 TÜR - Türschloss Test",
|
||||
"data": {
|
||||
"item_id": "TEST_DOOR_001",
|
||||
"name": "Miele Türschloss für Waschmaschine W1 Serie",
|
||||
"warnings": [],
|
||||
"attributes": {
|
||||
"attribute_1": "Türverriegelung",
|
||||
"attribute_2": "Kompatibel mit Miele",
|
||||
"attribute_3": "Mechanisches Schloss"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
print("🧪 Enhanced AI Schema Generator Test Suite")
|
||||
print("=" * 60)
|
||||
|
||||
for test_case in test_cases:
|
||||
print(f"\n🔧 {test_case['name']}")
|
||||
print("-" * 40)
|
||||
|
||||
try:
|
||||
# Schema Generator aufrufen
|
||||
script_path = "/var/www/vhosts/intelectra.de/httpdocs/core/python/enhanced_ai_schema_generator.py"
|
||||
json_input = json.dumps(test_case['data'])
|
||||
|
||||
result = subprocess.run([
|
||||
"python3", script_path, json_input
|
||||
], capture_output=True, text=True, timeout=30)
|
||||
|
||||
if result.returncode == 0:
|
||||
response = json.loads(result.stdout)
|
||||
|
||||
print("✅ Status:", "SUCCESS" if response.get('success') else "FAILED")
|
||||
print("📊 Schema generiert:", response.get('schema_generated', False))
|
||||
print("🗄️ Database powered:", response.get('database_powered', False))
|
||||
print("🔍 Probleme gefunden:", response.get('problems_found', 0))
|
||||
print("🆔 Item ID:", response.get('item_id'))
|
||||
|
||||
# Schema-Datei prüfen und analysieren
|
||||
schema_file = f"/var/www/vhosts/intelectra.de/httpdocs/core/python/logs/enhanced_schema_{test_case['data']['item_id']}.json"
|
||||
try:
|
||||
with open(schema_file, 'r', encoding='utf-8') as f:
|
||||
schema = json.load(f)
|
||||
|
||||
print("\n📋 Schema Details:")
|
||||
print(f" - Generator: {schema.get('_meta', {}).get('generator', 'Unknown')}")
|
||||
print(f" - DB Enabled: {schema.get('_meta', {}).get('database_enabled', False)}")
|
||||
print(f" - Sicherheitshinweise: {len(schema.get('safetyConsiderations', []))}")
|
||||
print(f" - Problem-Lösungen: {len(schema.get('solves', []))}")
|
||||
print(f" - Kompatible Marken: {schema.get('compatibleWith', {}).get('brands', [])}")
|
||||
|
||||
# Problem-Details anzeigen
|
||||
problems = schema.get('solves', [])
|
||||
if problems:
|
||||
print("\n🔧 Gefundene Probleme:")
|
||||
for i, problem in enumerate(problems[:3], 1): # Nur erste 3
|
||||
print(f" {i}. {problem.get('problem', 'N/A')}")
|
||||
print(f" Urgency: {problem.get('urgencyLevel', 'N/A')}")
|
||||
print(f" Source: {problem.get('dataSource', 'N/A')}")
|
||||
|
||||
except FileNotFoundError:
|
||||
print("⚠️ Schema-Datei nicht gefunden")
|
||||
|
||||
else:
|
||||
print("❌ Fehler:", result.stderr)
|
||||
print("Output:", result.stdout)
|
||||
|
||||
except Exception as e:
|
||||
print(f"💥 Test fehlgeschlagen: {str(e)}")
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("🎯 Test Suite abgeschlossen!")
|
||||
|
||||
# Log-Datei checken
|
||||
log_file = "/var/www/vhosts/intelectra.de/httpdocs/core/python/logs/enhanced_ai_schema.log"
|
||||
if os.path.exists(log_file):
|
||||
print(f"\n📝 Log-Datei gefunden: {log_file}")
|
||||
try:
|
||||
with open(log_file, 'r') as f:
|
||||
lines = f.readlines()[-5:] # Letzte 5 Zeilen
|
||||
if lines:
|
||||
print("Letzte Log-Einträge:")
|
||||
for line in lines:
|
||||
print(f" {line.strip()}")
|
||||
except:
|
||||
print(" (Log-Datei konnte nicht gelesen werden)")
|
||||
|
||||
def test_database_fallback():
|
||||
"""Testet Fallback-Verhalten wenn DB nicht verfügbar"""
|
||||
print("\n🔄 Database Fallback Test")
|
||||
print("-" * 30)
|
||||
|
||||
# Test ohne DB-Verbindung (sollte Fallback verwenden)
|
||||
test_data = {
|
||||
"item_id": "TEST_FALLBACK_001",
|
||||
"name": "Generic Pumpe für Test",
|
||||
"attributes": {"test": "fallback"}
|
||||
}
|
||||
|
||||
try:
|
||||
script_path = "/var/www/vhosts/intelectra.de/httpdocs/core/python/enhanced_ai_schema_generator.py"
|
||||
json_input = json.dumps(test_data)
|
||||
|
||||
result = subprocess.run([
|
||||
"python3", script_path, json_input
|
||||
], capture_output=True, text=True, timeout=30)
|
||||
|
||||
if result.returncode == 0:
|
||||
response = json.loads(result.stdout)
|
||||
print("✅ Fallback funktioniert:", response.get('success', False))
|
||||
print("🗄️ Database powered:", response.get('database_powered', False))
|
||||
else:
|
||||
print("❌ Fallback failed")
|
||||
|
||||
except Exception as e:
|
||||
print(f"💥 Fallback test error: {str(e)}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_enhanced_schema_generation()
|
||||
test_database_fallback()
|
||||
Executable
+78
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
🧪 Test Script für AI Schema Generator
|
||||
SICHER: Testet ohne Live-Shop zu beeinträchtigen
|
||||
"""
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
def test_schema_generation():
|
||||
"""Testet Schema-Generierung mit Beispiel-Daten"""
|
||||
|
||||
# Test-Daten (wie sie von PHP kommen würden)
|
||||
test_data = {
|
||||
"item_id": "283272",
|
||||
"name": "universelle Zusatzpumpe für bessere Förderhöhe / für Zwischeneinbau",
|
||||
"warnings": [
|
||||
{
|
||||
"name": ".WARNUNG! Gefahr eines elektrischen Schlags",
|
||||
"beschreibung": "Schalten Sie das Gerät aus und ziehen Sie den Netzstecker aus der Steckdose, bevor Sie mit Reparatur- oder Wartungsarbeiten beginnen.",
|
||||
"final_bilddateiname": "ISO_7010_W012.svg"
|
||||
},
|
||||
{
|
||||
"name": ".Quetschgefahr",
|
||||
"beschreibung": "Warnung, Quetschgefahr!",
|
||||
"final_bilddateiname": "ISO_7010_W019.svg"
|
||||
}
|
||||
],
|
||||
"attributes": {
|
||||
"attribute_1": "Pumpe für Haushaltsgeräte",
|
||||
"attribute_2": "Kompatibel mit Siemens, Bosch",
|
||||
"attribute_3": "Ablaufpumpe"
|
||||
}
|
||||
}
|
||||
|
||||
try:
|
||||
# Schema Generator aufrufen
|
||||
script_path = "/var/www/vhosts/intelectra.de/httpdocs/core/python/ai_shopping_schema_generator.py"
|
||||
json_input = json.dumps(test_data)
|
||||
|
||||
result = subprocess.run([
|
||||
"python3", script_path, json_input
|
||||
], capture_output=True, text=True, timeout=30)
|
||||
|
||||
print("🧪 AI Schema Generator Test")
|
||||
print("=" * 50)
|
||||
|
||||
if result.returncode == 0:
|
||||
response = json.loads(result.stdout)
|
||||
print("✅ Status:", "SUCCESS" if response.get('success') else "FAILED")
|
||||
print("📊 Schema generiert:", response.get('schema_generated', False))
|
||||
print("🆔 Item ID:", response.get('item_id'))
|
||||
print("⏰ Timestamp:", response.get('timestamp'))
|
||||
|
||||
# Schema-Datei prüfen
|
||||
schema_file = f"/var/www/vhosts/intelectra.de/httpdocs/core/python/logs/schema_{test_data['item_id']}.json"
|
||||
try:
|
||||
with open(schema_file, 'r', encoding='utf-8') as f:
|
||||
schema = json.load(f)
|
||||
print("\n📋 Generiertes Schema:")
|
||||
print(f" - Name: {schema.get('name')}")
|
||||
print(f" - Sicherheitshinweise: {len(schema.get('safetyConsiderations', []))}")
|
||||
print(f" - Problem-Lösungen: {len(schema.get('solves', []))}")
|
||||
print(f" - Kompatibilität: {schema.get('compatibleWith', {}).get('brands', [])}")
|
||||
|
||||
except FileNotFoundError:
|
||||
print("⚠️ Schema-Datei nicht gefunden")
|
||||
|
||||
else:
|
||||
print("❌ Fehler:", result.stderr)
|
||||
print("Output:", result.stdout)
|
||||
|
||||
except Exception as e:
|
||||
print(f"💥 Test fehlgeschlagen: {str(e)}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_schema_generation()
|
||||
Reference in New Issue
Block a user