From 1a18e372cdff3fb4a4aff6f0d9adaee183c13b32 Mon Sep 17 00:00:00 2001 From: gwen Date: Fri, 4 Sep 2026 11:11:52 +0200 Subject: [PATCH] add use cases --- .gitignore | 1 + doc/HuggingFaceGettingStarted.md | 191 +++++++++++++++++++++++++++++ doc/Tasks.md | 50 +++++++- doc/UseCases.md | 104 ++++++++++++++++ doc/index.md | 4 +- experiments/ManualProxySettings.md | 50 ++++++++ experiments/SimpleProxyQuestion.md | 104 ++++++++++++++++ experiments/discussion.txt | 10 ++ 8 files changed, 512 insertions(+), 2 deletions(-) create mode 100644 doc/HuggingFaceGettingStarted.md create mode 100644 doc/UseCases.md create mode 100644 experiments/ManualProxySettings.md create mode 100644 experiments/SimpleProxyQuestion.md create mode 100644 experiments/discussion.txt diff --git a/.gitignore b/.gitignore index 1945a93..f0cb2f7 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ overrides bribes site/ .obsidian +.task/ diff --git a/doc/HuggingFaceGettingStarted.md b/doc/HuggingFaceGettingStarted.md new file mode 100644 index 0000000..65f3011 --- /dev/null +++ b/doc/HuggingFaceGettingStarted.md @@ -0,0 +1,191 @@ + +--- + +je sais utiliser ollama.py, j'ai un ordi avec 32G de RAM, +Je voudrais me mettre au Hugging Face Hub, avec des petits modèles : Qwen 2.5 0.5B pour le français, SmolLM2 360M pour l’anglais. Phi-3 Mini Gemma 2 2B, etc... +tu peux m'expliquer comment faire ? faut-il utiliser transformer.py de hugging face ? + +--- + +Oui, utiliser `transformers.py` de Hugging Face est exactement la bonne approche pour charger et utiliser ces modèles. C'est la bibliothèque principale de la plateforme. + +Pour te lancer avec tes modèles (Qwen 2.5 0.5B, SmolLM2 360M, etc.), voici les clés à retenir, en partant de ce que tu connais avec Ollama. + +### Le cœur de la méthode : `AutoModelForCausalLM` et `AutoTokenizer` + +La manière standard et la plus simple est d'utiliser les classes `AutoModelForCausalLM` et `AutoTokenizer` . Le préfixe `Auto` est pratique car il permet de charger n'importe quel modèle sans avoir à connaître sa classe exacte . + +```python +from transformers import AutoModelForCausalLM, AutoTokenizer + +nom_du_modele = "Qwen/Qwen2.5-0.5B-Instruct" # Par exemple + +tokenizer = AutoTokenizer.from_pretrained(nom_du_modele) +modele = AutoModelForCausalLM.from_pretrained( + nom_du_modele, + device_map="auto", # Laisse transformers gérer l'emplacement (CPU/GPU) + torch_dtype="auto" # Laisse le modèle choisir le type de données (float16, bfloat16...) +) +``` + +Pour un modèle comme **SmolLM2**, ce serait `"HuggingFaceTB/SmolLM2-360M-Instruct"` . + +### Le rôle crucial du tokenizer + +Le tokenizer ne se contente pas de découper le texte. Pour les modèles de type "Instruct" (comme ceux que tu as listés), il **doit** appliquer un *chat template*. Ce template ajoute les tokens spéciaux (comme `<|im_start|>` pour Qwen ou `` pour Gemma) qui indiquent au modèle où commence le rôle de l'utilisateur, celui de l'assistant, etc. . + +C'est la méthode `apply_chat_template()` qui s'en charge : + +```python +messages = [ + {"role": "user", "content": "Quelle est la capitale de la France ?"} +] + +# Générer le prompt formaté +prompt_formate = tokenizer.apply_chat_template( + messages, + tokenize=False, # On veut le texte, pas les IDs pour l'instant + add_generation_prompt=True # Ajoute le token pour que le modèle commence à répondre +) + +# Tokenizer le prompt pour le modèle +inputs = tokenizer(prompt_formate, return_tensors="pt").to(modele.device) +``` + +### Générer la réponse + +Enfin, on utilise la méthode `generate()` du modèle, en veillant à ne garder que la nouvelle partie générée (sans le prompt). + +```python +outputs = modele.generate(**inputs, max_new_tokens=500) + +# Décoder uniquement la nouvelle partie +reponse = tokenizer.decode(outputs[0][inputs['input_ids'].shape[-1]:], skip_special_tokens=True) +print(reponse) +``` + +### Conseils pour ton ordinateur de 32 Go de RAM + +Tes choix de modèles sont parfaits pour une machine comme la tienne. + +* **Les modèles très légers (0.5B, 360M)** : Ils sont conçus pour tourner sur des appareils avec des ressources limitées. Par exemple, un modèle SmolLM2 360M n'utilise qu'environ **700 Mo** de mémoire pour l'inférence . Le Qwen 2.5 0.5B est un excellent choix pour le français . +* **Optimisation pour les modèles plus gros** : Pour des modèles comme Phi-3 Mini (3.8B) ou Gemma 2 2B, tu peux utiliser la quantification (par exemple, des modèles en `4-bit` comme ceux trouvés sur le Hub) pour réduire drastiquement leur empreinte mémoire. Avec 32 Go de RAM, tu as de la marge. +* **Stabilité sur Mac (MPS)** : Si tu es sur un Mac récent avec puce M, tu pourras utiliser l'accélération GPU (`device_map="mps"`). Attention : pour un entraînement (fine-tuning), il est parfois plus stable d'utiliser le type `torch.float32` plutôt que `float16` pour éviter des erreurs de calcul (NaN) . Pour la simple inférence, ce ne sera pas un problème. + +### L'alternative : `pipeline()` + +Pour une prise en main encore plus rapide, la fonction `pipeline()` de Transformers est idéale . Elle gère automatiquement la tokenisation et la génération. + +```python +from transformers import pipeline + +generateur = pipeline("text-generation", model="Qwen/Qwen2.5-0.5B-Instruct") +resultat = generateur([{"role": "user", "content": "Bonjour !"}], max_new_tokens=100) +print(resultat[0]['generated_text']) +``` + +En résumé, `transformers.py` est l'outil par excellence pour tes besoins. Commence par charger un modèle, joue avec `apply_chat_template()` et `generate()`, et tu maîtriseras vite le fonctionnement. + +N'hésite pas si tu as d'autres questions, par exemple sur le chargement d'un modèle quantifié pour économiser encore plus de mémoire ! + +--- + +ok et comment je fais pour être vraiment en local, c'est-à-dire avec ollama je fais un ollama pull , là je fais comment pour récupérer le modèle ? + +--- + +Avec Hugging Face, le processus est un peu différent d'`ollama pull`. Tu ne télécharges pas un seul fichier `.gguf` comme avec Ollama, mais un dossier complet contenant le modèle, son tokenizer et sa configuration. Tu as plusieurs options, du plus automatique au plus manuel. + +### 💡 Méthode 1 : Le téléchargement automatique avec `transformers` + +C'est la méthode que tu as déjà vue, mais avec l'assurance que tout reste local. + +Quand tu utilises `AutoModelForCausalLM.from_pretrained("nom_du_modele")`, le code va automatiquement : +1. **Vérifier le cache** : Par défaut, les modèles sont stockés dans `~/.cache/huggingface/transformers/` . +2. **Télécharger** : Si le modèle n'est pas trouvé, il sera téléchargé depuis le Hub de Hugging Face. + +Pour garantir qu'il ne cherche **jamais** à se connecter à internet (même si le modèle est manquant), tu peux utiliser l'option `local_files_only=True` . + +```python +from transformers import AutoModelForCausalLM, AutoTokenizer + +nom_du_modele = "Qwen/Qwen2.5-0.5B-Instruct" + +# La première exécution va télécharger le modèle. +# Les suivantes le chargeront depuis le cache. +tokenizer = AutoTokenizer.from_pretrained(nom_du_modele) +modele = AutoModelForCausalLM.from_pretrained( + nom_du_modele, + device_map="auto", + torch_dtype="auto" +) + +# Pour être sûr de ne jamais utiliser Internet (mode hors-ligne) : +# tokenizer = AutoTokenizer.from_pretrained(nom_du_modele, local_files_only=True) +# modele = AutoModelForCausalLM.from_pretrained(nom_du_modele, local_files_only=True) +``` + +Tu peux aussi personnaliser l'emplacement du cache avec le paramètre `cache_dir` ou la variable d'environnement `HF_HOME` . + +### 🧩 Méthode 2 : Téléchargement via `huggingface_hub` (équivalent de `pull`) + +Cette approche te donne un contrôle plus granulaire. Elle est idéale pour pré-télécharger un modèle ou pour gérer des cas particuliers comme les modèles au format GGUF . + +```python +from huggingface_hub import snapshot_download + +# Télécharge tout le modèle dans le dossier "./mon_dossier_qwen" +snapshot_download( + repo_id="Qwen/Qwen2.5-0.5B-Instruct", + local_dir="./mon_dossier_qwen", + local_dir_use_symlinks=False # Désactive les liens symboliques pour avoir une copie réelle +) +``` + +Une fois téléchargé, tu peux charger le modèle depuis ce dossier local : +```python +tokenizer = AutoTokenizer.from_pretrained("./mon_dossier_qwen") +modele = AutoModelForCausalLM.from_pretrained("./mon_dossier_qwen") +``` + +### 📁 Pour mémoire : La structure d'un modèle Hugging Face + +Pour que `transformers` reconnaisse un modèle, son dossier doit contenir des fichiers précis : +* `config.json` : La configuration du modèle (nombre de couches, etc.) . +* `pytorch_model.bin` ou `*.safetensors` : Les poids du modèle. C'est l'équivalent du fichier `.gguf` d'Ollama . +* `tokenizer_config.json`, `vocab.json`, `merges.txt` : Les fichiers nécessaires au tokenizer . + +### ⚙️ Gérer le mode hors-ligne (comme un pro) + +L'option `local_files_only=True` est efficace, mais la manière standard est d'utiliser des variables d'environnement, surtout si tu prévois de travailler souvent hors-ligne . + +Avant d'exécuter ton script, tu peux définir ces variables pour que **tous** les appels à la bibliothèque Hugging Face soient forcés à utiliser le cache local : + +```bash +# Dans ton terminal +export HF_HUB_OFFLINE=1 +export TRANSFORMERS_OFFLINE=1 +``` +Ou en Python : +```python +import os +os.environ["HF_HUB_OFFLINE"] = "1" +os.environ["TRANSFORMERS_OFFLINE"] = "1" +``` + +La différence est importante : +* `local_files_only=True` à l'appel : fonctionne bien, mais doit être passé à chaque fonction. +* `HF_HUB_OFFLINE=1` : agit comme un "kill switch" global. Même si une bibliothèque tente un téléchargement, elle échouera en levant une erreur, ce qui est parfait pour un environnement de production ou air-gappé . + +### 📝 En résumé + +| Action | Avec Ollama | Avec Hugging Face (transformers) | +| :--- | :--- | :--- | +| **Télécharger un modèle** | `ollama pull ` | `AutoModel.from_pretrained("")` (télécharge et charge) OU `snapshot_download` (télécharge seulement) | +| **Charger un modèle** | `ollama run ` | `AutoModel.from_pretrained("./mon_dossier")` (si déjà téléchargé) | +| **Stockage** | `~/.ollama/models` (fichiers `.gguf`) | `~/.cache/huggingface/transformers/` | +| **Garantir le hors-ligne** | (Implicite, pas de téléchargement sans `pull`) | `local_files_only=True` ou `HF_HUB_OFFLINE=1` | + +La grande force de Hugging Face est sa flexibilité : une fois que tu as téléchargé le dossier d'un modèle, il est totalement autonome. Tu peux le déplacer, le copier, et le charger sans jamais avoir à refaire de requête réseau. + + diff --git a/doc/Tasks.md b/doc/Tasks.md index b0145e9..4818dd2 100644 --- a/doc/Tasks.md +++ b/doc/Tasks.md @@ -1,9 +1,57 @@ # Tasks -## Structured output +## Choix du source + +Le source rougail doit-il etre : + +- en rougail (YAML) : non (la persona de rougail-ai ne connaît pas le format Rougail) +- en JSON : à tester +- en format markdown : c'est le format compréhensible par l'IA de base donc les tests partent là dessus + +--- + +**est-ce utile ?** + +## Savoir comment faire en Rougail : + +- exporter en json (ça je crois que c'est dans la doc) +- faire un equivalent make_dict() +le make_dict(), c'est pour que l'ia aie les valeurs et pas seulement la structure. + +Mais étant donné l'approche choisie, il n'est pas opportun de communiquer les valeurs +à rougail-ai. + +Pour l'instant, on n'a pas de use case qui demande un truc du genre : tiens c'est quoi la valeur ???? + +en fait, si on veut une valeur il faut faire du structured output et un tool +qui appelle rougail et qui donne la valeur du moment. + + +!!! attention "Attention" + il ne faut surtout pas charger des valeurs dans la context window du LLM sinon + cela va perturber le reasonning il va s'emmeler les pinceaux + +--- + +**pour la suite** + +## choix des meilleurs LLM + +- choisir les meilleurs LLM, qui se comportent le mieux tout en étant légers +- est-ce possible de le faire dans le navigateur ??? + +## Structured output et tools Ne renvoyer **que** la variable recherchée, par exemple `manual.https_proxy.address`, ou bien le nom de la famille et la liste des variables dedans Utiliser un schéma pydantic avec du structured output dessus. + + +## openWebUI + +Tester openWebUI pour ollama, pour l'interface + +--- + diff --git a/doc/UseCases.md b/doc/UseCases.md new file mode 100644 index 0000000..7a5f22e --- /dev/null +++ b/doc/UseCases.md @@ -0,0 +1,104 @@ +# Use cases + +## todo + +- le 1/ n'est pas fini, il y a des règlages à faire, j'ai eu des résultats bizarres +- le 2/ n'est pas commencé +- le 3/ on verra après + +## Use case 1 + +!!! example "Use case 1" + je veux récupérer une liste de path de variable qui a tel rôle + +1/ "je veux récupérer une liste de path de variable qui a tel rôle + la compréhension de cette variable" + +et aussi des explications (ce qu'elle a compris de telle ou telle partie de la conf +par exemple les explications du mode manuel. + + +exemple: comme le test avec la conf HTTPS. + +Ce use case est presque fait, à part le fait que ce n'est pas la peine +de configurer la persona comme un storage, car il se pose des questions +byzarres ensuite. + +Ce qu'on veut s'est récupérer les paths des variables +(pour ensuite les passer a une interface mais c'est un autre use case). + + +!!! important "Persona" + **A mettre dans la persona** + + On considère comme étant une variable non seulement les variables mais + les familles aussi. + +Rougail-ai rend compte des sous-groupes. +Sans la notion de famille, mais Rougail-ai explique spontanément +les variables à renseigner si tu enclenches le mode manuel par exemple. + +Il faudrait deux possibilités : les paths oui, pas seulement les nom court. + +Les deux en fait, les noms longs et les noms courts. + +Mais les noms longs sont plus importants, parce que si on a le path on a tout le contexte derrière. + +faire des tests : + +- lorsque ça retourne une variable +- lorsque ça retourne une variable qui est une famille en fait + + +## Use Case 2 + +Ce 2eme usecase c'est + +!!! example "Use case 2" + j'aimerais que tu m'explique ma conf + tiens tu peux m'expliquer comment est configuré le proxy chez moi ? + +(Sachant qu'il ne faut même pas expliquer à rougail-ai que **c'est** une conf...) + +2/ "je veux comprendre ma configuration actuelle : +ça retourne une explication textuelle + une liste de path des variables concernées" + +En sortie, pour l'instant, on veut juste du texte. +On veut que rougail-ai nous explique textuellement + +- la nature de la "conf" +- la liste des variables qui sont concernées + +**pour le moment rougail-ai retourne la liste des path qui sont concernés** + +!!! note "Rappel" + + on veut que rougail-ai ne fasse rien d'opérationnel, + on veut qu'elle délègue à rougail dès qu'il y a une opération à calculer. + +Mais cela c'est un autre use case. + +--- + +**étapes ultérieures** + +## Use Case 3 + +3/ "suggère moi une configuration permettant d'arriver à ce resultat +et il retourne une liste de path + valeur" + +Rougail-ai peut décider d'ouvrir des widgets genre formulaires. + +Là on est dans le "generated app". + +!!! example "Exemple" + + "ok ton proxy est configuré mais pas le HTTPS pour le moment si tu veux configurer le HTTPS tien voilà la liste des variables" + +Au niveau de la génération des widgets, c'est déplacé dans un autre projet pour l'instant: + +- l'ia lance des widgets un peu comme le faisait [zenity](https://forge.cloud.silique.fr/gremond/baklava/src/branch/main/doc/Zenity1.md) + (sur gnome) + + + + diff --git a/doc/index.md b/doc/index.md index 186c96d..e1dded4 100644 --- a/doc/index.md +++ b/doc/index.md @@ -1,7 +1,8 @@ # Rougail AI -## todo +## Use cases and tasks +- [[UseCases]] - [[Tasks]] ## content @@ -10,3 +11,4 @@ - [[ChoixLllm]] - [[ChoixLllmQuery]] - [[Tools]] +- [[HuggingFaceGettingStarted]] diff --git a/experiments/ManualProxySettings.md b/experiments/ManualProxySettings.md new file mode 100644 index 0000000..57c56d2 --- /dev/null +++ b/experiments/ManualProxySettings.md @@ -0,0 +1,50 @@ +>>> How can I switch to manual configuration? +Thinking... + +Okay, so the user is asking how to switch to manual configuration based on the provided markdown documentation. Let me break down the information from the markdown to figure out the +best way to respond. + +First, looking at the markdown, there's a section under "Manual proxy configuration" which includes a note. The note says, "Disabled: when the variable 'Configure Proxy Access to the +Internet' hasn't the value 'Manual proxy configuration'." So, the variable in question is probably the one named "proxy_mode" because that's where the configuration options are set. + +The user wants to switch to manual configuration, which means they need to set the "proxy_mode" variable to "Manual proxy configuration." I should explain that clearly. Also, it's good +to mention that this will allow them to configure HTTP, HTTPS, and SOCKS proxies with specific addresses and ports. + +I should structure the response step-by-step to make it easy to follow. Maybe start by telling them to set the proxy_mode variable, then list the specific variables they need to +configure, and perhaps give examples of those configurations for clarity. + +I should also ensure that the instructions are concise and direct, avoiding unnecessary jargon but still technical enough since it's about variables and configuration. Making sure to +highlight the key points without overwhelming them is important. + +Wait, do I need to mention anything about the other options like auto or no_proxy? Probably not, since the user is asking specifically about manual configuration. But it's good to +briefly explain what the other options are for context. + +Also, I should make sure that the response is helpful and guides the user on the next steps after changing the variable. Maybe suggest checking the documentation again for details on +each variable. + +Putting it all together, the response should be straightforward, explaining the necessary variable change and what that entails. +...done thinking. + + + +To switch to manual proxy configuration, you need to configure the `proxy_mode` variable to `Manual proxy configuration`. This means setting the value of the variable `proxy_mode` to `"Manual proxy configuration"`. + +Once this variable is set to `"Manual proxy configuration"`, you can configure the HTTP, HTTPS, and SOCKS proxies as follows: + +1. **HTTP Proxy**: + - Use the variable `manual.http_proxy.address` to specify the HTTP proxy address. + - Use the variable `manual.http_proxy.port` to specify the HTTP proxy port (default: 8080). + +2. **HTTPS Proxy**: + - Use the variable `manual.https_proxy.address` to specify the HTTPS proxy address. + - Use the variable `manual.https_proxy.port` to specify the HTTPS proxy port (default: 8080). + +3. **SOCKS Proxy**: + - Use the variable `manual.socks_proxy.address` to specify the SOCKS proxy address. + - Use the variable `manual.socks_proxy.port` to specify the SOCKS proxy port (default: 1080). + - Use the variable `manual.socks_proxy.version` to specify the SOCKS proxy version (default: v5). + +By configuring these variables, you can set up manual proxy settings for HTTP, HTTPS, and SOCKS. + + diff --git a/experiments/SimpleProxyQuestion.md b/experiments/SimpleProxyQuestion.md new file mode 100644 index 0000000..98028ce --- /dev/null +++ b/experiments/SimpleProxyQuestion.md @@ -0,0 +1,104 @@ +>>> give me some information about the proxy +Thinking... + +Alright, let's see. The user provided a markdown document that describes a data structure for variables related to proxy settings. They want me to act as a database that returns +information about these variables based on the user's request. The user specifically asked for information about the proxy. + +First, I need to understand the structure of the data. The markdown has a root variable `proxy_mode` which is of type `choice` with several options. Each option is a node in the data +structure. For example, "No proxy" is one node, "Auto-detect proxy settings..." is another, and so on. + +The user is asking for information about the proxy, which I interpret as wanting to know about the variables under the "proxy_mode" node. So, I should list all the possible values +(children) of `proxy_mode` and explain each briefly. + +I should present this information in a clear and organized manner, perhaps as a list. Each value should be a subheader with its description. Since the user mentioned acting as a +database, using headings and bullet points would make the response easy to read. + +I should also make sure to highlight the default value and any important details, like the note about the "disabled" state for some variables. + +Finally, I need to ensure that the response is friendly and helpful, acknowledging the user's query and providing the necessary information without being too technical. +...done thinking. + + + +The proxy-related variables are organized under the root variable **`proxy_mode`**, which is of type `choice` with the following possible values: + +### 1. **No proxy** *(default)* + - **Description**: Disables proxy access entirely. + - **Note**: This is the default value. + +--- + +### 2. **Auto-detect proxy settings for this network** + - **Description**: Automatically detects and configures proxy settings based on the current network environment. + +--- + +### 3. **Use system proxy settings** + - **Description**: Configures the proxy to use system-provided proxy settings. + +--- + +### 4. **Manual proxy configuration** + - **Description**: Allows manual configuration of the proxy settings. + - **Note**: This option is enabled only when `proxy_mode` is set to "Manual proxy configuration." + +--- + +### 5. **Automatic proxy configuration URL** + - **Description**: Automatically configures the proxy settings based on a specified URL. + +--- + +### 6. **SOCKS proxy** *(disabled by default)* + - **Description**: Configuration for SOCKS proxy settings. + - **Note**: This is a hidden variable and can be enabled by setting its corresponding variable to "manual" or "auto." + +--- + +### 7. **HTTP Proxy** + - **Description**: Configuration for HTTP proxy settings. + - **Variables**: + - `http_proxy.address`: Mandatory, type `domainname` or IP address. + - `http_proxy.port`: Mandatory, type `port` (default: 8080). + +--- + +### 8. **HTTPS Proxy** + - **Description**: Configuration for HTTPS proxy settings. + - **Variables**: + - `https_proxy.address`: Mandatory, type `domainname` or IP address. + - `https_proxy.port`: Mandatory, type `port` (default: same as HTTP proxy port). + - `use_for_https`: Boolean (default: true) to enable HTTPS proxy. + +--- + +### 9. **Manual Proxy Configuration** + - **Description**: Configuration for manual proxy settings. + - **Variables**: + - `manual.http_proxy.address`: Mandatory, type `domainname` or IP address. + - `manual.http_proxy.port`: Mandatory, type `port` (default: 8080). + - `manual.use_for_https`: Boolean (default: true) to enable HTTPS proxy. + +--- + +### 10. **SOCKS Proxy Configuration** + - **Description**: Configuration for SOCKS proxy settings. + - **Variables**: + - `manual.socks_proxy.address`: Mandatory, type `domainname` or IP address. + - `manual.socks_proxy.port`: Mandatory, type `port` (default: 1080). + - `manual.socks_proxy.version`: Choice (`v4` or `v5`, default: `v5`). + +--- + +### 11. **Auto Proxy Configuration URL** + - **Description**: Configuration for automatic proxy settings based on a specified URL. + +--- + +### 12. **No Proxy Address** + - **Description**: Specifies the address for which the proxy will be disabled. + +--- + +This structure allows for flexible configuration of proxy settings, either manually, automatically, or through a combination of both. + diff --git a/experiments/discussion.txt b/experiments/discussion.txt new file mode 100644 index 0000000..995ba9a --- /dev/null +++ b/experiments/discussion.txt @@ -0,0 +1,10 @@ +Oh, and since the user is working with in-memory storage, I should mention how they can update the variables in their code. Maybe they're using a tool that allows them to write to the +storage, so I should include an example of how to set these variables programmatically. + +-> pas bon du tout. TODO : enlever cette question du "in-memory storage" dans la persona ? + +en même temps c'est lors d'une discussion prolongée que ça ressort. + + + +