|
En même temps c'est son taff. Les LLM (on devrait arrêter de dire IA, ca n'en est pas) c'est juste des supers algos pour faire de jolie trucs en assemblant le masse de donnée possible. Ca n'invente rien. D'où les soucis ici. Claude va pomper les repos git d'étudiants qui ont fait ca pour leur devoirs, fait un gloubi boulga de tout ca et pont ce truc. Il n'invente rien. Si demain on lui demande un truc qui n'existe pas, il est perdu. Il en est incapable.
A quel moment c'est fabuleux ? Y'a tjs pas une version correcte de sortie... Pour un truc supposé être tout puissant c'est un peu la dèche...
L'IA a a créé ce petit jeu 3D avec moi en mode balec qui est parti d'un prompt de 2 lignes. y a quelques bugs mineurs qui se règlent en 1 prompt d'une ligne à chaque fois, et encore le coup des textures qui changent et des blocs qui décalent sils sont contre une bord quand on pivote, ce ne sont pas des bugs, juste des choses à préciser.
T'es tellement blasé du truc que tu vas louper non pas le wagon mais le train entier. Ta remarque sur "ce sont juste des algos", "ça n'invente rien" démontrent que t'es resté coincé à quelques années maintenant en arrière. Tu te trompes sur Claude.
Il va halluciner si tu lui demandes une nouvelle loi mathématique, évidemment, son job c'est de te répondre quoi qu'il arrive. Mais ça ne veut pas dire qu'il n'invente rien. Il ne pompe pas en faisant du C/c. Il recompose tout, tu peux obtenir des patterns absolument inédits.
voici la nouvelle version du Tetris :
Pour evaluer la capacité de l'IA a coder, faut lui filer des taches simples mais "nouvelles" sur le net.
Par exemple coder une gui en RUST (choix de la library gui au choix de l'IA), qui implemente une ouverture de fichier son wav, mp3, ogg, autre... une visualisation simple du spectre, possibilité de lecture, quelques outils simples genre un algo de nettoyage du bruit open source, ou de suppression des blancs.
Avec sauvegarde du resultat dans le format de notre choix bien sur.
L'IA sera super forte pour te pondre une architecture abstraite ou te proposer des technos pertinentes pour répondre au besoin, mais elle se mettra à halluciner en inventant des crates imaginaires dès qu'elle voudra cracher du code un peu plus compliqué qu'ouvrir une fenêtre et afficher un bouton.
Y a pas que pour l'architecture qu'elle sera balaise, sur les choix de techos etc elle va t'épater aussi.
J'ai bien envie de tester ton défi aussi ce soir. je note : coder une gui en RUST (choix de la library gui au choix de l'IA), qui implemente une ouverture de fichier son wav, mp3, ogg, autre... une visualisation simple du spectre, possibilité de lecture, quelques outils simples genre un algo de nettoyage du bruit open source, ou de suppression des blancs.
Voilà mon projet informatique :
je me suis permis de retravailler ton prompt :
1. Définis un modèle de données pour un réseau de métro
Tu dois modéliser les entités suivantes :
- Circuit de voie : état
ou
- Aiguille : état
ou
- Signal : état
ou
- Itinéraire : état
,
ou
.
Un itinéraire va d’un signal origine à un signal destination, en passant par une séquence de circuits et d’aiguilles.
2. Génère un exemple de base de données d’un réseau fictif
- Propose un exemple complet de base de données correspondant à ce modèle, comprenant au moins :
- 5 circuits de voie
- 2 aiguilles
- 3 signaux
- 2 itinéraires
Structure-la au format JSON ou toute structure facilement exploitable en code.
3. Développe le code serveur et IHM pour animer la représentation du réseau
- Choisis un framework web léger (ex : Flask, FastAPI, Express.js, etc.) pour le serveur et une IHM simple (ex : HTML/JS, React, etc.).
- Affiche dynamiquement :
- Les circuits de voie avec leur état (
/
)
- Les aiguilles avec leur état (
/
)
- Les signaux avec leur état (
/
)
- Les itinéraires avec leur état (
/
/
)
- Représentation :
- Un train = un rectangle, affiché dès que deux circuits de voie consécutifs sont occupés.
- Les états doivent pouvoir changer dynamiquement (par API ou websocket).
4. Génère un simulateur simple pour animer le logiciel
- Crée un script/simulateur qui fait se déplacer un train unique sur le réseau fictif :
- Le train occupe les circuits de voie de façon séquentielle, modifiant dynamiquement l’état des circuits, des aiguilles et des signaux selon la logique du réseau.
- L’interface doit montrer visuellement ce déplacement en temps réel.
Objectif final :
Obtiens le projet complet, prêt à lancer localement, avec une IHM web interactive représentant le réseau, capable d’animer un train sur le réseau fictif.
voici le résultat, 1 prompt unique :
Résumé du projet
J'ai créé un système complet de supervision d'un réseau de métro avec :
1. Architecture
- Backend : FastAPI avec WebSocket pour les mises à jour temps réel
- Frontend : HTML5 Canvas pour la visualisation dynamique
- Communication : REST API + WebSocket bidirectionnel
2. Fonctionnalités principales
- Visualisation en temps réel du réseau (circuits, aiguilles, signaux)
- Détection automatique des trains (2 circuits consécutifs occupés)
- Gestion des itinéraires avec vérification de sécurité
- Simulateur de circulation de train
- Contrôle manuel des éléments du réseau
3. Points techniques notables
- État centralisé côté serveur avec diffusion WebSocket
- Rendu Canvas optimisé avec mise à jour différentielle
- Logique métier respectant les contraintes ferroviaires
- API RESTful complète pour toutes les opérations
4. Pour démarrer
- Créez les 3 fichiers (JSON, Python, HTML)
- Installez FastAPI :
pip install fastapi uvicorn websockets
- Lancez :
- Ouvrez :
Le système est prêt à l'emploi et peut être étendu facilement avec de nouveaux éléments de réseau ou des fonctionnalités supplémentaires comme plusieurs trains, la gestion des zones de manœuvre, ou l'intégration avec des systèmes SCADA réels.
modèle de données du réseau
{
"circuits": {
"C1": {
"id": "C1",
"nom": "Circuit 1",
"etat": "libre",
"position": { "x": 100, "y": 200 }
},
"C2": {
"id": "C2",
"nom": "Circuit 2",
"etat": "libre",
"position": { "x": 200, "y": 200 }
},
"C3": {
"id": "C3",
"nom": "Circuit 3",
"etat": "libre",
"position": { "x": 300, "y": 200 }
},
"C4": {
"id": "C4",
"nom": "Circuit 4",
"etat": "libre",
"position": { "x": 400, "y": 150 }
},
"C5": {
"id": "C5",
"nom": "Circuit 5",
"etat": "libre",
"position": { "x": 400, "y": 250 }
}
},
"aiguilles": {
"A1": {
"id": "A1",
"nom": "Aiguille 1",
"etat": "normal",
"position": { "x": 250, "y": 200 },
"circuit_avant": "C2",
"circuit_normal": "C3",
"circuit_reverse": "C4"
},
"A2": {
"id": "A2",
"nom": "Aiguille 2",
"etat": "normal",
"position": { "x": 350, "y": 200 },
"circuit_avant": "C3",
"circuit_normal": "C5",
"circuit_reverse": "C4"
}
},
"signaux": {
"S1": {
"id": "S1",
"nom": "Signal 1",
"etat": "permissif",
"position": { "x": 80, "y": 180 },
"circuit_protege": "C1"
},
"S2": {
"id": "S2",
"nom": "Signal 2",
"etat": "restrictif",
"position": { "x": 280, "y": 180 },
"circuit_protege": "C3"
},
"S3": {
"id": "S3",
"nom": "Signal 3",
"etat": "restrictif",
"position": { "x": 420, "y": 230 },
"circuit_protege": "C5"
}
},
"itineraires": {
"I1": {
"id": "I1",
"nom": "Itinéraire 1",
"etat": "detruit",
"signal_origine": "S1",
"signal_destination": "S3",
"circuits": ["C1", "C2", "C3", "C5"],
"aiguilles": {
"A1": "normal",
"A2": "normal"
}
},
"I2": {
"id": "I2",
"nom": "Itinéraire 2",
"etat": "detruit",
"signal_origine": "S1",
"signal_destination": "S2",
"circuits": ["C1", "C2", "C3"],
"aiguilles": {
"A1": "normal"
}
}
},
"connexions": [
{ "de": "C1", "vers": "C2" },
{ "de": "C2", "vers": "A1" },
{ "de": "A1", "vers": "C3", "condition": "normal" },
{ "de": "A1", "vers": "C4", "condition": "reverse" },
{ "de": "C3", "vers": "A2" },
{ "de": "A2", "vers": "C5", "condition": "normal" },
{ "de": "A2", "vers": "C4", "condition": "reverse" }
]
}
Code serveur (FastAPI + WebSocket)
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
import json
import asyncio
from typing import List, Dict, Any
import time
from pathlib import Path
app = FastAPI()
# Configuration CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Chargement des données du réseau
with open('reseau_metro.json', 'r', encoding='utf-8') as f:
reseau_data = json.load(f)
# État actuel du réseau
etat_reseau = {
"circuits": reseau_data["circuits"].copy(),
"aiguilles": reseau_data["aiguilles"].copy(),
"signaux": reseau_data["signaux"].copy(),
"itineraires": reseau_data["itineraires"].copy(),
"trains": {}
}
# Gestionnaire de connexions WebSocket
class ConnectionManager:
def __init__(self):
self.active_connections: List[WebSocket] = []
async def connect(self, websocket: WebSocket):
await websocket.accept()
self.active_connections.append(websocket)
def disconnect(self, websocket: WebSocket):
self.active_connections.remove(websocket)
async def broadcast(self, message: dict):
for connection in self.active_connections:
try:
await connection.send_json(message)
except:
pass
manager = ConnectionManager()
@app.get("/")
async def get():
with open('index.html', 'r', encoding='utf-8') as f:
return HTMLResponse(content=f.read())
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await manager.connect(websocket)
try:
# Envoyer l'état initial
await websocket.send_json({
"type": "etat_complet",
"data": etat_reseau
})
while True:
data = await websocket.receive_text()
# Garder la connexion active
except WebSocketDisconnect:
manager.disconnect(websocket)
@app.get("/api/etat")
async def get_etat():
return etat_reseau
@app.post("/api/circuit/{circuit_id}/etat/{etat}")
async def update_circuit(circuit_id: str, etat: str):
if circuit_id in etat_reseau["circuits"]:
etat_reseau["circuits"][circuit_id]["etat"] = etat
await manager.broadcast({
"type": "update_circuit",
"circuit_id": circuit_id,
"etat": etat
})
# Mettre à jour les trains
await update_trains()
return {"status": "ok"}
@app.post("/api/aiguille/{aiguille_id}/etat/{etat}")
async def update_aiguille(aiguille_id: str, etat: str):
if aiguille_id in etat_reseau["aiguilles"]:
etat_reseau["aiguilles"][aiguille_id]["etat"] = etat
await manager.broadcast({
"type": "update_aiguille",
"aiguille_id": aiguille_id,
"etat": etat
})
return {"status": "ok"}
@app.post("/api/signal/{signal_id}/etat/{etat}")
async def update_signal(signal_id: str, etat: str):
if signal_id in etat_reseau["signaux"]:
etat_reseau["signaux"][signal_id]["etat"] = etat
await manager.broadcast({
"type": "update_signal",
"signal_id": signal_id,
"etat": etat
})
return {"status": "ok"}
@app.post("/api/itineraire/{itineraire_id}/activer")
async def activer_itineraire(itineraire_id: str):
if itineraire_id in etat_reseau["itineraires"]:
itineraire = etat_reseau["itineraires"][itineraire_id]
# Vérifier que tous les circuits sont libres
for circuit_id in itineraire["circuits"]:
if etat_reseau["circuits"][circuit_id]["etat"] == "occupe":
return {"status": "error", "message": "Circuit occupé"}
# Positionner les aiguilles
for aiguille_id, position in itineraire["aiguilles"].items():
etat_reseau["aiguilles"][aiguille_id]["etat"] = position
# Mettre le signal origine en permissif
signal_origine = itineraire["signal_origine"]
etat_reseau["signaux"][signal_origine]["etat"] = "permissif"
# Changer l'état de l'itinéraire
etat_reseau["itineraires"][itineraire_id]["etat"] = "forme"
await manager.broadcast({
"type": "etat_complet",
"data": etat_reseau
})
return {"status": "ok"}
async def update_trains():
"""Détecte les trains (2 circuits consécutifs occupés)"""
trains = {}
connexions = reseau_data["connexions"]
for conn in connexions:
circuit1 = conn["de"]
circuit2 = conn["vers"]
# Vérifier si les deux circuits sont occupés
if (circuit1 in etat_reseau["circuits"] and
circuit2 in etat_reseau["circuits"] and
etat_reseau["circuits"][circuit1]["etat"] == "occupe" and
etat_reseau["circuits"][circuit2]["etat"] == "occupe"):
# Vérifier les conditions d'aiguillage si nécessaire
if "condition" in conn:
# Trouver l'aiguille concernée
aiguille_id = circuit1 if circuit1.startswith("A") else None
if aiguille_id and etat_reseau["aiguilles"][aiguille_id]["etat"] != conn["condition"]:
continue
# Créer un train
train_id = f"T_{circuit1}_{circuit2}"
pos1 = etat_reseau["circuits"][circuit1]["position"]
pos2 = etat_reseau["circuits"][circuit2]["position"]
trains[train_id] = {
"id": train_id,
"position": {
"x": (pos1["x"] + pos2["x"]) / 2,
"y": (pos1["y"] + pos2["y"]) / 2
},
"circuits": [circuit1, circuit2]
}
etat_reseau["trains"] = trains
await manager.broadcast({
"type": "update_trains",
"trains": trains
})
# Simulateur de train
class TrainSimulator:
def __init__(self):
self.position_actuelle = 0
self.chemin = ["C1", "C2", "C3", "C5"] # Chemin par défaut
self.running = False
async def start(self):
self.running = True
while self.running:
# Libérer l'ancien circuit
if self.position_actuelle > 0:
ancien_circuit = self.chemin[self.position_actuelle - 1]
await update_circuit(ancien_circuit, "libre")
# Occuper le circuit actuel et le suivant
circuit_actuel = self.chemin[self.position_actuelle]
await update_circuit(circuit_actuel, "occupe")
if self.position_actuelle < len(self.chemin) - 1:
circuit_suivant = self.chemin[self.position_actuelle + 1]
await update_circuit(circuit_suivant, "occupe")
# Avancer
self.position_actuelle += 1
if self.position_actuelle >= len(self.chemin):
# Libérer le dernier circuit
await update_circuit(self.chemin[-1], "libre")
self.position_actuelle = 0
await asyncio.sleep(2) # Pause de 2 secondes
def stop(self):
self.running = False
simulator = TrainSimulator()
@app.post("/api/simulation/start")
async def start_simulation():
asyncio.create_task(simulator.start())
return {"status": "simulation démarrée"}
@app.post("/api/simulation/stop")
async def stop_simulation():
simulator.stop()
# Libérer tous les circuits
for circuit_id in etat_reseau["circuits"]:
await update_circuit(circuit_id, "libre")
return {"status": "simulation arrêtée"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
Interface HTML/JavaScript :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Réseau de Métro - Supervision</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #1a1a1a;
color: #fff;
}
.container {
max-width: 1400px;
margin: 0 auto;
}
h1 {
text-align: center;
color: #4CAF50;
}
.controls {
display: flex;
gap: 20px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.control-group {
background: #2a2a2a;
padding: 15px;
border-radius: 8px;
flex: 1;
min-width: 250px;
}
.control-group h3 {
margin-top: 0;
color: #4CAF50;
}
button {
background: #4CAF50;
color: white;
border: none;
padding: 10px 20px;
margin: 5px;
border-radius: 5px;
cursor: pointer;
transition: background 0.3s;
}
button:hover {
background: #45a049;
}
button.danger {
background: #f44336;
}
button.danger:hover {
background: #da190b;
}
#reseau-canvas {
background: #2a2a2a;
border: 2px solid #4CAF50;
border-radius: 10px;
display: block;
margin: 0 auto;
}
.status {
margin-top: 20px;
padding: 10px;
background: #2a2a2a;
border-radius: 8px;
}
.status-item {
display: inline-block;
margin: 5px 10px;
padding: 5px 10px;
background: #3a3a3a;
border-radius: 5px;
}
.circuit-libre { color: #4CAF50; }
.circuit-occupe { color: #f44336; }
.signal-permissif { color: #4CAF50; }
.signal-restrictif { color: #f44336; }
.aiguille-normal { color: #2196F3; }
.aiguille-reverse { color: #FF9800; }
.legend {
display: flex;
gap: 20px;
margin: 20px 0;
flex-wrap: wrap;
justify-content: center;
}
.legend-item {
display: flex;
align-items: center;
gap: 10px;
}
.legend-color {
width: 20px;
height: 20px;
border-radius: 3px;
}
</style>
</head>
<body>
<div class="container">
<h1>Système de Supervision du Réseau de Métro</h1>
<div class="controls">
<div class="control-group">
<h3>Simulation</h3>
<button onclick="startSimulation()">▶️ Démarrer la simulation</button>
<button onclick="stopSimulation()" class="danger">⏹️ Arrêter la simulation</button>
</div>
<div class="control-group">
<h3>Itinéraires</h3>
<button onclick="activerItineraire('I1')">Activer Itinéraire 1 (S1→S3)</button>
<button onclick="activerItineraire('I2')">Activer Itinéraire 2 (S1→S2)</button>
</div>
<div class="control-group">
<h3>Aiguilles</h3>
<button onclick="toggleAiguille('A1')">Basculer Aiguille 1</button>
<button onclick="toggleAiguille('A2')">Basculer Aiguille 2</button>
</div>
</div>
<div class="legend">
<div class="legend-item">
<div class="legend-color" style="background: #4CAF50;"></div>
<span>Circuit libre</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background: #f44336;"></div>
<span>Circuit occupé</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background: #FFD700;"></div>
<span>Train</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background: #2196F3;"></div>
<span>Aiguille normale</span>
</div>
<div class="legend-item">
<div class="legend-color" style="background: #FF9800;"></div>
<span>Aiguille inversée</span>
</div>
</div>
<canvas id="reseau-canvas" width="600" height="400"></canvas>
<div class="status" id="status">
<h3>État du réseau</h3>
<div id="status-content"></div>
</div>
</div>
<script>
const canvas = document.getElementById('reseau-canvas');
const ctx = canvas.getContext('2d');
let ws = null;
let etatReseau = null;
// Connexion WebSocket
function connectWebSocket() {
ws = new WebSocket('ws://localhost:8000/ws');
ws.onopen = () => {
console.log('Connecté au serveur');
};
ws.onmessage = (event) => {
const message = JSON.parse(event.data);
handleMessage(message);
};
ws.onclose = () => {
console.log('Déconnecté du serveur');
setTimeout(connectWebSocket, 2000);
};
}
function handleMessage(message) {
switch(message.type) {
case 'etat_complet':
etatReseau = message.data;
updateDisplay();
break;
case 'update_circuit':
if (etatReseau) {
etatReseau.circuits[message.circuit_id].etat = message.etat;
updateDisplay();
}
break;
case 'update_aiguille':
if (etatReseau) {
etatReseau.aiguilles[message.aiguille_id].etat = message.etat;
updateDisplay();
}
break;
case 'update_signal':
if (etatReseau) {
etatReseau.signaux[message.signal_id].etat = message.etat;
updateDisplay();
}
break;
case 'update_trains':
if (etatReseau) {
etatReseau.trains = message.trains;
updateDisplay();
}
break;
}
}
function updateDisplay() {
drawNetwork();
updateStatus();
}
function drawNetwork() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (!etatReseau) return;
// Dessiner les voies (connexions)
ctx.strokeStyle = '#666';
ctx.lineWidth = 3;
// Connexions simples entre circuits
drawLine('C1', 'C2');
drawLine('C2', 'C3');
drawLine('C3', 'C5');
drawLine('C2', 'C4');
drawLine('C3', 'C4');
// Dessiner les circuits de voie
for (const [id, circuit] of Object.entries(etatReseau.circuits)) {
const color = circuit.etat === 'libre' ? '#4CAF50' : '#f44336';
drawCircuit(circuit.position.x, circuit.position.y, id, color);
}
// Dessiner les aiguilles
for (const [id, aiguille] of Object.entries(etatReseau.aiguilles)) {
const color = aiguille.etat === 'normal' ? '#2196F3' : '#FF9800';
drawAiguille(aiguille.position.x, aiguille.position.y, id, color);
}
// Dessiner les signaux
for (const [id, signal] of Object.entries(etatReseau.signaux)) {
const color = signal.etat === 'permissif' ? '#4CAF50' : '#f44336';
drawSignal(signal.position.x, signal.position.y, id, color);
}
// Dessiner les trains
for (const [id, train] of Object.entries(etatReseau.trains || {})) {
drawTrain(train.position.x, train.position.y);
}
}
function drawLine(from, to) {
const posFrom = etatReseau.circuits[from]?.position || etatReseau.aiguilles[from]?.position;
const posTo = etatReseau.circuits[to]?.position || etatReseau.aiguilles[to]?.position;
if (posFrom && posTo) {
ctx.beginPath();
ctx.moveTo(posFrom.x, posFrom.y);
ctx.lineTo(posTo.x, posTo.y);
ctx.stroke();
}
}
function drawCircuit(x, y, id, color) {
ctx.fillStyle = color;
ctx.fillRect(x - 20, y - 10, 40, 20);
ctx.fillStyle = '#fff';
ctx.font = '12px Arial';
ctx.textAlign = 'center';
ctx.fillText(id, x, y + 4);
}
function drawAiguille(x, y, id, color) {
ctx.fillStyle = color;
ctx.beginPath();
ctx.moveTo(x, y - 15);
ctx.lineTo(x - 15, y + 15);
ctx.lineTo(x + 15, y + 15);
ctx.closePath();
ctx.fill();
ctx.fillStyle = '#fff';
ctx.font = '12px Arial';
ctx.textAlign = 'center';
ctx.fillText(id, x, y + 30);
}
function drawSignal(x, y, id, color) {
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(x, y, 12, 0, 2 * Math.PI);
ctx.fill();
ctx.fillStyle = '#fff';
ctx.font = '10px Arial';
ctx.textAlign = 'center';
ctx.fillText(id, x, y + 4);
}
function drawTrain(x, y) {
ctx.fillStyle = '#FFD700';
ctx.fillRect(x - 25, y - 12, 50, 24);
ctx.fillStyle = '#000';
ctx.font = '14px Arial';
ctx.textAlign = 'center';
ctx.fillText('��', x, y + 5);
}
function updateStatus() {
if (!etatReseau) return;
let html = '<div>';
// Circuits
html += '<h4>Circuits de voie:</h4>';
for (const [id, circuit] of Object.entries(etatReseau.circuits)) {
const className = circuit.etat === 'libre' ? 'circuit-libre' : 'circuit-occupe';
html += `<span class="status-item ${className}">${id}: ${circuit.etat}</span>`;
}
// Aiguilles
html += '<h4>Aiguilles:</h4>';
for (const [id, aiguille] of Object.entries(etatReseau.aiguilles)) {
const className = aiguille.etat === 'normal' ? 'aiguille-normal' : 'aiguille-reverse';
html += `<span class="status-item ${className}">${id}: ${aiguille.etat}</span>`;
}
// Signaux
html += '<h4>Signaux:</h4>';
for (const [id, signal] of Object.entries(etatReseau.signaux)) {
const className = signal.etat === 'permissif' ? 'signal-permissif' : 'signal-restrictif';
html += `<span class="status-item ${className}">${id}: ${signal.etat}</span>`;
}
html += '</div>';
document.getElementById('status-content').innerHTML = html;
}
// Fonctions de contrôle
async function startSimulation() {
const response = await fetch('/api/simulation/start', { method: 'POST' });
console.log('Simulation démarrée');
}
async function stopSimulation() {
const response = await fetch('/api/simulation/stop', { method: 'POST' });
console.log('Simulation arrêtée');
}
async function activerItineraire(id) {
const response = await fetch(`/api/itineraire/${id}/activer`, { method: 'POST' });
console.log(`Itinéraire ${id} activé`);
}
async function toggleAiguille(id) {
if (!etatReseau) return;
const nouvelEtat = etatReseau.aiguilles[id].etat === 'normal' ? 'reverse' : 'normal';
const response = await fetch(`/api/aiguille/${id}/etat/${nouvelEtat}`, { method: 'POST' });
console.log(`Aiguille ${id} basculée en ${nouvelEtat}`);
}
// Initialisation
connectWebSocket();
</script>
</body>
</html>
instructions d'installation et d'utilisation :
Système de Supervision du Réseau de Métro
Prérequis
Python 3.8+
pip (gestionnaire de paquets Python)
Installation
Créer un nouveau dossier pour le projet
mkdir metro-supervision
cd metro-supervision
Créer les fichiers nécessaires
Créez les trois fichiers suivants dans le dossier :
reseau_metro.json
(copier le contenu de l'artifact "Modèle de données")
main.py
(copier le contenu de l'artifact "Serveur FastAPI")
index.html
(copier le contenu de l'artifact "Interface web")
Installer les dépendances Python
pip install fastapi uvicorn websockets
Lancement
Démarrer le serveur
python main.py
Le serveur démarrera sur
http://localhost:8000
Ouvrir l'interface web
Ouvrez votre navigateur et accédez à :
http://localhost:8000
Utilisation
Interface principale
L'interface affiche :
Le réseau de voies : circuits (rectangles), aiguilles (triangles), signaux (cercles)
Les états en temps réel :
Circuits : vert (libre) ou rouge (occupé)
Aiguilles : bleu (position normale) ou orange (position inversée)
Signaux : vert (permissif) ou rouge (restrictif)
Les trains : rectangles jaunes avec emoji ��
Commandes disponibles
Simulation automatique
Démarrer la simulation
: Un train parcourt automatiquement le réseau
Arrêter la simulation
: Arrête le train et libère tous les circuits
Gestion des itinéraires
Activer Itinéraire 1
: Configure le chemin S1→S3 (via C1-C2-C3-C5)
Activer Itinéraire 2
: Configure le chemin S1→S2 (via C1-C2-C3)
Contrôle manuel des aiguilles
Basculer Aiguille 1
: Change la position de l'aiguille A1
Basculer Aiguille 2
: Change la position de l'aiguille A2
Logique du système
Détection des trains
Un train apparaît automatiquement quand 2 circuits consécutifs sont occupés
Le train est positionné entre les deux circuits
Itinéraires
Un itinéraire réserve un chemin complet avec :
Vérification que tous les circuits sont libres
Positionnement automatique des aiguilles
Signal origine mis en permissif
État de l'itinéraire : détruit → enregistré → formé
Simulation
Le train se déplace de circuit en circuit
Occupe 2 circuits à la fois (position actuelle et suivante)
Libère automatiquement les circuits derrière lui
Boucle sur le parcours (retour au début à la fin)
Structure du réseau
Le réseau exemple comprend :
5 circuits de voie (C1 à C5) formant une voie avec embranchement
2 aiguilles (A1, A2) permettant de choisir le chemin
3 signaux (S1, S2, S3) protégeant les zones
2 itinéraires prédéfinis pour la circulation
S1 → C1 → C2 → A1 → C3 → A2 → C5 → S3
↓ ↓
C4 ←------┘
↓
S2
API REST disponible
Le serveur expose les endpoints suivants :
GET /api/etat
: Obtenir l'état complet du réseau
POST /api/circuit/{id}/etat/{libre|occupe}
: Modifier l'état d'un circuit
POST /api/aiguille/{id}/etat/{normal|reverse}
: Modifier l'état d'une aiguille
POST /api/signal/{id}/etat/{permissif|restrictif}
: Modifier l'état d'un signal
POST /api/itineraire/{id}/activer
: Activer un itinéraire
POST /api/simulation/start
: Démarrer la simulation
POST /api/simulation/stop
: Arrêter la simulation
WebSocket
L'interface utilise une connexion WebSocket (
ws://localhost:8000/ws
) pour recevoir les mises à jour en temps réel :
etat_complet
: État complet du réseau
update_circuit
: Mise à jour d'un circuit
update_aiguille
: Mise à jour d'une aiguille
update_signal
: Mise à jour d'un signal
update_trains
: Mise à jour de la position des trains
Personnalisation
Pour modifier le réseau :
Éditez le fichier
reseau_metro.json
Ajoutez/modifiez les circuits, aiguilles, signaux et itinéraires
Mettez à jour les connexions pour définir la topologie
Ajustez les positions (x, y) pour l'affichage
Dépannage
Le serveur ne démarre pas : Vérifiez que le port 8000 est libre
L'interface ne se charge pas : Vérifiez que les 3 fichiers sont dans le même dossier
La simulation ne fonctionne pas : Actualisez la page et reconnectez-vous au WebSocket
qu'en penses tu ?
Non
Pour le Tetris je continuerai ce soir.
Dernière modification par Tonton Jack ; 30/05/2025 à 14h58.
|