From 3073beb5e7b9ad66c5ee87009cfc934c938b30f4 Mon Sep 17 00:00:00 2001 From: Edern Deneuville Date: Fri, 11 Sep 2026 11:59:52 +0200 Subject: [PATCH] Initial ai typewriter implementation --- src/ai_typewriter/config.py | 54 +++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/ai_typewriter/config.py diff --git a/src/ai_typewriter/config.py b/src/ai_typewriter/config.py new file mode 100644 index 0000000..cef092b --- /dev/null +++ b/src/ai_typewriter/config.py @@ -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)), + )