v1.0 - Version stable: multi-PC, détection UI-DETR-1, 3 modes exécution
- Frontend v4 accessible sur réseau local (192.168.1.40) - Ports ouverts: 3002 (frontend), 5001 (backend), 5004 (dashboard) - Ollama GPU fonctionnel - Self-healing interactif - Dashboard confiance Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1833,6 +1833,234 @@ def api_services_stop_all():
|
||||
return jsonify({"results": results, "timestamp": datetime.now().isoformat()})
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# API Configuration - Interface de configuration centralisee
|
||||
# =============================================================================
|
||||
|
||||
CONFIG_FILE_PATH = BASE_PATH / "data" / "config" / "system_config.json"
|
||||
|
||||
def load_system_config():
|
||||
"""Charge la configuration systeme depuis le fichier JSON."""
|
||||
try:
|
||||
if CONFIG_FILE_PATH.exists():
|
||||
with open(CONFIG_FILE_PATH, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
except Exception as e:
|
||||
api_logger.error(f"Erreur chargement config: {e}")
|
||||
# Config par defaut
|
||||
return {
|
||||
"version": "1.0.0",
|
||||
"services": {},
|
||||
"llm": {"provider": "ollama", "base_url": "http://localhost:11434", "model": "qwen2.5:7b"},
|
||||
"vlm": {"provider": "ollama", "base_url": "http://localhost:11434", "model": "qwen2.5vl:7b"},
|
||||
"detection": {"owl_model": "google/owlv2-base-patch16-ensemble", "confidence_threshold": 0.3},
|
||||
"database": {"type": "sqlite", "path": "data/training/workflows.db"},
|
||||
"security": {"enable_encryption": True, "require_authentication": False}
|
||||
}
|
||||
|
||||
def save_system_config(config):
|
||||
"""Sauvegarde la configuration systeme dans le fichier JSON."""
|
||||
try:
|
||||
CONFIG_FILE_PATH.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(CONFIG_FILE_PATH, 'w', encoding='utf-8') as f:
|
||||
json.dump(config, f, indent=2, ensure_ascii=False)
|
||||
return True
|
||||
except Exception as e:
|
||||
api_logger.error(f"Erreur sauvegarde config: {e}")
|
||||
return False
|
||||
|
||||
|
||||
@app.route('/api/config')
|
||||
def get_config():
|
||||
"""Retourne la configuration complete du systeme."""
|
||||
try:
|
||||
config = load_system_config()
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"config": config,
|
||||
"timestamp": datetime.now().isoformat()
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({"success": False, "error": str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/config', methods=['POST'])
|
||||
def update_config():
|
||||
"""Met a jour la configuration complete du systeme."""
|
||||
try:
|
||||
new_config = request.get_json()
|
||||
if not new_config:
|
||||
return jsonify({"success": False, "error": "Configuration vide"}), 400
|
||||
|
||||
# Garder la version
|
||||
current = load_system_config()
|
||||
new_config['version'] = current.get('version', '1.0.0')
|
||||
|
||||
if save_system_config(new_config):
|
||||
api_logger.info("Configuration systeme mise a jour")
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": "Configuration sauvegardee",
|
||||
"timestamp": datetime.now().isoformat()
|
||||
})
|
||||
else:
|
||||
return jsonify({"success": False, "error": "Erreur lors de la sauvegarde"}), 500
|
||||
except Exception as e:
|
||||
return jsonify({"success": False, "error": str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/config/<section>')
|
||||
def get_config_section(section):
|
||||
"""Retourne une section specifique de la configuration."""
|
||||
try:
|
||||
config = load_system_config()
|
||||
if section not in config:
|
||||
return jsonify({"success": False, "error": f"Section '{section}' introuvable"}), 404
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"section": section,
|
||||
"data": config[section],
|
||||
"timestamp": datetime.now().isoformat()
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({"success": False, "error": str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/config/<section>', methods=['PUT'])
|
||||
def update_config_section(section):
|
||||
"""Met a jour une section specifique de la configuration."""
|
||||
try:
|
||||
section_data = request.get_json()
|
||||
if not section_data:
|
||||
return jsonify({"success": False, "error": "Donnees vides"}), 400
|
||||
|
||||
config = load_system_config()
|
||||
config[section] = section_data
|
||||
|
||||
if save_system_config(config):
|
||||
api_logger.info(f"Section config '{section}' mise a jour")
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": f"Section '{section}' sauvegardee",
|
||||
"timestamp": datetime.now().isoformat()
|
||||
})
|
||||
else:
|
||||
return jsonify({"success": False, "error": "Erreur lors de la sauvegarde"}), 500
|
||||
except Exception as e:
|
||||
return jsonify({"success": False, "error": str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/config/test-connection', methods=['POST'])
|
||||
def test_connection():
|
||||
"""Teste la connexion a un service (LLM, base de donnees, etc.)."""
|
||||
try:
|
||||
data = request.get_json()
|
||||
service_type = data.get('type')
|
||||
|
||||
if service_type == 'ollama':
|
||||
# Test connexion Ollama
|
||||
import urllib.request
|
||||
url = data.get('base_url', 'http://localhost:11434') + '/api/tags'
|
||||
try:
|
||||
with urllib.request.urlopen(url, timeout=5) as response:
|
||||
models = json.loads(response.read().decode())
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": "Connexion Ollama OK",
|
||||
"models": [m.get('name') for m in models.get('models', [])]
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({"success": False, "error": f"Connexion Ollama echouee: {e}"})
|
||||
|
||||
elif service_type == 'database':
|
||||
# Test connexion base de donnees
|
||||
db_path = data.get('path') or 'data/training/workflows.db'
|
||||
full_path = BASE_PATH / db_path
|
||||
if full_path.exists():
|
||||
return jsonify({"success": True, "message": f"Base de donnees accessible: {db_path}"})
|
||||
else:
|
||||
return jsonify({"success": False, "error": f"Fichier introuvable: {full_path}"})
|
||||
|
||||
elif service_type == 'service':
|
||||
# Test connexion a un service HTTP
|
||||
port = data.get('port')
|
||||
host = data.get('host', 'localhost')
|
||||
import socket
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
s.settimeout(2)
|
||||
try:
|
||||
s.connect((host, int(port)))
|
||||
return jsonify({"success": True, "message": f"Service {host}:{port} accessible"})
|
||||
except:
|
||||
return jsonify({"success": False, "error": f"Service {host}:{port} inaccessible"})
|
||||
|
||||
return jsonify({"success": False, "error": "Type de test inconnu"})
|
||||
except Exception as e:
|
||||
return jsonify({"success": False, "error": str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/config/ollama-models')
|
||||
def get_ollama_models():
|
||||
"""Recupere la liste des modeles Ollama disponibles."""
|
||||
try:
|
||||
config = load_system_config()
|
||||
base_url = config.get('llm', {}).get('base_url', 'http://localhost:11434')
|
||||
|
||||
import urllib.request
|
||||
url = base_url + '/api/tags'
|
||||
with urllib.request.urlopen(url, timeout=5) as response:
|
||||
data = json.loads(response.read().decode())
|
||||
models = [m.get('name') for m in data.get('models', [])]
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"models": models,
|
||||
"timestamp": datetime.now().isoformat()
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({"success": False, "error": str(e), "models": []}), 500
|
||||
|
||||
|
||||
@app.route('/api/config/export')
|
||||
def export_config():
|
||||
"""Exporte la configuration en JSON."""
|
||||
try:
|
||||
config = load_system_config()
|
||||
return Response(
|
||||
json.dumps(config, indent=2, ensure_ascii=False),
|
||||
mimetype='application/json',
|
||||
headers={'Content-Disposition': 'attachment;filename=rpa_config.json'}
|
||||
)
|
||||
except Exception as e:
|
||||
return jsonify({"success": False, "error": str(e)}), 500
|
||||
|
||||
|
||||
@app.route('/api/config/import', methods=['POST'])
|
||||
def import_config():
|
||||
"""Importe une configuration depuis un fichier JSON."""
|
||||
try:
|
||||
if 'file' in request.files:
|
||||
file = request.files['file']
|
||||
config = json.load(file)
|
||||
else:
|
||||
config = request.get_json()
|
||||
|
||||
if not config:
|
||||
return jsonify({"success": False, "error": "Configuration vide"}), 400
|
||||
|
||||
if save_system_config(config):
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"message": "Configuration importee avec succes",
|
||||
"timestamp": datetime.now().isoformat()
|
||||
})
|
||||
else:
|
||||
return jsonify({"success": False, "error": "Erreur lors de l'import"}), 500
|
||||
except json.JSONDecodeError:
|
||||
return jsonify({"success": False, "error": "Format JSON invalide"}), 400
|
||||
except Exception as e:
|
||||
return jsonify({"success": False, "error": str(e)}), 500
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Main
|
||||
# =============================================================================
|
||||
|
||||
Reference in New Issue
Block a user