From 724bcd85722cc1febda42ac65499870269316b79 Mon Sep 17 00:00:00 2001 From: gwen Date: Mon, 14 Sep 2026 21:22:34 +0200 Subject: [PATCH] webllm --- .gitignore | 1 + doc/WebLlm.md | 44 +++++++++++++++++++++++- webllm/index.html | 14 ++++++++ webllm/index.js | 55 ++++++++++++++++++++++++++++++ webllm/index.js.1 | 28 +++++++++++++++ webllm/package.json | 5 +++ webllm/persona.txt | 75 +++++++++++++++++++++++++++++++++++++++++ webllm/personaLoader.js | 16 +++++++++ 8 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 webllm/index.html create mode 100644 webllm/index.js create mode 100644 webllm/index.js.1 create mode 100644 webllm/package.json create mode 100644 webllm/persona.txt create mode 100644 webllm/personaLoader.js diff --git a/.gitignore b/.gitignore index f0cb2f7..d9a6c29 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ bribes site/ .obsidian .task/ +webllm/node_modules/ diff --git a/doc/WebLlm.md b/doc/WebLlm.md index 1ecfa6c..6ff3e5d 100644 --- a/doc/WebLlm.md +++ b/doc/WebLlm.md @@ -34,9 +34,51 @@ Use a recent Chrome/Edge (≥ 113) or Safari 18+ (chrome://flags/#enable-unsafe- ## install webllm - [Suivre l'install](https://github.com/mlc-ai/web-llm) dans le readme. +``` +sudo apt install -y nodejs npm + +npm install @mlc-ai/web-llm + + python -m"http.server" 8000 +``` + +ou bien, lancer le serveur nodejs : +``` +npm install -g serve +serve +``` + +### usage + +La méthode principale : le System Prompt. Exemple de script: + +```javascript + +import { CreateMLCEngine } from "@mlc-ai/web-llm"; + +// 1. Définir la persona (comme votre instruction SYSTEM dans Ollama) +const systemPrompt = "Tu es un assistant culinaire expert, spécialisé dans la cuisine française. Tu réponds toujours avec enthousiasme et proposes des alternatives aux ingrédients difficiles à trouver. Tu ne parles jamais de sujets hors de la cuisine."; + +const messages = [ + // 2. Le message système définit le comportement pour toute la conversation + { role: "system", content: systemPrompt }, + { role: "user", content: "Comment faire une bonne quiche lorraine ?" } +]; + +// 3. Envoyer la requête +const engine = await CreateMLCEngine("Llama-3.1-8B-Instruct-q4f32_1-MLC"); +const reply = await engine.chat.completions.create({ messages }); + +console.log(reply.choices[0].message.content); + +``` + +- Aller dans le dossier `webllm` et lancer un serveur type `python -m"http.server"` +dans ce dossier. +- Utiliser un browser compatible (j'ai utilisé un-googled-chromium), + le résultat du chat apparaît dans la console. ## install the python mlc local chat utility diff --git a/webllm/index.html b/webllm/index.html new file mode 100644 index 0000000..e6a0ad6 --- /dev/null +++ b/webllm/index.html @@ -0,0 +1,14 @@ + + + + + Test WebLLM + + +

Test de WebLLM

+
+ + + + + diff --git a/webllm/index.js b/webllm/index.js new file mode 100644 index 0000000..d4db07c --- /dev/null +++ b/webllm/index.js @@ -0,0 +1,55 @@ +// import { CreateMLCEngine } from "@mlc-ai/web-llm"; + +import { CreateMLCEngine } from "./node_modules/@mlc-ai/web-llm/lib/index.js"; + + +// Callback function to update model loading progress +const initProgressCallback = (initProgress) => { + console.log(initProgress); +}; +const selectedModel = "Llama-3.1-8B-Instruct-q4f32_1-MLC"; + +const engine = await CreateMLCEngine( + selectedModel, + { initProgressCallback: initProgressCallback }, // engineConfig +); + +// chat + +const messages = [ + { role: "system", content: "You are a helpful AI assistant." }, + { role: "user", content: "Hello!" }, +]; + +// 1. Définir la persona (comme votre instruction SYSTEM dans Ollama) +//const systemPrompt = "Tu es un assistant culinaire expert, spécialisé dans la cuisine française. Tu réponds toujours avec enthousiasme et proposes des alternatives aux ingrédients difficiles à trouver. Tu ne parles jamais de sujets hors de la cuisine."; + +//const messages = [ +// // 2. Le message système définit le comportement pour toute la conversation +// { role: "system", content: systemPrompt }, +// { role: "user", content: "Comment faire une bonne quiche lorraine ?" } +//]; + +//import { loadPersona } from './personaLoader.js'; + +// --- + +// Chunks is an AsyncGenerator object +const chunks = await engine.chat.completions.create({ + messages, + temperature: 0 +// stream: true, // <-- Enable streaming +// stream_options: { include_usage: true }, +}); + +let reply = ""; +for await (const chunk of chunks) { + reply += chunk.choices[0]?.delta.content || ""; + console.log(reply); + if (chunk.usage) { + console.log(chunk.usage); // only last chunk has usage + } +} + +const fullReply = await engine.getMessage(); +console.log(fullReply); diff --git a/webllm/index.js.1 b/webllm/index.js.1 new file mode 100644 index 0000000..d086e9c --- /dev/null +++ b/webllm/index.js.1 @@ -0,0 +1,28 @@ +// import { CreateMLCEngine } from "@mlc-ai/web-llm"; + +import { CreateMLCEngine } from "./node_modules/@mlc-ai/web-llm/lib/index.js"; + + +// Callback function to update model loading progress +const initProgressCallback = (initProgress) => { + console.log(initProgress); +}; +const selectedModel = "Llama-3.1-8B-Instruct-q4f32_1-MLC"; + +const engine = await CreateMLCEngine( + selectedModel, + { initProgressCallback: initProgressCallback }, // engineConfig +); + +// chat + +const messages = [ + { role: "system", content: "You are a helpful AI assistant." }, + { role: "user", content: "Hello!" }, +]; + +const reply = await engine.chat.completions.create({ + messages, +}); +console.log(reply.choices[0].message); +console.log(reply.usage); diff --git a/webllm/package.json b/webllm/package.json new file mode 100644 index 0000000..3652d11 --- /dev/null +++ b/webllm/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "@mlc-ai/web-llm": "^0.2.85" + } +} diff --git a/webllm/persona.txt b/webllm/persona.txt new file mode 100644 index 0000000..622a43b --- /dev/null +++ b/webllm/persona.txt @@ -0,0 +1,75 @@ +Provided this markdown documentation: + +```markdown +| Variable | Description | +|------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **proxy_mode**
[`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | Configure Proxy Access to the Internet.
**Choices**:
• No proxy **← (default)**
• Auto-detect proxy settings for this network
• Use system proxy settings
• Manual proxy configuration
• Automatic proxy configuration URL | + +# Manual proxy configuration + +> [!NOTE] +> +> **Path**: manual\ +> *`disabled`*\ +> **Disabled**: when the variable "[Configure Proxy Access to the Internet](#proxy_mode)" hasn't the value "Manual proxy configuration". + +## HTTP Proxy + +> [!NOTE] +> +> **Path**: manual.http_proxy + +| Variable | Description | +|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **manual.http_proxy.address**
[`domainname`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | HTTP proxy address.
**Validators**:
• type domainname
• the domain name can be an IP | +| **manual.http_proxy.port**
[`port`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | HTTP proxy port.
**Validators**:
• well-known ports (1 to 1023) are allowed
• registred ports (1024 to 49151) are allowed
• private ports (greater than 49152) are allowed
**Default**: 8080 | + +| Variable | Description | +|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------| +| **manual.use_for_https**
[`boolean`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | Also use this proxy for HTTPS.
**Default**: true | + +## HTTPS Proxy + +> [!NOTE] +> +> **Path**: manual.https_proxy\ +> *`hidden`*\ +> **Hidden**: when the variable "[Also use this proxy for HTTPS](#manual.use_for_https)" has the value "true". + +| Variable | Description | +|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **manual.https_proxy.address**
[`domainname`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | HTTPS proxy address.
**Validators**:
• type domainname
• the domain name can be an IP
**Default**: the value of the variable "[HTTP proxy address](#manual.http_proxy.address)". | +| **manual.https_proxy.port**
[`port`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` | HTTPS proxy port.
**Validators**:
• well-known ports (1 to 1023) are allowed
• registred ports (1024 to 49151) are allowed
• private ports (greater than 49152) are allowed
**Default**: the value of the variable "[HTTP proxy port](#manual.http_proxy.port)". | + +## SOCKS Proxy + +> [!NOTE] +> +> **Path**: manual.socks_proxy + +| Variable | Description | +|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **manual.socks_proxy.address**
[`domainname`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) | SOCKS proxy address.
**Validators**:
• type domainname
• the domain name can be an IP | +| **manual.socks_proxy.port**
[`port`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` *`disabled`* | SOCKS proxy port.
**Validators**:
• well-known ports (1 to 1023) are allowed
• registred ports (1024 to 49151) are allowed
• private ports (greater than 49152) are allowed
**Default**: 1080
**Disabled**: when the variable "[SOCKS proxy address](#manual.socks_proxy.address)" has the value "null". | +| **manual.socks_proxy.version**
[`choice`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` *`disabled`* | SOCKS host version used by proxy.
**Choices**:
• v4
• v5 **← (default)**
**Disabled**: when the variable "[SOCKS proxy address](#manual.socks_proxy.address)" has the value "null". | + +| Variable | Description | +|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **auto**
[`web address`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `mandatory` *`disabled`* | Automatic proxy configuration URL.
**Validators**:
• well-known ports (1 to 1023) are allowed
• registred ports (1024 to 49151) are allowed
• type domainname
• the domain name can be a hostname
**Disabled**: when the variable "[Configure Proxy Access to the Internet](#proxy_mode)" hasn't the value "Automatic proxy configuration URL". | +| **no_proxy**
[`domainname`](https://rougail.readthedocs.io/en/latest/variable.html#variables-types) `multiple` *`disabled`* `unique` | Address for which proxy will be desactivated.
Connections to localhost, 127.0.0.1/8 and ::1 are never proxied.
**Validators**:
• type domainname
• the domain name can starts by a dot
• the domain name can be a hostname
• the domain name can be an IP
• the domain name can be network in CIDR format
**Examples**:
• .mozilla.org
• .net.nz
• 192.168.1.0/24
**Disabled**: when the variable "[Configure Proxy Access to the Internet](#proxy_mode)" has the value "No proxy". | + +``` + +This markdown describes an organised data set. +It describes some kind of a storage content with variables names. +These variables are organised into groups of data in a tree-like structure, that is Some variables can contain variables. +Like a folder structure in a hard disk, you have long names and short names. +When the user talks about a variable's name, he means the long name. +The user want to retrieve a variable name (or a list of variable names) that have a given role, along with an understanding of the variable itself. +You help the user in: +- retieving the variables +- understanding the retrieved variable's role. +That's like some kind of a database storage that returns all or part of its data structure depending on the user's request. +You can retrive the variables corresponding to the user's query because we're dealing here with a consistent data structure. +If the user asks you for information about a particular variable, provide him with that information. +In summary, you act as a query tool for a data structure that is described in the markdown documentation provided to you. diff --git a/webllm/personaLoader.js b/webllm/personaLoader.js new file mode 100644 index 0000000..7180946 --- /dev/null +++ b/webllm/personaLoader.js @@ -0,0 +1,16 @@ +// personaLoader.js +export async function loadPersona(filepath = './persona.txt') { + try { + const response = await fetch(filepath); + + if (!response.ok) { + throw new Error(`Erreur ${response.status}: impossible de charger la persona`); + } + + const systemPrompt = await response.text(); + return systemPrompt.trim(); + } catch (error) { + console.error("Erreur chargement persona:", error.message); + throw error; + } +}