Créer un Assistant IA Personnel 100% Local avec Ollama et Docker

📅 16 février 2026
📁 Développement
Tutoriel
Construire un Assistant IA Local — Mat-Univer.tech
📡 Guide Complet

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.

📅 Février 2026 ⏱ ~30 min de lecture 🛠 Python, Docker, FastAPI, Ollama

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èleRAMVitesseQualitéAvis
Llama 3.3 70B Q2~12 GB15-25 secExcellent❌ Trop lent
Llama 3.1 8B Q4~6 GB3-5 secTrès bon⭐ OPTIMAL
Llama 3.2 3B~3 GB1-2 secCorrect✅ Backup
Mistral 7B v0.3~5 GB3-4 secTrès bon✅ Alternative
Phi-3 Mini 3.8B~3 GB1-2 secBon✅ 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

ComposantMinimumRecommandé
CPU4 cores8+ cores
RAM12 GB16 GB+
Stockage20 GB50 GB
OSLinux (Ubuntu/Debian)Ubuntu 22.04+ LTS
GPUAucun (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 :

  1. Provisionner votre serveur Linux
  2. Suivre la checklist de déploiement
  3. Tester avec un appareil
  4. Déployer sur tous vos appareils
  5. Personnaliser selon vos besoins

L'assistant IA du futur, c'est celui que vous construisez !


Article rédigé par un développeur passionné d'IA et de privacy.

Dernière mise à jour : Février 2026

Technologies : Python, FastAPI, Docker, Ollama, Llama, WebSocket, Nginx, SQLite