Dans ce tutoriel, tu vas créer une application de diagnostic PC avec Flask et Python : informations système (CPU, RAM, disques, réseau), liste des processus avec possibilité de les arrêter, programmes installés et formulaire de support. Un outil de helpdesk concret, basé sur psutil et Bootstrap.
Salut, c’est repartie pour un nouveau tutoriel sur Flask et Python. Dans ce tutoriel, je te guide pas à pas dans la création d’une application web professionnelle de diagnostic système pour techniciens IT. Tu apprendras à créer une interface moderne permettant de monitorer, gérer et diagnostiquer des PC Windows à distance.

Introduction : une application de diagnostic PC avec Flask
En tant que développeur et technicien IT depuis plusieurs années, j’ai souvent eu besoin d’outils pour diagnostiquer rapidement les problèmes sur les postes de travail Windows. Les solutions existantes sont soit trop complexes, soit payantes, soit ne répondent pas exactement aux besoins.
C’est pourquoi j’ai décidé de créer HelpDesk Info, une application web légère et moderne qui permet de:
– ✅ Collecter toutes les informations système en un clin d’œil
– ✅ Gérer les programmes installés (avec désinstallation à distance)
– ✅ Contrôler les services Windows
– ✅ Monitorer les processus en temps réel
– ✅ Exporter des rapports de diagnostic
Ce que tu vas construire
Coté backend, nous verrons comment créer une application Flask structurée et professionnelle, comment utiliser psutil pour collecter des informations système, comment interagir avec le registre Windows via winreg, comment exécuter des commandes PowerShell depuis Python, comment Implémenter une gestion d’erreurs robuste et enfin comment configurer un système de logging professionnel.
Côté frontend, nous verrons comment créer une interface moderne avec Bootstrap 5, comment implémenter des animations et transitions CSS, comment utiliser DataTables pour des tableaux interactifs et enfin comment créer un système de notifications toast personnalisé
Nous utiliserons une architecture MVC pour applications Flask, la sécurisation des entrées utilisateur, et de stechniques de gestion des erreurs et exceptions


Étape 1 : Mise en place de l’environnement
1) Créer le projet
Ouvre un terminal et crée le dossier principal:
mkdir helpdesk-info
cd helpdesk-infoterminal2) Créer / activer l’environnement virtuel (Windows)
Un environnement virtuel isole les dépendances de ton projet:
python -m venv venv
venv\Scripts\activateterminal3) Installer les dépendances
Crée le fichier fichier requirements.txt
Flask>=3.0.0
psutil>=5.9.0
requests>=2.31.0requirements.txtPuis installe les dépendances:
pip install -r requirements.txtterminalCes étapes peuvent se faire depuis ton terminal ou ton invite de commandes sous Windows
Étape 2 : Structure du projet
Arborescence :
Création rapide (Windows) :
mkdir static templates
type nul > main.py
type nul > static\style.css
type nul > templates\index.htmlterminalÉtape 3 : Backend Flask (collecte système)
1) Base Flask + imports
Ouvre main.py et commençons par les imports et la configuration. Dans main.py, initialise Flask, les imports et les logs :
"""
HelpDesk Info - Application de diagnostic PC professionnel
Auteur: Michael - LM-Code (https://lm-code.be)
"""
from flask import Flask, render_template, request, send_file, jsonify
import platform
import socket
import psutil
import requests
import datetime
import os
import subprocess
import winreg
import logging
from io import BytesIO
# Configuration de l'application Flask
app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(24)
app.config['JSON_AS_ASCII'] = False
# Configuration du système de logs
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('helpdesk.log'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)main.pySECRET_KEY sécurise les sessions Flask, JSON_AS_ASCII=False permet les caractères accentués dans le JSON et logging crée un fichier de log pour tracer les actions.
2) Fonctions clés
get_size(): convertit les octets (RAM, disque…)get_system_info(): récupère hostname, OS, CPU, RAM, disques, réseau, IP publique (ipify)
def get_size(bytes_value, suffix="B"):
"""
Convertit une taille en octets vers un format lisible.
Exemple: 1536 → "1.50 KB"
"""
factor = 1024
for unit in ["", "K", "M", "G", "T"]:
if bytes_value < factor:
return f"{bytes_value:.2f} {unit}{suffix}"
bytes_value /= factor
return f"{bytes_value:.2f} P{suffix}"main.py3) Route principale /
La fonction la plus importante : elle collecte toutes les données:
def get_system_info():
"""
Collecte complète des informations système.
Returns:
dict: Toutes les informations système formatées
"""
# IP publique via service externe
try:
public_ip = requests.get("https://api.ipify.org", timeout=5).text
logger.info(f"IP publique récupérée: {public_ip}")
except Exception as e:
logger.warning(f"Impossible de récupérer l'IP publique: {e}")
public_ip = "Non disponible"
# Temps de démarrage et uptime
boot_time = datetime.datetime.fromtimestamp(psutil.boot_time())
uptime = datetime.datetime.now() - boot_time
# Informations des disques
disk_info = []
for part in psutil.disk_partitions():
try:
usage = psutil.disk_usage(part.mountpoint)
disk_info.append({
"device": part.device,
"mountpoint": part.mountpoint,
"fstype": part.fstype,
"total": get_size(usage.total),
"used": get_size(usage.used),
"free": get_size(usage.free),
"percent": usage.percent
})
except PermissionError:
continue
# Informations réseau
net_info = []
mac_address = "Non disponible"
for interface_name, interface_addresses in psutil.net_if_addrs().items():
for address in interface_addresses:
if str(address.family) == 'AddressFamily.AF_INET':
net_info.append({
"interface": interface_name,
"ip": address.address,
"netmask": address.netmask if address.netmask else "N/A"
})
# Dictionnaire de retour
return {
"hostname": socket.gethostname(),
"username": os.getlogin(),
"os": f"{platform.system()} {platform.release()}",
"architecture": platform.machine(),
"cpu": platform.processor(),
"cores_physical": psutil.cpu_count(logical=False),
"cores_total": psutil.cpu_count(logical=True),
"cpu_usage": psutil.cpu_percent(interval=1),
"ram_total": get_size(psutil.virtual_memory().total),
"ram_used": get_size(psutil.virtual_memory().used),
"ram_available": get_size(psutil.virtual_memory().available),
"boot_time": boot_time.strftime("%Y-%m-%d %H:%M:%S"),
"uptime": str(uptime).split('.')[0],
"ip_public": public_ip,
"mac_address": mac_address,
"disks": disk_info,
"network": net_info
}main.py- GET : affiche les infos systèm
- POST : récupère le texte “problème” décrit par l’utilisateur
- psutil.cpu_percent(): Utilisation CPU en temps réel
- psutil.virtual_memory(): Statistiques mémoire RAM
- psutil.disk_partitions(): Liste des disques
- Gestion des erreurs avec try/except pour éviter les crashs
4) Lancer l’app
En bas du fichier :
if __name__ == "__main__":
app.run(host="127.0.0.1", port=5000, debug=True, threaded=True)main.pyÉtape 4 : Frontend (Bootstrap + onglets)
Dans templates/index.html :
- Charger Bootstrap 5.3.2 + DataTables + Bootstrap Icons + ton CSS
- Créer un header (card + dégradé)
- Ajouter des onglets :
- Infos Système
- Programmes
- Services
- Processus
Dans l’onglet “Infos Système” :
- affichage des champs (readonly)
- textarea “Décrivez votre problème”
- boutons : Exporter / Envoyer
Étape 5 : CSS
Dans static/style.css :
- variables CSS (couleurs, ombres, transitions)
- fond en dégradé
- header avec effet shimmer
- onglets stylisés
- boutons avec hover + ombre
Étape 6 : Programmes (Windows Registry)
Backend :
get_installed_programs()viawinreg- endpoint
/programsqui renvoie JSON
Frontend :
- table DataTables
#programsTable - chargement via jQuery
$.getJSON('/programs')
Étape 7 : Services Windows (PowerShell)
Backend :
get_services()viaGet-Service- endpoint
/services(JSON) - endpoint
/service_action(POST) : start/stop/restart avec validation + logs
Frontend :
- table DataTables + badges Running/Stopped
- boutons actions : start/stop/restart
Étape 8 : Processus (psutil)
Backend :
def get_processes():
"""Récupère la liste des processus actifs"""
processes = []
for proc in psutil.process_iter(['pid', 'name', 'cpu_percent', 'memory_info']):
try:
info = proc.info
info['memory'] = get_size(info['memory_info'].rss)
del info['memory_info']
processes.append(info)
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
return processes
@app.route("/processes")
def processes():
"""Endpoint API pour les processus"""
try:
return jsonify(get_processes())
except Exception as e:
logger.error(f"Erreur: {e}")
return jsonify([]), 500main.py- endpoint
/processes(JSON) - endpoint
/kill_process(POST) : terminate/kill avec confirmation + gestion AccessDenied
@app.route("/kill_process", methods=["POST"])
def kill_process():
"""Termine un processus par son PID"""
try:
data = request.get_json()
if not data or 'pid' not in data:
return jsonify({"success": False, "message": "PID manquant"}), 400
pid = int(data.get("pid"))
if not psutil.pid_exists(pid):
return jsonify({"success": False, "message": "Processus inexistant"}), 404
logger.info(f"Terminaison du processus PID: {pid}")
process = psutil.Process(pid)
process_name = process.name()
process.terminate()
try:
process.wait(timeout=5)
return jsonify({
"success": True,
"message": f"Processus '{process_name}' (PID: {pid}) terminé"
})
except psutil.TimeoutExpired:
process.kill()
return jsonify({
"success": True,
"message": f"Processus forcé à se terminer"
})
except psutil.AccessDenied:
return jsonify({
"success": False,
"message": "Accès refusé. Privilèges administrateur requis."
}), 403
except Exception as e:
logger.error(f"Erreur: {e}")
return jsonify({"success": False, "message": str(e)}), 500main.pyCette application peut lire les informations de ton système et terminer des processus. Garde-la en local (127.0.0.1) et ne l’expose jamais sur Internet, surtout avec debug=True, qui permet d’exécuter du code à distance.
Frontend :
- table DataTables + mise en couleur CPU
- bouton “Tuer” (confirm)
// Fonction de terminaison de processus
function killProcess(pid, name) {
if (!confirm(`Terminer "${name}" (PID: ${pid}) ?\n\nCela peut causer une perte de données.`)) {
return;
}
showToast(`Arrêt du processus ${pid} en cours...`, 'info');
fetch('/kill_process', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ pid })
})
.then(res => res.json())
.then(data => {
if (data.success) {
showToast(data.message, 'success');
setTimeout(() => $('#proc-tab').click(), 1500);
} else {
showToast(data.message, 'error');
}
});
}
// Chargement des processus
$('#proc-tab').on('shown.bs.tab', () => {
loadTable('/processes', '#processesTable', [
{ data: 'pid' },
{ data: 'name' },
{
data: 'cpu_percent',
render: function(data) {
const percentage = parseFloat(data) || 0;
let colorClass = 'text-success';
if (percentage > 50) colorClass = 'text-warning';
if (percentage > 80) colorClass = 'text-danger';
return `<span class="${colorClass} fw-bold">${percentage.toFixed(1)}%</span>`;
}
},
{ data: 'memory' },
{
data: null,
render: function(data, type, row) {
return `<button class="btn btn-sm btn-danger" onclick="killProcess(${row.pid}, '${row.name}')" title="Terminer">
<i class="bi bi-x-circle"></i> Tuer
</button>`;
}
}
]);
});templates/index.htmlÉtape 9 : Export du rapport
Backend :
- endpoint
/export - génère un
.txt(infos + listes) en mémoire (BytesIO) - retourne
send_file(..., as_attachment=True)

Et voilà, notre projet est prêt. Merci d’avoir suivi ce tutoriel jusqu’au bout! J’espère que tu as appris des techniques utiles pour tes futurs projets. N’hésite pas à adapter ce projet à tes besoins spécifiques. Laisse tes avis en commentaire ou si tu as des questions.
Il est important de télécharger le code source tout en suivant le tuto.
Pour aller plus loin
- Prépare ton environnement avec le guide créer un environnement virtuel Python
- Découvre un autre projet Flask complet : l’outil de gestion de projets avec Flask et MySQL
- Consulte la documentation de psutil pour ajouter la température ou la batterie
FAQ : questions fréquentes
L’application fonctionne-t-elle sur macOS et Linux ?
Les informations système et les processus fonctionnent partout grâce à psutil. La liste des programmes installés utilise le registre Windows (winreg) et ne fonctionne donc que sous Windows.
Pourquoi certains processus ne peuvent pas être arrêtés ?
Les processus système ou ceux d’un autre utilisateur nécessitent des droits administrateur. L’application intercepte l’erreur AccessDenied et affiche un message au lieu de planter.
Puis-je mettre cette application en ligne ?
Non, elle est conçue pour un usage local : elle donne accès aux informations de la machine et peut arrêter des processus. Garde-la sur 127.0.0.1 et désactive le mode debug hors développement.
Comment obtenir l’adresse IP publique ?
L’application interroge le service ipify. Sans connexion Internet, cette information ne s’affiche simplement pas.

