murmur

Guide de murmur

Tout pour ajouter murmur à un site, choisir comment l'IA est appelée, indexer vos pages et utiliser le paquet npm.

Démarrage rapide

Collez cette ligne avant </body> sur chaque page de votre site :

<script type="module" src="https://maxgfr.github.io/murmur/cdn/murmur.js"></script>

Une bulle apparaît en bas à droite. Sans option, elle répond à partir du texte de la page que lit le visiteur, avec un petit modèle d'IA qui tourne dans son navigateur (après son accord pour un téléchargement unique de 1,1 Go) ; le visiteur peut brancher sa propre clé d'IA à la place depuis les réglages IA. Pour répondre à partir de tout le site, construisez un index (voir Indexer votre site) ; pour un modèle hébergé sans rien à régler côté visiteur, passez par un proxy (voir Modèles d'IA et clés).

Le configurateur de la page d'accueil écrit la ligne pour vous.

Options

Chaque option est un attribut data- de la balise script. Toutes sont facultatives.

AttributEffet
data-indexURL du fichier d'index écrit par murmur index, par exemple /murmur-index.json. Sans lui, le widget lit la page courante.
data-endpointURL de votre proxy compatible OpenAI (https). Les visiteurs discutent alors sans clé.
data-modeproxy, local, auto (par défaut) ou key : qui répond (voir Modèles d'IA et clés).
data-preloadQuand le modèle du navigateur se télécharge : question (par défaut), open, idle ou consent.
data-localfalse désactive le modèle qui tourne dans le navigateur du visiteur, utilisé par défaut quand il n'y a pas de proxy : le visiteur a alors besoin de sa propre clé.
data-providerFournisseur présélectionné pour les visiteurs qui apportent leur clé : openai, anthropic, google, mistral, openrouter, groq…
data-modelIdentifiant du modèle : celui présélectionné pour les visiteurs, ou celui demandé à votre proxy.
data-instructionsVos consignes à l'assistant : qui il est, son ton, ce dont il ne doit pas parler.
data-title, data-greeting, data-placeholder, data-buttonLe titre du panneau, le premier message, le texte indicatif du champ et le libellé de la bulle.
data-langLangue de l'interface et des réponses : fr ou en. Par défaut, le lang de la page, puis celui du navigateur.
data-positionbottom-right (par défaut) ou bottom-left.
data-accentN'importe quelle couleur CSS pour la bulle, l'en-tête et les messages du visiteur.
data-themeauto (par défaut, suit le système), light ou dark.
data-opentrue ouvre le panneau au chargement.
data-storage-keyPréfixe de ce que le widget enregistre, pour séparer deux widgets sur un même domaine.

Indexer votre site

L'index est un fichier JSON de vos pages découpées en passages sous leurs titres. Construisez-le à partir du dossier de sortie de votre site, après votre générateur de site statique :

npx murmur-rag index ./dist --out ./dist/murmur-index.json

Il lit tous les fichiers .html, .md et .txt. Dans le HTML, il garde le contenu de main (ou article, ou body) et ignore la navigation, les en-têtes, pieds de page, formulaires et scripts. Ajoutez data-murmur-ignore à tout élément à laisser de côté.

OptionEffet
--outOù écrire l'index (par défaut murmur-index.json).
--basePréfixe d'URL des pages, pour un site servi sous un sous-chemin comme /docs/.
--rootSélecteur CSS du contenu de chaque page.
--excludeSélecteurs CSS à ignorer, en plus de ceux par défaut.
--max-chunkLongueur maximale d'un passage en caractères (2000 par défaut).

La commande accepte aussi un site en ligne : npx murmur-rag index https://exemple.fr/sitemap.xml récupère toutes les pages du sitemap.

Dans une GitHub Action

Ajoutez une étape après votre build, avant l'envoi de l'artefact Pages :

- run: npx murmur-rag index ./_site --base /mon-depot/ --out ./_site/murmur-index.json

Modèles d'IA et clés

Choisissez comment la bulle répond avec data-mode. Une clé écrite dans une page web est lisible par tout le monde, donc murmur n'en prend jamais : votre clé reste dans votre Worker, et celle d'un visiteur dans son propre navigateur.

data-modeQui répond
proxyVotre Worker, qui garde votre clé. Implicite avec data-endpoint. Ce qu'utilisent la plupart des sites.
localUn modèle dans le navigateur du visiteur, et rien d'autre : pas de réglages de clé.
auto (par défaut)Votre proxy s'il est défini ; sinon le modèle du navigateur, le visiteur restant libre de brancher sa propre clé.
keyLa clé de chaque visiteur, rien d'autre.

Votre Worker garde la clé

Déployez le Worker Cloudflare d'exemple. Il garde votre clé en secret, transmet les requêtes de chat à n'importe quelle API compatible OpenAI (OpenRouter, OpenAI, Groq, Mistral…), n'accepte que l'origine de votre site, fixe le modèle et plafonne la longueur de chaque réponse. Ensuite :

<script type="module" src="https://maxgfr.github.io/murmur/cdn/murmur.js"
  data-endpoint="https://murmur-proxy.vous.workers.dev/v1" data-model="openai/gpt-5-mini"></script>

Fixez une limite de dépenses chez votre fournisseur : quiconque peut ouvrir votre site peut utiliser votre proxy.

Un modèle dans le navigateur du visiteur

Avec data-mode="local" (ou par défaut quand il n'y a pas de proxy), le navigateur fait tourner LFM3 1.7B de Liquid AI (octobre 2026), dans ses poids 4 bits pour WebGPU, via Transformers.js. Les questions ne quittent jamais l'appareil.

data-preload indique quand les poids (environ 1,1 Go) se téléchargent :

data-preloadLe téléchargement démarre
question (par défaut)À la première question, avec une barre de progression discrète au-dessus du champ.
openQuand le visiteur ouvre la bulle : le modèle est souvent prêt quand il a fini de taper.
idleDès que la page est inactive, même si le visiteur n'ouvre jamais la bulle.
consentAprès l'accord du visiteur, sur une demande qui nomme le modèle et sa taille.

Les poids restent dans le cache du navigateur, et murmur demande au navigateur de les conserver (stockage persistant) pour qu'un téléchargement d'1 Go ne soit pas effacé. À la visite suivante, un modèle déjà en cache est préparé en arrière-plan, sans réseau, quel que soit data-preload : la première réponse arrive alors en quelques secondes.

Il faut WebGPU (Chrome, Edge ou Safari récents) et un GPU avec environ 1,5 Go de mémoire libre ; sinon, la bulle le dit. Un modèle de 1,7 milliard de paramètres est moins précis qu'un modèle hébergé.

Chaque visiteur apporte sa clé

Avec data-mode="key", ou depuis les réglages IA dans le mode par défaut, le visiteur choisit un fournisseur et un modèle, colle une clé, la teste et enregistre. llm-connect chiffre la clé en AES-GCM sous une clé que la page ne peut pas exporter, la garde dans le navigateur (pour la session, ou sur l'appareil si le visiteur le demande) et ne l'envoie qu'au fournisseur choisi. Le visiteur peut aussi brancher le widget sur Ollama ou LM Studio sur sa propre machine.

Le navigateur appelle directement le fournisseur, qui doit donc accepter les appels depuis une page web (CORS) : c'est le cas d'OpenAI, Anthropic, Google, Mistral, OpenRouter, Groq, Together, DeepInfra, xAI et des serveurs locaux avec CORS activé.

Paquet npm

npm install murmur-rag

Le paquet est découpé pour ne prendre que ce dont vous avez besoin :

ImportContenu
murmur-ragcreateMurmur, le moteur sans interface, plus tout /rag.
murmur-rag/ragbm25Retriever, buildIndex, splitText, formatSources, citedSources, l'interface Retriever.
murmur-rag/indexerindexPages, indexDocument, extractSections.
murmur-rag/llmproxySettings, visitorStore, resolveSettings, au-dessus de llm-connect.
murmur-rag/locallocalModel, un modèle AI SDK qui tourne dans la page sur WebGPU ; hasWebGPU, DEFAULT_LOCAL_MODEL. Demande @huggingface/transformers.
murmur-rag/widgetmountMurmur, defineMurmurChat, MurmurChat, renderMarkdown.
murmur-rag/embedL'entrée de la balise script : lit les attributs data- et monte la bulle.

Sans interface

import { createMurmur } from "murmur-rag";
import { anthropic } from "@ai-sdk/anthropic";

const murmur = createMurmur({ index, model: anthropic("claude-sonnet-5-5"), language: "fr" });
const answer = await murmur.ask("Que comprend l'offre Pro ?");
for await (const part of answer.textStream) process.stdout.write(part);
const { cited } = await answer.done; // numéros des passages cités

Votre propre retriever

Tout objet doté de search(query, { limit, budgetTokens }) qui renvoie des passages remplace BM25 : un index d'embeddings, une API de recherche, une base de données.

const retriever = {
  async search(query) {
    const hits = await maRecherche(query);
    return hits.map((h) => ({ doc: 0, url: h.url, title: h.title, heading: "", anchor: "", text: h.text }));
  },
};
mountMurmur({ retriever, llm: { endpoint: "https://proxy.exemple.fr/v1" } });

Style et événements

Le widget vit dans un Shadow DOM : votre CSS ne peut pas le casser et le sien ne déborde pas sur votre page. Changez son style par des propriétés personnalisées sur murmur-chat :

murmur-chat {
  --murmur-accent: #0b5cad;
  --murmur-accent-ink: #ffffff;
  --murmur-font: "Inter", sans-serif;
  --murmur-radius: 12px;
  --murmur-z: 1000;
}

Il émet un événement murmur:state à chaque étape (searching, streaming, done, error) avec les passages trouvés et ceux cités : le standard de la page d'accueil est dessiné à partir de lui.

document.querySelector("murmur-chat").addEventListener("murmur:state", (e) => {
  console.log(e.detail.state, e.detail.passages, e.detail.cited);
});

Vie privée et sécurité

FAQ

Ça marche sur GitHub Pages ?

Oui : murmur, ce sont des fichiers statiques. Ce site est sur GitHub Pages et sa bulle répond à partir de son propre index, construit dans son workflow de déploiement.

Quel modèle choisir ?

Un modèle rapide et peu cher suffit : le travail consiste à lire quelques passages et à les résumer. Les réglages proposent le modèle recommandé de chaque fournisseur.

Et si la réponse n'est pas sur mon site ?

L'assistant a pour consigne de le dire et d'indiquer où chercher, plutôt que d'inventer. Si aucun passage ne correspond à la question, il en est informé.

Peut-on utiliser la recherche sans IA ?

Oui : bm25Retriever(index).search(query) de murmur-rag/rag renvoie les passages correspondants avec leurs liens, de quoi faire une simple recherche sur le site.