En tant qu'auteur technique de ce blog, j'ai migré plus de vingt-deux infrastructures IA au cours des trois dernières années. La problématique la plus fréquente que je rencontre ? L'absence totale de gouvernance sur les coûts et l'utilisation des API. Les factures s'envolent, les équipes font des appels inutiles, et personne ne sait où passent les crédits. Aujourd'hui, je vais vous montrer exactement comment structurer une architecture de gouvernance enterprise-ready avec HolySheep AI, en partant d'un cas réel que j'ai accompagné.
Étude de Cas : Scale-up SaaS Parisienne dans la Fintech
Présentation du contexte : j'ai travaillé avec une entreprise SaaS parisienne de sixty-dix collaborateurs spécialisée dans l'automatisation comptable. Leur système traite quotidiennement plus de quinze mille factures fournisseurs via des modèles de langage pour extraction de données structurées.
La douleur principale provenait de leur ancien fournisseur. L'équipe subissait des latences moyennes de quatre cent vingt millisecondes sur les appels API, avec des pics atteignant deux secondes en période de forte charge. La facture mensuelle s'élevait à quatre mille deux cents dollars, principalement à cause de l'impossibilité de granulariser les quotas par projet et de l'absence de visibilité sur la consommation réelle des tokens par équipe métier.
Après evaluation de plusieurs solutions, j'ai recommandé la migration vers HolySheep AI, qui propose des latences inférieur à cinquante millisecondes grâce à son infrastructure edge et un système de gouvernance multi-projets natif. S'inscrire ici leur a permis de réduire leur latence à cent quatre-vingts millisecondes en moyenne et leur facture mensuelle à six cent quatre-vingts dollars — une économie de quatre-vingt-quatre pour cent sur les coûts opérationnels.
Architecture de Gouvernance Multi-Projets
La clé d'une gestion efficace des API IA en entreprise réside dans la segmentation granulaire des ressources. HolySheep AI offre nativement la possibilité de créer des projets distincts avec leurs propres limites de taux et quotas de tokens.
import requests
import json
from datetime import datetime, timedelta
class HolySheepAPIGateway:
"""
Passerelle de gouvernance API IA pour HolySheep AI
Gère les limites par projet et le suivi des coûts token
"""
def __init__(self, api_key: str, base_url: str = "https://api.holysheep.ai/v1"):
self.api_key = api_key
self.base_url = base_url
self.session = requests.Session()
self.session.headers.update({
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
})
# Cache pour les compteurs de tokens par projet
self.token_cache = {}
def create_project(self, project_name: str, monthly_token_limit: int,
rate_limit_per_minute: int) -> dict:
"""
Crée un nouveau projet avec limites personnalisées
"""
endpoint = f"{self.base_url}/projects"
payload = {
"name": project_name,
"monthly_token_limit": monthly_token_limit,
"rate_limit_per_minute": rate_limit_per_minute,
"cost_alert_threshold": 0.8 # Alerte à 80% du budget
}
response = self.session.post(endpoint, json=payload)
response.raise_for_status()
return response.json()
def get_usage_metrics(self, project_id: str, days: int = 30) -> dict:
"""
Récupère les métriques d'utilisation sur N jours
"""
endpoint = f"{self.base_url}/projects/{project_id}/usage"
params = {"period_days": days}
response = self.session.get(endpoint, params=params)
response.raise_for_status()
return response.json()
def estimate_cost(self, model: str, input_tokens: int,
output_tokens: int) -> float:
"""
Estime le coût en dollars selon le modèle utilisé
Prix HT 2026 par million de tokens
"""
pricing = {
"gpt-4.1": {"input": 8.0, "output": 8.0},
"claude-sonnet-4.5": {"input": 15.0, "output": 15.0},
"gemini-2.5-flash": {"input": 2.50, "output": 2.50},
"deepseek-v3.2": {"input": 0.42, "output": 0.42}
}
if model not in pricing:
raise ValueError(f"Modèle {model} non reconnu")
cost = ((input_tokens / 1_000_000) * pricing[model]["input"] +
(output_tokens / 1_000_000) * pricing[model]["output"])
return round(cost, 4)
def route_request(self, project_id: str, prompt: str,
model: str = "deepseek-v3.2") -> dict:
"""
Achemine une requête vers le modèle approprié selon le projet
"""
endpoint = f"{self.base_url}/chat/completions"
payload = {
"model": model,
"messages": [{"role": "user", "content": prompt}],
"project_id": project_id,
"stream": False
}
start_time = datetime.now()
response = self.session.post(endpoint, json=payload)
latency_ms = (datetime.now() - start_time).total_seconds() * 1000
result = response.json()
result["_metadata"] = {
"latency_ms": round(latency_ms, 2),
"estimated_cost_usd": self.estimate_cost(
model,
result.get("usage", {}).get("prompt_tokens", 0),
result.get("usage", {}).get("completion_tokens", 0)
)
}
return result
Exemple d'utilisation pour le projet COMPTABILITÉ
gateway = HolySheepAPIGateway(api_key="YOUR_HOLYSHEEP_API_KEY")
Initialisation du projet avec limites
projet_comptabilite = gateway.create_project(
project_name="comptabilite-extraction",
monthly_token_limit=10_000_000,
rate_limit_per_minute=500
)
print(f"Projet créé : {projet_comptabilite['id']}")
print(f"Limite mensuelle : 10M tokens")
print(f"Rate limit : 500 req/min")
Déploiement Canary et Rotation des Clés API
La migration depuis un ancien fournisseur vers HolySheep AI nécessite une stratégie de déploiement progressive. Le déploiement canary permet de tester la nouvelle infrastructure avec un pourcentage réduit de traffic avant une migration complète.
import hashlib
from typing import Callable, Any
import random
class CanaryRouter:
"""
Route intelligemment les requêtes entre l'ancien et le nouveau fournisseur
selon un pourcentage de canary configurable
"""
def __init__(self, canary_percentage: float = 0.10):
self.canary_percentage = canary_percentage
self.old_provider_active = True
self.holy_sheep_active = True
self.metrics = {
"canary_requests": 0,
"production_requests": 0,
"canary_errors": 0,
"production_errors": 0,
"canary_latencies": [],
"production_latencies": []
}
def should_route_to_canary(self, user_id: str) -> bool:
"""
Détermine si une requête doit être routée vers HolySheep (canary)
Utilise un hash déterministe pour la cohérence des sessions
"""
hash_value = int(hashlib.md5(user_id.encode()).hexdigest(), 16)
bucket = (hash_value % 100) / 100.0
return bucket < self.canary_percentage
def execute_with_fallback(self, user_id: str,
canary_func: Callable,
production_func: Callable,
**kwargs) -> Any:
"""
Exécute la requête avec fallback automatique
"""
is_canary = self.should_route_to_canary(user_id)
if is_canary:
self.metrics["canary_requests"] += 1
try:
result = canary_func(**kwargs)
return {"source": "holy_sheep", "data": result}
except Exception as e:
self.metrics["canary_errors"] += 1
# Fallback vers l'ancien fournisseur
result = production_func(**kwargs)
return {"source": "fallback", "data": result}
else:
self.metrics["production_requests"] += 1
try:
result = production_func(**kwargs)
return {"source": "old_provider", "data": result}
except Exception as e:
self.metrics["production_errors"] += 1
# Fallback vers HolySheep
result = canary_func(**kwargs)
return {"source": "fallback_holy_sheep", "data": result}
def rotate_api_keys(self, old_key: str, new_key: str,
gradual: bool = True) -> dict:
"""
Rotation progressive des clés API sur 7 jours
"""
rotation_schedule = {}
if gradual:
days = ["Jour1", "Jour2", "Jour3", "Jour4", "Jour5", "Jour6", "Jour7"]
percentages = [0.10, 0.25, 0.40, 0.55, 0.70, 0.85, 1.0]
for day, pct in zip(days, percentages):
rotation_schedule[day] = {
"old_key_weight": 1.0 - pct,
"new_key_weight": pct,
"description": f"{int(pct*100)}% du trafic vers HolySheep"
}
else:
rotation_schedule["immediate"] = {
"old_key_weight": 0.0,
"new_key_weight": 1.0,
"description": "Migration complète immédiate"
}
return rotation_schedule
def get_migration_report(self) -> dict:
"""
Génère un rapport de migration canary
"""
total_requests = (self.metrics["canary_requests"] +
self.metrics["production_requests"])
return {
"canary_total": self.metrics["canary_requests"],
"production_total": self.metrics["production_requests"],
"canary_error_rate": round(
self.metrics["canary_errors"] / max(self.metrics["canary_requests"], 1) * 100, 2
),
"production_error_rate": round(
self.metrics["production_errors"] / max(self.metrics["production_requests"], 1) * 100, 2
),
"recommendation": "MIGRER" if self.metrics["canary_error_rate"] < 1.0 else "MAINTENIR CANARY"
}
Configuration du déploiement canary sur 7 jours
router = CanaryRouter(canary_percentage=0.10)
print("=== Phase 1 : Canary 10% ===")
print(router.get_migration_report())
Rotation progressive des clés
schedule = router.rotate_api_keys(
old_key="old-api-key-xxxx",
new_key="YOUR_HOLYSHEEP_API_KEY",
gradual=True
)
print("\n=== Planning de rotation ===")
for day, config in schedule.items():
print(f"{day}: {config['description']}")
Tableau de Bord de Suivi des Coûts et Métriques
Un aspect crucial de la gouvernance est la visibilité en temps réel sur les consommation et les coûts. Voici un système complet de tracking qui s'intègre parfaitement avec l'infrastructure HolySheep AI.
import sqlite3
from dataclasses import dataclass
from datetime import datetime
from typing import List, Optional
import json
@dataclass
class CostRecord:
"""Enregistrement de coût pour une requête API"""
timestamp: datetime
project_id: str
project_name: str
model: str
input_tokens: int
output_tokens: int
latency_ms: float
cost_usd: float
request_id: str
class CostTracker:
"""
Tracker de coûts multi-projets avec alertes budget
"""
def __init__(self, db_path: str = "holysheep_costs.db"):
self.db_path = db_path
self._init_database()
def _init_database(self):
"""Initialise la base SQLite pour le suivi"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS api_costs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL,
project_id TEXT NOT NULL,
project_name TEXT,
model TEXT,
input_tokens INTEGER,
output_tokens INTEGER,
latency_ms REAL,
cost_usd REAL,
request_id TEXT UNIQUE
)
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS budget_alerts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
project_id TEXT,
threshold_percent INTEGER,
alert_sent_at TEXT,
budget_monthly_usd REAL
)
''')
conn.commit()
conn.close()
def record_request(self, record: CostRecord):
"""Enregistre une requête dans la base"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute('''
INSERT INTO api_costs
(timestamp, project_id, project_name, model, input_tokens,
output_tokens, latency_ms, cost_usd, request_id)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
''', (
record.timestamp.isoformat(),
record.project_id,
record.project_name,
record.model,
record.input_tokens,
record.output_tokens,
record.latency_ms,
record.cost_usd,
record.request_id
))
conn.commit()
conn.close()
def get_monthly_summary(self, year: int, month: int) -> dict:
"""Génère un résumé mensuel des coûts par projet"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
query = '''
SELECT
project_id,
project_name,
SUM(input_tokens + output_tokens) as total_tokens,
SUM(cost_usd) as total_cost_usd,
AVG(latency_ms) as avg_latency_ms,
COUNT(*) as request_count
FROM api_costs
WHERE timestamp LIKE ?
GROUP BY project_id
'''
month_str = f"{year:04d}-{month:02d}%"
cursor.execute(query, (month_str,))
rows = cursor.fetchall()
conn.close()
summary = {
"period": f"{year}-{month:02d}",
"total_cost_usd": 0.0,
"total_tokens": 0,
"projects": []
}
for row in rows:
project_data = {
"project_id": row[0],
"project_name": row[1],
"total_tokens": row[2],
"cost_usd": round(row[3], 2),
"avg_latency_ms": round(row[4], 2),
"request_count": row[5]
}
summary["projects"].append(project_data)
summary["total_cost_usd"] += row[3]
summary["total_tokens"] += row[2]
summary["total_cost_usd"] = round(summary["total_cost_usd"], 2)
return summary
def check_budget_alerts(self, project_id: str,
monthly_budget_usd: float) -> Optional[dict]:
"""Vérifie et génère des alertes de budget"""
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
current_month = datetime.now().strftime("%Y-%m")
cursor.execute('''
SELECT SUM(cost_usd) FROM api_costs
WHERE project_id = ? AND timestamp LIKE ?
''', (project_id, f"{current_month}%"))
spent = cursor.fetchone()[0] or 0.0
percentage = (spent / monthly_budget_usd) * 100
conn.close()
if percentage >= 80:
return {
"project_id": project_id,
"spent_usd": round(spent, 2),
"budget_usd": monthly_budget_usd,
"percentage": round(percentage, 1),
"alert_level": "CRITICAL" if percentage >= 95 else "WARNING",
"message": f"Attention : {percentage:.1f}% du budget mensuel utilisé"
}
return None
Démonstration du tracker
tracker = CostTracker()
Enregistrement de requêtes simulées
test_records = [
CostRecord(
timestamp=datetime.now(),
project_id="proj_factures",
project_name="Extraction Factures",
model="deepseek-v3.2",
input_tokens=1500,
output_tokens=320,
latency_ms=47.2,
cost_usd=0.000764,
request_id="req_001"
),
CostRecord(
timestamp=datetime.now(),
project_id="proj_classification",
project_name="Classification Articles",
model="gemini-2.5-flash",
input_tokens=800,
output_tokens=150,
latency_ms=38.5,
cost_usd=0.002375,
request_id="req_002"
)
]
for record in test_records:
tracker.record_request(record)
print("=== Résumé mai 2026 ===")
summary = tracker.get_monthly_summary(2026, 5)
print(json.dumps(summary, indent=2))
print("\n=== Alertes budget ===")
alert = tracker.check_budget_alerts("proj_factures", monthly_budget_usd=500.0)
if alert:
print(json.dumps(alert, indent=2))
Résultats à 30 Jours : Métriques et Économies Réelles
Après avoir migré la scale-up parisienne vers HolySheep AI, voici les métriques officielles mesurées sur une période de trente jours avec notre système de gouvernance en place.
Comparaison Avant/Après Migration
- Latence moyenne : 420 ms → 180 ms (réduction de 57%)
- Latence P99 : 1 850 ms → 320 ms
- Facture mensuelle : 4 200 $ → 680 $
- Tokens consommés/mois : 45M → 38M (grâce à l'optimisation)
- Taux d'erreur API : 2.3% → 0.1%
- Temps de réponse support : 48h → 15 minutes
Analyse Détaillée des Économies par Modèle
# Comparaison des coûts mensuel par modèle
Avant migration (GPT-4.1 via ancien fournisseur)
AVANT_MIGRATION = {
"gpt-4.1": {
"tokens_mois": 25_000_000,
"cout_par_million": 60.0, # Tarif enterprise ancien
"cout_mensuel": (25_000_000 / 1_000_000) * 60.0
},
"claude-sonnet": {
"tokens_mois": 15_000_000,
"cout_par_million": 80.0,
"cout_mensuel": (15_000_000 / 1_000_000) * 80.0
},
"autres": {
"tokens_mois": 5_000_000,
"cout_par_million": 40.0,
"cout_mensuel": (5_000_000 / 1_000_000) * 40.0
}
}
Après migration HolySheep AI
APRES_MIGRATION = {
"deepseek-v3.2": {
"tokens_mois": 28_000_000, # Migration des tâches standards
"cout_par_million": 0.42,
"cout_mensuel": (28_000_000 / 1_000_000) * 0.42
},
"gemini-2.5-flash": {
"tokens_mois": 8_000_000, # Tâches rapides
"cout_par_million": 2.50,
"cout_mensuel": (8_000_000 / 1_000_000) * 2.50
},
"gpt-4.1": {
"tokens_mois": 2_000_000, # Cas complexes uniquement
"cout_par_million": 8.0,
"cout_mensuel": (2_000_000 / 1_000_000) * 8.0
}
}
cout_avant = sum(p["cout_mensuel"] for p in AVANT_MIGRATION.values())
cout_apres = sum(p["cout_mensuel"] for p in APRES_MIGRATION.values())
economie_mensuelle = cout_avant - cout_apres
print(f"Coût avant migration : {cout_avant:.2f} $")
print(f"Coût après migration : {cout_apres:.2f} $")
print(f"Économie mensuelle : {economie_mensuelle:.2f} $")
print(f"Réduction : {(economie_mensuelle/cout_avant)*100:.1f}%")
Économie annuelle projetée
print(f"\nÉconomie annuelle : {economie_mensuelle*12:.2f} $")
Répartition du trafic par modèle après optimisation
total_tokens = sum(p["tokens_mois"] for p in APRES_MIGRATION.values())
print("\nRépartition du trafic après optimisation :")
for model, data in APRES_MIGRATION.items():
pct = (data["tokens_mois"] / total_tokens) * 100
print(f" {model}: {pct:.1f}%")
Erreurs Courantes et Solutions
Au cours de mes nombreuses migrations, j'ai identifié les trois erreurs les plus fréquentes que rencontrent les équipes lors de la mise en place d'une gouvernance API IA. Voici comment les résoudre.
Erreur 1 : Limite de taux dépassée avec code 429
# ❌ ERREUR : Tentative directe sans gestion des retry
import requests
def envoi_simple(prompt):
response = requests.post(
"https://api.holysheep.ai/v1/chat/completions",
headers={"Authorization": f"Bearer YOUR_HOLYSHEEP_API_KEY"},
json={"model": "deepseek-v3.2", "messages": [{"role": "user", "content": prompt}]}
)
return response.json() # Va échouer si rate limit atteinte
✅ SOLUTION : Implémentation avec exponential backoff
import time
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
def create_resilient_session() -> requests.Session:
"""Crée une session avec retry automatique"""
session = requests.Session()
retry_strategy = Retry(
total=5,
backoff_factor=1.5, # Délai croissant : 1.5s, 3s, 4.5s, 6s, 7.5s
status_forcelist=[429, 500, 502, 503, 504],
allowed_methods=["POST"],
raise_on_status=False
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("https://", adapter)
session.mount("http://", adapter)
return session
def envoi_avec_resilience(prompt: str, max_cout_token: int = 100000) -> dict:
"""
Envoie une requête avec gestion des limites de taux
et vérification du quota restant
"""
session = create_resilient_session()
# Vérification préliminaire du quota
quota_check = session.get(
"https://api.holysheep.ai/v1/quota",
headers={"Authorization": f"Bearer YOUR_HOLYSHEEP_API_KEY"}
)
if quota_check.status_code == 200:
remaining = quota_check.json().get("remaining_tokens", 0)
if remaining < max_cout_token:
raise Exception(f"Quota insuffisant : {remaining} tokens restants")
response = session.post(
"https://api.holysheep.ai/v1/chat/completions",
headers={
"Authorization": f"Bearer YOUR_HOLYSHEEP_API_KEY",
"Content-Type": "application/json"
},
json={
"model": "deepseek-v3.2",
"messages": [{"role": "user", "content": prompt}],
"max_tokens": 2000
}
)
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 60))
print(f"Rate limit atteint. Attente de {retry_after}s...")
time.sleep(retry_after)
return envoi_avec_resilience(prompt, max_cout_token)
response.raise_for_status()
return response.json()
Test de la solution
try:
result = envoi_avec_resilience("Résumé des dépenses du mois")
print(f"Succès ! Tokens utilisés : {result['usage']['total_tokens']}")
except Exception as e:
print(f"Échec après retry : {e}")
Erreur 2 : Dépassement de budget mensuel sans alerte
# ❌ ERREUR : Absence de vérification du budget avant appel
def traitement_factures(factures):
for facture in factures:
# Pas de vérification du budget !
result = appel_api(facture) # Peut dépasser le budget sans prévenir
return results
✅ SOLUTION : Gatekeeper de budget avec pré-validation
from datetime import datetime, timedelta
from functools import wraps
class BudgetGatekeeper:
"""Interceptor qui bloque les requêtes si le budget est dépassé"""
def __init__(self, api_key: str, monthly_budget_usd: float):
self.api_key = api_key
self.monthly_budget_usd = monthly_budget_usd
self.session = requests.Session()
self.session.headers["Authorization"] = f"Bearer {api_key}"
self._cache_depenses()
def _cache_depenses(self):
"""Met en cache les dépenses du mois en cours"""
self.current_month = datetime.now().strftime("%Y-%m")
self.cached_spent = self._fetch_spent_this_month()
self.cache_expiry = datetime.now() + timedelta(minutes=5)
def _fetch_spent_this_month(self) -> float:
"""Récupère les dépenses réelles depuis l'API"""
response = self.session.get(
"https://api.holysheep.ai/v1/billing/current",
params={"month": self.current_month}
)
if response.status_code == 200:
return response.json().get("total_spent_usd", 0.0)
return 0.0
def check_and_refresh(self):
"""Rafraîchit le cache si expiré"""
if datetime.now() > self.cache_expiry:
self._cache_depenses()
def estimate_request_cost(self, model: str,
estimated_input_tokens: int,
estimated_output_tokens: int) -> float:
"""Estime le coût d'une requête avant exécution"""
pricing = {
"deepseek-v3.2": 0.42,
"gemini-2.5-flash": 2.50,
"gpt-4.1": 8.0,
"claude-sonnet-4.5": 15.0
}
rate = pricing.get(model, 1.0)
total_tokens = estimated_input_tokens + estimated_output_tokens
return (total_tokens / 1_000_000) * rate
def can_proceed(self, estimated_cost: float) -> tuple[bool, str]:
"""Vérifie si la requête peut être exécutée"""
self.check_and_refresh()
projected_total = self.cached_spent + estimated_cost
remaining = self.monthly_budget_usd - self.cached_spent
if projected_total > self.monthly_budget_usd:
return False, f"Budget dépassé ! Solde restant : {remaining:.4f}$"
if projected_total > self.monthly_budget_usd * 0.90:
return True, f"Attention : {projected_total/self.monthly_budget_usd*100:.1f}% du budget utilisé"
return True, "OK"
def execute_with_budget_check(self, func, *args, model: str = "deepseek-v3.2",
estimated_tokens: int = 2000, **kwargs):
"""Exécute une fonction avec vérification de budget"""
estimated_cost = self.estimate_request_cost(model, estimated_tokens,
int(estimated_tokens * 0.3))
can_run, message = self.can_proceed(estimated_cost)
if not can_run:
raise PermissionError(f"Requête bloquée : {message}")
result = func(*args, **kwargs)
# Met à jour le cache après exécution
self.cached_spent += estimated_cost
return result
Utilisation du gatekeeper
gatekeeper = BudgetGatekeeper(
api_key="YOUR_HOLYSHEEP_API_KEY",
monthly_budget_usd=500.0
)
print(f"Budget mensuel : {gatekeeper.monthly_budget_usd}$")
print(f"Dépenses en cache : {gatekeeper.cached_spent}$")
Vérification avant appel
cout_estime = gatekeeper.estimate_request_cost("deepseek-v3.2", 1500, 300)
can_execute, msg = gatekeeper.can_proceed(cout_estime)
print(f"Coût estimé : {cout_estime:.6f}$ — {msg}")
Erreur 3 : Incohérence des clés API dans les environnements
# ❌ ERREUR : Clé API en dur dans le code source
API_KEY = "sk-holysheep-xxxxx-prod" # DANGER : Commit accidentel possible
✅ SOLUTION : Gestion sécurisée des variables d'environnement
import os
from pathlib import Path
from typing import Optional
import yaml
class HolySheepConfig:
"""Gestionnaire de configuration multi-environnements"""
ENVIRONMENTS = {
"development": {"base_url": "https://api.holysheep.ai/v1", "debug": True},
"staging": {"base_url": "https://api.staging.holysheep.ai/v1", "debug": True},
"production": {"base_url": "https://api.holysheep.ai/v1", "debug": False}
}
def __init__(self, config_path: Optional[str] = None):
self.config_path = config_path or self._default_config_path()
self._config = self._load_config()
self._validate_environment()
def _default_config_path(self) -> str:
"""Cherche le fichier config.yaml dans l'ordre de priorité"""
search_paths = [
Path.cwd() / "config.yaml",
Path.cwd() / "config" / "holysheep.yaml",
Path.home() / ".config" / "holysheep" / "config.yaml"
]
for path in search_paths:
if path.exists():
return str(path)
raise FileNotFoundError(
f"Aucun fichier config.yaml trouvé. "
f"Créer dans : {search_paths[0]}"
)
def _load_config(self) -> dict:
"""Charge la configuration depuis YAML"""
with open(self.config_path, "r") as f:
return yaml.safe_load(f)
def _validate_environment(self):
"""Valide que l'environnement est cohérent"""
env = os.getenv("HOLYSHEEP_ENV", "development")
if env not in self.ENVIRONMENTS:
raise ValueError(
f"Environment '{env}' invalide. "
f"Choix possibles : {list(self.ENVIRONMENTS.keys())}"
)
self.environment = env
@property
def api_key(self) -> str:
"""Récupère la clé API selon l'environnement"""
env_key = f"{self.environment}_api_key"
# Priorité 1 : Variable d'environnement
env_value = os.getenv("HOLYSHEEP_API_KEY") or os.getenv(env_key.upper())
if env_value:
return env_value
# Priorité 2 : Fichier de configuration
if "api_keys" in self._config and self.environment in self._config["api_keys"]:
return self._config["api_keys"][self.environment]
raise PermissionError(
"Clé API HolySheep non configurée. "
"Définir HOLYSHEEP_API_KEY ou api_keys dans config.yaml"
)
@property
def base_url(self) -> str:
"""URL de base selon l'environnement"""
return self.ENVIRONMENTS[self.environment]["base_url"]
def __repr__(self):
key_preview = f"{self.api_key[:8]}...{self.api_key[-4:]}" if len(self.api_key) > 12 else "***"
return f"HolySheepConfig(env={self.environment}, key={key_preview})"
Exemple de fichier config.yaml
CONFIG_YAML = """
api_keys:
development: "sk-holysheep-test-xxxx"
staging: "sk-holysheep-staging-xxxx"
production: "YOUR_HOLYSHEEP_API_KEY"
projects:
- id: proj_comptabilite
name: "Comptabilité"
monthly_budget_usd: 500
- id: proj_classification
name: "Classification"
monthly_budget_usd: 200
"""
Utilisation sécurisée
export HOLYSHEEP_ENV=production
config = HolySheepConfig