Skip to main content
Des outils comme NotebookLM ont changé ce que les gens attendent d’un tas de documents de recherche. Vous ajoutez des sources, vous posez des questions et vous obtenez des réponses qui renvoient au matériel, puis vous générez une conversation entre deux animateurs que vous pouvez écouter en marchant. Ce guide construit tout cela, en environ deux cents lignes de Python, sur cinq endpoints Venice. Rien n’est stocké en dehors de votre machine, à part les requêtes elles-mêmes, et Venice ne les conserve pas.

Exécuter ce carnet dans Google Colab

Toutes les étapes ci-dessous sous forme de carnet exécutable, avec l’aperçu qui se lit en ligne. Rien à installer.

Fonctionnement

Cinq endpoints, chacun avec un seul rôle : La récupération est ici délibérément simple : des vecteurs dans une liste Python, une similarité cosinus dans une boucle. C’est la juste dose de mécanique pour quelques dizaines de sources et cela garde les rouages visibles. Quand vous en aurez besoin de plus, Créer un bot RAG privé couvre le même pipeline avec une véritable base vectorielle et une passe de re-classement.

Mise en place

Une seule dépendance, et une clé depuis la page des paramètres API.
Créez notebook.py et commencez par les imports et la configuration. Les deux listes en bas constituent tout l’état du carnet : sources enregistre ce que vous avez ajouté, et chunks contient les morceaux consultables.
HOSTS associe un nom d’animateur à une voix. Les deux voix proviennent de tts-xai-v1, et cela compte : les voix appartiennent aux modèles, et envoyer une voix d’une famille à un modèle d’une autre est l’erreur la plus courante lorsqu’on débute avec l’endpoint de synthèse vocale.

Choisir un modèle qui ne vieillira pas

Coder en dur un modèle de chat dans un projet garantit son vieillissement. Venice publie via /models/traits quel modèle occupe actuellement chaque rôle, ce qui vous permet de demander le modèle par défaut du moment plutôt que d’en nommer un.
D’autres traits sont disponibles si ce carnet n’a pas la forme que vous voulez. most_intelligent vous fournit un modèle plus puissant pour la synthèse qui demande beaucoup de raisonnement, et default_reasoning vous en donne un qui raisonne à voix ouverte. Voir Modèles pour la liste complète.

Ajouter des sources

Une source est soit une URL soit un fichier sur le disque, et Venice a un endpoint pour chacun. Tous deux renvoient du texte brut, ce qui est le but : le reste du carnet ne se soucie pas de la provenance d’une source.
/augment/scrape renvoie du Markdown plutôt que du HTML brut, il n’y a donc pas de code de nettoyage à écrire. /augment/text-parser accepte les PDF, Word, Excel et texte brut jusqu’à 25 Mo, et retourne un décompte de tokens à côté du texte. Traitement de documents couvre toutes ses options.

Découpage et embeddings

Embedder un document entier produit un unique vecteur qui est une moyenne de tout ce qui y est dit, ce qui est trop grossier pour récupérer une affirmation précise. Le découper produit des vecteurs qui veulent chacun dire quelque chose. Découpez sur les frontières de paragraphes plutôt que sur un nombre fixe de caractères. Un chunk qui s’arrête au milieu d’une phrase est mal récupéré, parce que son embedding est celui d’un fragment.
embed traite par lots parce que l’endpoint prend une liste, et une seule requête pour soixante-quatre chunks est bien plus rapide en temps réel que soixante-quatre requêtes. text-embedding-bge-m3 renvoie 1024 dimensions et gère bien les sources multilingues. Ajouter une source, c’est désormais lire, découper, embedder et enregistrer. La magnitude de chaque vecteur est stockée à côté de lui, parce qu’elle ne change jamais et que la recalculer à l’intérieur de la boucle de similarité serait du travail perdu.
Le number est ce qui rend la citation possible par la suite. Chaque chunk se souvient de la source dont il provient, de sorte qu’une réponse peut y renvoyer.

Récupérer les bons passages

Similarité cosinus entre le vecteur de la question et chaque vecteur de chunk, tri, top k. Pour quelques milliers de chunks, cela s’exécute plus vite que l’appel réseau qui a produit le vecteur de la question.

Répondre avec des citations

La différence entre une réponse ancrée et une supposition assurée tient entièrement au prompt. Deux instructions font le travail : ne répondre qu’à partir des notes, et le dire lorsque les notes ne suffisent pas. Sans la seconde, un modèle comblera discrètement la lacune avec sa mémoire, ce qui est exactement le mode de défaillance que vous cherchez à éliminer par conception. Numéroter les notes dans le prompt donne au modèle un vocabulaire de citation. Il écrit [2], et vous pouvez remonter à la source correspondante.
Extraire les crochets à nouveau vaut bien la ligne unique. Cela vous dit quelles sources ont réellement porté la réponse, et c’est ainsi que vous remarquez qu’une source que vous pensiez centrale n’est jamais citée.

Rédiger le script de l’aperçu

C’est là que le carnet cesse d’être une boîte de recherche. Un résumé, c’est quelque chose qu’on lit ; un aperçu, c’est quelque chose qu’on écoute, et les deux appellent une prose différente. Le dialogue fonctionne mieux à l’oral parce que le tour de parole fait la mise en rythme pour vous, et une question posée par un animateur est une manière naturelle d’introduire l’idée suivante. Trois contraintes comptent, et toutes trois viennent de l’audio et non du texte :
  • Pas de markdown, pas d’URL. Un modèle de synthèse vocale lit https://docs.venice.ai un caractère à la fois.
  • Développez les abréviations. T E E la première fois, pas tee.
  • Variez la longueur des tours. Des tours de longueur égale donnent l’impression de deux personnes qui se lisent une liste à haute voix.
Demander du JSON avec un schéma est ce qui rend le résultat exploitable. Du texte libre demanderait un parsing, et les étiquettes de locuteur sont précisément le genre de chose sur laquelle un modèle s’autorise à être créatif. L’enum sur speaker garantit que chaque tour correspond à une voix dont vous disposez.
L’aperçu couvre les sources en largeur plutôt que de répondre à une question, donc spread échantillonne des chunks sur l’ensemble de la collection au lieu de récupérer par similarité. Prendre un chunk sur n est grossier et fonctionne bien : cela atteint la fin des documents longs, ce que prendre les douze premiers ne ferait jamais. Traitez le nombre de tours comme un indice plutôt que comme une instruction. Demander seize en a produit ici de seize à vingt-huit, selon ce que les sources avaient à dire. S’il vous faut un plafond dur, tronquez turns avant le rendu plutôt que de discuter avec le prompt.

Assembler deux voix en une seule piste

Chaque tour devient une requête de synthèse vocale, avec la voix choisie selon qui parle.
Lire les frames de chaque clip, plutôt que d’enregistrer vingt fichiers et de les recoller ensuite, est ce qui garde la jointure propre. Concaténer de l’audio encodé comme du MP3 ne fonctionne pas de manière fiable, parce que chaque fichier porte ses propres en-têtes. Les frames décodées ne sont que des échantillons, et les assembler revient à ajouter des octets. Deux détails font sonner le résultat comme intentionnel. L’en-tête de la sortie provient du premier clip plutôt que de constantes, si bien que la fréquence d’échantillonnage est toujours correcte pour le modèle que vous avez choisi. Et un quart de seconde de silence entre les tours donne à l’oreille un temps pour enregistrer que le locuteur a changé. Sans cela, les animateurs se marchent sur la fin des phrases de l’autre.
pool.map préserve l’ordre d’entrée, si bien que les tours reviennent dans l’ordre où ils ont été écrits, peu importe lequel finit en premier. Quatre workers sont un plafond délibéré plutôt qu’un maximum : davantage de concurrence commencera à renvoyer des 429 sur les paliers inférieurs, et le job est déjà dominé par le tour le plus long.

Exécution

L’ingestion et la réponse prennent quelques secondes. L’audio est la partie lente, et cela varie avec la charge : environ six minutes de parole prennent entre trente secondes et trois minutes à rendre.

Le rendre vôtre

Les sources sont tout l’enjeu. Tout ce qui vient ensuite est borné par ce que vous mettez en entrée. Les pages scrapées entraînent avec elles leur navigation et leurs pieds de page, ce qui est sans conséquence pour les réponses mais se manifeste dans un aperçu par un animateur discutant sérieusement d’un index de documentation. Si cela arrive, écartez les chunks en dessous d’un seuil de longueur ou filtrez le mobilier évident avant l’embedding. Changez les voix. HOSTS n’est qu’un dictionnaire à deux entrées. tts-xai-v1 propose vingt-six voix, et d’autres familles ont les leurs ; GET /models?type=tts liste les voices par modèle. Deux voix qui contrastent nettement se suivent plus facilement que deux qui sont simplement différentes. Clonez la vôtre. Clonage de voix transforme un court échantillon en un identifiant de voix que vous pouvez glisser directement dans HOSTS. Ajoutez un troisième participant. Rien dans le pipeline ne suppose deux locuteurs, sauf l’enum du schéma. Ajouter un intervieweur qui ne pose que des questions change considérablement le rendu. Gardez le script. Écrire turns dans un fichier JSON à côté de l’audio coûte deux lignes et vous épargne un re-rendu à chaque fois que vous voulez retoucher une phrase.

Pour aller plus loin

Bot RAG privé

Le même pipeline de récupération avec une véritable base vectorielle et un re-classement.

Réponses citées avec recherche web

Trouver les sources automatiquement au lieu de les nommer soi-même.

Synthèse vocale

Référence de l’endpoint de synthèse vocale, de ses voix et du streaming.

Traitement de documents

Tout ce que le parser de documents accepte, et ce qu’il retourne.