Déploiement du modèle multimodal Youtu-VL-4B : Interface Gradio et API compatible OpenAI sur un seul port

1. Introduction : Une seule interface, deux expériences

Vous est-il déjà arrivé de vouloir tester un modèle d'IA multimodal, mais de vous retrouver bloqué par une configuration environnementale complexe, des dépendances multiples, et pour finir, de découvrir que l'interface web et le service API sont deux entités distinctes avec des ports différents et des configurations fastidieuses ? Le simple fait de faire fonctionner le modèle peut vous prendre une bonne partie de la journée.

Le package Youtu-VL-4B-Instruct que je vais vous présenter aujourd'hui résout parfaitement ce problème. Il s'agit d'un modèle léger de langage visuel multimodal open-source du Tencent YouTu Lab, ne pesant que 4 milliards de paramètres mais offrant des performances impressionnantes. Ce que j'ai trouvé particulièrement pratique, c'est qu'il intègre à la fois une interface web Gradio et un service API compatible OpenAI, le tout accessible via un seul et même port (7860 par défaut).

Qu'est-ce que cela signifie pour vous ? Vous lancez un seul service et vous pouvez interagir avec le modèle via un navigateur en téléchargeant des images et en conversant en temps réel, tout en pouvant l'intégrer à vos propres applications via une interface de programmation. Plus besoin de configurer des ports séparés pour chaque service, ni de vous soucier de leur communication. Pour les développeurs, cela représente un gain de temps considérable en termes de déploiement et de débogage.

J'ai passé un certain temps à créer un package complet pour ce modèle, incluant les fichiers du modèle, l'environnement d'exécution, l'interface web et le service API. Il vous suffit de télécharger le package et de lancer le service pour être opérationnel en quelques minutes. Que vous souhaitiez rapidement tester les capacités de l'IA multimodale ou l'intégrer à votre projet, cette solution répondra à vos besoins.

2. Préparation de l'environnement et démarrage rapide

2.1 Vérification des exigences matérielles

Avant de commencer, examinons les exigences matérielles. Bien que ce modèle ne pèse que 4 milliards de paramètres, ce qui est considéré comme "léger", il nécessite tout de même une quantité de mémoire GPU respectable.

Composant matériel Configuration minimale Configuration recommandée
GPU Carte NVIDIA, 16 Go de VRAM RTX 4090 (24 Go) ou supérieure
Mémoire vive (RAM) 16 Go 32 Go ou plus
Espace de stockage 20 Go d'espace libre 30 Go ou plus
Version CUDA 12.x 12.4 ou plus récent

Si vous disposez d'une RTX 4090, l'exécution sera particulièrement fluide. Pour d'autres cartes graphiques, tant que vous avez au moins 16 Go de VRAM, cela devrait fonctionner. Côté mémoire vive, 16 Go est le minimum ; si vous exécutez d'autres applications simultanément, 32 Go serait plus judicieux.

L'espace de stockage est principalement destiné aux fichiers du modèle, qui occupent environ 6 Go. En ajoutant le système et d'autres fichiers, prévoyez 20 Go pour être tranquille.

2.2 Démarrage et gestion du service

Le package est préconfiguré avec le service Supervisor pour la gestion. Le démarrage et l'arrêt sont extrêmement simples. Le service s'exécute par défaut sur le port 7860, fournissant simultanément l'interface web et le service API.

Après le démarrage, vérifiez l'état du service :


# Vérifier l'état d'exécution du service
supervisorctl status youtu-vl-4b-instruct-gguf

Si vous voyez l'état RUNNING, cela signifie que le service a démarré correctement. Si le service n'est pas en cours d'exécution, vous pouvez le démarrer manuellement :


# Démarrer le service
supervisorctl start youtu-vl-4b-instruct-gguf

# Redémarrer le service (nécessaire après modification de la configuration)
supervisorctl restart youtu-vl-4b-instruct-gguf

# Arrêter le service
supervisorctl stop youtu-vl-4b-instruct-gguf

2.3 Configuration du port (si nécessaire)

Par défaut, le service s'exécute sur le port 7860. Si ce port est déjà utilisé par une autre application ou si vous souhaitez en utiliser un autre, la modification est très simple.

Localisez le script de démarrage :


# Modifier le script de démarrage
nano /usr/local/bin/start-youtu-vl-4b-instruct-gguf-service.sh

Vous y trouverez un contenu similaire à ceci :


#!/bin/bash
source /opt/youtu-vl/venv/bin/activate

echo "Starting Youtu-VL-4B-Instruct-GGUF service..."

exec python /opt/youtu-vl/server.py \
  --host 0.0.0.0 \
  --port 7860  # Modifiez ce nombre ici

Remplacez --port 7860 par le numéro de port de votre choix, par exemple 8080, puis enregistrez le fichier. Après la modification, vous devrez redémarrer le service pour qu'elle prenne effet :


supervisorctl restart youtu-vl-4b-instruct-gguf

3. Prise en main rapide de l'interface Web

3.1 Accès et présentation de l'interface

Une fois le service démarré, ouvrez votre navigateur et accédez à http://[IP_de_votre_serveur]:7860. Si vous l'exécutez localement, utilisez simplement http://localhost:7860.

Au premier chargement, vous verrez une interface épurée, divisée en trois zones principales :

  • Zone de téléchargement d'images à gauche : Vous pouvez y glisser-déposer des images ou cliquer pour sélectionner des fichiers.
  • Zone d'affichage des conversations à droite : L'historique de vos échanges avec le modèle s'affichera ici.
  • Zone de saisie et de contrôle en bas : C'est ici que vous taperez vos questions, ajusterez les paramètres de génération et enverrez vos requêtes.

L'interface est conçue pour être intuitive ; même si vous n'avez jamais utilisé d'outil similaire, vous trouverez rapidement les fonctionnalités dont vous avez besoin.

3.2 Trois modes d'utilisation

Cette interface Web prend en charge trois modes d'utilisation principaux, adaptés à différents besoins.

Mode 1 : Conversation textuelle pureSi vous souhaitez simplement discuter avec l'IA sans traiter d'images, ce mode est le plus simple. Tapez directement votre question dans la zone de saisie en bas, par exemple :

  • "Écris un algorithme de tri à bulles en Python"
  • "Explique-moi ce qu'est un réseau neuronal"
  • "Aide-moi à rédiger un e-mail professionnel"

Cliquez sur le bouton d'envoi ou appuyez sur Entrée, et le modèle commencera à générer une réponse. Après quelques secondes, la réponse apparaîtra dans la zone de conversation à droite.

Mode 2 : Téléchargement d'images et questions-réponsesC'est la fonctionnalité clé du modèle multimodal. Vous pouvez télécharger une image et ensuite poser toutes les questions relatives à cette image.

Étapes :

  1. Cliquez sur le bouton "Télécharger" à gauche pour sélectionner une image locale.
  2. Une fois l'image téléchargée, un aperçu s'affichera dans la zone de gauche.
  3. Tapez votre question dans la zone de saisie en bas.
  4. Cliquez sur Envoyer.

Par exemple, si vous téléchargez une photo de rue, vous pouvez demander :

  • "Combien de voitures y a-t-il sur la photo ?"
  • "Quel est cet endroit ? Ressemble-t-il à une ville particulière ?"
  • "Décris le style architectural des bâtiments sur la photo."

Mode 3 : Description automatique d'imagesSi vous téléchargez une image sans poser de question textuelle, le modèle générera automatiquement une description détaillée de l'image.

Cette fonction est particulièrement utile pour comprendre rapidement le contenu principal d'une image. Si vous avez un graphique complexe ou une photo de scène, le modèle vous en décrira le contenu, y compris les objets, les scènes, les couleurs et la disposition.

3.3 Réglage des paramètres de génération

À côté de la zone de saisie, plusieurs paramètres vous permettent d'ajuster la qualité et le style des résultats générés :

  • Température (Temperature) : Contrôle le caractère aléatoire du texte généré. Une valeur plus élevée (proche de 1.0) produit des résultats plus créatifs et diversifiés ; une valeur plus basse (proche de 0) donne des résultats plus déterministes et conservateurs. Une valeur entre 0.3 et 0.7 est généralement appropriée.
  • Top-P : Une autre méthode pour contrôler le caractère aléatoire. Une valeur plus faible concentre la génération sur les mots les plus probables ; une valeur plus élevée augmente la diversité. Il est souvent utilisé en combinaison avec la température.
  • Longueur de génération maximale : Limite le nombre maximum de tokens que le modèle peut générer en une seule fois. Pour des questions complexes ou des réponses détaillées, augmentez cette valeur, par exemple à 1024 ou 2048.
  • Pénalité de répétition : Empêche le modèle de répéter le même contenu. Plus la valeur est élevée, plus la pénalité est forte. Généralement, une valeur entre 1.1 et 1.2 donne de bons résultats.

Lors de vos premières utilisations, je vous recommande de conserver les paramètres par défaut, puis de les ajuster selon vos besoins une fois que vous serez plus familier avec l'outil.

4. Détails du service API et exemples d'appels

4.1 Configuration de base de l'API

En plus de l'interface Web, ce package fournit une API complète compatible avec OpenAI. Cela vous permet d'appeler le modèle par programmation et de l'intégrer à vos propres applications.

L'adresse de base de l'API est http://[IP_de_votre_serveur]:7860/api/v1/ et elle prend en charge les requêtes au format standard OpenAI. Toutes les fonctionnalités liées aux conversations sont implémentées via le point d'accès /api/v1/chat/completions.

Note importante : Lors de chaque appel à l'API, vous devez inclure un message système (system message) dans la liste messages. Le contenu doit être fixe : "You are a helpful assistant.". Sans cela, le modèle pourrait produire des résultats anormaux. C'est une exigence spécifique à ce modèle, n'oubliez pas de l'ajouter à chaque appel. #### 4.2 Appel d'API pour la conversation textuelle pure

Si vous n'avez besoin que de la fonctionnalité de conversation textuelle, l'appel est simple. Voici un exemple complet en Python :


import requests
import json

# Adresse de l'API
url = "http://localhost:7860/api/v1/chat/completions"

# En-têtes de la requête
headers = {
    "Content-Type": "application/json"
}

# Données de la requête
data = {
    "model": "Youtu-VL-4B-Instruct-GGUF",  # Nom du modèle fixe
    "messages": [
        {
            "role": "system",
            "content": "You are a helpful assistant."  # Doit être inclus
        },
        {
            "role": "user",
            "content": "Écris une fonction en Python pour calculer le produit de deux matrices"
        }
    ],
    "max_tokens": 1024,  # Longueur maximale de génération
    "temperature": 0.7,   # Paramètre de température
    "top_p": 0.9          # Paramètre Top-P
}

# Envoi de la requête
response = requests.post(url, headers=headers, data=json.dumps(data))

# Analyse de la réponse
if response.status_code == 200:
    result = response.json()
    answer = result["choices"][0]["message"]["content"]
    print("Réponse du modèle :", answer)
else:
    print("Échec de la requête :", response.status_code, response.text)

Dans cet exemple, nous demandons au modèle d'écrire une fonction Python pour la multiplication de matrices. Les paramètres temperature et top_p contrôlent le style du texte généré ; vous pouvez les ajuster selon vos besoins.

4.3 Appel d'API pour la compréhension d'images et le dialogue visuel

La fonctionnalité de compréhension d'images nécessite de passer l'image encodée en base64. Comme les données encodées en base64 peuvent être volumineuses, il est conseillé d'utiliser un langage de programmation comme Python pour les appels.


import base64
import requests
import json

def encode_image_to_base64(image_path):
    """Encode une image en base64"""
    with open(image_path, "rb") as image_file:
        return base64.b64encode(image_file.read()).decode('utf-8')

def ask_about_image(image_path, question):
    """Pose une question sur une image"""
    # Préparation de l'adresse de l'API
    url = "http://localhost:7860/api/v1/chat/completions"
    
    # Encodage de l'image
    image_b64 = encode_image_to_base64(image_path)
    
    # Construction des données de la requête
    data = {
        "model": "Youtu-VL-4B-Instruct-GGUF",
        "messages": [
            {
                "role": "system",
                "content": "You are a helpful assistant."
            },
            {
                "role": "user",
                "content": [
                    {
                        "type": "image_url",
                        "image_url": {
                            "url": f"data:image/jpeg;base64,{image_b64}"
                        }
                    },
                    {
                        "type": "text",
                        "text": question
                    }
                ]
            }
        ],
        "max_tokens": 1024
    }
    
    # Envoi de la requête (le traitement d'image peut prendre du temps, définissez un délai d'attente long)
    try:
        response = requests.post(url, json=data, timeout=120)
        response.raise_for_status()  # Lève une exception en cas d'erreur HTTP
        result = response.json()
        return result["choices"][0]["message"]["content"]
    except requests.exceptions.RequestException as e:
        return f"Échec de la requête : {str(e)}"

# Exemple d'utilisation
image_path = "example.jpg"
question = "Veuillez décrire en détail le contenu de cette image, y compris la scène, les objets, les couleurs et la disposition."
answer = ask_about_image(image_path, question)
print("Description de l'image :", answer)

Cette fonction encapsule le processus complet de questionnement sur image. Vous pouvez fournir le chemin de l'image et la question, et la fonction renverra la réponse du modèle. Notez que le délai d'attente est défini à 120 secondes, car le traitement d'image peut prendre un certain temps.

4.4 API pour tâches visuelles avancées

Le modèle prend également en charge des tâches visuelles plus spécialisées, telles que la détection d'objets, la localisation d'objets, etc. Ces fonctions sont déclenchées par différents prompts, sans nécessiter de configuration de paramètres supplémentaires.

Exemple de détection d'objets : ```

def detect_objects(image_path): """Détecte tous les objets dans une image donnée""" image_b64 = encode_image_to_base64(image_path)

data = {
    "model": "Youtu-VL-4B-Instruct-GGUF",
    "messages": [
        {
            "role": "system",
            "content": "You are a helpful assistant."
        },
        {
            "role": "user",
            "content": [
                {
                    "type": "image_url",
                    "image_url": {
                        "url": f"data:image/jpeg;base64,{image_b64}"
                    }
                },
                {
                    "type": "text",
                    "text": "Detect all objects in the provided image."
                }
            ]
        }
    ],
    "max_tokens": 4096  # Les résultats de détection peuvent être longs
}

response = requests.post(
    "http://localhost:7860/api/v1/chat/completions",
    json=data,
    timeout=120
)

result = response.json()
detection_result = result["choices"][0]["message"]["content"]

# Analyser le résultat (format : <ref>catégorie</ref><box>coordonnées</box>)
return parse_detection_result(detection_result)

Le modèle retournera un format similaire à : `<ref>person</ref><box>0.1 0.2 0.3 0.4</box>`, indiquant qu'une personne a été détectée avec des coordonnées de boîte englobante de (0.1, 0.2, 0.3, 0.4).

**Exemple de localisation d'objets** : ```

def locate_object(image_path, object_description):
    """Localise un objet spécifique dans une image"""
    image_b64 = encode_image_to_base64(image_path)
    
    data = {
        "model": "Youtu-VL-4B-Instruct-GGUF",
        "messages": [
            {
                "role": "system",
                "content": "You are a helpful assistant."
            },
            {
                "role": "user",
                "content": [
                    {
                        "type": "image_url",
                        "image_url": {
                            "url": f"data:image/jpeg;base64,{image_b64}"
                        }
                    },
                    {
                        "type": "text",
                        "text": f"Please provide the bounding box coordinate of the region this sentence describes: {object_description}"
                    }
                ]
            }
        ],
        "max_tokens": 4096
    }
    
    response = requests.post(
        "http://localhost:7860/api/v1/chat/completions",
        json=data,
        timeout=120
    )
    
    result = response.json()
    location_result = result["choices"][0]["message"]["content"]
    
    # Analyser les coordonnées de la boîte englobante (format : <box>x_min y_min x_max y_max</box>)
    return parse_bounding_box(location_result)

Ceci retournera les coordonnées de la boîte englobante de l'objet spécifié, au format <box>0.15 0.25 0.35 0.45</box>, indiquant la position de l'objet.

4.5 Autres interfaces API

Outre le point d'accès principal pour les conversations, le service propose d'autres interfaces utiles :

Chemin de l'interface Méthode Description
/api/v1/models GET Obtient la liste des modèles ; renvoie des informations sur les modèles actuellement disponibles.
/health GET Vérification de l'état de santé ; renvoie l'état du service.
/docs GET Documentation de l'API (générée automatiquement avec FastAPI).
/ GET Interface Web Gradio.

Vous pouvez vérifier si le service fonctionne correctement en accédant à l'interface /health :


curl http://localhost:7860/health

Si le service fonctionne, il retournera {"status":"healthy"}.

5. Scénarios d'application réels et exemples de code

5.1 Description automatique de produits e-commerce

Si vous êtes un développeur de plateforme e-commerce, vous pouvez utiliser ce modèle pour générer automatiquement des descriptions de produits, économisant ainsi beaucoup de temps par rapport à la rédaction manuelle.


class ProductDescriptionGenerator:
    """Générateur automatique de descriptions de produits"""
    
    def __init__(self, api_url="http://localhost:7860/api/v1/chat/completions"):
        self.api_url = api_url
    
    def generate_description(self, image_path, product_info):
        """
        Génère une description de produit à partir d'une image et d'informations.
        
        Args:
            image_path: Chemin de l'image du produit.
            product_info: Dictionnaire d'informations produit (catégorie, marque, etc.).
        Returns:
            La description générée.
        """
        # Encodage de l'image
        image_b64 = self._encode_image(image_path)
        
        # Construction du prompt
        prompt = f"""Voici une image de {product_info.get('category', 'produit')}.
        Marque : {product_info.get('brand', 'Inconnue')}
        Veuillez générer une description détaillée du produit, incluant :
        1. Caractéristiques visuelles (couleur, forme, matériau, etc.)
        2. Points de conception et caractéristiques uniques
        3. Scénarios d'utilisation et suggestions
        4. Arguments de vente marketing pertinents
        
        La description doit être attrayante et adaptée à une plateforme e-commerce."""
        
        # Appel de l'API
        response = requests.post(
            self.api_url,
            json={
                "model": "Youtu-VL-4B-Instruct-GGUF",
                "messages": [
                    {"role": "system", "content": "You are a helpful assistant."},
                    {
                        "role": "user",
                        "content": [
                            {
                                "type": "image_url",
                                "image_url": {"url": f"data:image/jpeg;base64,{image_b64}"}
                            },
                            {"type": "text", "text": prompt}
                        ]
                    }
                ],
                "max_tokens": 512,
                "temperature": 0.7
            },
            timeout=60
        )
        
        if response.status_code == 200:
            return response.json()["choices"][0]["message"]["content"]
        else:
            raise Exception(f"Échec de l'appel API : {response.status_code}")
    
    def _encode_image(self, image_path):
        """Méthode interne : Encodage d'image"""
        with open(image_path, "rb") as f:
            return base64.b64encode(f.read()).decode()

# Exemple d'utilisation
generator = ProductDescriptionGenerator()

product_info = {
    "category": "Chaussures de sport",
    "brand": "Marque de sport X",
    "price_range": "Milieu à haut de gamme"
}

description = generator.generate_description("sneakers.jpg", product_info)
print("Description générée du produit :", description)

Cette classe encapsule la fonctionnalité de génération de descriptions de produits. Vous pouvez fournir l'image du produit et des informations de base, et elle générera automatiquement une description adaptée au e-commerce.

5.2 Modération de contenu et détection de sécurité

Pour les plateformes de contenu, la modération automatique des images téléchargées par les utilisateurs est une exigence importante. Ce modèle peut aider à identifier le contenu sensible dans les images.


class ContentModerator:
    """Modérateur de contenu"""
    
    def __init__(self, api_url="http://localhost:7860/api/v1/chat/completions"):
        self.api_url = api_url
        self.safety_categories = [
            "Contenu violent ou sanglant",
            "Contenu inapproprié ou sensible", 
            "Informations textuelles non conformes",
            "Problèmes potentiels de droits d'auteur"
        ]
    
    def check_image_safety(self, image_path):
        """
        Vérifie la sécurité d'une image.
        
        Args:
            image_path: Chemin de l'image.
        Returns:
            Dictionnaire des résultats de modération.
        """
        image_b64 = self._encode_image(image_path)
        
        # Construction du prompt d'audit
        categories_str = "\n".join([f"{i+1}. {cat}" for i, cat in enumerate(self.safety_categories)])
        prompt = f"""Veuillez analyser attentivement cette image et déterminer si elle contient l'un des contenus non sécurisés suivants :
{categories_str}

Si des problèmes sont identifiés, veuillez décrire précisément le problème et sa localisation dans l'image.
Si l'image est sécurisée, veuillez répondre "L'image est sécurisée".
Répondez en français."""
        
        try:
            response = requests.post(
                self.api_url,
                json={
                    "model": "Youtu-VL-4B-Instruct-GGUF",
                    "messages": [
                        {"role": "system", "content": "You are a helpful assistant."},
                        {
                            "role": "user",
                            "content": [
                                {
                                    "type": "image_url",
                                    "image_url": {"url": f"data:image/jpeg;base64,{image_b64}"}
                                },
                                {"type": "text", "text": prompt}
                            ]
                        }
                    ],
                    "max_tokens": 256,
                    "temperature": 0.3  # Température basse pour des résultats plus certains
                },
                timeout=90
            )
            
            if response.status_code == 200:
                result_text = response.json()["choices"][0]["message"]["content"]
                
                # Analyse des résultats de modération
                if "L'image est sécurisée" in result_text:
                    return {
                        "safe": True,
                        "details": "L'image est sécurisée",
                        "full_response": result_text
                    }
                else:
                    return {
                        "safe": False,
                        "details": result_text,
                        "full_response": result_text
                    }
            else:
                return {
                    "safe": False,
                    "details": f"Service de modération anormal : {response.status_code}",
                    "error": True
                }
                
        except Exception as e:
            return {
                "safe": False,
                "details": f"Erreur lors du processus de modération : {str(e)}",
                "error": True
            }
    
    def batch_check(self, image_paths):
        """Vérifie plusieurs images en lot."""
        results = {}
        for path in image_paths:
            results[path] = self.check_image_safety(path)
        return results

# Exemple d'utilisation
moderator = ContentModerator()
result = moderator.check_image_safety("user_upload.jpg")

if result["safe"]:
    print("L'image a passé la vérification.")
else:
    print("Problème avec l'image :", result["details"])
    
    # Vous pouvez traiter davantage, par exemple enregistrer des journaux, notifier les administrateurs, etc.
    if not result.get("error"):
        log_moderation_event("user_upload.jpg", result["details"])

Ce modérateur de contenu peut être intégré à votre plateforme pour vérifier automatiquement la sécurité des images téléchargées par les utilisateurs. Il renvoie des résultats de modération détaillés, vous permettant de décider si l'image doit être approuvée.

5.3 Extraction de texte d'images de documents

Le traitement de textes dans des documents numérisés ou des photos est une demande courante. Ce modèle peut vous aider à extraire le texte des images et à le organiser sous forme structurée.


class DocumentOCRProcessor:
    """Processeur OCR pour documents"""
    
    def __init__(self, api_url="http://localhost:7860/api/v1/chat/completions"):
        self.api_url = api_url
    
    def extract_text_from_document(self, image_path, document_type="general"):
        """
        Extrait du texte à partir d'une image de document.
        
        Args:
            image_path: Chemin de l'image du document.
            document_type: Type de document, influençant la stratégie d'extraction.
        Returns:
            Le contenu textuel extrait, organisé par paragraphe.
        """
        image_b64 = self._encode_image(image_path)
        
        # Ajustement du prompt en fonction du type de document
        if document_type == "receipt":
            prompt = """Ceci est l'image d'un reçu ou d'une facture. Veuillez extraire toutes les informations textuelles et les organiser selon le format suivant :
            1. Nom du commerçant
            2. Date et heure de la transaction
            3. Liste des articles (nom, quantité, prix unitaire, prix total)
            4. Montant total
            5. Autres informations
            
            Si les données sont sous forme de tableau, veuillez les organiser en un tableau Markdown."""
        elif document_type == "form":
            prompt = """Ceci est l'image d'un formulaire ou d'un tableau. Veuillez extraire tout le texte en conservant la structure originale du tableau.
            Sortie sous forme de tableau Markdown, en assurant l'alignement des lignes et des colonnes."""
        else:  # general
            prompt = """Veuillez identifier tout le texte présent dans l'image et l'organiser selon le format suivant :
            1. Titre (si présent, marqué par #)
            2. Contenu principal (organisé en paragraphes, en conservant la structure originale)
            3. Éléments de liste (marqués par -)
            4. Données tabulaires (si présentes, en format tableau Markdown)
            5. Légendes ou annotations d'image (si présentes)
            
            Veuillez conserver l'ordre et la structure originaux du texte."""
        
        try:
            response = requests.post(
                self.api_url,
                json={
                    "model": "Youtu-VL-4B-Instruct-GGUF",
                    "messages": [
                        {"role": "system", "content": "You are a helpful assistant."},
                        {
                            "role": "user",
                            "content": [
                                {
                                    "type": "image_url",
                                    "image_url": {"url": f"data:image/jpeg;base64,{image_b64}"}
                                },
                                {"type": "text", "text": prompt}
                            ]
                        }
                    ],
                    "max_tokens": 2048,  # Les documents peuvent être longs
                    "temperature": 0.1    # Basse température pour garantir la précision
                },
                timeout=120
            )
            
            if response.status_code == 200:
                extracted_text = response.json()["choices"][0]["message"]["content"]
                return self._post_process_text(extracted_text)
            else:
                raise Exception(f"Échec du traitement OCR : {response.status_code}")
                
        except requests.exceptions.Timeout:
            return "Délai d'attente dépassé, veuillez essayer de compresser l'image ou de réduire la quantité de texte."
        except Exception as e:
            return f"Erreur de traitement : {str(e)}"
    
    def _post_process_text(self, text):
        """Post-traitement du texte extrait"""
        # Vous pouvez ajouter ici des logiques de post-traitement, telles que :
        # 1. Suppression des lignes vides excessives
        # 2. Correction des erreurs OCR courantes
        # 3. Formatage de la sortie
        lines = text.split('\n')
        cleaned_lines = [line.strip() for line in lines if line.strip()]
        return '\n'.join(cleaned_lines)
    
    def _encode_image(self, image_path):
        """Méthode interne : Encodage d'image"""
        with open(image_path, "rb") as f:
            return base64.b64encode(f.read()).decode()

# Exemple d'utilisation
processor = DocumentOCRProcessor()

# Traitement d'un document général
document_text = processor.extract_text_from_document("document.jpg", "general")
print("Contenu du document extrait :")
print(document_text)

# Traitement d'un reçu
receipt_text = processor.extract_text_from_document("receipt.jpg", "receipt")
print("\nInformations du reçu extraites :")
print(receipt_text)

Ce processeur de documents peut utiliser différentes stratégies d'extraction en fonction du type de document (général, reçu, tableau), et retourne un contenu textuel structuré. Pour les reçus et les tableaux, il tente de les organiser dans un format plus lisible.

5.4 Amélioration des chatbots de service client

L'ajout de capacités de compréhension d'images aux robots de service client permet à ces derniers de mieux comprendre les requêtes des utilisateurs.


class VisionEnhancedChatbot:
    """Chatbot avec capacités visuelles"""
    
    def __init__(self, api_url="http://localhost:7860/api/v1/chat/completions"):
        self.api_url = api_url
        self.conversation_history = []
    
    def reset_conversation(self):
        """Réinitialise l'historique de conversation"""
        self.conversation_history = [
            {"role": "system", "content": "You are a helpful customer service assistant."}
        ]
    
    def chat(self, user_input, image_path=None):
        """
        Dialogue avec l'utilisateur, prend en charge texte et images.
        
        Args:
            user_input: Entrée textuelle de l'utilisateur.
            image_path: Optionnel, chemin de l'image téléchargée par l'utilisateur.
        Returns:
            La réponse du robot.
        """
        # Construction du message
        if image_path:
            # Si une image est présente, l'encoder
            image_b64 = self._encode_image(image_path)
            user_message_content = [
                {
                    "type": "image_url",
                    "image_url": {"url": f"data:image/jpeg;base64,{image_b64}"}
                },
                {"type": "text", "text": user_input}
            ]
        else:
            # Message purement textuel
            user_message_content = user_input
        
        # Ajout à l'historique
        self.conversation_history.append({
            "role": "user",
            "content": user_message_content
        })
        
        # Appel de l'API
        try:
            response = requests.post(
                self.api_url,
                json={
                    "model": "Youtu-VL-4B-Instruct-GGUF",
                    "messages": self.conversation_history,
                    "max_tokens": 512,
                    "temperature": 0.7
                },
                timeout=60
            )
            
            if response.status_code == 200:
                bot_reply = response.json()["choices"][0]["message"]["content"]
                
                # Ajout à l'historique
                self.conversation_history.append({
                    "role": "assistant",
                    "content": bot_reply
                })
                
                return bot_reply
            else:
                error_msg = f"Désolé, le service est temporairement indisponible (code d'erreur : {response.status_code})"
                self.conversation_history.append({
                    "role": "assistant",
                    "content": error_msg
                })
                return error_msg
                
        except requests.exceptions.Timeout:
            timeout_msg = "Délai d'attente dépassé, veuillez réessayer plus tard ou simplifier votre requête."
            self.conversation_history.append({
                "role": "assistant",
                "content": timeout_msg
            })
            return timeout_msg
    
    def _encode_image(self, image_path):
        """Méthode interne : Encodage d'image"""
        with open(image_path, "rb") as f:
            return base64.b64encode(f.read()).decode()

# Exemple d'utilisation
bot = VisionEnhancedChatbot()

# Conversation purement textuelle
response1 = bot.chat("Quelle est votre politique de retour ?")
print("Service Client :", response1)

# Conversation avec image (l'utilisateur télécharge une image de produit)
response2 = bot.chat("Cette rayure est-elle couverte par la garantie ?", "product_damage.jpg")
print("Service Client :", response2)

# Conversation continue (maintien du contexte)
response3 = bot.chat("Comment dois-je demander une réparation alors ?")
print("Service Client :", response3)

Ce chatbot peut gérer des conversations avec des images. Lorsqu'un utilisateur télécharge une image et pose une question, il peut fournir une réponse plus précise en tenant compte du contenu de l'image. L'historique de conversation est conservé, prenant en charge les dialogues multi-tours.

6. Optimisation des performances et bonnes pratiques

6.1 Suggestions d'optimisation pour le traitement d'images

Le temps de traitement des images dépend principalement de leur taille. Voici quelques données de test et suggestions :

Taille de l'image Temps de traitement estimé Recommandation
Moins de 500 Ko 5-15 secondes Réponse rapide, adaptée à l'interaction en temps réel.
500 Ko - 1 Mo 15-30 secondes Acceptable, expérience utilisateur décente.
1 Mo - 3 Mo 30-60 secondes Nécessite un peu de patience.
3 Mo - 5 Mo 1-2 minutes Il est recommandé de compresser l'image au préalable.
Plus de 5 Mo Peut dépasser 2 minutes Non recommandé, temps de traitement trop long.

Pour une meilleure expérience, voici quelques conseils :

  1. Compresser l'image avant le téléchargement : Utilisez des outils pour réduire la taille de l'image à moins de 1 Mo, ce qui diminuera considérablement le temps de traitement.
  2. Ajuster la résolution : Si des détails haute résolution ne sont pas essentiels, réduisez la résolution (par exemple, de 1920x1080 à 1280x720).
  3. Async pour le traitement par lots : Si vous devez traiter plusieurs images, utilisez des tâches asynchrones au lieu d'attendre une par une.
  4. Définir des délais d'attente raisonnables : Lors des appels API, définissez des délais d'attente appropriés en fonction de la taille de l'image.

6.2 Techniques de rédaction de prompts

De bons prompts permettent au modèle de donner de meilleurs résultats. Voici quelques astuces pratiques :

Pour les tâches de description d'images :- Ne vous contentez pas de dire "Décris cette image", soyez plus précis : "Décris en détail la scène, les personnes, les objets, les couleurs et la disposition de l'image."

  • Si vous avez besoin d'informations spécifiques, demandez directement : "Combien de personnes y a-t-il sur la photo ? Que font-elles ? Quelles couleurs portent-elles ?"
  • Vous pouvez spécifier le format : "Décris le contenu principal de cette image en trois points."

Pour les tâches OCR :- Spécifiez la langue : "Identifie le texte chinois dans l'image" ou "Extrais le texte anglais de l'image."

  • Si un format est nécessaire : "Organise le texte extrait par paragraphe, en conservant les sauts de ligne d'origine."
  • Pour les tableaux : "Identifie le tableau dans l'image et affiche-le au format tableau Markdown."

Pour les tâches de questions-réponses :- Soyez précis dans vos questions : "Quelle est la marque de la voiture rouge sur la photo ?" est mieux que "Qu'est-ce que c'est ?"

  • Demandez du raisonnement : "En te basant sur le contenu de l'image, quelle saison penses-tu qu'il s'agit ? Pourquoi ?"
  • Utilisez le contexte : "Comparée à l'image précédente, qu'est-ce qui est différent sur cette image ?"

Astuces générales :- Définissez le rôle dans le message système : "Tu es un analyste d'images professionnel" ou "Tu es un assistant de traitement de documents méticuleux."

  • Spécifiez le format de sortie : "Réponds en format JSON" ou "Liste les éléments sous forme de liste."
  • Contrôlez la longueur de génération : "Décris en environ 100 mots" ou "Réponds brièvement, pas plus de 50 mots."

6.3 Gestion des erreurs et débogage

Vous pouriez rencontrer quelques problèmes lors de l'utilisation. Voici quelques scénarios courants et leurs solutions :

Problème 1 : Le service ne démarre pas ou la page ne s'affiche pas- Vérifiez l'état du service : supervisorctl status youtu-vl-4b-instruct-gguf

  • Vérifiez si le port est utilisé : netstat -tlnp | grep 7860
  • Vérifiez les paramètres du pare-feu : assurez-vous que le port 7860 est ouvert.
  • Consultez les journaux : tail -f /var/log/supervisor/youtu-vl-4b-instruct-gguf*.log

Problème 2 : Longue attente après l'envoi d'une requête- L'image est peut-être trop grande et le traitement prend du temps.

  • Vérifiez si la mémoire GPU est suffisante : utilisez nvidia-smi pour voir l'utilisation de la VRAM.
  • Essayez de compresser l'image ou de réduire sa résolution.
  • Vérifiez la connexion réseau et la charge du serveur.

Problème 3 : Contenu de réponse anormal ou non pertinent- Vérifiez si le message système est inclus (doit contenir "You are a helpful assistant.").

  • Essayez d'ajuster le paramètre temperature (entre 0.3 et 0.7 pour plus de stabilité).
  • Videz l'historique de conversation et recommencez.
  • Vérifiez si le prompt est clair et précis.

Problème 4 : L'API renvoie une erreur- Vérifiez si le format de la requête est correct, en particulier l'encodage base64 de l'image.

  • Vérifiez les en-têtes : Content-Type: application/json.
  • Vérifiez le nom du modèle : doit être "Youtu-VL-4B-Instruct-GGUF".
  • Examinez le message d'erreur spécifique renvoyé par l'API.

Problème 5 : Échec du téléchargement de l'image- Vérifiez le format de l'image (formats courants comme JPG, PNG, WEBP sont supportés).

  • Vérifiez la taille de l'image (recommandé < 5 Mo).
  • Essayez un autre navigateur.
  • Vérifiez l'espace disque disponible sur le serveur.

6.4 Suggestions de surveillance et de maintenance

Si vous prévoyez d'utiliser ce service en production, il est conseillé de mettre en place des mesures de surveillance et de maintenance :

  1. Vérification de l'état du service : Accédez régulièrement à l'interface /health pour vous assurer que le service fonctionne correctement.
  2. Surveillance des ressources : Surveillez l'utilisation de la VRAM GPU, de la mémoire vive et du CPU.
  3. Collecte des journaux : Rassemblez les journaux du service pour faciliter le dépannage.
  4. Redémarrage automatique : Configurez Supervisor ou systemd pour redémarrer automatiquement le service en cas d'anomalie.
  5. Sauvegarde de la configuration : Sauvegardez régulièrement la configuraton du service et les fichiers du modèle.

7. Conclusion

Après une période d'utilisation et de tests, je trouve que Youtu-VL-4B-Instruct est un modèle multimodal véritablement pratique. Son principal avantage réside dans son équilibre : 4 milliards de paramètres permettent une exécution fluide sur la plupart des cartes graphiques grand public, tandis que l'architecture VLUAS garantit de bonnes capacités de compréhension visuelle.

Ce qui me plaît le plus dans cette solution, c'est sa conception "tout-en-un". Un seul service, deux interfaces (Web et API), un seul port, ce qui simplifie considérablement le déploiement et l'utilisation. C'est très pratique, que ce soit pour tester rapidement les capacités du modèle ou pour l'intégrer à des systèmes existants.

En termes de performances réelles, il se distingue dans plusieurs domaines :

  1. Description d'images : Il identifie assez précisément les scènes, objets, couleurs, etc., et fournit des descriptions relativement détaillées.
  2. Questions-réponses visuelles : Les réponses aux questions spécifiques sur une image sont généralement pertinentes.
  3. Reconnaissance de texte : Il offre une bonne capacité de reconnaissance de texte mixte (chinois/anglais), en particulier pour le texte imprimé.
  4. Détection d'objets : Il peut détecter des objets courants et fournir des informations de localisation.

Bien sûr, il présente aussi des limitations. Par exemple, la vitesse de traitement peut être lente pour les images volumineuses, sa compréhension peut être insuffisante pour des domaines très spécialisés, et il ne prend pas en charge les tâches de prédiction dense (comme la segmentation sémantique). Cependant, pour la plupart des cas d'utilisation, ces limitations ont un impact limité.

Mon conseil : si vous avez besoin de capacités multimodales mais que vous ne souhaitez pas investir massivement dans l'entraînement ou le déploiement de modèles très volumineux, cette solution mérite d'être essayée. Elle est particulièrement adaptée aux projets de petite et moyenne taille, au développement de prototypes ou à des fins éducatives, offrant un excellent point de départ.

Lors de l'utilisation pratique, commencez par l'interface Web pour vous familiariser avec les capacités et les caractéristiques du modèle. Ensuite, une fois que vous avez une bonne compréhension, intégrez-le à vos applications via l'API. N'oubliez pas d'optimiser la taille des images et de concevoir des prompts judicieux pour obtenir de meilleurs résultats.

Étiquettes: IA multimodale Youtu-VL-4B Gradio API OpenAI déploiement AI

Publié le 23 juin à 22h05