Construire un Assistant IA Personnel 100% Local
Un guide complet pour créer votre propre JARVIS / FRIDAY — contrôle multi-appareils, voix, médias, messages, le tout sans aucune donnée envoyée à des tiers.
Introduction : Pourquoi un Assistant IA Local ?
Dans un monde où nos données personnelles sont constamment collectées par les géants de la tech, avoir un assistant IA 100% local et privé devient un véritable atout. Imaginez un assistant inspiré de JARVIS ou FRIDAY d'Iron Man, capable de :
- 🎮 Contrôler tous vos appareils à distance
- 🗣️ Répondre vocalement en plusieurs langues
- 📺 Gérer vos médias (vidéos, musique)
- 📱 Répondre à vos messages automatiquement
- 📸 Prendre des photos via caméra
- 🌍 Utiliser la localisation GPS
- ⚙️ Exécuter des commandes système
- 🔄 Automatiser vos routines quotidiennes
- 🔒 Zéro données envoyées à des tiers
Dans ce guide, nous allons construire cet assistant de A à Z en utilisant des technologies open-source modernes. Tout tournera sur votre propre serveur, garantissant une confidentialité absolue.
Vue d'Ensemble de l'Architecture
Notre assistant repose sur une architecture modulaire et scalable :
┌──────────────────────────────────────────────────────┐
│ VPS/Serveur Linux │
│ │
│ ┌────────────────────────────────┐ │
│ │ Nginx (Reverse Proxy) │ │
│ │ Port 443 (HTTPS) + SSL │ │
│ └────────────────────────────────┘ │
│ ↓ │
│ ┌────────────────────────────────┐ │
│ │ FastAPI + WebSocket │ │
│ │ API REST + Auth JWT │ │
│ └────────────────────────────────┘ │
│ ↓ │
│ ┌────────────────────────────────┐ │
│ │ Ollama (LLM Local) │ │
│ │ Llama 3.1 8B / Mistral 7B │ │
│ └────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────┐ │
│ │ SQLite Database │ │
│ │ Historique + Contexte + Logs │ │
│ └────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
↕
HTTPS chiffré (TLS/SSL)
↕
┌──────────────────────────────────────────────────────┐
│ Clients (Windows/Android/Linux) │
│ │
│ Agent Local : │
│ - WebSocket client + Auto-reconnexion │
│ - Contrôle système + TTS/STT vocal │
│ - Caméra / GPS │
└──────────────────────────────────────────────────────┘
Choix du Modèle LLM
Le cœur de notre assistant est le modèle de langage. Voici une comparaison pour un serveur avec 16GB RAM et CPU multi-core :
| Modèle | RAM | Vitesse | Qualité | Avis |
|---|---|---|---|---|
| Llama 3.3 70B Q2 | ~12 GB | 15-25 sec | Excellent | ❌ Trop lent |
| Llama 3.1 8B Q4 | ~6 GB | 3-5 sec | Très bon | ⭐ OPTIMAL |
| Llama 3.2 3B | ~3 GB | 1-2 sec | Correct | ✅ Backup |
| Mistral 7B v0.3 | ~5 GB | 3-4 sec | Très bon | ✅ Alternative |
| Phi-3 Mini 3.8B | ~3 GB | 1-2 sec | Bon | ✅ Ultra-rapide |
Recommandation : Llama 3.1 8B Q4 offre le meilleur compromis vitesse/qualité/RAM pour un assistant réactif.
⚠️ Note importante : Avec le contexte long (historique conversations), la RAM peut monter jusqu'à 10 GB. Surveillez et limitez la taille du contexte si nécessaire.
Configuration du Serveur
Prérequis Serveur
| Composant | Minimum | Recommandé |
|---|---|---|
| CPU | 4 cores | 8+ cores |
| RAM | 12 GB | 16 GB+ |
| Stockage | 20 GB | 50 GB |
| OS | Linux (Ubuntu/Debian) | Ubuntu 22.04+ LTS |
| GPU | Aucun (CPU only) | NVIDIA (accélération) |
Installation des dépendances
# Mise à jour système
sudo apt update && sudo apt upgrade -y
# Installation Docker
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
# Installation Docker Compose
sudo apt install docker-compose-plugin -y
# Vérification
docker --version
docker compose version
# Installation Nginx
sudo apt install nginx certbot python3-certbot-nginx -y
Structure du Projet Docker
Arborescence des fichiers
/opt/assistant-ia/
├── docker-compose.yml
├── .env
├── .env.example
│
├── services/
│ └── api/
│ ├── Dockerfile
│ ├── requirements.txt
│ └── app/
│ ├── main.py
│ ├── config.py
│ ├── ai_personality.py
│ ├── routes/
│ │ ├── chat.py
│ │ ├── devices.py
│ │ ├── actions.py
│ │ └── auth.py
│ ├── models/
│ │ ├── conversation.py
│ │ ├── device.py
│ │ └── user.py
│ └── services/
│ ├── ollama_client.py
│ ├── websocket_manager.py
│ └── command_executor.py
│
├── config/
│ ├── ai_personality.json
│ └── routines.json
│
├── data/
├── logs/
└── shared/
├── outputs/
└── uploads/
Fichier docker-compose.yml
version: '3.8'
services:
ollama:
image: ollama/ollama:latest
container_name: ai-assistant-ollama
restart: unless-stopped
volumes:
- ollama-models:/root/.ollama
environment:
- OLLAMA_HOST=0.0.0.0:11434
- OLLAMA_ORIGINS=*
networks:
- assistant-network
deploy:
resources:
limits:
memory: 10G
reservations:
memory: 6G
api:
build: ./services/api
container_name: ai-assistant-api
restart: unless-stopped
ports:
- "127.0.0.1:8888:8888"
volumes:
- ./services/api/app:/app
- ./config:/config:ro
- ./data:/data
- ./logs:/logs
- ./shared:/shared
environment:
- OLLAMA_URL=http://ollama:11434
- DATABASE_PATH=/data/assistant.db
- LOG_LEVEL=INFO
- JWT_SECRET=${JWT_SECRET}
- ALLOWED_ORIGINS=${ALLOWED_ORIGINS}
depends_on:
- ollama
networks:
- assistant-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8888/health"]
interval: 30s
timeout: 10s
retries: 3
networks:
assistant-network:
driver: bridge
volumes:
ollama-models:
Fichier .env.example
# JWT Secret (générer avec: openssl rand -hex 32)
JWT_SECRET=your_secret_key_here_change_this
# CORS Origins
ALLOWED_ORIGINS=https://yourdomain.com
# Configuration Ollama
OLLAMA_MODEL=llama3.1:8b
OLLAMA_CONTEXT_LENGTH=4096
# Base de données
DATABASE_PATH=/data/assistant.db
# Logging
LOG_LEVEL=INFO
Système de Personnalité
Le System Prompt
Le system prompt définit le comportement de votre assistant :
Fichier : config/ai_personality.json
{
"name": "Assistant",
"version": "1.0",
"personality": {
"tone": "professionnel avec touche d'humour",
"style": "concis et direct",
"proactivity": true
},
"system_prompt": "Tu es un assistant IA personnel avancé...",
"capabilities": [
"device_control",
"media_management",
"messaging",
"camera_control",
"gps_location",
"system_commands",
"routines_automation"
]
}
Implémentation Python
Fichier : services/api/app/ai_personality.py
import json
from datetime import datetime
from typing import Dict, List, Optional
class AIPersonality:
def __init__(self, config_path: str = "/config/ai_personality.json"):
with open(config_path, 'r', encoding='utf-8') as f:
self.config = json.load(f)
def get_system_prompt(
self,
connected_devices: Optional[List[str]] = None,
user_context: Optional[Dict] = None
) -> str:
"""Génère le system prompt avec contexte dynamique"""
prompt = self.config['system_prompt']
current_date = datetime.now().strftime("%d %B %Y, %H:%M")
devices_list = ", ".join(connected_devices) if connected_devices else "Aucun"
prompt = prompt.replace("{current_date}", current_date)
prompt = prompt.replace("{connected_devices}", devices_list)
if user_context:
context_str = "\n\nCONTEXTE UTILISATEUR:"
for key, value in user_context.items():
context_str += f"\n- {key}: {value}"
prompt += context_str
return prompt
def get_capabilities(self) -> List[str]:
return self.config.get('capabilities', [])
# Utilisation
personality = AIPersonality()
system_prompt = personality.get_system_prompt(
connected_devices=["PC-Bureau", "Téléphone-Android"],
user_context={"location": "Maison", "time_of_day": "matin"}
)
API FastAPI — Backend Principal
Point d'entrée main.py
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.middleware.cors import CORSMiddleware
import uvicorn, os
from routes import chat, devices, actions, auth
from services.websocket_manager import ConnectionManager
from services.ollama_client import OllamaClient
from ai_personality import AIPersonality
app = FastAPI(title="Assistant IA Personnel API", version="1.0.0")
app.add_middleware(
CORSMiddleware,
allow_origins=os.getenv("ALLOWED_ORIGINS", "*").split(","),
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
manager = ConnectionManager()
ollama = OllamaClient(base_url=os.getenv("OLLAMA_URL"))
personality = AIPersonality()
app.include_router(chat.router, prefix="/api/chat", tags=["Chat"])
app.include_router(devices.router, prefix="/api/devices", tags=["Devices"])
app.include_router(actions.router, prefix="/api/actions", tags=["Actions"])
app.include_router(auth.router, prefix="/api/auth", tags=["Auth"])
@app.get("/health")
async def health_check():
ollama_status = await ollama.check_health()
return {
"status": "healthy",
"ollama": "connected" if ollama_status else "disconnected",
"connected_clients": len(manager.active_connections)
}
@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: str):
await manager.connect(websocket, client_id)
try:
while True:
data = await websocket.receive_json()
if data.get("type") == "chat":
system_prompt = personality.get_system_prompt(
connected_devices=manager.get_connected_devices()
)
response = await ollama.generate(
prompt=data.get("message"),
system_prompt=system_prompt
)
await manager.send_personal_message({
"type": "response",
"message": response
}, client_id)
except WebSocketDisconnect:
manager.disconnect(client_id)
if __name__ == "__main__":
uvicorn.run("main:app", host="0.0.0.0", port=8888, reload=True)
Client Ollama
Fichier : services/ollama_client.py
import aiohttp, asyncio
from typing import Optional
class OllamaClient:
def __init__(self, base_url: str = "http://localhost:11434"):
self.base_url = base_url
self.model = "llama3.1:8b"
async def check_health(self) -> bool:
try:
async with aiohttp.ClientSession() as session:
async with session.get(f"{self.base_url}/api/tags") as r:
return r.status == 200
except:
return False
async def generate(self, prompt: str, system_prompt: Optional[str] = None) -> str:
messages = []
if system_prompt:
messages.append({"role": "system", "content": system_prompt})
messages.append({"role": "user", "content": prompt})
payload = {
"model": self.model,
"messages": messages,
"stream": False,
"options": {"temperature": 0.7, "num_predict": 2048}
}
try:
async with aiohttp.ClientSession() as session:
async with session.post(
f"{self.base_url}/api/chat", json=payload,
timeout=aiohttp.ClientTimeout(total=60)
) as r:
if r.status == 200:
result = await r.json()
return result['message']['content']
return f"Erreur Ollama: {r.status}"
except asyncio.TimeoutError:
return "❌ Timeout: Modèle trop lent"
except Exception as e:
return f"❌ Erreur: {str(e)}"
Configuration Nginx
Fichier : /etc/nginx/sites-available/assistant-ia
server {
listen 80;
server_name yourdomain.com;
location / {
return 301 https://$server_name$request_uri;
}
}
server {
listen 443 ssl http2;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
add_header Strict-Transport-Security "max-age=31536000" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "DENY" always;
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
limit_req zone=api_limit burst=20 nodelay;
location /api/ {
proxy_pass http://127.0.0.1:8888;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_cache_bypass $http_upgrade;
}
location /ws/ {
proxy_pass http://127.0.0.1:8888;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 86400;
}
location /health {
proxy_pass http://127.0.0.1:8888/health;
access_log off;
}
}
# Activation
sudo ln -s /etc/nginx/sites-available/assistant-ia /etc/nginx/sites-enabled/
sudo nginx -t
sudo certbot --nginx -d yourdomain.com
sudo systemctl restart nginx
Client Agent Python
import asyncio, websockets, json, platform, psutil
from typing import Dict, Callable
class AssistantAgent:
def __init__(self, server_url: str, device_id: str, token: str):
self.server_url = server_url
self.device_id = device_id
self.token = token
self.ws = None
self.handlers: Dict[str, Callable] = {}
def register_handler(self, action_type: str, handler: Callable):
self.handlers[action_type] = handler
async def connect(self):
while True:
try:
uri = f"{self.server_url}/ws/{self.device_id}"
headers = {"Authorization": f"Bearer {self.token}"}
async with websockets.connect(uri, extra_headers=headers) as ws:
self.ws = ws
print(f"✅ Connecté au serveur")
await self.send_device_info()
async for message in ws:
await self.handle_message(message)
except websockets.ConnectionClosed:
print("❌ Déconnecté. Reconnexion dans 5s...")
await asyncio.sleep(5)
except Exception as e:
print(f"❌ Erreur: {e}")
await asyncio.sleep(5)
async def send_device_info(self):
info = {
"type": "device_info",
"data": {
"platform": platform.system(),
"hostname": platform.node(),
"cpu_count": psutil.cpu_count(),
"memory_total": psutil.virtual_memory().total
}
}
await self.ws.send(json.dumps(info))
async def handle_message(self, message: str):
try:
data = json.loads(message)
action_type = data.get("type")
if action_type in self.handlers:
result = await self.handlers[action_type](data)
await self.ws.send(json.dumps({
"type": "action_result",
"action": action_type,
"result": result
}))
except json.JSONDecodeError:
print(f"❌ Message invalide")
async def main():
agent = AssistantAgent(
server_url="wss://yourdomain.com",
device_id="pc-bureau-001",
token="your_jwt_token_here"
)
await agent.connect()
if __name__ == "__main__":
asyncio.run(main())
Cas d'Usage Pratiques
🎬 Scénario 1 : Contrôle médias cross-device
User (depuis téléphone) :
"Lance le prochain épisode de ma série sur mon PC"
Assistant IA :
1. Identifie l'appareil cible (PC-Bureau)
2. Recherche le dernier épisode regardé
3. Trouve le fichier suivant
4. Envoie commande de lecture au PC
5. ✅ "Episode 12 lancé sur ton PC"
🌅 Scénario 2 : Routine matinale automatisée
[7h00 — Déclenchement automatique]
1. Vérifie la météo locale
2. Lit les notifications importantes
3. Lance la playlist "Morning"
4. Ouvre VS Code sur le PC
5. Affiche l'agenda du jour
"Bonjour ! Il fait 22°C aujourd'hui.
Tu as 3 notifications et 2 réunions."
💬 Scénario 3 : Réponse automatique
User : "Si quelqu'un m'écrit dans les 2h,
réponds que je suis en réunion"
Assistant :
1. Active le mode auto-réponse
2. Détecte nouveau message de "Maman"
3. Répond automatiquement
4. 💬 "Réponse envoyée à Maman"
📸 Scénario 4 : Photo à distance
User (depuis PC) :
"Prends une photo avec la caméra de mon téléphone"
Assistant :
1. Envoie commande au téléphone
2. Active la caméra arrière
3. Capture l'image
4. Upload vers /shared/outputs/
5. ✅ "Photo sauvegardée"
Fonctionnalités Avancées
1. Text-to-Speech (TTS) — Voix de l'assistant
Utilisez Piper TTS (local et rapide) :
pip install piper-tts
# Télécharger une voix française
wget https://huggingface.co/rhasspy/piper-voices/resolve/main/\
fr/fr_FR/siwis/medium/fr_FR-siwis-medium.onnx
wget https://huggingface.co/rhasspy/piper-voices/resolve/main/\
fr/fr_FR/siwis/medium/fr_FR-siwis-medium.onnx.json
from piper import PiperVoice
import wave
class TTSManager:
def __init__(self, model_path: str):
self.voice = PiperVoice.load(model_path)
def speak(self, text: str, output_file: str = "output.wav"):
with wave.open(output_file, 'wb') as wav_file:
self.voice.synthesize(text, wav_file)
return output_file
tts = TTSManager("fr_FR-siwis-medium.onnx")
tts.speak("Bonjour ! Je suis votre assistant.")
2. Speech-to-Text (STT) — Commandes vocales
Utilisez Whisper pour la reconnaissance vocale :
pip install faster-whisper
from faster_whisper import WhisperModel
class STTManager:
def __init__(self, model_size: str = "base"):
self.model = WhisperModel(model_size, device="cpu", compute_type="int8")
def transcribe(self, audio_file: str, language: str = "fr") -> str:
segments, info = self.model.transcribe(audio_file, language=language)
return " ".join([s.text for s in segments]).strip()
stt = STTManager("base")
text = stt.transcribe("voice_command.wav", language="fr")
print(f"Commande détectée: {text}")
3. Détection de Wake Word
import pvporcupine, pyaudio, struct
class WakeWordDetector:
def __init__(self, keyword_path: str, access_key: str):
self.porcupine = pvporcupine.create(
access_key=access_key,
keyword_paths=[keyword_path]
)
self.audio_stream = pyaudio.PyAudio().open(
rate=self.porcupine.sample_rate,
channels=1, format=pyaudio.paInt16,
input=True,
frames_per_buffer=self.porcupine.frame_length
)
def listen(self):
print("🎤 En écoute du wake word...")
while True:
pcm = self.audio_stream.read(self.porcupine.frame_length)
pcm = struct.unpack_from(
"h" * self.porcupine.frame_length, pcm
)
if self.porcupine.process(pcm) >= 0:
print("✅ Wake word détecté !")
return True
Base de Données SQLite
import sqlite3
from datetime import datetime
def init_database(db_path: str = "/data/assistant.db"):
conn = sqlite3.connect(db_path)
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS conversations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
device_id TEXT NOT NULL,
user_message TEXT NOT NULL,
assistant_response TEXT NOT NULL,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
)''')
c.execute('''CREATE TABLE IF NOT EXISTS devices (
id TEXT PRIMARY KEY,
name TEXT NOT NULL,
platform TEXT,
last_seen DATETIME,
status TEXT DEFAULT 'offline'
)''')
c.execute('''CREATE TABLE IF NOT EXISTS routines (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
trigger_type TEXT NOT NULL,
trigger_value TEXT,
actions TEXT NOT NULL,
enabled BOOLEAN DEFAULT 1
)''')
c.execute('''CREATE TABLE IF NOT EXISTS user_context (
key TEXT PRIMARY KEY,
value TEXT NOT NULL,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
)''')
conn.commit()
conn.close()
print("✅ Base de données initialisée")
Routines Automatisées
Fichier : config/routines.json
{
"routines": [
{
"name": "morning_routine",
"enabled": true,
"trigger": { "type": "time", "value": "07:00" },
"conditions": [
{ "type": "day_of_week",
"value": ["monday","tuesday","wednesday","thursday","friday"] }
],
"actions": [
{ "type": "tts_speak", "message": "Bonjour !", "device": "all" },
{ "type": "media_play", "playlist": "Morning", "device": "pc-bureau" },
{ "type": "open_app", "app": "vscode", "device": "pc-bureau" }
]
},
{
"name": "night_mode",
"enabled": true,
"trigger": { "type": "time", "value": "23:00" },
"actions": [
{ "type": "device_mode", "mode": "do_not_disturb", "device": "all" },
{ "type": "tts_speak", "message": "Bonne nuit !", "device": "smartphone" }
]
}
]
}
Sécurité et Bonnes Pratiques
1. Authentification JWT
from datetime import datetime, timedelta
from jose import JWTError, jwt
from passlib.context import CryptContext
import os
SECRET_KEY = os.getenv("JWT_SECRET")
ALGORITHM = "HS256"
EXPIRE_MINUTES = 10080 # 7 jours
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def create_access_token(data: dict):
to_encode = data.copy()
expire = datetime.utcnow() + timedelta(minutes=EXPIRE_MINUTES)
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
def verify_token(token: str):
try:
return jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
except JWTError:
return None
2. Rate Limiting
from collections import defaultdict
from datetime import datetime, timedelta
class RateLimiter:
def __init__(self, max_requests: int = 100, window_seconds: int = 60):
self.max_requests = max_requests
self.window = timedelta(seconds=window_seconds)
self.requests = defaultdict(list)
def is_allowed(self, client_id: str) -> bool:
now = datetime.now()
self.requests[client_id] = [
t for t in self.requests[client_id] if now - t < self.window
]
if len(self.requests[client_id]) >= self.max_requests:
return False
self.requests[client_id].append(now)
return True
3. Chiffrement des données
from cryptography.fernet import Fernet
import base64, os
class Encryptor:
def __init__(self, key: str = None):
if key is None:
key = os.getenv("ENCRYPTION_KEY")
self.fernet = Fernet(key.encode())
def encrypt(self, data: str) -> str:
encrypted = self.fernet.encrypt(data.encode())
return base64.b64encode(encrypted).decode()
def decrypt(self, encrypted_data: str) -> str:
decoded = base64.b64decode(encrypted_data.encode())
return self.fernet.decrypt(decoded).decode()
Monitoring et Maintenance
Script de monitoring
#!/bin/bash
# monitor.sh
echo "=== Monitoring Assistant IA ==="
echo "📦 Containers Docker:"
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
echo "💾 Utilisation RAM:"
docker stats --no-stream --format "table {{.Container}}\t{{.MemUsage}}\t{{.CPUPerc}}"
echo "💿 Espace disque:"
du -sh /opt/assistant-ia/*
echo "❌ Dernières erreurs:"
tail -n 10 /opt/assistant-ia/logs/api.log | grep -i error
echo "✅ Monitoring terminé"
Script de backup
#!/bin/bash
# backup.sh
BACKUP_DIR="/backup/assistant-ia"
DATE=$(date +%Y%m%d_%H%M%S)
mkdir -p $BACKUP_DIR
cp /opt/assistant-ia/data/assistant.db $BACKUP_DIR/assistant_${DATE}.db
tar -czf $BACKUP_DIR/config_${DATE}.tar.gz /opt/assistant-ia/config/
find $BACKUP_DIR -mtime +30 -type f -delete
echo "✅ Backup terminé: $BACKUP_DIR"
# Automatisation avec cron (crontab -e)
0 3 * * * /opt/assistant-ia/backup.sh >> /opt/assistant-ia/logs/backup.log 2>&1
0 * * * * /opt/assistant-ia/monitor.sh >> /opt/assistant-ia/logs/monitor.log 2>&1
Troubleshooting
Ollama est lent
- Vérifier RAM :
docker stats - Réduire
OLLAMA_CONTEXT_LENGTHà 2048 - Utiliser un modèle plus petit (Llama 3.2 3B)
- Ajouter swap :
sudo fallocate -l 4G /swapfile - Limiter l'historique à 5 messages
WebSocket se déconnecte
- Vérifier logs :
tail -f logs/api.log - L'agent a auto-reconnexion (5 secondes)
- Vérifier firewall port 443
- Augmenter
proxy_read_timeoutà 86400 dans Nginx
SSL ne fonctionne pas
- Vérifier DNS :
ping yourdomain.com - Ports 80/443 ouverts :
sudo ufw allow 80/tcp && sudo ufw allow 443/tcp - Logs Nginx :
tail -f /var/log/nginx/error.log - Renouveler certificat :
sudo certbot renew
Checklist de Déploiement
✅ Phase 1 : Infrastructure (Jour 1)
- Serveur Linux avec 16GB+ RAM configuré
- Docker et Docker Compose installés
- Nginx installé
- Domaine pointant vers le serveur
- Ports 80/443 ouverts
✅ Phase 2 : Backend (Jours 2-3)
- Structure /opt/assistant-ia créée
- docker-compose.yml configuré
- .env avec secrets générés
- FastAPI avec routes de base
- Ollama avec modèle téléchargé
- Base SQLite initialisée
- SSL configuré avec Certbot
✅ Phase 3 : Client Agents (Jours 4-5)
- Agent Python fonctionnel
- WebSocket stable
- Handlers commandes système
- TTS/STT intégré
- Agent déployé sur appareils
🔄 Phase 4 : Fonctionnalités (Jours 6-14)
- Contrôle médias (VLC, Spotify)
- Gestion messages (Telegram)
- Caméra et photos
- Localisation GPS
- Routines automatisées
- Wake word detection
🔄 Phase 5 : Production (Semaine 3+)
- Monitoring automatique
- Backups quotidiens
- Rate limiting
- Logs rotatifs
- Documentation utilisateur
Évolutions Futures
Intégrations possibles
- 🏠 Home Assistant : Contrôle domotique
- 📊 Grafana : Dashboards monitoring
- 🔔 Notifications Push : Firebase / NTFY
- 🎮 Game integration : Contrôle jeux PC
- 📧 Email : Lecture et réponse auto
- 📅 Calendrier : Google Calendar, Outlook
- 🌐 Web scraping : Surveillance prix, news
- 🚗 Véhicule connecté : Via API constructeur
Améliorations IA
- 🧠 RAG : Mémoire longue durée avec ChromaDB
- 👁️ Vision : LLaVA pour analyse d'images
- 🎵 Reconnaissance musicale locale
- 🗺️ Navigation : Assistant de trajet
- 📚 Knowledge Base : RAG sur vos documents
Conclusion
Vous avez maintenant tous les éléments pour construire votre propre assistant IA personnel 100% local et privé. Ce système offre confidentialité totale, contrôle complet, compatibilité multi-plateformes, et tout cela avec des technologies open source gratuites.
💡 Conseil : Commencez simple avec les fonctionnalités de base, puis ajoutez progressivement les features avancées. Rome ne s'est pas construite en un jour !
Prochaines étapes :
- Provisionner votre serveur Linux
- Suivre la checklist de déploiement
- Tester avec un appareil
- Déployer sur tous vos appareils
- Personnaliser selon vos besoins
L'assistant IA du futur, c'est celui que vous construisez !