Vous avez déjà utilisé des API d’intelligence artificielle ? Si vous avez déjà intégré OpenAI API ou Mistral API, vous savez que les réponses de l’IA sont très imprévisibles, même si notre prompt demande un format JSON, cela ne fonctionne pas à tous les coups.
Pour résoudre ce problème, nous allons utiliser le concept de function calling, qui est disponible dans la plus part des API d’IA. Cela va plutôt dépendre du model.
Les function calling, c’est quoi ?
Les function calling sont des fonctions qui sont appelées par l’IA. On va donc pouvoir exécuter des fonctions de notre choix pendant la réponse ou alors … Formater la réponse avec des clés prédéfinies.
Dans ce tutoriel, je ne vais pas explorer l’exécution de fonctions externe, mais plutôt je vais utiliser les fonctions callings pour formater la réponse, ce qui va nous permettre de récupérer des données structurées de la même façon à tout les coups.
Si vous ne le savez pas, Mistral est une IA open source, développée par des français ! Mistral
Elle dispose de plusieurs models, qui permettent différentes utilisations. Cela dépend donc de vos besoins ! Il existe même un modèle de vision qui permet d’extraire les données d’une image !
Est-ce qu’on ne ferait pas un petit workflow avec deux modèles ?
Projet
Bon, pour avoir un petit exemple, je vais coder rapidement une API qui va nous permettre l’upload d’une image d’un excel de commande de pièce. Avec cette image nous allons utiliser le modèle de vision de Mistral pour extraire les données de la pièce et ensuite le model de texte avec une function calling pour formater la réponse.
J’utiliserai l’image suivante pour mes tests :
Start
Pour le développement rapidement de cette API, je vais utiliser Bun avec Hono pour avoir une API rapidement et simplement.
Si vous voulez découvrir comment débuter avec Bun et Hono, j’ai réalisé récemment un article sur le sujet : Découverte de Bun
Upload de fichier
Voici mes deux fichiers qui me permettent d’upload une image et de récupérer le base64 de l’image qui permettra l’envoie à l’api de mistral.
{ type: "text", text: "Please analyze the provided image. If it contains a table, extract each row and convert it into a structured JSON format. For each row, use the exact values without filling in missing fields with data from other rows. If a field is empty, leave it empty. Ensure that each JSON object represents exactly one row of the table. Thank you!" },
return c.text(`File uploaded and analyzed : ${analyzeResult}`);
});
Maintenant, si on reteste notre POST d’image dans postman, nous devrions avoir le texte de l’image grâce à l’IA !
Nous voyons que l’IA nous donne le texte de l’image, mais la structure n’est pas parfaite, il y a du texte, JSON etc. Ce qui n’est pas idéal pour traiter notre sortie de façon automatique, pour intéragir avec d’autres partie de notre code.
Function calling
Nous arrivons enfin au sujet principal de cet article, les function calling, nous allons structurer la réponse d’analyse d’IA pour que nous n’ayons que un JSON avec des clés prédéfinies.
Pour cela, nous devrons utiliser un autre modèle qui prend en charge les function calling : mistral-small-latest.
Toujours dans le ExtractorImage.ts, nous allons ajouter du code :
src/controllers/ExtractorImage.ts
const tools:any[] = [
{
"type": "function",
"function": {
"name": "retrieve_product_information",
"description": "Retrieve detailed information about a product including manufacturer, description, quantity, and supplier.",
"parameters": {
"type": "object",
"properties": {
"product_name": {
"type": "string",
"description": "The name of the product to retrieve information about.",
},
"manufacture": {
"type": "string",
"description": "The name of the manufacturer or brand of the product.",
},
"description": {
"type": "string",
"description": "A brief description of the product, including its features and specifications.",
},
"fabricant": {
"type": "string",
"description": "The company responsible for producing the product.",
},
"qty": {
"type": "integer",
"description": "The quantity of the product available in stock.",
messages: [{ role: "user", content: `Extract all information from the provided text and format the response using the tools in JSON format. Do not reply with any text; use only the provided tools to format the response. The text: ${text}` }],
À présent vous savez utiliser l’IA pour retourner des données structurées, faites plusieurs upload, vous verrez que vous aurez toujours votre JSON structuré de la même façon ! 🚀
Maintenant que vous avez appris à utiliser les function calling, vous pouvez intégrer facilement l’IA en contrôlant son output dans votre code, j’espère que ce tutoriel vous a aidé pour comprendre ce concept et vous donnera des idées pour vos projets 🙃
Réseaux sociaux
Comme d’habitude, n’hésitez pas à me rejoindre sur les réseaux sociaux pour plus de contenu !
Bonjour à tous ! Aujourd’hui on se retrouve pour découvrir Bun !
C’est quoi Bun ?
Bun est un framework de développement qui a pour but de ‘remplacer’ NodeJS pour le développement en TypeScript/JavaScript.
Bun contient plusieurs modules natifs, il va aussi nous permettre de gérer les packages NPM mais aussi de réaliser des tests unitaires très facilement.
Avant de commencer
Avant d’aller dans notre éditeur de code préféré, je tiens à souligner que je n’ai jamais fait de TypeScript, donc ce sera de la découverte pour moi.
L’idée, c’est de créer un projet qui sera une petite API, une base de données SQLite et de créer les tests unitaires.
Le projet
Mais on va coder quoi ?
Pour créer cet article, je profite d’un projet qui m’a été donné à mon école (CESI).
Le projet est assez grand pour le peu de temps accordé donc nous devons prioriser les tâches, je ne vais pas vous expliquer tout le sujet, donc je vais juste vous énoncer quelques user stories que nous avons choisies.
User stories
User storie 1
En tant qu’utilisateur je souhaite m’inscrire pour parier sur un match.
Remarque : L’utilisateur ne peut pas s’incrire s’il a moins de 18 ans. Il faut également connaître le pays de l’utilisateur.
User storie 2
En tant qu’utilisateur je veux pouvoir me connecter à mon compte.
Remarque : Un token JWT de 1H devra être fournis.
User storie 3
En tant qu’utilisateur je peux visualiser les matchs disponibles ainsi que leurs côtes.
Remarque : Pas besoins de compte pour visualiser les matchs.
Remarque : Les matchs seront fictifs dans un JSON.
User storie 4
(optionnel) En tant qu’utilisateur connecté je peux parier sur un match une somme.
Remarque : Le match ne doit pas être en cours de jeu.
Installation de bun
Maintenant que nous avons nos user stories qui déterminent nos tâches, on va pouvoir commencer à coder !
Pour commencer, on va installer bun.
Sous linux et MacOS nous utiliserons cette commande :
Fenêtre de terminal
curl-fsSLhttps://bun.sh/install|bash
Voici la sortie de la commande :
Fenêtre de terminal
Added"~/.bun/bin"to$PATHin"~/.zshrc"
Togetstarted,run:
exec/usr/bin/zsh
bun--help
Nous allons donc réaliser la commence exec et tester bun —help.
Screen de bun —help :
Parfait tout va bien !
Je vais créer un nouveau dossier que je vais appeler “bun-trd”
Fenêtre de terminal
mkdirbun-trd
Et je vais aller dans le dossier :
Fenêtre de terminal
cdbun-trd
Création du projet
Maintenant nous allons créer le projet avec bun init.
Fenêtre de terminal
buninit
Nous voyons que nous avons un dossier avec tous les fichiers nécessaires pour notre projet. (Pas comme NodeJS, créer ne crée pas le fichier index.js)
Dans le package.json je vais ajouter la partie scripts qui va nous permettre de lancer le fichier index.ts qui contient un console.log.
"scripts": {
"dev": "bun --hot index.ts"
},
C’est quoi —hot ? Magie ! C’est une option qui permet de lancer le programme avec hot reload. Pas besoin d’ajouter nodemon ou autres. :)
Il nous reste plus qu’à lancer le projet avec bun run dev
Et voilà notre projet est lancé !
Avant de bien structurer notre projet, nous allons ajouter Hono, u module qui permet la création d’API Rest très facilement.
Ajout de Hono
Normalement nous pouvons faire bun create hono projetname, mais comme nous avons déjà initialisé notre projet, nous allons utiliser bun add hono
On va commencer les choses sérieuse, donc je vais structurer le projet.
Voici ma structure choisis :
.
├── bun.lockb
├── nodes_modules
├── package.json
├── README.md
├── data
├── .env
├── tests
├── src
│ ├── controllers
│ ├── index.ts
│ ├── models
│ └── utils
└── tsconfig.json
Persistance des données
Avant de commencer notre api nous allons explorer la persistance des données, pour cela nous allons utiliser une base de données SQLite.
newHTTPException(400, { message: "Tous les champs sont obligatoires" })
);
});
});
Encore une fois, j’ai commenté au maximum les différentes parties de mon code pour que vous compreniez mieux l’utilité, et pour moi ici quand je regarderai mon tutoriel plus tard ^^”
Maintenant on va lancer notre test avec la commande bun test
Connexion d’un utilisateur
Je ne vais pas vous détailler tout le projet, mais je trouve ça intéressant d’avoir plusieurs outils à notre disposition directement, comme le hash de mot de passe ou le connecteur de base de données.
Pour continuer sur cette lancé je vais utiliser une autre intégration, la génération de token JWT ! Ce n’est pas vraiment bun qui l’intégre mais Hono embarque directement le module https://hono.dev/docs/helpers/jwt
Dans userController je vais donc ajouter le code suivant :
// Login utilisateur
import { sign } from "hono/jwt";
//Fonction de login de l'utilisateur
export async function fonctionUserLogin(userInput: Pick<userInput, "email" | "password">) {
//Vérification des champs obligatoires
if (!userInput.email || !userInput.password) {
throw new HTTPException(400, {
message: "Tous les champs sont obligatoires",
});
}
//Requete dans la base de données pour récupérer l'utilisateur
const user = db
.query("SELECT * FROM users WHERE email = ?")
.get(userInput.email) as user; //Nécessite as user en TS pour typé le résultat de la query
//Erreur si l'utilisateur n'existe pas
if(!user){
throw new HTTPException(400, { message: "Utilisateur inexistant" });
const result = await fonctionUserLogin(userInput);
return c.text(result);
});
Dans l’index.ts on va rajouter une route /login
app.post("/login", ...userLogin);
Résultat :
Parfait tout ça ! Mais maintenant, je me demande comment faire les tests de login, sachant qu’on mock la fonction db donc on insère par l’utilisateur dedans.
En demandant à GPTo il m’a indiqué qu’en mode test notre NODE_ENV est égal à test. Donc nous pourrions modifier db.ts pour créer une database de test.
Et spoiler alerte, il a raison !
J’ai testé sans créer la base de données de test, c’est une galère de mock toutes les commandes SQLite.
Donc je vais faire un if à la création de la base de données pour créer une base de données de test si la variable d’environnement NODE_ENV est égale à test.
//Connexion à la base de données (La création est faite si elle n'existe pas)
Avec le changement de base de données, j’ai du intégré la suppression des données dans la tables, mais j’ai pu rajouter aussi le test d’erreur lorsque l’email existe déjà !
Voici mon fichier complet de test à présent :
//Import des class de test via bun:test
import { describe, expect, test, jest } from"bun:test";
Tout va bien ! C’est très simple mais mon but encore une fois est de faire des tests unitaires, donc c’est parti !
test unitaire
J’ai décidé de faire un seul test unitaire, car pour les matchs il faudrait implémenter une forte logique pour une gestion parfaite, mais je pense avoir assez détaillé les tests dans la partie utilisateur, ce qui m’a permis d’acquérir de nouvelles connaissances sur jest et bun.
describe("Recupéation des matchs seulement du jour", ()=> {
test("Recupération des matchs du jour", async()=> {
const match = await fonctionViewMatch();
const today = newDate();
expect(match.length).toBeGreaterThan(0);
match.forEach((m)=> {
expect(m.date.getDate()).toBe(today.getDate());
})
});
})
Ce fichier permet de vérifier que la fonction fonctionViewMatch retourne bien des données et que c’est donnée soit uniquement des matchs du jour.
Conclusion
J’espère que cet article vous a plu et vous donnera envie de tester Bun !
Etant une personne qui n’est jamais fait de TypeScript, je n’ai pas ressenti d’énorme difficulté, je suis même étonné de la facilité d’utilisation. Cela ne change pas énormément de JavaScript, à part l’ajout d’un typage qui permet une sécurité accrue sur l’input/output des données.
Bien sûr, je n’ai pas exploré toutes les possibilités de TypeScript/Bun, mais je pense que c’est une première expérience très intéressante !
En utilisant VueJS dans son état le plus pur possible, il nous arrive d’importer plusieurs fois des fonctions/méthodes, ici je veux parler de Ref, Watch, onMouted ou encore d’autre comme route et router de vue-router.
Si vous avez déjà utilisé des frameworks comme Nuxt, vous avez remarqué que vous n’avez pas besoin de cela, même pour les components, de l’auto import qui nous rend plus efficaces et rend le code plus propre.
Cependant, tous les frameworks ne sont pas doté de cette technologie, ni Vue dans son état brute.
Dans cet article de blog je vais donc vous montrer comment y remédier 🙂 Il suffit de 2 librairies très puissantes qui vont faire gagner beaucoup de lignes de code.
Pour commencer je vais créer un projet Vue avec vite :
On va maintenant suivre la documentation est faire un premier npm install.
npmi-Dunplugin-auto-import
Dans le fichier vite.config.js nous allons ajouter l’import et indiquer le plugin pour qu’il soit chargé au build de l’application. Ensuite, en suivant la documentation, nous allons pré importer des librairies dans un tableau.
A présent dans mon component TheWelcome, je peux utiliser ref sans l’import
Je vais supprimer aussi les import de vue-router dans mon app.vue
Et ça fonctionne :D
Maintenant on va supprimer toutes la partie script setup, avec unplugin-vue-components , fini l’import de component !
Un petit npm install
npmiunplugin-vue-components-D
On retourne dans vite.config.js et on ajoute notre plugin dans vite.
J’ai supprimé l’import de component dans App.vue
Et cela fonctionne parfaitement !
J’espère que ces librairies vous plairont mais aussi qu’elles vous seront utiles 😁
Pour finir, n’hésitez pas à me rejoindre sur les réseaux sociaux pour plus de contenu !