Metadata-Version: 2.4
Name: xecai
Version: 0.1.0
Summary: Add your description here
Author: Adrian Vispalia
License: MIT License
        
        Copyright (c) 2026 Adrian Vispalia Moreno
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: pydantic>=2.12.5
Provides-Extra: aws
Requires-Dist: aiobotocore>=3.2.0; extra == "aws"
Requires-Dist: boto3>=1.42.55; extra == "aws"
Provides-Extra: google
Requires-Dist: google-genai>=1.65.0; extra == "google"
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.84.0; extra == "anthropic"
Provides-Extra: openai
Requires-Dist: openai>=2.24.0; extra == "openai"
Provides-Extra: redis
Requires-Dist: redis>=5.0.0; extra == "redis"
Provides-Extra: postgresql
Requires-Dist: psycopg[binary,pool]>=3.1.18; extra == "postgresql"
Requires-Dist: pgvector>=0.2.5; extra == "postgresql"
Provides-Extra: pinecone
Requires-Dist: pinecone>=8.1.0; extra == "pinecone"
Provides-Extra: all
Requires-Dist: aiobotocore>=3.2.0; extra == "all"
Requires-Dist: boto3>=1.42.55; extra == "all"
Requires-Dist: google-genai>=1.65.0; extra == "all"
Requires-Dist: anthropic>=0.84.0; extra == "all"
Requires-Dist: openai>=2.24.0; extra == "all"
Requires-Dist: redis>=5.0.0; extra == "all"
Requires-Dist: motor>=3.3.2; extra == "all"
Requires-Dist: psycopg[binary,pool]>=3.1.18; extra == "all"
Requires-Dist: pinecone>=8.1.0; extra == "all"
Requires-Dist: pgvector>=0.2.5; extra == "all"
Dynamic: license-file

# Xecai - Cross compatible and extendable AI interface

Develop code for different LLMs and AI services, change very few lines. Easily customise the behaviour so that it fits your requirements.


> This library is currently focused on RAG purposes, no Agent implementation (this may change in the future).


## Examples

### Chat interface

<details>

```python
from chat.implementations.openai.openai_chat import OpenAIChat


messages = [Message(content="what model are you?", message_type=MessageType.USER)]
prompt = "you are a helpful bot"
model = "gpt-4o"
chat = OpenAIChat()
chat.check_model(model)

response, stats = chat.invoke(model, prompt, messages)
print(response)

for text, stats in chat.stream(model, prompt, messages):
    if text:
        print(text, end="", flush=True)
```

</details>


### VectorDB interface

<details>

```python
from vector_db.implementations.postgresql.postgresql_vector_db import PostgreSQLVectorDB
from embeddings.implementations.openai.openai_embedding import OpenAIEmbedding
from models import SearchType

vector_db = PostgreSQLVectorDB(
    embedding_interface=OpenAIEmbedding(), embedding_model="text-embedding-3-small"
)

chunks = vector_db.sync_retrieve(
    query="this is an example query",
    k=3,
    search_type=SearchType.HYBRID,
)
print(chunks)
```

</details>

### Memory interface

<details>

```python
from memory.implementations.postgresql.postgresql_memory import PostgreSQLMemory
from models import Conversation, Message, MessageType

memory = PostgreSQLMemory()

conversation = memory.sync_get_conversation("example_conversation_id") else Conversation()
print(conversation)

conversation.messages.append(Message(message_type=MessageType.USER, content="example query"))
memory.sync_save_conversation(conversation)
```

</details>


## Typical rag workflow

```mermaid
graph TD
    %% Refined Palette with Intense Cherry and Ink Black
    %% Outlines perfectly hidden by matching stroke to fill color
    
    classDef input fill:#0074D9,stroke:#0074D9,color:#FFFFFF,font-weight:bold,rx:8,ry:8;
    classDef process fill:#003366,stroke:#003366,color:#FFFFFF,rx:8,ry:8;
    classDef condition fill:#FF851B,stroke:#FF851B,color:#FFFFFF,font-weight:bold,rx:8,ry:8;
    
    %% Lighter Grey for the output node
    classDef output fill:#F8FAFC,stroke:#F8FAFC,color:#0B0F19,font-weight:bold,rx:8,ry:8;
    
    %% Intense Cherry
    classDef condense fill:#BA0C2F,stroke:#BA0C2F,color:#FFFFFF,rx:8,ry:8;
    
    %% Ink Black
    classDef retrieve fill:#0B0F19,stroke:#0B0F19,color:#FFFFFF,rx:8,ry:8;

    %% Clean, subtle slate-gray connecting lines
    linkStyle default stroke:#A0AAB2,stroke-width:2px,fill:none;

    %% Nodes
    Query([Receive User Query]):::input
    FetchHistory[Fetch Conversation History]:::process
    CheckHistory{History Exists?}:::condition
    CondenseQuery[Condense Query with Context]:::condense
    RetrieveChunks[(Retrieve Context Chunks)]:::retrieve
    LLMResponse([Generate LLM Response]):::output

    %% Flow
    Query --> FetchHistory
    FetchHistory --> CheckHistory
    CheckHistory -- "Yes" --> CondenseQuery
    CheckHistory -- "No" --> RetrieveChunks
    CondenseQuery --> RetrieveChunks
    RetrieveChunks --> LLMResponse
```

You can find an example of the typical RAG implemented with FastAPI on `examples/simple_rag.py`.


## Differences with projects that have a  similar objective

| Library | Notes |
| ------- | ----- |
| JustLLMs | Requests are made directly with http. More LLMs supported and many more features (agents, tools, etc.). I personally prefer using the official SDKs.  |
| LiteLLM & Agents SDK + LiteLLM | Local proxy router where you send the requests to be translated, adds complexity to the project and another element to the infrastructure. |
| LangChain | The most popular one. Bloated in some features, complex implementations that make it difficult to change its behaviours. |
| OpenRouter | All requests are sent to a 3rd party + additional charges. |

## Notes

- I will implement Azure OpenAI's chat implementation if this gets enough traction (I don't want to loose my free Azure credits unless it is worth it).
- Retries are left to the user to put and customise (check out `examples/retry_example.py`), as it adds a lot of complexity to have a default retry logic but also let the user modify it.
- Agents and tools will be evaluated later, the focus is to make this library simple and not bloated, providing the core functionalities and letting you easily extend them.
