Metadata-Version: 2.4
Name: sunholo
Version: 0.144.2
Summary: AI DevOps - a package to help deploy GenAI to the Cloud.
Author-email: Holosun ApS <multivac@sunholo.com>
License: Apache License, Version 2.0
Project-URL: Homepage, https://github.com/sunholo-data/sunholo-py
Project-URL: Download, https://github.com/sunholo-data/sunholo-py/archive/refs/tags/v0.118.0.tar.gz
Keywords: llms,devops,google_cloud_platform
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Build Tools
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE.txt
Requires-Dist: google-auth
Requires-Dist: pydantic
Requires-Dist: requests
Requires-Dist: ruamel.yaml
Requires-Dist: tenacity
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-asyncio>=1.0.0; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Provides-Extra: all
Requires-Dist: a2a-python>=0.0.1; extra == "all"
Requires-Dist: aiofiles; extra == "all"
Requires-Dist: aiohttp; extra == "all"
Requires-Dist: anthropic[vertex]; extra == "all"
Requires-Dist: asyncpg; extra == "all"
Requires-Dist: azure-identity; extra == "all"
Requires-Dist: azure-storage-blob; extra == "all"
Requires-Dist: fastapi; extra == "all"
Requires-Dist: fastmcp>=2.12.0; extra == "all"
Requires-Dist: flask>=3.1.0; extra == "all"
Requires-Dist: google-auth; extra == "all"
Requires-Dist: google-auth-httplib2; extra == "all"
Requires-Dist: google-auth-oauthlib; extra == "all"
Requires-Dist: google-cloud-aiplatform>=1.58.0; extra == "all"
Requires-Dist: google-api-python-client; extra == "all"
Requires-Dist: google-cloud-alloydb-connector[pg8000]; extra == "all"
Requires-Dist: google-cloud-bigquery; extra == "all"
Requires-Dist: google-cloud-build; extra == "all"
Requires-Dist: google-cloud-service-control; extra == "all"
Requires-Dist: google-cloud-logging; extra == "all"
Requires-Dist: google-cloud-storage; extra == "all"
Requires-Dist: google-cloud-pubsub; extra == "all"
Requires-Dist: google-cloud-discoveryengine>=0.13.4; extra == "all"
Requires-Dist: google-cloud-texttospeech; extra == "all"
Requires-Dist: google-generativeai>=0.7.1; extra == "all"
Requires-Dist: google-genai>=0.2.2; extra == "all"
Requires-Dist: gunicorn; extra == "all"
Requires-Dist: httpcore; extra == "all"
Requires-Dist: httpx; extra == "all"
Requires-Dist: jsonschema; extra == "all"
Requires-Dist: lancedb; extra == "all"
Requires-Dist: langchain>=0.2.16; extra == "all"
Requires-Dist: langchain-experimental>=0.0.61; extra == "all"
Requires-Dist: langchain-community>=0.2.11; extra == "all"
Requires-Dist: langchain-openai>=0.3.2; extra == "all"
Requires-Dist: langchain-google-genai>=2.0.9; extra == "all"
Requires-Dist: langchain_google_alloydb_pg; extra == "all"
Requires-Dist: langchain-anthropic>=0.1.23; extra == "all"
Requires-Dist: langchain-google-vertexai; extra == "all"
Requires-Dist: langchain-unstructured; extra == "all"
Requires-Dist: langfuse==2.60.9; extra == "all"
Requires-Dist: mcp>=1.1.1; extra == "all"
Requires-Dist: numpy; extra == "all"
Requires-Dist: opencv-python; extra == "all"
Requires-Dist: pg8000; extra == "all"
Requires-Dist: pgvector; extra == "all"
Requires-Dist: pillow; extra == "all"
Requires-Dist: playwright; extra == "all"
Requires-Dist: psutil; extra == "all"
Requires-Dist: psycopg2-binary; extra == "all"
Requires-Dist: pydantic; extra == "all"
Requires-Dist: pypdf; extra == "all"
Requires-Dist: pytest; extra == "all"
Requires-Dist: pytest-asyncio>=1.0.0; extra == "all"
Requires-Dist: pytest-cov; extra == "all"
Requires-Dist: python-hcl2; extra == "all"
Requires-Dist: python-socketio; extra == "all"
Requires-Dist: pytesseract; extra == "all"
Requires-Dist: requests; extra == "all"
Requires-Dist: rich; extra == "all"
Requires-Dist: sounddevice; extra == "all"
Requires-Dist: supabase; extra == "all"
Requires-Dist: tabulate; extra == "all"
Requires-Dist: tantivy; extra == "all"
Requires-Dist: tenacity; extra == "all"
Requires-Dist: tiktoken; extra == "all"
Requires-Dist: unstructured[all-docs,local-inference]; extra == "all"
Requires-Dist: xlwings; extra == "all"
Provides-Extra: langchain
Requires-Dist: langchain; extra == "langchain"
Requires-Dist: langchain_experimental; extra == "langchain"
Requires-Dist: langchain-community; extra == "langchain"
Requires-Dist: langsmith; extra == "langchain"
Requires-Dist: langchain-unstructured; extra == "langchain"
Provides-Extra: azure
Requires-Dist: azure-identity; extra == "azure"
Requires-Dist: azure-storage-blob; extra == "azure"
Provides-Extra: cli
Requires-Dist: jsonschema>=4.21.1; extra == "cli"
Requires-Dist: rich; extra == "cli"
Provides-Extra: database
Requires-Dist: asyncpg; extra == "database"
Requires-Dist: supabase; extra == "database"
Requires-Dist: sqlalchemy; extra == "database"
Requires-Dist: pg8000; extra == "database"
Requires-Dist: pgvector; extra == "database"
Requires-Dist: psycopg2-binary; extra == "database"
Requires-Dist: lancedb; extra == "database"
Requires-Dist: tantivy; extra == "database"
Provides-Extra: pipeline
Requires-Dist: GitPython; extra == "pipeline"
Requires-Dist: lark; extra == "pipeline"
Requires-Dist: langchain>=0.2.16; extra == "pipeline"
Requires-Dist: langchain-unstructured; extra == "pipeline"
Requires-Dist: psutil; extra == "pipeline"
Requires-Dist: pypdf; extra == "pipeline"
Requires-Dist: pytesseract; extra == "pipeline"
Requires-Dist: tabulate; extra == "pipeline"
Requires-Dist: unstructured[all-docs,local-inference]; extra == "pipeline"
Provides-Extra: gcp
Requires-Dist: a2a-python>=0.0.1; extra == "gcp"
Requires-Dist: aiofiles; extra == "gcp"
Requires-Dist: anthropic[vertex]; extra == "gcp"
Requires-Dist: google-api-python-client; extra == "gcp"
Requires-Dist: google-auth-httplib2; extra == "gcp"
Requires-Dist: google-auth-oauthlib; extra == "gcp"
Requires-Dist: google-cloud-alloydb-connector[pg8000]; extra == "gcp"
Requires-Dist: google-cloud-aiplatform>=1.58.0; extra == "gcp"
Requires-Dist: google-cloud-bigquery; extra == "gcp"
Requires-Dist: google-cloud-build; extra == "gcp"
Requires-Dist: google-cloud-service-control; extra == "gcp"
Requires-Dist: google-cloud-storage; extra == "gcp"
Requires-Dist: google-cloud-logging; extra == "gcp"
Requires-Dist: google-cloud-pubsub; extra == "gcp"
Requires-Dist: google-cloud-discoveryengine>=0.13.4; extra == "gcp"
Requires-Dist: google-cloud-texttospeech; extra == "gcp"
Requires-Dist: google-genai>=0.2.2; extra == "gcp"
Requires-Dist: google-generativeai>=0.8.3; extra == "gcp"
Requires-Dist: langchain; extra == "gcp"
Requires-Dist: langchain-google-genai>=2.0.0; extra == "gcp"
Requires-Dist: langchain_google_alloydb_pg>=0.2.2; extra == "gcp"
Requires-Dist: langchain-google-vertexai; extra == "gcp"
Requires-Dist: pillow; extra == "gcp"
Provides-Extra: ollama
Requires-Dist: pillow; extra == "ollama"
Requires-Dist: ollama>=0.4.7; extra == "ollama"
Provides-Extra: openai
Requires-Dist: langchain-openai>=0.3.2; extra == "openai"
Requires-Dist: tiktoken; extra == "openai"
Provides-Extra: anthropic
Requires-Dist: fastmcp>=2.12.0; extra == "anthropic"
Requires-Dist: langchain-anthropic>=0.1.23; extra == "anthropic"
Requires-Dist: mcp>=1.1.1; extra == "anthropic"
Provides-Extra: tools
Requires-Dist: openapi-spec-validator; extra == "tools"
Requires-Dist: playwright; extra == "tools"
Provides-Extra: http
Requires-Dist: aiohttp; extra == "http"
Requires-Dist: fastapi; extra == "http"
Requires-Dist: flask>=3.1.0; extra == "http"
Requires-Dist: gunicorn; extra == "http"
Requires-Dist: httpcore; extra == "http"
Requires-Dist: httpx; extra == "http"
Requires-Dist: langchain; extra == "http"
Requires-Dist: langfuse==2.60.9; extra == "http"
Requires-Dist: python-socketio; extra == "http"
Requires-Dist: requests; extra == "http"
Requires-Dist: tenacity; extra == "http"
Provides-Extra: excel
Requires-Dist: xlwings; extra == "excel"
Requires-Dist: requests; extra == "excel"
Requires-Dist: rich; extra == "excel"
Provides-Extra: iac
Requires-Dist: python-hcl2; extra == "iac"
Provides-Extra: tts
Requires-Dist: google-cloud-texttospeech; extra == "tts"
Requires-Dist: numpy; extra == "tts"
Requires-Dist: sounddevice; extra == "tts"
Provides-Extra: video
Requires-Dist: opencv-python; extra == "video"
Dynamic: license-file

# Sunholo Python Library

[![PyPi Version](https://img.shields.io/pypi/v/sunholo.svg)](https://pypi.python.org/pypi/sunholo/)
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Python Version](https://img.shields.io/pypi/pyversions/sunholo.svg)](https://pypi.python.org/pypi/sunholo/)

🚀 **AI DevOps framework for building GenAI applications on Google Cloud Platform**

Sunholo is a comprehensive Python framework that streamlines the development, deployment, and management of Generative AI applications (VACs - Virtual Agent Computers). It provides a configuration-driven approach with deep integration into Google Cloud services while supporting multiple AI providers.

## 🎯 What is Sunholo?

Sunholo helps you:
- 🤖 Build conversational AI agents with any LLM provider (Vertex AI, OpenAI, Anthropic, Ollama)
- ☁️ Deploy to Google Cloud Run with automatic scaling
- 🗄️ Use AlloyDB and Discovery Engine for vector storage and search
- 🔄 Handle streaming responses and async processing
- 📄 Process documents with chunking and embedding pipelines
- 🔧 Manage complex configurations with YAML files
- 🎨 Create APIs, web apps, and chat bots

## 🚀 Quick Start

### Prerequisites

Install [uv](https://docs.astral.sh/uv/) - a fast, modern Python package manager:

```bash
# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
```

### Installation

```bash
# Install with CLI tools (recommended)
uv tool install --from "sunholo[cli]" sunholo

# Install with all features including GCP
uv tool install --from "sunholo[cli]" sunholo --with "sunholo[all]"
```

### Your First VAC

1. **Initialize a new project:**
```bash
sunholo init my-ai-agent
cd my-ai-agent
```

2. **Configure your AI agent:**
Edit `config/vac_config.yaml`:
```yaml
kind: vacConfig
apiVersion: v1
vac:
  my-agent:
    llm: vertex
    model: gemini-1.5-pro
    agent: simple
    description: "My AI agent powered by Google Cloud"
```

3. **Chat with your agent locally:**
```bash
sunholo vac chat my-agent
```

4. **Run your agent as a local Flask app:**
```bash
sunholo deploy my-agent
```

## 📋 Features

### Core Capabilities

- **Multi-Model Support**: Integrate Vertex AI, OpenAI, Anthropic, Ollama in one app
- **Document Processing**: Chunk, embed, and index documents with Discovery Engine
- **Vector Databases**: Native support for AlloyDB, LanceDB, Supabase
- **Streaming**: Real-time response streaming for chat applications
- **Async Processing**: Pub/Sub integration for background tasks
- **Authentication**: Built-in Google Cloud IAM and custom auth

### Google Cloud Integration

- **Vertex AI**: Access Gemini, PaLM, and custom models
- **AlloyDB**: PostgreSQL-compatible vector database
- **Discovery Engine**: Enterprise search and RAG
- **Cloud Run**: Serverless deployment
- **Cloud Storage**: Document and file management
- **Pub/Sub**: Asynchronous message processing
- **Cloud Logging**: Centralized logging

### Framework Support

- **Web Frameworks**: Flask and FastAPI templates
- **AI Frameworks**: LangChain and LlamaIndex integration
- **MCP Integration**: Model Context Protocol server and client support
- **Observability**: Langfuse for tracing and monitoring
- **API Standards**: OpenAI-compatible endpoints

## 🛠 Installation Options

### Using uv

```bash
# Core CLI features
uv tool install --from "sunholo[cli]" sunholo

# With Google Cloud Platform integration
uv tool install --from "sunholo[cli]" sunholo --with "sunholo[gcp]"

# With specific LLM providers
uv tool install --from "sunholo[cli]" sunholo --with "sunholo[openai]"
uv tool install --from "sunholo[cli]" sunholo --with "sunholo[anthropic]"

# With database support
uv tool install --from "sunholo[cli]" sunholo --with "sunholo[database]"

# Everything
uv tool install --from "sunholo[cli]" sunholo --with "sunholo[all]"
```

### Managing Installations

```bash
# Upgrade
uv tool upgrade sunholo

# List installed
uv tool list

# Uninstall
uv tool uninstall sunholo
```

### Development Setup

```bash
# Clone repository
git clone https://github.com/sunholo-data/sunholo-py.git
cd sunholo-py

# Install in development mode
uv venv
uv pip install -e ".[all]"

# Run tests
pytest tests/
```

## ⚙️ Configuration

Sunholo uses YAML configuration files:

```yaml
# config/vac_config.yaml
kind: vacConfig
apiVersion: v1
gcp_config:
  project_id: my-gcp-project
  location: us-central1
vac:
  my-agent:
    llm: vertex
    model: gemini-1.5-pro
    agent: langchain
    memory:
      - alloydb:
          project_id: my-gcp-project
          region: us-central1
          cluster: my-cluster
          instance: my-instance
    tools:
      - search
      - calculator
```

## 🔧 CLI Commands

```bash
# Project Management
sunholo init <project-name>              # Create new project from template
sunholo list-configs                     # List all configurations
sunholo list-configs --validate          # Validate configurations

# Development
sunholo vac chat <vac-name>             # Chat with a VAC locally
sunholo vac list                        # List available VACs  
sunholo vac get-url <vac-name>          # Get Cloud Run URL for a VAC
sunholo proxy start <service>           # Start local proxy to cloud service
sunholo proxy list                      # List running proxies
sunholo deploy <vac-name>               # Run Flask app locally

# Document Processing
sunholo embed <vac-name>                # Process and embed documents
sunholo merge-text <folder> <output>    # Merge files for context

# Cloud Services
sunholo discovery-engine create <name>   # Create Discovery Engine instance
sunholo vertex list-extensions          # List Vertex AI extensions
sunholo swagger <vac-name>              # Generate OpenAPI spec

# Integration Tools
sunholo excel-init                      # Initialize Excel plugin
sunholo llamaindex <query>              # Query with LlamaIndex
sunholo mcp list-tools                  # List MCP tools
sunholo tts <text>                      # Text-to-speech synthesis
```

## 📝 Examples

### Chat with History Extraction

```python
from sunholo.utils import ConfigManager
from sunholo.components import pick_llm
from sunholo.agents import extract_chat_history

config = ConfigManager('my-agent')
llm = pick_llm(config=config)

# Extract chat history from messages
chat_history = [
    {"role": "user", "content": "Hello"},
    {"role": "assistant", "content": "Hi there!"}
]
history_str = extract_chat_history(chat_history)

# Use in prompt
response = llm.invoke(f"Given this history:\n{history_str}\n\nUser: How are you?")
```

### Document Processing with Chunker

```python
from sunholo.chunker import direct_file_to_embed
from sunholo.utils import ConfigManager

config = ConfigManager('my-agent')

# Process a file directly
result = direct_file_to_embed(
    "document.pdf",
    embed_prefix="doc",
    metadata={"source": "user_upload"},
    vectorstore=config.vacConfig("vectorstore")
)
```

### Vertex AI with Memory Tools

```python
from sunholo.vertex import get_vertex_memories
from sunholo.utils import ConfigManager

config = ConfigManager('my-agent')

# Get Vertex AI memory configuration
memory_config = get_vertex_memories(config)

# Use with Vertex AI
if memory_config:
    print(f"Memory tools configured: {memory_config}")
```

### Streaming Response with Flask

```python
from sunholo.agents import send_to_qa
from flask import Response, request

@app.route('/vac/streaming/<vac_name>', methods=['POST'])
def streaming_endpoint(vac_name):
    question = request.json.get('user_input')
    
    def generate():
        # Stream responses from the QA system
        response = send_to_qa(
            question, 
            vac_name=vac_name,
            stream=True
        )
        if hasattr(response, '__iter__'):
            for chunk in response:
                yield f"data: {chunk}\n\n"
        else:
            yield f"data: {response}\n\n"
    
    return Response(generate(), content_type='text/event-stream')
```

### Discovery Engine Integration

```python
from sunholo.discovery_engine import DiscoveryEngineClient

# Initialize client
client = DiscoveryEngineClient(
    project_id='my-project',
    data_store_id='my-datastore'
)

# Search documents
results = client.search("What is Vertex AI?")
for result in results:
    print(f"Content: {result.chunk.content}")
    print(f"Score: {result.relevance_score}")
```

## 🧪 Testing

```bash
# Run all tests
pytest tests/

# Run specific test file
pytest tests/test_config.py

# Run with coverage
pytest --cov=src/sunholo tests/

# Run async tests
pytest tests/test_async_genai2.py
```

## 📚 Documentation

- 📖 **Full Documentation**: https://dev.sunholo.com/
- 🎓 **Tutorials**: https://dev.sunholo.com/docs/howto/
- 🤖 **VAC Examples**: https://github.com/sunholo-data/vacs-public
- 🎧 **Audio Overview**: [Listen to the NotebookLM podcast](https://drive.google.com/file/d/1GvwRmiYDjPjN2hXQ8plhnVDByu6TmgCQ/view?usp=drive_link)

## 🤝 Contributing

We welcome contributions! See our [Contributing Guidelines](CONTRIBUTING.md).

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
3. Commit your changes (`git commit -m 'Add AmazingFeature'`)
4. Push to the branch (`git push origin feature/AmazingFeature`)
5. Open a Pull Request

## 📜 License

This project is licensed under the Apache License 2.0 - see the [LICENSE](LICENSE.txt) file for details.

```
Copyright [2024] [Holosun ApS]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0
```

## 🙏 Support

- 📧 Email: multivac@sunholo.com
- 🐛 Issues: [GitHub Issues](https://github.com/sunholo-data/sunholo-py/issues)
- 💬 Discussions: [GitHub Discussions](https://github.com/sunholo-data/sunholo-py/discussions)
- 📖 Documentation: https://dev.sunholo.com/
