Initial ai typewriter implementation

This commit is contained in:
Edern Deneuville
2026-09-11 11:59:52 +02:00
parent 4ae815c142
commit 3073beb5e7
+54
View File
@@ -0,0 +1,54 @@
from __future__ import annotations
import json
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Literal
Provider = Literal["ollama", "gemini"]
@dataclass(frozen=True)
class AppConfig:
provider: Provider = "ollama"
model: str = "llama3.1"
api_key: str = ""
server_url: str = "http://localhost:11434"
hotkey: str = "ctrl+alt+a"
request_timeout_seconds: float = 120.0
copy_wait_seconds: float = 1.0
type_delay_seconds: float = 0.0
restore_clipboard: bool = True
system_prompt: str = (
"Réponds directement et de manière ultra-concise. "
"Aucune phrase d'introduction, aucune salutation, aucun formatage superflu. "
"Uniquement la réponse brute."
)
def _coerce_provider(value: Any) -> Provider:
provider = str(value or "ollama").lower().strip()
if provider not in {"ollama", "gemini"}:
raise ValueError("config.provider doit être 'ollama' ou 'gemini'")
return provider # type: ignore[return-value]
def load_config(path: str | Path = "config.json") -> AppConfig:
cfg_path = Path(path)
if not cfg_path.exists():
raise FileNotFoundError(
f"Configuration introuvable: {cfg_path}. Copiez config.json.template vers config.json."
)
data = json.loads(cfg_path.read_text(encoding="utf-8"))
return AppConfig(
provider=_coerce_provider(data.get("provider", "ollama")),
model=str(data.get("model", "llama3.1")),
api_key=str(data.get("api_key", "")),
server_url=str(data.get("server_url", "http://localhost:11434")).rstrip("/"),
hotkey=str(data.get("hotkey", "ctrl+alt+a")).lower(),
request_timeout_seconds=float(data.get("request_timeout_seconds", 120)),
copy_wait_seconds=float(data.get("copy_wait_seconds", 1)),
type_delay_seconds=float(data.get("type_delay_seconds", 0)),
restore_clipboard=bool(data.get("restore_clipboard", True)),
system_prompt=str(data.get("system_prompt", AppConfig.system_prompt)),
)