Final_Assignment_Template / tools /describe_image_tool.py
Hobysenny's picture
Upload 9 files
e8579ca verified
Raw
History Blame Contribute Delete
4.95 kB
import base64
import os
from smolagents import Tool, ChatMessage, OpenAIServerModel
from dotenv import load_dotenv
from typing import List
GEMMA_API_KEY = os.getenv('GEMMA_API_KEY')
class DescribeImageTool(Tool):
"""
Tool to analyze and describe any image using Gemma 4 Vision API.
Args:
image_path (str): Path to the image file.
description_type (str): Type of description to generate. Options:
- "general": General description of the image
- "detailed": Detailed analysis of the image
- "chess": Analysis of a chess position
- "text": Extract and describe text from the image
- "custom": Custom description based on user prompt
Returns:
str: Description of the image based on the requested type.
"""
name = "describe_image"
description = "Analyzes and describes images using Gemma 4 multimodal capabilities."
inputs = {
"image_path": {"type": "string", "description": "Path to the image file"},
"description_type": {
"type": "string",
"description": "Type of description to generate (general, detailed, chess, text, custom)",
"nullable": True,
},
"custom_prompt": {
"type": "string",
"description": "Custom prompt for description (only used when description_type is 'custom')",
"nullable": True,
},
}
output_type = "string"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Configuration de l'accès à Gemma 4 (ex: via ton endpoint Ollama)
# Ajuste le model_id et l'api_key selon ton fichier config/variables d'environnement
self.model = OpenAIServerModel(
model_id='gemma4:31b-cloud',
api_base='https://ollama.com/v1',
api_key= GEMMA_API_KEY,
temperature=0.0,
max_tokens=2048,
timeout=180,
)
def encode_image(self, image_path: str) -> str:
"""Encode image to base64 string."""
with open(image_path, "rb") as image_file:
return base64.b64encode(image_file.read()).decode("utf-8")
def get_prompt(self, description_type: str, custom_prompt: str = None) -> str:
"""Get appropriate prompt based on description type."""
prompts = {
"general": "Provide a general description of this image. Focus on the main subjects, colors, and overall scene.",
"detailed": """Analyze this image in detail. Include:
1. Main subjects and their relationships
2. Colors, lighting, and composition
3. Any text or symbols present
4. Context or possible meaning
5. Notable details or interesting elements""",
"chess": """Analyze this chess position and provide a detailed description including:
1. List of pieces on the board for both white and black
2. Whose turn it is to move
3. Basic evaluation of the position
4. Any immediate tactical opportunities or threats
5. Suggested next moves with brief explanations""",
"text": "Extract and describe any text present in this image. If there are multiple pieces of text, organize them clearly.",
}
# Fallback de sécurité si description_type est None ou invalide
if not description_type:
description_type = "general"
return (
custom_prompt
if description_type == "custom"
else prompts.get(description_type, prompts["general"])
)
def forward(
self,
image_path: str,
description_type: str = "general",
custom_prompt: str = None,
) -> str:
try:
if not os.path.exists(image_path):
return f"Error: Image file not found at {image_path}"
# 1. Encodage Base64
base64_image = self.encode_image(image_path)
# 2. Récupération du prompt de consigne
prompt = self.get_prompt(description_type, custom_prompt)
# 3. Préparation du payload compatible avec Gemma 4
payload = [
{"type": "text", "text": prompt},
{
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{base64_image}"
},
}
]
# 4. Appel avec ChatMessage (propre à smolagents)
messages = [
ChatMessage(role="user", content=payload)
]
response = self.model(messages)
return response.content
except Exception as e:
return f"Error analyzing image: {str(e)}"