semantio 0.0.1__py3-none-any.whl → 0.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- semantio/agent.py +119 -50
 - semantio/llm/__init__.py +12 -5
 - semantio/llm/anthropic.py +41 -28
 - semantio/llm/base_llm.py +10 -1
 - semantio/llm/deepseek.py +27 -0
 - semantio/llm/gemini.py +50 -0
 - semantio/llm/groq.py +90 -8
 - semantio/llm/mistral.py +27 -0
 - semantio/llm/openai.py +125 -15
 - {semantio-0.0.1.dist-info → semantio-0.0.2.dist-info}/METADATA +7 -6
 - {semantio-0.0.1.dist-info → semantio-0.0.2.dist-info}/RECORD +15 -12
 - {semantio-0.0.1.dist-info → semantio-0.0.2.dist-info}/LICENSE +0 -0
 - {semantio-0.0.1.dist-info → semantio-0.0.2.dist-info}/WHEEL +0 -0
 - {semantio-0.0.1.dist-info → semantio-0.0.2.dist-info}/entry_points.txt +0 -0
 - {semantio-0.0.1.dist-info → semantio-0.0.2.dist-info}/top_level.txt +0 -0
 
    
        semantio/agent.py
    CHANGED
    
    | 
         @@ -20,31 +20,35 @@ import os 
     | 
|
| 
       20 
20 
     | 
    
         
             
            # Configure logging
         
     | 
| 
       21 
21 
     | 
    
         
             
            logging.basicConfig(level=logging.INFO)
         
     | 
| 
       22 
22 
     | 
    
         
             
            logger = logging.getLogger(__name__)
         
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            class Assistant(BaseModel):
         
     | 
| 
       24 
25 
     | 
    
         
             
                # -*- Agent settings
         
     | 
| 
       25 
     | 
    
         
            -
                name: Optional[str] = Field(None, description="Name of the  
     | 
| 
       26 
     | 
    
         
            -
                description: Optional[str] = Field(None, description="Description of the  
     | 
| 
       27 
     | 
    
         
            -
                instructions: Optional[List[str]] = Field(None, description="List of instructions for the  
     | 
| 
      
 26 
     | 
    
         
            +
                name: Optional[str] = Field(None, description="Name of the assistant.")
         
     | 
| 
      
 27 
     | 
    
         
            +
                description: Optional[str] = Field(None, description="Description of the assistant's role.")
         
     | 
| 
      
 28 
     | 
    
         
            +
                instructions: Optional[List[str]] = Field(None, description="List of instructions for the assistant.")
         
     | 
| 
       28 
29 
     | 
    
         
             
                model: Optional[str] = Field(None, description="This one is not in the use.")
         
     | 
| 
       29 
30 
     | 
    
         
             
                show_tool_calls: bool = Field(False, description="Whether to show tool calls in the response.")
         
     | 
| 
       30 
31 
     | 
    
         
             
                markdown: bool = Field(False, description="Whether to format the response in markdown.")
         
     | 
| 
       31 
     | 
    
         
            -
                tools: Optional[List[BaseTool]] = Field(None, description="List of tools available to the  
     | 
| 
       32 
     | 
    
         
            -
                user_name: Optional[str] = Field("User", description="Name of the user interacting with the  
     | 
| 
       33 
     | 
    
         
            -
                emoji: Optional[str] = Field(":robot:", description="Emoji to represent the  
     | 
| 
      
 32 
     | 
    
         
            +
                tools: Optional[List[BaseTool]] = Field(None, description="List of tools available to the assistant.")
         
     | 
| 
      
 33 
     | 
    
         
            +
                user_name: Optional[str] = Field("User", description="Name of the user interacting with the assistant.")
         
     | 
| 
      
 34 
     | 
    
         
            +
                emoji: Optional[str] = Field(":robot:", description="Emoji to represent the assistant in the CLI.")
         
     | 
| 
       34 
35 
     | 
    
         
             
                rag: Optional[RAG] = Field(None, description="RAG instance for context retrieval.")
         
     | 
| 
       35 
36 
     | 
    
         
             
                knowledge_base: Optional[Any] = Field(None, description="Knowledge base for domain-specific information.")
         
     | 
| 
       36 
37 
     | 
    
         
             
                llm: Optional[str] = Field(None, description="The LLM provider to use (e.g., 'groq', 'openai', 'anthropic').")
         
     | 
| 
       37 
38 
     | 
    
         
             
                llm_model: Optional[str] = Field(None, description="The specific model to use for the LLM provider.")
         
     | 
| 
       38 
39 
     | 
    
         
             
                llm_instance: Optional[BaseLLM] = Field(None, description="The LLM instance to use.")
         
     | 
| 
       39 
40 
     | 
    
         
             
                json_output: bool = Field(False, description="Whether to format the response as JSON.")
         
     | 
| 
       40 
     | 
    
         
            -
                api: bool = Field(False, description="Whether to generate an API for the  
     | 
| 
      
 41 
     | 
    
         
            +
                api: bool = Field(False, description="Whether to generate an API for the assistant.")
         
     | 
| 
       41 
42 
     | 
    
         
             
                api_config: Optional[Dict] = Field(
         
     | 
| 
       42 
43 
     | 
    
         
             
                    None,
         
     | 
| 
       43 
44 
     | 
    
         
             
                    description="Configuration for the API (e.g., host, port, authentication).",
         
     | 
| 
       44 
45 
     | 
    
         
             
                )
         
     | 
| 
       45 
46 
     | 
    
         
             
                api_generator: Optional[Any] = Field(None, description="The API generator instance.")
         
     | 
| 
       46 
47 
     | 
    
         
             
                expected_output: Optional[Union[str, Dict]] = Field(None, description="The expected format or structure of the output.")
         
     | 
| 
       47 
     | 
    
         
            -
                semantic_model: Optional[Any] = Field(None, description="SentenceTransformer model for semantic matching.") 
     | 
| 
      
 48 
     | 
    
         
            +
                semantic_model: Optional[Any] = Field(None, description="SentenceTransformer model for semantic matching.")
         
     | 
| 
      
 49 
     | 
    
         
            +
                team: Optional[List['Assistant']] = Field(None, description="List of assistants in the team.")
         
     | 
| 
      
 50 
     | 
    
         
            +
                auto_tool: bool = Field(False, description="Whether to automatically detect and call tools.")
         
     | 
| 
      
 51 
     | 
    
         
            +
                
         
     | 
| 
       48 
52 
     | 
    
         
             
                # Allow arbitrary types
         
     | 
| 
       49 
53 
     | 
    
         
             
                model_config = ConfigDict(arbitrary_types_allowed=True)
         
     | 
| 
       50 
54 
     | 
    
         | 
| 
         @@ -52,8 +56,9 @@ class Agent(BaseModel): 
     | 
|
| 
       52 
56 
     | 
    
         
             
                    super().__init__(**kwargs)
         
     | 
| 
       53 
57 
     | 
    
         
             
                    # Initialize the model and tools here if needed
         
     | 
| 
       54 
58 
     | 
    
         
             
                    self._initialize_model()
         
     | 
| 
       55 
     | 
    
         
            -
                    # Automatically discover and register tools
         
     | 
| 
       56 
     | 
    
         
            -
                    self.tools  
     | 
| 
      
 59 
     | 
    
         
            +
                    # Automatically discover and register tools if not provided
         
     | 
| 
      
 60 
     | 
    
         
            +
                    if self.tools is None:
         
     | 
| 
      
 61 
     | 
    
         
            +
                        self.tools = self._discover_tools()
         
     | 
| 
       57 
62 
     | 
    
         
             
                    # Pass the LLM instance to each tool
         
     | 
| 
       58 
63 
     | 
    
         
             
                    for tool in self.tools:
         
     | 
| 
       59 
64 
     | 
    
         
             
                        tool.llm = self.llm_instance
         
     | 
| 
         @@ -66,6 +71,41 @@ class Agent(BaseModel): 
     | 
|
| 
       66 
71 
     | 
    
         
             
                    if self.api:
         
     | 
| 
       67 
72 
     | 
    
         
             
                        self._generate_api()
         
     | 
| 
       68 
73 
     | 
    
         | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                def _generate_response_from_image(self,message: str, image: Union[str, Image], markdown: bool = False, **kwargs) -> str:
         
     | 
| 
      
 76 
     | 
    
         
            +
                    """
         
     | 
| 
      
 77 
     | 
    
         
            +
                    Send the image to the LLM for analysis if the LLM supports vision.
         
     | 
| 
      
 78 
     | 
    
         
            +
                    Supports both local images (PIL.Image) and image URLs.
         
     | 
| 
      
 79 
     | 
    
         
            +
                    """
         
     | 
| 
      
 80 
     | 
    
         
            +
                    try:
         
     | 
| 
      
 81 
     | 
    
         
            +
                        # Check if the LLM supports vision
         
     | 
| 
      
 82 
     | 
    
         
            +
                        if not self.llm_instance or not self.llm_instance.supports_vision:
         
     | 
| 
      
 83 
     | 
    
         
            +
                            raise ValueError("Vision is not supported for the current model.")
         
     | 
| 
      
 84 
     | 
    
         
            +
                        prompt = self._build_prompt(message, context=None)
         
     | 
| 
      
 85 
     | 
    
         
            +
                        # Handle image URL
         
     | 
| 
      
 86 
     | 
    
         
            +
                        if isinstance(image, str) and image.startswith("http"):
         
     | 
| 
      
 87 
     | 
    
         
            +
                            # Directly pass the URL to the LLM
         
     | 
| 
      
 88 
     | 
    
         
            +
                            return self.llm_instance.generate_from_image_url(prompt,image, **kwargs)
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                        # Handle local image (PIL.Image)
         
     | 
| 
      
 91 
     | 
    
         
            +
                        elif isinstance(image, Image):
         
     | 
| 
      
 92 
     | 
    
         
            +
                            # Convert the image to bytes
         
     | 
| 
      
 93 
     | 
    
         
            +
                            if image.mode == "RGBA":
         
     | 
| 
      
 94 
     | 
    
         
            +
                                image = image.convert("RGB")  # Convert RGBA to RGB
         
     | 
| 
      
 95 
     | 
    
         
            +
                            image_bytes = io.BytesIO()
         
     | 
| 
      
 96 
     | 
    
         
            +
                            image.save(image_bytes, format="JPEG")  # Save as PNG (or any supported format)
         
     | 
| 
      
 97 
     | 
    
         
            +
                            image_bytes = image_bytes.getvalue()
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                            # Generate response using base64-encoded image bytes
         
     | 
| 
      
 100 
     | 
    
         
            +
                            return self.llm_instance.generate_from_image(prompt,image_bytes, **kwargs)
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 103 
     | 
    
         
            +
                            raise ValueError("Unsupported image type. Provide either a URL or a PIL.Image.")
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                    except Exception as e:
         
     | 
| 
      
 106 
     | 
    
         
            +
                        logger.error(f"Failed to generate response from image: {e}")
         
     | 
| 
      
 107 
     | 
    
         
            +
                        return f"An error occurred while processing the image: {e}"
         
     | 
| 
      
 108 
     | 
    
         
            +
                    
         
     | 
| 
       69 
109 
     | 
    
         
             
                def _discover_tools(self) -> List[BaseTool]:
         
     | 
| 
       70 
110 
     | 
    
         
             
                    """
         
     | 
| 
       71 
111 
     | 
    
         
             
                    Automatically discover and register tools from the 'tools' directory.
         
     | 
| 
         @@ -122,12 +162,24 @@ class Agent(BaseModel): 
     | 
|
| 
       122 
162 
     | 
    
         
             
                        },
         
     | 
| 
       123 
163 
     | 
    
         
             
                        "openai": {
         
     | 
| 
       124 
164 
     | 
    
         
             
                            "class": "OpenAILlm",
         
     | 
| 
       125 
     | 
    
         
            -
                            "default_model": "gpt- 
     | 
| 
      
 165 
     | 
    
         
            +
                            "default_model": "gpt-4o",
         
     | 
| 
       126 
166 
     | 
    
         
             
                        },
         
     | 
| 
       127 
167 
     | 
    
         
             
                        "anthropic": {
         
     | 
| 
       128 
168 
     | 
    
         
             
                            "class": "AnthropicLlm",
         
     | 
| 
       129 
169 
     | 
    
         
             
                            "default_model": "claude-2.1",
         
     | 
| 
       130 
170 
     | 
    
         
             
                        },
         
     | 
| 
      
 171 
     | 
    
         
            +
                        "deepseek": {
         
     | 
| 
      
 172 
     | 
    
         
            +
                            "class": "DeepSeekLLM",
         
     | 
| 
      
 173 
     | 
    
         
            +
                            "default_model": "deepseek-chat",
         
     | 
| 
      
 174 
     | 
    
         
            +
                        },
         
     | 
| 
      
 175 
     | 
    
         
            +
                        "gemini": {
         
     | 
| 
      
 176 
     | 
    
         
            +
                            "class": "GeminiLLM",
         
     | 
| 
      
 177 
     | 
    
         
            +
                            "default_model": "gemini-1.5-flash",
         
     | 
| 
      
 178 
     | 
    
         
            +
                        },
         
     | 
| 
      
 179 
     | 
    
         
            +
                        "mistral": {
         
     | 
| 
      
 180 
     | 
    
         
            +
                            "class": "MistralLLM",
         
     | 
| 
      
 181 
     | 
    
         
            +
                            "default_model": "mistral-large-latest",
         
     | 
| 
      
 182 
     | 
    
         
            +
                        },
         
     | 
| 
       131 
183 
     | 
    
         
             
                    }
         
     | 
| 
       132 
184 
     | 
    
         | 
| 
       133 
185 
     | 
    
         
             
                    # Normalize the LLM provider name (case-insensitive)
         
     | 
| 
         @@ -156,23 +208,16 @@ class Agent(BaseModel): 
     | 
|
| 
       156 
208 
     | 
    
         
             
                    retriever = Retriever(vector_store)
         
     | 
| 
       157 
209 
     | 
    
         
             
                    return RAG(retriever)
         
     | 
| 
       158 
210 
     | 
    
         | 
| 
       159 
     | 
    
         
            -
                def load_image_from_url(self, image_url: str) -> Image:
         
     | 
| 
       160 
     | 
    
         
            -
                    """Load an image from a URL and return it as a PIL Image."""
         
     | 
| 
       161 
     | 
    
         
            -
                    response = requests.get(image_url)
         
     | 
| 
       162 
     | 
    
         
            -
                    image_bytes = response.content
         
     | 
| 
       163 
     | 
    
         
            -
                    return Image.open(io.BytesIO(image_bytes))
         
     | 
| 
       164 
     | 
    
         
            -
             
     | 
| 
       165 
211 
     | 
    
         
             
                def print_response(
         
     | 
| 
       166 
212 
     | 
    
         
             
                    self,
         
     | 
| 
       167 
213 
     | 
    
         
             
                    message: Optional[Union[str, Image, List, Dict]] = None,
         
     | 
| 
       168 
214 
     | 
    
         
             
                    stream: bool = False,
         
     | 
| 
       169 
215 
     | 
    
         
             
                    markdown: bool = False,
         
     | 
| 
      
 216 
     | 
    
         
            +
                    tools: Optional[List[BaseTool]] = None,
         
     | 
| 
      
 217 
     | 
    
         
            +
                    team: Optional[List['Assistant']] = None,
         
     | 
| 
       170 
218 
     | 
    
         
             
                    **kwargs,
         
     | 
| 
       171 
219 
     | 
    
         
             
                ) -> Union[str, Dict]:  # Add return type hint
         
     | 
| 
       172 
     | 
    
         
            -
                    """Print the  
     | 
| 
       173 
     | 
    
         
            -
                    if isinstance(message, Image):
         
     | 
| 
       174 
     | 
    
         
            -
                        # Handle image input
         
     | 
| 
       175 
     | 
    
         
            -
                        message = self._process_image(message)
         
     | 
| 
      
 220 
     | 
    
         
            +
                    """Print the assistant's response to the console and return it."""
         
     | 
| 
       176 
221 
     | 
    
         | 
| 
       177 
222 
     | 
    
         
             
                    if stream:
         
     | 
| 
       178 
223 
     | 
    
         
             
                        # Handle streaming response
         
     | 
| 
         @@ -182,26 +227,21 @@ class Agent(BaseModel): 
     | 
|
| 
       182 
227 
     | 
    
         
             
                            response += chunk
         
     | 
| 
       183 
228 
     | 
    
         
             
                        return response
         
     | 
| 
       184 
229 
     | 
    
         
             
                    else:
         
     | 
| 
       185 
     | 
    
         
            -
             
     | 
| 
       186 
     | 
    
         
            -
                        response = self._generate_response(message, markdown=markdown, **kwargs)
         
     | 
| 
      
 230 
     | 
    
         
            +
                        # Generate and return the response
         
     | 
| 
      
 231 
     | 
    
         
            +
                        response = self._generate_response(message, markdown=markdown, tools=tools, team=team, **kwargs)
         
     | 
| 
       187 
232 
     | 
    
         
             
                        print(response)  # Print the response to the console
         
     | 
| 
       188 
233 
     | 
    
         
             
                        return response
         
     | 
| 
       189 
234 
     | 
    
         | 
| 
       190 
     | 
    
         
            -
                def _process_image(self, image: Image) -> str:
         
     | 
| 
       191 
     | 
    
         
            -
                    """Process the image and return a string representation."""
         
     | 
| 
       192 
     | 
    
         
            -
                    # Convert the image to text or extract relevant information
         
     | 
| 
       193 
     | 
    
         
            -
                    # For now, we'll just return a placeholder string
         
     | 
| 
       194 
     | 
    
         
            -
                    return "Image processed. Extracted text: [Placeholder]"
         
     | 
| 
       195 
235 
     | 
    
         | 
| 
       196 
236 
     | 
    
         
             
                def _stream_response(self, message: str, markdown: bool = False, **kwargs) -> Iterator[str]:
         
     | 
| 
       197 
     | 
    
         
            -
                    """Stream the  
     | 
| 
      
 237 
     | 
    
         
            +
                    """Stream the assistant's response."""
         
     | 
| 
       198 
238 
     | 
    
         
             
                    # Simulate streaming by yielding chunks of the response
         
     | 
| 
       199 
239 
     | 
    
         
             
                    response = self._generate_response(message, markdown=markdown, **kwargs)
         
     | 
| 
       200 
240 
     | 
    
         
             
                    for chunk in response.split():
         
     | 
| 
       201 
241 
     | 
    
         
             
                        yield chunk + " "
         
     | 
| 
       202 
242 
     | 
    
         | 
| 
       203 
243 
     | 
    
         
             
                def register_tool(self, tool: BaseTool):
         
     | 
| 
       204 
     | 
    
         
            -
                    """Register a tool for the  
     | 
| 
      
 244 
     | 
    
         
            +
                    """Register a tool for the assistant."""
         
     | 
| 
       205 
245 
     | 
    
         
             
                    if self.tools is None:
         
     | 
| 
       206 
246 
     | 
    
         
             
                        self.tools = []
         
     | 
| 
       207 
247 
     | 
    
         
             
                    self.tools.append(tool)
         
     | 
| 
         @@ -216,7 +256,7 @@ class Agent(BaseModel): 
     | 
|
| 
       216 
256 
     | 
    
         | 
| 
       217 
257 
     | 
    
         
             
                    # Create a prompt for the LLM
         
     | 
| 
       218 
258 
     | 
    
         
             
                    prompt = f"""
         
     | 
| 
       219 
     | 
    
         
            -
                    You are an AI  
     | 
| 
      
 259 
     | 
    
         
            +
                    You are an AI assistant that helps users by selecting the most appropriate tool to answer their query. Below is a list of available tools and their functionalities:
         
     | 
| 
       220 
260 
     | 
    
         | 
| 
       221 
261 
     | 
    
         
             
                    {self._get_tool_descriptions()}
         
     | 
| 
       222 
262 
     | 
    
         | 
| 
         @@ -250,7 +290,7 @@ class Agent(BaseModel): 
     | 
|
| 
       250 
290 
     | 
    
         
             
                    """
         
     | 
| 
       251 
291 
     | 
    
         
             
                    # Create a prompt for the LLM to analyze the query and select tools
         
     | 
| 
       252 
292 
     | 
    
         
             
                    prompt = f"""
         
     | 
| 
       253 
     | 
    
         
            -
                    You are an AI  
     | 
| 
      
 293 
     | 
    
         
            +
                    You are an AI assistant that helps analyze user queries and select the most appropriate tools.
         
     | 
| 
       254 
294 
     | 
    
         
             
                    Below is a list of available tools and their functionalities:
         
     | 
| 
       255 
295 
     | 
    
         | 
| 
       256 
296 
     | 
    
         
             
                    {self._get_tool_descriptions()}
         
     | 
| 
         @@ -284,20 +324,43 @@ class Agent(BaseModel): 
     | 
|
| 
       284 
324 
     | 
    
         
             
                        return []
         
     | 
| 
       285 
325 
     | 
    
         | 
| 
       286 
326 
     | 
    
         | 
| 
       287 
     | 
    
         
            -
                def _generate_response(self, message: str, markdown: bool = False, **kwargs) -> str:
         
     | 
| 
       288 
     | 
    
         
            -
                    """Generate the  
     | 
| 
       289 
     | 
    
         
            -
                    # Use the  
     | 
| 
       290 
     | 
    
         
            -
                     
     | 
| 
       291 
     | 
    
         
            -
             
     | 
| 
      
 327 
     | 
    
         
            +
                def _generate_response(self, message: str, markdown: bool = False, tools: Optional[List[BaseTool]] = None, team: Optional[List['Assistant']] = None, **kwargs) -> str:
         
     | 
| 
      
 328 
     | 
    
         
            +
                    """Generate the assistant's response, including tool execution and context retrieval."""
         
     | 
| 
      
 329 
     | 
    
         
            +
                    # Use the specified tools or team if provided
         
     | 
| 
      
 330 
     | 
    
         
            +
                    if tools is not None:
         
     | 
| 
      
 331 
     | 
    
         
            +
                        self.tools = tools
         
     | 
| 
      
 332 
     | 
    
         
            +
                    if team is not None:
         
     | 
| 
      
 333 
     | 
    
         
            +
                        return self._generate_team_response(message, team, markdown=markdown, **kwargs)
         
     | 
| 
      
 334 
     | 
    
         
            +
             
     | 
| 
      
 335 
     | 
    
         
            +
                    # Initialize tool_outputs as an empty dictionary
         
     | 
| 
      
 336 
     | 
    
         
            +
                    tool_outputs = {}
         
     | 
| 
       292 
337 
     | 
    
         
             
                    responses = []
         
     | 
| 
       293 
     | 
    
         
            -
                    tool_outputs = {}  # Store outputs of all tools for collaboration
         
     | 
| 
       294 
338 
     | 
    
         | 
| 
       295 
     | 
    
         
            -
                    #  
     | 
| 
      
 339 
     | 
    
         
            +
                    # Use the LLM to analyze the query and dynamically select tools when auto_tool is enabled
         
     | 
| 
      
 340 
     | 
    
         
            +
                    if self.auto_tool:
         
     | 
| 
      
 341 
     | 
    
         
            +
                        tool_calls = self._analyze_query_and_select_tools(message)
         
     | 
| 
      
 342 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 343 
     | 
    
         
            +
                        # Check if tools are provided
         
     | 
| 
      
 344 
     | 
    
         
            +
                        if self.tools:
         
     | 
| 
      
 345 
     | 
    
         
            +
                            tool_calls = [
         
     | 
| 
      
 346 
     | 
    
         
            +
                                {
         
     | 
| 
      
 347 
     | 
    
         
            +
                                    "tool": tool.__class__.__name__,
         
     | 
| 
      
 348 
     | 
    
         
            +
                                    "input": {
         
     | 
| 
      
 349 
     | 
    
         
            +
                                        "query": message,  # Use the message as the query
         
     | 
| 
      
 350 
     | 
    
         
            +
                                        "context": None,  # No context provided by default
         
     | 
| 
      
 351 
     | 
    
         
            +
                                    }
         
     | 
| 
      
 352 
     | 
    
         
            +
                                }
         
     | 
| 
      
 353 
     | 
    
         
            +
                                for tool in self.tools
         
     | 
| 
      
 354 
     | 
    
         
            +
                            ]
         
     | 
| 
      
 355 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 356 
     | 
    
         
            +
                            tool_calls = kwargs.get("tool_calls", [])
         
     | 
| 
      
 357 
     | 
    
         
            +
             
     | 
| 
      
 358 
     | 
    
         
            +
                        # Execute tools if any are detected
         
     | 
| 
       296 
359 
     | 
    
         
             
                    if tool_calls:
         
     | 
| 
       297 
360 
     | 
    
         
             
                        for tool_call in tool_calls:
         
     | 
| 
       298 
361 
     | 
    
         
             
                            tool_name = tool_call["tool"]
         
     | 
| 
       299 
362 
     | 
    
         
             
                            tool_input = tool_call["input"]
         
     | 
| 
       300 
     | 
    
         
            -
             
     | 
| 
      
 363 
     | 
    
         
            +
             
     | 
| 
       301 
364 
     | 
    
         
             
                            # Find the tool
         
     | 
| 
       302 
365 
     | 
    
         
             
                            tool = next((t for t in self.tools if t.name.lower() == tool_name.lower()), None)
         
     | 
| 
       303 
366 
     | 
    
         
             
                            if tool:
         
     | 
| 
         @@ -333,9 +396,8 @@ class Agent(BaseModel): 
     | 
|
| 
       333 
396 
     | 
    
         
             
                        except Exception as e:
         
     | 
| 
       334 
397 
     | 
    
         
             
                            logger.error(f"Failed to generate LLM response: {e}")
         
     | 
| 
       335 
398 
     | 
    
         
             
                            responses.append(f"An error occurred while generating the analysis: {e}")
         
     | 
| 
       336 
     | 
    
         
            -
             
     | 
| 
       337 
     | 
    
         
            -
                    # If no tools were executed, proceed with the original logic
         
     | 
| 
       338 
399 
     | 
    
         
             
                    if not tool_calls:
         
     | 
| 
      
 400 
     | 
    
         
            +
                        # If no tools were executed, proceed with the original logic
         
     | 
| 
       339 
401 
     | 
    
         
             
                        # Retrieve relevant context using RAG
         
     | 
| 
       340 
402 
     | 
    
         
             
                        rag_context = self.rag.retrieve(message) if self.rag else None
         
     | 
| 
       341 
403 
     | 
    
         
             
                        # Retrieve relevant context from the knowledge base (API result)
         
     | 
| 
         @@ -370,8 +432,15 @@ class Agent(BaseModel): 
     | 
|
| 
       370 
432 
     | 
    
         
             
                        if markdown:
         
     | 
| 
       371 
433 
     | 
    
         
             
                            return f"**Response:**\n\n{response}"
         
     | 
| 
       372 
434 
     | 
    
         
             
                        return response
         
     | 
| 
       373 
     | 
    
         
            -
             
     | 
| 
       374 
     | 
    
         
            -
                     
     | 
| 
      
 435 
     | 
    
         
            +
                    # Combine all responses into a single string
         
     | 
| 
      
 436 
     | 
    
         
            +
                    return "\n\n".join(responses)
         
     | 
| 
      
 437 
     | 
    
         
            +
                
         
     | 
| 
      
 438 
     | 
    
         
            +
                def _generate_team_response(self, message: str, team: List['Assistant'], markdown: bool = False, **kwargs) -> str:
         
     | 
| 
      
 439 
     | 
    
         
            +
                    """Generate a response using a team of assistants."""
         
     | 
| 
      
 440 
     | 
    
         
            +
                    responses = []
         
     | 
| 
      
 441 
     | 
    
         
            +
                    for assistant in team:
         
     | 
| 
      
 442 
     | 
    
         
            +
                        response = assistant.print_response(message, markdown=markdown, **kwargs)
         
     | 
| 
      
 443 
     | 
    
         
            +
                        responses.append(f"**{assistant.name}:**\n\n{response}")
         
     | 
| 
       375 
444 
     | 
    
         
             
                    return "\n\n".join(responses)
         
     | 
| 
       376 
445 
     | 
    
         | 
| 
       377 
446 
     | 
    
         
             
                def _build_prompt(self, message: str, context: Optional[List[Dict]]) -> str:
         
     | 
| 
         @@ -509,7 +578,7 @@ class Agent(BaseModel): 
     | 
|
| 
       509 
578 
     | 
    
         
             
                    exit_on: Optional[List[str]] = None,
         
     | 
| 
       510 
579 
     | 
    
         
             
                    **kwargs,
         
     | 
| 
       511 
580 
     | 
    
         
             
                ):
         
     | 
| 
       512 
     | 
    
         
            -
                    """Run the  
     | 
| 
      
 581 
     | 
    
         
            +
                    """Run the assistant in a CLI app."""
         
     | 
| 
       513 
582 
     | 
    
         
             
                    from rich.prompt import Prompt
         
     | 
| 
       514 
583 
     | 
    
         | 
| 
       515 
584 
     | 
    
         
             
                    if message:
         
     | 
| 
         @@ -524,15 +593,15 @@ class Agent(BaseModel): 
     | 
|
| 
       524 
593 
     | 
    
         
             
                        self.print_response(message=message, **kwargs)
         
     | 
| 
       525 
594 
     | 
    
         | 
| 
       526 
595 
     | 
    
         
             
                def _generate_api(self):
         
     | 
| 
       527 
     | 
    
         
            -
                    """Generate an API for the  
     | 
| 
      
 596 
     | 
    
         
            +
                    """Generate an API for the assistant if api=True."""
         
     | 
| 
       528 
597 
     | 
    
         
             
                    from .api.api_generator import APIGenerator
         
     | 
| 
       529 
598 
     | 
    
         
             
                    self.api_generator = APIGenerator(self)
         
     | 
| 
       530 
     | 
    
         
            -
                    print(f"API generated for  
     | 
| 
      
 599 
     | 
    
         
            +
                    print(f"API generated for assistant '{self.name}'. Use `.run_api()` to start the API server.")
         
     | 
| 
       531 
600 
     | 
    
         | 
| 
       532 
601 
     | 
    
         
             
                def run_api(self):
         
     | 
| 
       533 
     | 
    
         
            -
                    """Run the API server for the  
     | 
| 
      
 602 
     | 
    
         
            +
                    """Run the API server for the assistant."""
         
     | 
| 
       534 
603 
     | 
    
         
             
                    if not hasattr(self, 'api_generator'):
         
     | 
| 
       535 
     | 
    
         
            -
                        raise ValueError("API is not enabled for this  
     | 
| 
      
 604 
     | 
    
         
            +
                        raise ValueError("API is not enabled for this assistant. Set `api=True` when initializing the assistant.")
         
     | 
| 
       536 
605 
     | 
    
         | 
| 
       537 
606 
     | 
    
         
             
                    # Get API configuration
         
     | 
| 
       538 
607 
     | 
    
         
             
                    host = self.api_config.get("host", "0.0.0.0") if self.api_config else "0.0.0.0"
         
     | 
    
        semantio/llm/__init__.py
    CHANGED
    
    | 
         @@ -1,17 +1,24 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            from .openai import OpenAILlm
         
     | 
| 
       2 
     | 
    
         
            -
            from .anthropic import  
     | 
| 
       3 
     | 
    
         
            -
            # from .llama import LlamaLlm
         
     | 
| 
      
 2 
     | 
    
         
            +
            from .anthropic import AnthropicLLM
         
     | 
| 
       4 
3 
     | 
    
         
             
            from .groq import GroqLlm
         
     | 
| 
      
 4 
     | 
    
         
            +
            from .mistral import MistralLLM
         
     | 
| 
      
 5 
     | 
    
         
            +
            from .deepseek import DeepSeekLLM
         
     | 
| 
      
 6 
     | 
    
         
            +
            from .gemini import GeminiLLM
         
     | 
| 
       5 
7 
     | 
    
         | 
| 
       6 
8 
     | 
    
         
             
            def get_llm(provider: str, **kwargs):
         
     | 
| 
       7 
9 
     | 
    
         
             
                provider = provider.lower()  # Convert provider name to lowercase
         
     | 
| 
       8 
10 
     | 
    
         
             
                if provider == "openai":
         
     | 
| 
       9 
11 
     | 
    
         
             
                    return OpenAILlm(**kwargs)
         
     | 
| 
       10 
12 
     | 
    
         
             
                elif provider == "anthropic":
         
     | 
| 
       11 
     | 
    
         
            -
                    return  
     | 
| 
       12 
     | 
    
         
            -
                # elif provider == "llama":
         
     | 
| 
       13 
     | 
    
         
            -
                #     return LlamaLlm(**kwargs)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    return AnthropicLLM(**kwargs)
         
     | 
| 
       14 
14 
     | 
    
         
             
                elif provider == "groq":
         
     | 
| 
       15 
15 
     | 
    
         
             
                    return GroqLlm(**kwargs)
         
     | 
| 
      
 16 
     | 
    
         
            +
                elif provider == "mistral":
         
     | 
| 
      
 17 
     | 
    
         
            +
                    return MistralLLM(**kwargs)
         
     | 
| 
      
 18 
     | 
    
         
            +
                elif provider == "deepseek":
         
     | 
| 
      
 19 
     | 
    
         
            +
                    return DeepSeekLLM(**kwargs)
         
     | 
| 
      
 20 
     | 
    
         
            +
                elif provider == "gemini":
         
     | 
| 
      
 21 
     | 
    
         
            +
                    return GeminiLLM(**kwargs)
         
     | 
| 
      
 22 
     | 
    
         
            +
                
         
     | 
| 
       16 
23 
     | 
    
         
             
                else:
         
     | 
| 
       17 
24 
     | 
    
         
             
                    raise ValueError(f"Unsupported LLM provider: {provider}")
         
     | 
    
        semantio/llm/anthropic.py
    CHANGED
    
    | 
         @@ -1,39 +1,52 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import os
         
     | 
| 
       1 
2 
     | 
    
         
             
            from typing import List, Dict, Optional
         
     | 
| 
       2 
3 
     | 
    
         
             
            from .base_llm import BaseLLM
         
     | 
| 
       3 
4 
     | 
    
         
             
            import anthropic
         
     | 
| 
       4 
     | 
    
         
            -
            import os
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
            class  
     | 
| 
       7 
     | 
    
         
            -
                def __init__(
         
     | 
| 
       8 
     | 
    
         
            -
                     
     | 
| 
       9 
     | 
    
         
            -
                     
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
      
 6 
     | 
    
         
            +
            class AnthropicLLM(BaseLLM):
         
     | 
| 
      
 7 
     | 
    
         
            +
                def __init__(self, model: str = "claude-3-5-sonnet-20241022", api_key: Optional[str] = None):
         
     | 
| 
      
 8 
     | 
    
         
            +
                    """
         
     | 
| 
      
 9 
     | 
    
         
            +
                    Initialize the Anthropic LLM class.
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                    Args:
         
     | 
| 
      
 12 
     | 
    
         
            +
                        model (str): The name of the model (e.g., claude-3-5-sonnet-20241022).
         
     | 
| 
      
 13 
     | 
    
         
            +
                        api_key (Optional[str]): The Anthropic API key. If not provided, it fetches from the environment.
         
     | 
| 
      
 14 
     | 
    
         
            +
                    """
         
     | 
| 
       12 
15 
     | 
    
         
             
                    self.model = model
         
     | 
| 
       13 
16 
     | 
    
         
             
                    self.api_key = api_key or os.getenv("ANTHROPIC_API_KEY")
         
     | 
| 
       14 
17 
     | 
    
         
             
                    if not self.api_key:
         
     | 
| 
       15 
18 
     | 
    
         
             
                        raise ValueError("Anthropic API key is required. Set ANTHROPIC_API_KEY environment variable or pass it explicitly.")
         
     | 
| 
       16 
     | 
    
         
            -
                    self.client = anthropic. 
     | 
| 
      
 19 
     | 
    
         
            +
                    self.client = anthropic.Anthropic(api_key=self.api_key)
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def generate(self, prompt: str, context: Optional[List[Dict]] = None, memory: Optional[List[Dict]] = None) -> str:
         
     | 
| 
      
 22 
     | 
    
         
            +
                    """
         
     | 
| 
      
 23 
     | 
    
         
            +
                    Generate text using Anthropic's Claude model.
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    Args:
         
     | 
| 
      
 26 
     | 
    
         
            +
                        prompt (str): The user prompt.
         
     | 
| 
      
 27 
     | 
    
         
            +
                        context (Optional[List[Dict]]): Context to include in the conversation.
         
     | 
| 
      
 28 
     | 
    
         
            +
                        memory (Optional[List[Dict]]): Memory from previous interactions.
         
     | 
| 
       17 
29 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
             
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
                     
     | 
| 
       21 
     | 
    
         
            -
                     
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
                        messages.append({"role": "system", "content": "Context: " + str(context)})
         
     | 
| 
       30 
     | 
    
         
            -
                    messages.append({"role": "user", "content": prompt})
         
     | 
| 
      
 30 
     | 
    
         
            +
                    Returns:
         
     | 
| 
      
 31 
     | 
    
         
            +
                        str: The generated response from the model.
         
     | 
| 
      
 32 
     | 
    
         
            +
                    """
         
     | 
| 
      
 33 
     | 
    
         
            +
                    try:
         
     | 
| 
      
 34 
     | 
    
         
            +
                        # Prepare messages for the Anthropic API
         
     | 
| 
      
 35 
     | 
    
         
            +
                        messages = []
         
     | 
| 
      
 36 
     | 
    
         
            +
                        if memory:
         
     | 
| 
      
 37 
     | 
    
         
            +
                            messages.extend(memory)
         
     | 
| 
      
 38 
     | 
    
         
            +
                        if context:
         
     | 
| 
      
 39 
     | 
    
         
            +
                            messages.append({"role": "system", "content": "Context: " + str(context)})
         
     | 
| 
      
 40 
     | 
    
         
            +
                        messages.append({"role": "user", "content": prompt})
         
     | 
| 
       31 
41 
     | 
    
         | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
      
 42 
     | 
    
         
            +
                        # Call the Anthropic API
         
     | 
| 
      
 43 
     | 
    
         
            +
                        response = self.client.messages.create(
         
     | 
| 
      
 44 
     | 
    
         
            +
                            model=self.model,
         
     | 
| 
      
 45 
     | 
    
         
            +
                            max_tokens=1024,
         
     | 
| 
      
 46 
     | 
    
         
            +
                            messages=messages,
         
     | 
| 
      
 47 
     | 
    
         
            +
                        )
         
     | 
| 
       37 
48 
     | 
    
         | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
      
 49 
     | 
    
         
            +
                        # Extract and return the response
         
     | 
| 
      
 50 
     | 
    
         
            +
                        return response.content
         
     | 
| 
      
 51 
     | 
    
         
            +
                    except Exception as e:
         
     | 
| 
      
 52 
     | 
    
         
            +
                        raise ValueError(f"Error while generating response with Anthropic Claude: {e}")
         
     | 
    
        semantio/llm/base_llm.py
    CHANGED
    
    | 
         @@ -9,4 +9,13 @@ class BaseLLM(ABC): 
     | 
|
| 
       9 
9 
     | 
    
         
             
                    context: Optional[List[Dict]] = None,
         
     | 
| 
       10 
10 
     | 
    
         
             
                    memory: Optional[List[Dict]] = None,
         
     | 
| 
       11 
11 
     | 
    
         
             
                ) -> str:
         
     | 
| 
       12 
     | 
    
         
            -
                    pass
         
     | 
| 
      
 12 
     | 
    
         
            +
                    pass
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                @property
         
     | 
| 
      
 15 
     | 
    
         
            +
                def supports_vision(self) -> bool:
         
     | 
| 
      
 16 
     | 
    
         
            +
                    """Return True if the LLM supports vision tasks."""
         
     | 
| 
      
 17 
     | 
    
         
            +
                    return False
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def generate_from_image(self, image_bytes: bytes, **kwargs) -> str:
         
     | 
| 
      
 20 
     | 
    
         
            +
                    """Process an image if vision is supported. Default implementation raises an error."""
         
     | 
| 
      
 21 
     | 
    
         
            +
                    raise NotImplementedError("This LLM does not support vision tasks.")
         
     | 
    
        semantio/llm/deepseek.py
    ADDED
    
    | 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            from typing import List, Dict, Optional
         
     | 
| 
      
 2 
     | 
    
         
            +
            from .base_llm import BaseLLM
         
     | 
| 
      
 3 
     | 
    
         
            +
            from openai import OpenAI
         
     | 
| 
      
 4 
     | 
    
         
            +
            import os
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            class DeepSeekLLM(BaseLLM):
         
     | 
| 
      
 7 
     | 
    
         
            +
                def __init__(self, model: str = "deepseek-chat", api_key: Optional[str] = None):
         
     | 
| 
      
 8 
     | 
    
         
            +
                    self.model = model
         
     | 
| 
      
 9 
     | 
    
         
            +
                    self.api_key = api_key or os.getenv("DEEPSEEK_API_KEY")
         
     | 
| 
      
 10 
     | 
    
         
            +
                    if not self.api_key:
         
     | 
| 
      
 11 
     | 
    
         
            +
                        raise ValueError("DeepSeek API key is required. Set DEEPSEEK_API_KEY environment variable or pass it explicitly.")
         
     | 
| 
      
 12 
     | 
    
         
            +
                    self.client = OpenAI(api_key=self.api_key, base_url="https://api.deepseek.com")
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def generate(self, prompt: str, context: Optional[List[Dict]] = None, memory: Optional[List[Dict]] = None) -> str:
         
     | 
| 
      
 15 
     | 
    
         
            +
                    messages = []
         
     | 
| 
      
 16 
     | 
    
         
            +
                    if memory:
         
     | 
| 
      
 17 
     | 
    
         
            +
                        messages.extend(memory)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    if context:
         
     | 
| 
      
 19 
     | 
    
         
            +
                        messages.append({"role": "system", "content": "Context: " + str(context)})
         
     | 
| 
      
 20 
     | 
    
         
            +
                    messages.append({"role": "user", "content": prompt})
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    response = self.client.chat.completions.create(
         
     | 
| 
      
 23 
     | 
    
         
            +
                        model=self.model,
         
     | 
| 
      
 24 
     | 
    
         
            +
                        messages=messages,
         
     | 
| 
      
 25 
     | 
    
         
            +
                    )
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    return response.choices[0].message.content
         
     | 
    
        semantio/llm/gemini.py
    ADDED
    
    | 
         @@ -0,0 +1,50 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            import os
         
     | 
| 
      
 2 
     | 
    
         
            +
            from typing import List, Dict, Optional
         
     | 
| 
      
 3 
     | 
    
         
            +
            from .base_llm import BaseLLM
         
     | 
| 
      
 4 
     | 
    
         
            +
            from google import genai
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            class GeminiLLM(BaseLLM):
         
     | 
| 
      
 7 
     | 
    
         
            +
                def __init__(self, model: str = "gemini-1.5-flash", api_key: Optional[str] = None):
         
     | 
| 
      
 8 
     | 
    
         
            +
                    """
         
     | 
| 
      
 9 
     | 
    
         
            +
                    Initialize the Gemini LLM class.
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                    Args:
         
     | 
| 
      
 12 
     | 
    
         
            +
                        model (str): The name of the Gemini model (e.g., 'gemini-1.5-flash').
         
     | 
| 
      
 13 
     | 
    
         
            +
                        api_key (Optional[str]): The Gemini API key. If not provided, it fetches from the environment.
         
     | 
| 
      
 14 
     | 
    
         
            +
                    """
         
     | 
| 
      
 15 
     | 
    
         
            +
                    self.model = model
         
     | 
| 
      
 16 
     | 
    
         
            +
                    self.api_key = api_key or os.getenv("GEMINI_API_KEY")
         
     | 
| 
      
 17 
     | 
    
         
            +
                    if not self.api_key:
         
     | 
| 
      
 18 
     | 
    
         
            +
                        raise ValueError("Gemini API key is required. Set GEMINI_API_KEY environment variable or pass it explicitly.")
         
     | 
| 
      
 19 
     | 
    
         
            +
                    
         
     | 
| 
      
 20 
     | 
    
         
            +
                    # Initialize the client using the API key
         
     | 
| 
      
 21 
     | 
    
         
            +
                    self.client = genai.Client(api_key=self.api_key)
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                def generate(self, prompt: str, context: Optional[List[Dict]] = None, memory: Optional[List[Dict]] = None) -> str:
         
     | 
| 
      
 24 
     | 
    
         
            +
                    """
         
     | 
| 
      
 25 
     | 
    
         
            +
                    Generate text using Google's Gemini model.
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    Args:
         
     | 
| 
      
 28 
     | 
    
         
            +
                        prompt (str): The user prompt.
         
     | 
| 
      
 29 
     | 
    
         
            +
                        context (Optional[List[Dict]]): Context to include in the conversation.
         
     | 
| 
      
 30 
     | 
    
         
            +
                        memory (Optional[List[Dict]]): Memory from previous interactions.
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                    Returns:
         
     | 
| 
      
 33 
     | 
    
         
            +
                        str: The generated response from the model.
         
     | 
| 
      
 34 
     | 
    
         
            +
                    """
         
     | 
| 
      
 35 
     | 
    
         
            +
                    try:
         
     | 
| 
      
 36 
     | 
    
         
            +
                        # Prepare the chat history (optional context and memory)
         
     | 
| 
      
 37 
     | 
    
         
            +
                        history = memory if memory else []
         
     | 
| 
      
 38 
     | 
    
         
            +
                        if context:
         
     | 
| 
      
 39 
     | 
    
         
            +
                            history.append({"role": "system", "content": str(context)})
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                        # Generate the content using the specified Gemini model
         
     | 
| 
      
 42 
     | 
    
         
            +
                        response = self.client.models.generate_content(
         
     | 
| 
      
 43 
     | 
    
         
            +
                            model=self.model,
         
     | 
| 
      
 44 
     | 
    
         
            +
                            contents=prompt
         
     | 
| 
      
 45 
     | 
    
         
            +
                        )
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                        # Return the response text
         
     | 
| 
      
 48 
     | 
    
         
            +
                        return response.text
         
     | 
| 
      
 49 
     | 
    
         
            +
                    except Exception as e:
         
     | 
| 
      
 50 
     | 
    
         
            +
                        raise ValueError(f"Error while generating response with Gemini: {e}")
         
     | 
    
        semantio/llm/groq.py
    CHANGED
    
    | 
         @@ -1,4 +1,5 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
      
 1 
     | 
    
         
            +
            import base64
         
     | 
| 
      
 2 
     | 
    
         
            +
            from typing import Optional, List, Dict
         
     | 
| 
       2 
3 
     | 
    
         
             
            from .base_llm import BaseLLM
         
     | 
| 
       3 
4 
     | 
    
         
             
            import groq
         
     | 
| 
       4 
5 
     | 
    
         
             
            import os
         
     | 
| 
         @@ -15,12 +16,22 @@ class GroqLlm(BaseLLM): 
     | 
|
| 
       15 
16 
     | 
    
         
             
                        raise ValueError("Groq API key is required. Set GROQ_API_KEY environment variable or pass it explicitly.")
         
     | 
| 
       16 
17 
     | 
    
         
             
                    self.client = groq.Client(api_key=self.api_key)
         
     | 
| 
       17 
18 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
                 
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
                     
     | 
| 
       21 
     | 
    
         
            -
                     
     | 
| 
       22 
     | 
    
         
            -
                     
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
      
 19 
     | 
    
         
            +
                @property
         
     | 
| 
      
 20 
     | 
    
         
            +
                def supports_vision(self) -> bool:
         
     | 
| 
      
 21 
     | 
    
         
            +
                    """
         
     | 
| 
      
 22 
     | 
    
         
            +
                    Check if the model supports vision tasks.
         
     | 
| 
      
 23 
     | 
    
         
            +
                    """
         
     | 
| 
      
 24 
     | 
    
         
            +
                    # List of Groq models that support vision
         
     | 
| 
      
 25 
     | 
    
         
            +
                    vision_models = [
         
     | 
| 
      
 26 
     | 
    
         
            +
                        "llama-3.2-11b-vision-preview",
         
     | 
| 
      
 27 
     | 
    
         
            +
                        "llama-3.2-90b-vision-preview"
         
     | 
| 
      
 28 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 29 
     | 
    
         
            +
                    return self.model in vision_models
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                def generate(self, prompt: str, context: Optional[List[Dict]] = None, memory: Optional[List[Dict]] = None) -> str:
         
     | 
| 
      
 32 
     | 
    
         
            +
                    """
         
     | 
| 
      
 33 
     | 
    
         
            +
                    Generate a response to a text-based prompt.
         
     | 
| 
      
 34 
     | 
    
         
            +
                    """
         
     | 
| 
       24 
35 
     | 
    
         
             
                    # Prepare messages for the Groq API
         
     | 
| 
       25 
36 
     | 
    
         
             
                    messages = []
         
     | 
| 
       26 
37 
     | 
    
         
             
                    if memory:
         
     | 
| 
         @@ -36,4 +47,75 @@ class GroqLlm(BaseLLM): 
     | 
|
| 
       36 
47 
     | 
    
         
             
                    )
         
     | 
| 
       37 
48 
     | 
    
         | 
| 
       38 
49 
     | 
    
         
             
                    # Extract and return the response
         
     | 
| 
       39 
     | 
    
         
            -
                    return response.choices[0].message.content
         
     | 
| 
      
 50 
     | 
    
         
            +
                    return response.choices[0].message.content
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                def generate_from_image(self, prompt: str, image_bytes: bytes, **kwargs) -> str:
         
     | 
| 
      
 53 
     | 
    
         
            +
                    """
         
     | 
| 
      
 54 
     | 
    
         
            +
                    Process an image and generate a response if the model supports vision.
         
     | 
| 
      
 55 
     | 
    
         
            +
                    """
         
     | 
| 
      
 56 
     | 
    
         
            +
                    if not self.supports_vision:
         
     | 
| 
      
 57 
     | 
    
         
            +
                        raise ValueError(f"Model '{self.model}' does not support vision tasks.")
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                    try:
         
     | 
| 
      
 60 
     | 
    
         
            +
                        # Convert the image bytes to base64
         
     | 
| 
      
 61 
     | 
    
         
            +
                        image_base64 = base64.b64encode(image_bytes).decode("utf-8")
         
     | 
| 
      
 62 
     | 
    
         
            +
                        
         
     | 
| 
      
 63 
     | 
    
         
            +
                        # Construct the message payload
         
     | 
| 
      
 64 
     | 
    
         
            +
                        messages = [
         
     | 
| 
      
 65 
     | 
    
         
            +
                            {
         
     | 
| 
      
 66 
     | 
    
         
            +
                                "role": "user",
         
     | 
| 
      
 67 
     | 
    
         
            +
                                "content": [
         
     | 
| 
      
 68 
     | 
    
         
            +
                                    {"type": "text", "text": prompt},
         
     | 
| 
      
 69 
     | 
    
         
            +
                                    {
         
     | 
| 
      
 70 
     | 
    
         
            +
                                        "type": "image_url",
         
     | 
| 
      
 71 
     | 
    
         
            +
                                        "image_url": {
         
     | 
| 
      
 72 
     | 
    
         
            +
                                            "url": f"data:image/jpeg;base64,{image_base64}",
         
     | 
| 
      
 73 
     | 
    
         
            +
                                        },
         
     | 
| 
      
 74 
     | 
    
         
            +
                                    },
         
     | 
| 
      
 75 
     | 
    
         
            +
                                ],
         
     | 
| 
      
 76 
     | 
    
         
            +
                            }
         
     | 
| 
      
 77 
     | 
    
         
            +
                        ]
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                        # Call the Groq API with the base64-encoded image
         
     | 
| 
      
 80 
     | 
    
         
            +
                        response = self.client.chat.completions.create(
         
     | 
| 
      
 81 
     | 
    
         
            +
                            model=self.model,
         
     | 
| 
      
 82 
     | 
    
         
            +
                            messages=messages,
         
     | 
| 
      
 83 
     | 
    
         
            +
                            **kwargs,
         
     | 
| 
      
 84 
     | 
    
         
            +
                        )
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                        # Extract and return the response text
         
     | 
| 
      
 87 
     | 
    
         
            +
                        return response.choices[0].message.content
         
     | 
| 
      
 88 
     | 
    
         
            +
                    except Exception as e:
         
     | 
| 
      
 89 
     | 
    
         
            +
                        raise ValueError(f"Error while processing image with Groq vision model: {e}")
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                def generate_from_image_url(self, prompt: str, image_url: str, **kwargs) -> str:
         
     | 
| 
      
 93 
     | 
    
         
            +
                    """
         
     | 
| 
      
 94 
     | 
    
         
            +
                    Process an image URL and generate a response if the model supports vision.
         
     | 
| 
      
 95 
     | 
    
         
            +
                    """
         
     | 
| 
      
 96 
     | 
    
         
            +
                    if not self.supports_vision:
         
     | 
| 
      
 97 
     | 
    
         
            +
                        raise ValueError(f"Model '{self.model}' does not support vision tasks.")
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                    try:
         
     | 
| 
      
 100 
     | 
    
         
            +
                        # Call the Groq API with the image URL
         
     | 
| 
      
 101 
     | 
    
         
            +
                        response = self.client.chat.completions.create(
         
     | 
| 
      
 102 
     | 
    
         
            +
                            model=self.model,
         
     | 
| 
      
 103 
     | 
    
         
            +
                            messages=[
         
     | 
| 
      
 104 
     | 
    
         
            +
                                {
         
     | 
| 
      
 105 
     | 
    
         
            +
                                    "role": "user",
         
     | 
| 
      
 106 
     | 
    
         
            +
                                    "content": [
         
     | 
| 
      
 107 
     | 
    
         
            +
                                        {"type": "text", "text": prompt},
         
     | 
| 
      
 108 
     | 
    
         
            +
                                        {
         
     | 
| 
      
 109 
     | 
    
         
            +
                                            "type": "image_url",
         
     | 
| 
      
 110 
     | 
    
         
            +
                                            "image_url": {
         
     | 
| 
      
 111 
     | 
    
         
            +
                                                "url": image_url,
         
     | 
| 
      
 112 
     | 
    
         
            +
                                            },
         
     | 
| 
      
 113 
     | 
    
         
            +
                                        },
         
     | 
| 
      
 114 
     | 
    
         
            +
                                    ],
         
     | 
| 
      
 115 
     | 
    
         
            +
                                }
         
     | 
| 
      
 116 
     | 
    
         
            +
                            ],
         
     | 
| 
      
 117 
     | 
    
         
            +
                            **kwargs,
         
     | 
| 
      
 118 
     | 
    
         
            +
                        )
         
     | 
| 
      
 119 
     | 
    
         
            +
                        return response.choices[0].message.content
         
     | 
| 
      
 120 
     | 
    
         
            +
                    except Exception as e:
         
     | 
| 
      
 121 
     | 
    
         
            +
                        raise ValueError(f"Error while processing image URL with Groq vision model: {e}")
         
     | 
    
        semantio/llm/mistral.py
    ADDED
    
    | 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            from typing import List, Dict, Optional
         
     | 
| 
      
 2 
     | 
    
         
            +
            from .base_llm import BaseLLM
         
     | 
| 
      
 3 
     | 
    
         
            +
            from mistralai import Mistral
         
     | 
| 
      
 4 
     | 
    
         
            +
            import os
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            class MistralLLM(BaseLLM):
         
     | 
| 
      
 7 
     | 
    
         
            +
                def __init__(self, model: str = "mistral-large-latest", api_key: Optional[str] = None):
         
     | 
| 
      
 8 
     | 
    
         
            +
                    self.model = model
         
     | 
| 
      
 9 
     | 
    
         
            +
                    self.api_key = api_key or os.getenv("MISTRAL_API_KEY")
         
     | 
| 
      
 10 
     | 
    
         
            +
                    if not self.api_key:
         
     | 
| 
      
 11 
     | 
    
         
            +
                        raise ValueError("Mistral API key is required. Set MISTRAL_API_KEY environment variable or pass it explicitly.")
         
     | 
| 
      
 12 
     | 
    
         
            +
                    self.client = Mistral(api_key=self.api_key)
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                def generate(self, prompt: str, context: Optional[List[Dict]] = None, memory: Optional[List[Dict]] = None) -> str:
         
     | 
| 
      
 15 
     | 
    
         
            +
                    messages = []
         
     | 
| 
      
 16 
     | 
    
         
            +
                    if memory:
         
     | 
| 
      
 17 
     | 
    
         
            +
                        messages.extend(memory)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    if context:
         
     | 
| 
      
 19 
     | 
    
         
            +
                        messages.append({"role": "system", "content": "Context: " + str(context)})
         
     | 
| 
      
 20 
     | 
    
         
            +
                    messages.append({"role": "user", "content": prompt})
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    response = self.client.chat.complete(
         
     | 
| 
      
 23 
     | 
    
         
            +
                        model=self.model,
         
     | 
| 
      
 24 
     | 
    
         
            +
                        messages=messages,
         
     | 
| 
      
 25 
     | 
    
         
            +
                    )
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    return response.choices[0].message.content
         
     | 
    
        semantio/llm/openai.py
    CHANGED
    
    | 
         @@ -1,26 +1,136 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            from typing import List, Dict, Optional
         
     | 
| 
       2 
2 
     | 
    
         
             
            from .base_llm import BaseLLM
         
     | 
| 
       3 
     | 
    
         
            -
            import  
     | 
| 
      
 3 
     | 
    
         
            +
            from openai import OpenAI
         
     | 
| 
       4 
4 
     | 
    
         
             
            import os
         
     | 
| 
      
 5 
     | 
    
         
            +
            import base64
         
     | 
| 
       5 
6 
     | 
    
         | 
| 
       6 
7 
     | 
    
         
             
            class OpenAILlm(BaseLLM):
         
     | 
| 
       7 
     | 
    
         
            -
                def __init__(self, model: str = "gpt- 
     | 
| 
      
 8 
     | 
    
         
            +
                def __init__(self, model: str = "gpt-4o", api_key: Optional[str] = None):
         
     | 
| 
      
 9 
     | 
    
         
            +
                    """
         
     | 
| 
      
 10 
     | 
    
         
            +
                    Initialize the OpenAI LLM class.
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                    Args:
         
     | 
| 
      
 13 
     | 
    
         
            +
                        model (str): The name of the model (e.g., gpt-4o, gpt-4-vision).
         
     | 
| 
      
 14 
     | 
    
         
            +
                        api_key (Optional[str]): The OpenAI API key. If not provided, it fetches from the environment.
         
     | 
| 
      
 15 
     | 
    
         
            +
                    """
         
     | 
| 
       8 
16 
     | 
    
         
             
                    self.model = model
         
     | 
| 
       9 
17 
     | 
    
         
             
                    self.api_key = api_key or os.getenv("OPENAI_API_KEY")
         
     | 
| 
       10 
18 
     | 
    
         
             
                    if not self.api_key:
         
     | 
| 
       11 
19 
     | 
    
         
             
                        raise ValueError("OpenAI API key is required. Set OPENAI_API_KEY environment variable or pass it explicitly.")
         
     | 
| 
       12 
     | 
    
         
            -
                     
     | 
| 
      
 20 
     | 
    
         
            +
                    self.client = OpenAI(api_key=self.api_key)
         
     | 
| 
       13 
21 
     | 
    
         | 
| 
       14 
22 
     | 
    
         
             
                def generate(self, prompt: str, context: Optional[List[Dict]] = None, memory: Optional[List[Dict]] = None) -> str:
         
     | 
| 
       15 
     | 
    
         
            -
                     
     | 
| 
       16 
     | 
    
         
            -
                     
     | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
       18 
     | 
    
         
            -
                     
     | 
| 
       19 
     | 
    
         
            -
                         
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
       22 
     | 
    
         
            -
             
     | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
                         
     | 
| 
       25 
     | 
    
         
            -
                     
     | 
| 
       26 
     | 
    
         
            -
                     
     | 
| 
      
 23 
     | 
    
         
            +
                    """
         
     | 
| 
      
 24 
     | 
    
         
            +
                    Generate text using OpenAI's ChatCompletion API.
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                    Args:
         
     | 
| 
      
 27 
     | 
    
         
            +
                        prompt (str): The user prompt.
         
     | 
| 
      
 28 
     | 
    
         
            +
                        context (Optional[List[Dict]]): Context to include in the conversation.
         
     | 
| 
      
 29 
     | 
    
         
            +
                        memory (Optional[List[Dict]]): Memory from previous interactions.
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                    Returns:
         
     | 
| 
      
 32 
     | 
    
         
            +
                        str: The generated response from the model.
         
     | 
| 
      
 33 
     | 
    
         
            +
                    """
         
     | 
| 
      
 34 
     | 
    
         
            +
                    try:
         
     | 
| 
      
 35 
     | 
    
         
            +
                        # Prepare messages for the OpenAI API
         
     | 
| 
      
 36 
     | 
    
         
            +
                        messages = []
         
     | 
| 
      
 37 
     | 
    
         
            +
                        if memory:
         
     | 
| 
      
 38 
     | 
    
         
            +
                            messages.extend(memory)
         
     | 
| 
      
 39 
     | 
    
         
            +
                        if context:
         
     | 
| 
      
 40 
     | 
    
         
            +
                            messages.append({"role": "system", "content": "Context: " + str(context)})
         
     | 
| 
      
 41 
     | 
    
         
            +
                        messages.append({"role": "user", "content": prompt})
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                        # Call the ChatCompletion endpoint
         
     | 
| 
      
 44 
     | 
    
         
            +
                        response = self.client.chat.completions.create(
         
     | 
| 
      
 45 
     | 
    
         
            +
                            model=self.model,
         
     | 
| 
      
 46 
     | 
    
         
            +
                            messages=messages,
         
     | 
| 
      
 47 
     | 
    
         
            +
                        )
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                        # Extract and return the response:
         
     | 
| 
      
 50 
     | 
    
         
            +
                        return response.choices[0].message.content
         
     | 
| 
      
 51 
     | 
    
         
            +
                    except Exception as e:
         
     | 
| 
      
 52 
     | 
    
         
            +
                        raise ValueError(f"Error while generating response with OpenAI: {e}")
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                @property
         
     | 
| 
      
 55 
     | 
    
         
            +
                def supports_vision(self) -> bool:
         
     | 
| 
      
 56 
     | 
    
         
            +
                    """
         
     | 
| 
      
 57 
     | 
    
         
            +
                    Check if the model supports vision tasks.
         
     | 
| 
      
 58 
     | 
    
         
            +
                    """
         
     | 
| 
      
 59 
     | 
    
         
            +
                    # List of GPT models that support vision
         
     | 
| 
      
 60 
     | 
    
         
            +
                    vision_models =[
         
     | 
| 
      
 61 
     | 
    
         
            +
                        "gpt-4o", "gpt-4o mini", "o1", "o1 mini"
         
     | 
| 
      
 62 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 63 
     | 
    
         
            +
                    return self.model in vision_models
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                def generate_from_image_url(self, prompt: str, image_url: str, **kwargs) -> str:
         
     | 
| 
      
 66 
     | 
    
         
            +
                    """
         
     | 
| 
      
 67 
     | 
    
         
            +
                    Process an image URL with OpenAI's vision-capable models, using instructions as the prompt.
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                    Args:
         
     | 
| 
      
 70 
     | 
    
         
            +
                        image_url (str): The URL of the image.
         
     | 
| 
      
 71 
     | 
    
         
            +
                        instructions (str): Instructions provided as the prompt for image analysis.
         
     | 
| 
      
 72 
     | 
    
         
            +
                        kwargs: Additional parameters for the OpenAI API.
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                    Returns:
         
     | 
| 
      
 75 
     | 
    
         
            +
                        str: The response generated by the vision-capable model.
         
     | 
| 
      
 76 
     | 
    
         
            +
                    """
         
     | 
| 
      
 77 
     | 
    
         
            +
                    if not self.supports_vision:
         
     | 
| 
      
 78 
     | 
    
         
            +
                        raise ValueError(f"Model '{self.model}' does not support vision tasks.")
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                    try:
         
     | 
| 
      
 81 
     | 
    
         
            +
                        # Use instructions as the prompt in the API call
         
     | 
| 
      
 82 
     | 
    
         
            +
                        response = self.client.chat.completions.create(
         
     | 
| 
      
 83 
     | 
    
         
            +
                            model=self.model,
         
     | 
| 
      
 84 
     | 
    
         
            +
                            messages=[
         
     | 
| 
      
 85 
     | 
    
         
            +
                                {
         
     | 
| 
      
 86 
     | 
    
         
            +
                                    "role": "user",
         
     | 
| 
      
 87 
     | 
    
         
            +
                                    "content": [
         
     | 
| 
      
 88 
     | 
    
         
            +
                                        {"type": "text", "text": prompt},  # Using instructions as the prompt
         
     | 
| 
      
 89 
     | 
    
         
            +
                                        {"type": "image_url", "image_url": {"url": image_url,},},
         
     | 
| 
      
 90 
     | 
    
         
            +
                                    ],
         
     | 
| 
      
 91 
     | 
    
         
            +
                                }
         
     | 
| 
      
 92 
     | 
    
         
            +
                            ],
         
     | 
| 
      
 93 
     | 
    
         
            +
                            **kwargs,
         
     | 
| 
      
 94 
     | 
    
         
            +
                        )
         
     | 
| 
      
 95 
     | 
    
         
            +
                        return response.choices[0].message.content
         
     | 
| 
      
 96 
     | 
    
         
            +
                    except Exception as e:
         
     | 
| 
      
 97 
     | 
    
         
            +
                        raise ValueError(f"Error while processing image URL with OpenAI Vision model: {e}")
         
     | 
| 
      
 98 
     | 
    
         
            +
             
     | 
| 
      
 99 
     | 
    
         
            +
                def generate_from_image(self, prompt: str, image_bytes: bytes, **kwargs) -> str:
         
     | 
| 
      
 100 
     | 
    
         
            +
                    """
         
     | 
| 
      
 101 
     | 
    
         
            +
                    Process an image and generate a response if the model supports vision.
         
     | 
| 
      
 102 
     | 
    
         
            +
                    """
         
     | 
| 
      
 103 
     | 
    
         
            +
                    if not self.supports_vision:
         
     | 
| 
      
 104 
     | 
    
         
            +
                        raise ValueError(f"Model '{self.model}' does not support vision tasks.")
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                    try:
         
     | 
| 
      
 107 
     | 
    
         
            +
                        # Convert the image bytes to base64
         
     | 
| 
      
 108 
     | 
    
         
            +
                        image_base64 = base64.b64encode(image_bytes).decode("utf-8")
         
     | 
| 
      
 109 
     | 
    
         
            +
                        
         
     | 
| 
      
 110 
     | 
    
         
            +
                        # Construct the message payload
         
     | 
| 
      
 111 
     | 
    
         
            +
                        messages = [
         
     | 
| 
      
 112 
     | 
    
         
            +
                            {
         
     | 
| 
      
 113 
     | 
    
         
            +
                                "role": "user",
         
     | 
| 
      
 114 
     | 
    
         
            +
                                "content": [
         
     | 
| 
      
 115 
     | 
    
         
            +
                                    {"type": "text", "text": prompt},
         
     | 
| 
      
 116 
     | 
    
         
            +
                                    {
         
     | 
| 
      
 117 
     | 
    
         
            +
                                        "type": "image_url",
         
     | 
| 
      
 118 
     | 
    
         
            +
                                        "image_url": {
         
     | 
| 
      
 119 
     | 
    
         
            +
                                            "url": f"data:image/jpeg;base64,{image_base64}",
         
     | 
| 
      
 120 
     | 
    
         
            +
                                        },
         
     | 
| 
      
 121 
     | 
    
         
            +
                                    },
         
     | 
| 
      
 122 
     | 
    
         
            +
                                ],
         
     | 
| 
      
 123 
     | 
    
         
            +
                            }
         
     | 
| 
      
 124 
     | 
    
         
            +
                        ]
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                        # Call the Groq API with the base64-encoded image
         
     | 
| 
      
 127 
     | 
    
         
            +
                        response = self.client.chat.completions.create(
         
     | 
| 
      
 128 
     | 
    
         
            +
                            model=self.model,
         
     | 
| 
      
 129 
     | 
    
         
            +
                            messages=messages,
         
     | 
| 
      
 130 
     | 
    
         
            +
                            **kwargs,
         
     | 
| 
      
 131 
     | 
    
         
            +
                        )
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                        # Extract and return the response text
         
     | 
| 
      
 134 
     | 
    
         
            +
                        return response.choices[0].message.content
         
     | 
| 
      
 135 
     | 
    
         
            +
                    except Exception as e:
         
     | 
| 
      
 136 
     | 
    
         
            +
                        raise ValueError(f"Error while processing image with OpenAI vision model: {e}")
         
     | 
| 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            Metadata-Version: 2.1
         
     | 
| 
       2 
2 
     | 
    
         
             
            Name: semantio
         
     | 
| 
       3 
     | 
    
         
            -
            Version: 0.0. 
     | 
| 
       4 
     | 
    
         
            -
            Summary: A powerful SDK for building AI agents 
     | 
| 
      
 3 
     | 
    
         
            +
            Version: 0.0.2
         
     | 
| 
      
 4 
     | 
    
         
            +
            Summary: A powerful SDK for building AI agents
         
     | 
| 
       5 
5 
     | 
    
         
             
            Home-page: https://github.com/Syenah/semantio
         
     | 
| 
       6 
6 
     | 
    
         
             
            Author: Rakesh
         
     | 
| 
       7 
7 
     | 
    
         
             
            Author-email: rakeshsahoo689@gmail.com
         
     | 
| 
         @@ -19,7 +19,8 @@ License-File: LICENSE 
     | 
|
| 
       19 
19 
     | 
    
         
             
            Requires-Dist: openai
         
     | 
| 
       20 
20 
     | 
    
         
             
            Requires-Dist: anthropic
         
     | 
| 
       21 
21 
     | 
    
         
             
            Requires-Dist: groq
         
     | 
| 
       22 
     | 
    
         
            -
            Requires-Dist:  
     | 
| 
      
 22 
     | 
    
         
            +
            Requires-Dist: google-genai
         
     | 
| 
      
 23 
     | 
    
         
            +
            Requires-Dist: mistralai
         
     | 
| 
       23 
24 
     | 
    
         
             
            Requires-Dist: faiss-cpu
         
     | 
| 
       24 
25 
     | 
    
         
             
            Requires-Dist: pydantic
         
     | 
| 
       25 
26 
     | 
    
         
             
            Requires-Dist: requests
         
     | 
| 
         @@ -32,8 +33,6 @@ Requires-Dist: sentence-transformers 
     | 
|
| 
       32 
33 
     | 
    
         
             
            Requires-Dist: fuzzywuzzy
         
     | 
| 
       33 
34 
     | 
    
         
             
            Requires-Dist: duckduckgo-search
         
     | 
| 
       34 
35 
     | 
    
         
             
            Requires-Dist: yfinance
         
     | 
| 
       35 
     | 
    
         
            -
            Requires-Dist: forex-python
         
     | 
| 
       36 
     | 
    
         
            -
            Requires-Dist: qrcode
         
     | 
| 
       37 
36 
     | 
    
         | 
| 
       38 
37 
     | 
    
         
             
            # Semantio: The Mother of Your AI Agents
         
     | 
| 
       39 
38 
     | 
    
         | 
| 
         @@ -112,7 +111,9 @@ Semantio/ 
     | 
|
| 
       112 
111 
     | 
    
         
             
            │   │   ├── __init__.py
         
     | 
| 
       113 
112 
     | 
    
         
             
            │   │   ├── openai.py            # OpenAI integration
         
     | 
| 
       114 
113 
     | 
    
         
             
            │   │   ├── anthropic.py         # Anthropic (Claude) integration
         
     | 
| 
       115 
     | 
    
         
            -
            │   │   ├──  
     | 
| 
      
 114 
     | 
    
         
            +
            │   │   ├── deepseek.py          # Deepseek integration
         
     | 
| 
      
 115 
     | 
    
         
            +
            │   │   ├── gemini.py            # Gemini integration
         
     | 
| 
      
 116 
     | 
    
         
            +
            │   │   ├── mistral.py           # Mistral integration
         
     | 
| 
       116 
117 
     | 
    
         
             
            │   │   └── base_llm.py          # Base class for LLMs
         
     | 
| 
       117 
118 
     | 
    
         
             
            │   ├── knowledge_base/          # Knowledge base integration
         
     | 
| 
       118 
119 
     | 
    
         
             
            │   │   ├── __init__.py
         
     | 
| 
         @@ -1,5 +1,5 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            semantio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       2 
     | 
    
         
            -
            semantio/agent.py,sha256= 
     | 
| 
      
 2 
     | 
    
         
            +
            semantio/agent.py,sha256=mwcKaHy-HY26hxgCRZS5LZw1semlj59qF4uYcLpyqBc,30247
         
     | 
| 
       3 
3 
     | 
    
         
             
            semantio/memory.py,sha256=eNAwyAokppHzMcIyFgOw2hT2wnLQBd9GL4T5eallNV4,281
         
     | 
| 
       4 
4 
     | 
    
         
             
            semantio/rag.py,sha256=ROy3Pa1NURcDs6qQZ8IMoa5Xlzt6I-msEq0C1p8UgB0,472
         
     | 
| 
       5 
5 
     | 
    
         
             
            semantio/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
         @@ -11,12 +11,15 @@ semantio/knowledge_base/__init__.py,sha256=mvp0GFiGSjcxlkaDulAwKOCL9s6gsKTqhPKXF 
     | 
|
| 
       11 
11 
     | 
    
         
             
            semantio/knowledge_base/document_loader.py,sha256=nix0yZJ-JJoDbhLkpg5bKDMvNrwykmknI7MRIn0N81k,1910
         
     | 
| 
       12 
12 
     | 
    
         
             
            semantio/knowledge_base/retriever.py,sha256=XpdzKS1UCncJImVMtG67VXMC7lp2eRzKnShjvktsFMM,1271
         
     | 
| 
       13 
13 
     | 
    
         
             
            semantio/knowledge_base/vector_store.py,sha256=4Zv9kfqDD3cfn_4R8ZoLKdAQCZRYo_IENP_KkLB_RPc,987
         
     | 
| 
       14 
     | 
    
         
            -
            semantio/llm/__init__.py,sha256 
     | 
| 
       15 
     | 
    
         
            -
            semantio/llm/anthropic.py,sha256 
     | 
| 
       16 
     | 
    
         
            -
            semantio/llm/base_llm.py,sha256= 
     | 
| 
       17 
     | 
    
         
            -
            semantio/llm/ 
     | 
| 
      
 14 
     | 
    
         
            +
            semantio/llm/__init__.py,sha256=-4uKcqo9fBrEbvfxGE01XVHL9qEG2vKXfy5hlnUsRbw,779
         
     | 
| 
      
 15 
     | 
    
         
            +
            semantio/llm/anthropic.py,sha256=-JTso9vr88T3JSipxE60uZjqDgfla1QFoSEBpXW2pXw,2054
         
     | 
| 
      
 16 
     | 
    
         
            +
            semantio/llm/base_llm.py,sha256=VFl_2S4kqYDuCTWIfWMbKU5aNbVqOCG33E4APOSHF90,668
         
     | 
| 
      
 17 
     | 
    
         
            +
            semantio/llm/deepseek.py,sha256=oxX-Uw0_lY2sstYs5KGBGFB_hAZUbZomPADdib1mY2M,1100
         
     | 
| 
      
 18 
     | 
    
         
            +
            semantio/llm/gemini.py,sha256=er3zv1jOvWQBGbPuv4fS4pR_c_abHyhroe-rkXupOO4,1959
         
     | 
| 
      
 19 
     | 
    
         
            +
            semantio/llm/groq.py,sha256=1AH30paKzDIQjBjWPQPN44QwFHsIOVwI-a587-cDIVc,4285
         
     | 
| 
       18 
20 
     | 
    
         
             
            semantio/llm/llama.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       19 
     | 
    
         
            -
            semantio/llm/ 
     | 
| 
      
 21 
     | 
    
         
            +
            semantio/llm/mistral.py,sha256=NpvaB1cE6-jMEBdT0mTf6Ca4Qq2LS8QivDKI6AgdRjE,1061
         
     | 
| 
      
 22 
     | 
    
         
            +
            semantio/llm/openai.py,sha256=I3ab-d_zFxm-TDhYk6t1PzDtElPJEEQ2eSiARBNIGi4,5174
         
     | 
| 
       20 
23 
     | 
    
         
             
            semantio/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       21 
24 
     | 
    
         
             
            semantio/storage/cloud_storage.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
       22 
25 
     | 
    
         
             
            semantio/storage/local_storage.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         
     | 
| 
         @@ -32,9 +35,9 @@ semantio/utils/date_utils.py,sha256=x3oqRGv6ee_KCJ0LvCqqZh_FSgS6YGOHBwZQS4TJetY, 
     | 
|
| 
       32 
35 
     | 
    
         
             
            semantio/utils/file_utils.py,sha256=b_cMuJINEGk9ikNuNHSn9lsmICWwvtnCDZ03ndH_S2I,1779
         
     | 
| 
       33 
36 
     | 
    
         
             
            semantio/utils/logger.py,sha256=TmGbP8BRjLMWjXi2GWzZ0RIXt70x9qX3FuIqghCNlwM,510
         
     | 
| 
       34 
37 
     | 
    
         
             
            semantio/utils/validation_utils.py,sha256=iwoxEb4Q5ILqV6tbesMjPWPCCoL3AmPLejGUy6q8YvQ,1284
         
     | 
| 
       35 
     | 
    
         
            -
            semantio-0.0. 
     | 
| 
       36 
     | 
    
         
            -
            semantio-0.0. 
     | 
| 
       37 
     | 
    
         
            -
            semantio-0.0. 
     | 
| 
       38 
     | 
    
         
            -
            semantio-0.0. 
     | 
| 
       39 
     | 
    
         
            -
            semantio-0.0. 
     | 
| 
       40 
     | 
    
         
            -
            semantio-0.0. 
     | 
| 
      
 38 
     | 
    
         
            +
            semantio-0.0.2.dist-info/LICENSE,sha256=teQbWD2Zlcl1_Fo29o2tNbs6G26hbCQiUzds5fQGYlY,1063
         
     | 
| 
      
 39 
     | 
    
         
            +
            semantio-0.0.2.dist-info/METADATA,sha256=LsBDOM1gPw6rbzZ_-TIf4XJxf3DEWZ7s8KDd8_cDMw0,6800
         
     | 
| 
      
 40 
     | 
    
         
            +
            semantio-0.0.2.dist-info/WHEEL,sha256=ewwEueio1C2XeHTvT17n8dZUJgOvyCWCt0WVNLClP9o,92
         
     | 
| 
      
 41 
     | 
    
         
            +
            semantio-0.0.2.dist-info/entry_points.txt,sha256=zbPgevSLwcLpdRHqI_atE8EOt8lK2vRF1AoDflDTo18,53
         
     | 
| 
      
 42 
     | 
    
         
            +
            semantio-0.0.2.dist-info/top_level.txt,sha256=Yte_6mb-bh-I_lQwMjk1GijZkxPoX4Zmp3kBftC1ZlA,9
         
     | 
| 
      
 43 
     | 
    
         
            +
            semantio-0.0.2.dist-info/RECORD,,
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     | 
| 
         
            File without changes
         
     |