- 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>
256 lines
8.5 KiB
Python
256 lines
8.5 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Démarre le serveur API local pour le développement sur un port libre.
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import time
|
|
import subprocess
|
|
import requests
|
|
import tempfile
|
|
import shutil
|
|
from pathlib import Path
|
|
|
|
def load_env_local():
|
|
"""Charge les variables d'environnement depuis .env.local"""
|
|
env_path = Path(".env.local")
|
|
if not env_path.exists():
|
|
print("❌ Fichier .env.local non trouvé")
|
|
return False
|
|
|
|
print(f"📁 Chargement de {env_path}")
|
|
with open(env_path, 'r') as f:
|
|
for line in f:
|
|
line = line.strip()
|
|
if line and not line.startswith('#') and '=' in line:
|
|
key, value = line.split('=', 1)
|
|
os.environ[key.strip()] = value.strip()
|
|
if key.strip() in ['RPA_TOKEN_ADMIN', 'RPA_TOKEN_READONLY']:
|
|
print(f" ✓ {key.strip()}: {value.strip()[:16]}...")
|
|
return True
|
|
|
|
def find_free_port(start_port=8001):
|
|
"""Trouve un port libre"""
|
|
import socket
|
|
for port in range(start_port, start_port + 10):
|
|
try:
|
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
|
s.bind(('127.0.0.1', port))
|
|
return port
|
|
except OSError:
|
|
continue
|
|
return None
|
|
|
|
def create_dev_server_script(port):
|
|
"""Crée un script serveur temporaire avec le bon port"""
|
|
server_dir = Path("server")
|
|
original_script = server_dir / "api_upload.py"
|
|
|
|
if not original_script.exists():
|
|
print("❌ Fichier server/api_upload.py non trouvé")
|
|
return None
|
|
|
|
# Lire le script original
|
|
with open(original_script, 'r') as f:
|
|
content = f.read()
|
|
|
|
# Remplacer le port hardcodé
|
|
modified_content = content.replace(
|
|
'port=8000,',
|
|
f'port={port},'
|
|
)
|
|
|
|
# Créer un fichier temporaire
|
|
temp_script = server_dir / f"api_upload_dev_{port}.py"
|
|
with open(temp_script, 'w') as f:
|
|
f.write(modified_content)
|
|
|
|
print(f"✓ Script serveur temporaire créé: {temp_script}")
|
|
return temp_script
|
|
|
|
def start_dev_server():
|
|
"""Démarre le serveur de développement"""
|
|
print("🚀 === DÉMARRAGE SERVEUR DÉVELOPPEMENT ===")
|
|
|
|
# Charger les variables d'environnement
|
|
if not load_env_local():
|
|
return False
|
|
|
|
# Trouver un port libre
|
|
port = find_free_port(8001)
|
|
if not port:
|
|
print("❌ Aucun port libre trouvé")
|
|
return False
|
|
|
|
print(f"🌐 Port sélectionné: {port}")
|
|
|
|
# Créer le script serveur temporaire
|
|
temp_script = create_dev_server_script(port)
|
|
if not temp_script:
|
|
return False
|
|
|
|
try:
|
|
# Démarrer le serveur avec l'environnement virtuel
|
|
venv_python = Path("venv_v3/bin/python3")
|
|
if not venv_python.exists():
|
|
print("❌ Environnement virtuel venv_v3 non trouvé")
|
|
return False
|
|
|
|
print(f"🚀 Démarrage du serveur sur le port {port}...")
|
|
|
|
# Démarrer en arrière-plan
|
|
process = subprocess.Popen([
|
|
str(venv_python.absolute()), temp_script.name
|
|
], cwd="server", env=os.environ.copy())
|
|
|
|
print(f" PID: {process.pid}")
|
|
print(f" URL: http://127.0.0.1:{port}")
|
|
|
|
# Attendre que le serveur démarre
|
|
print("⏳ Attente du démarrage du serveur...")
|
|
for i in range(20):
|
|
time.sleep(1)
|
|
try:
|
|
response = requests.get(f"http://127.0.0.1:{port}/health", timeout=2)
|
|
if response.status_code in [200, 401]: # 401 = serveur répond mais auth requise
|
|
print("✅ Serveur démarré!")
|
|
break
|
|
except requests.exceptions.ConnectionError:
|
|
if i == 19:
|
|
print("❌ Serveur n'a pas démarré dans les temps")
|
|
process.terminate()
|
|
return False
|
|
print(f" Tentative {i+1}/20...")
|
|
|
|
# Tester l'authentification
|
|
print("🔐 Test d'authentification...")
|
|
token = os.environ.get('RPA_TOKEN_ADMIN')
|
|
|
|
try:
|
|
response = requests.get(
|
|
f"http://127.0.0.1:{port}/api/traces/status",
|
|
headers={"Authorization": f"Bearer {token}"},
|
|
timeout=5
|
|
)
|
|
|
|
if response.status_code == 200:
|
|
print("✅ Authentification réussie!")
|
|
|
|
# Tester l'upload avec le bon format
|
|
print("🧪 Test d'upload...")
|
|
test_data = b"test upload data"
|
|
files = {
|
|
"file": ("test_session.zip", test_data, "application/zip")
|
|
}
|
|
data = {
|
|
"session_id": "test_session_123"
|
|
}
|
|
upload_response = requests.post(
|
|
f"http://127.0.0.1:{port}/api/traces/upload",
|
|
headers={"Authorization": f"Bearer {token}"},
|
|
files=files,
|
|
data=data,
|
|
timeout=10
|
|
)
|
|
|
|
if upload_response.status_code == 200:
|
|
print("✅ Upload test réussi!")
|
|
|
|
# Mettre à jour .env.local avec la nouvelle URL
|
|
update_env_server_url(f"http://127.0.0.1:{port}/api/traces/upload")
|
|
|
|
# Sauvegarder les informations du serveur
|
|
save_server_info(process.pid, port, temp_script)
|
|
|
|
print("\\n🎉 === SERVEUR DÉVELOPPEMENT PRÊT ===")
|
|
print(f"✅ URL: http://127.0.0.1:{port}")
|
|
print(f"✅ PID: {process.pid}")
|
|
print(f"✅ Token: {token[:16]}...")
|
|
print("\\n📝 PROCHAINES ÉTAPES:")
|
|
print("1. Démarrer l'agent v0: cd agent_v0 && python main.py")
|
|
print("2. Capturer une session de test")
|
|
print("3. Vérifier que l'upload fonctionne")
|
|
print(f"\\n🛑 Pour arrêter: python3 stop_dev_server.py")
|
|
|
|
return True
|
|
else:
|
|
print(f"❌ Upload test échoué: {upload_response.status_code}")
|
|
print(f" Réponse: {upload_response.text}")
|
|
else:
|
|
print(f"❌ Authentification échouée: {response.status_code}")
|
|
print(f" Réponse: {response.text}")
|
|
|
|
except Exception as e:
|
|
print(f"❌ Erreur test: {e}")
|
|
|
|
# Nettoyer en cas d'échec
|
|
process.terminate()
|
|
return False
|
|
|
|
except Exception as e:
|
|
print(f"❌ Erreur démarrage serveur: {e}")
|
|
return False
|
|
|
|
finally:
|
|
# Nettoyer le script temporaire en cas d'échec
|
|
if temp_script and temp_script.exists():
|
|
try:
|
|
temp_script.unlink()
|
|
except:
|
|
pass
|
|
|
|
def update_env_server_url(new_url):
|
|
"""Met à jour l'URL du serveur dans .env.local"""
|
|
env_path = Path(".env.local")
|
|
if not env_path.exists():
|
|
return
|
|
|
|
with open(env_path, 'r') as f:
|
|
lines = f.readlines()
|
|
|
|
# Chercher et modifier la ligne RPA_SERVER_URL
|
|
modified = False
|
|
for i, line in enumerate(lines):
|
|
if line.strip().startswith('RPA_SERVER_URL='):
|
|
lines[i] = f"RPA_SERVER_URL={new_url}\\n"
|
|
modified = True
|
|
break
|
|
|
|
# Ajouter la ligne si elle n'existe pas
|
|
if not modified:
|
|
lines.append(f"RPA_SERVER_URL={new_url}\\n")
|
|
|
|
with open(env_path, 'w') as f:
|
|
f.writelines(lines)
|
|
|
|
print(f"✓ URL serveur mise à jour dans .env.local")
|
|
|
|
def save_server_info(pid, port, temp_script):
|
|
"""Sauvegarde les informations du serveur pour pouvoir l'arrêter"""
|
|
info = {
|
|
"pid": pid,
|
|
"port": port,
|
|
"temp_script": str(temp_script),
|
|
"started_at": time.strftime("%Y-%m-%d %H:%M:%S")
|
|
}
|
|
|
|
with open("dev_server_info.json", "w") as f:
|
|
import json
|
|
json.dump(info, f, indent=2)
|
|
|
|
print("✓ Informations serveur sauvegardées dans dev_server_info.json")
|
|
|
|
def main():
|
|
"""Démarrage du serveur de développement"""
|
|
print("🎯 === SERVEUR API DÉVELOPPEMENT ===")
|
|
|
|
if not start_dev_server():
|
|
print("❌ Échec du démarrage du serveur")
|
|
return False
|
|
|
|
return True
|
|
|
|
if __name__ == "__main__":
|
|
success = main()
|
|
exit(0 if success else 1) |