Metadata-Version: 2.4
Name: ingenious
Version: 0.2.2
Summary: An enterprise-grade Python library for quickly setting up APIs to interact with AI Agents
Project-URL: Homepage, https://github.com/Insight-Services-APAC/ingenious
Project-URL: Documentation, https://insight-services-apac.github.io/ingenious/
Project-URL: Repository, https://github.com/Insight-Services-APAC/ingenious
Project-URL: Issues, https://github.com/Insight-Services-APAC/ingenious/issues
Author-email: John Rampono <john.rampono@insight.com>, Kokko Ng <kokko.ng@insight.com>, Elliot Zhu <elliot.zhu@insight.com>
License: MIT
License-File: LICENSE
Keywords: agent,autogen,azure,fastapi
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.13
Requires-Dist: aiofiles>=24.1.0
Requires-Dist: autogen-agentchat>=0.5.7
Requires-Dist: autogen-ext>=0.5.7
Requires-Dist: azure-identity>=1.17.1
Requires-Dist: azure-keyvault-secrets>=4.10.0
Requires-Dist: azure-search-documents>=11.5.2
Requires-Dist: azure-storage-blob>=12.25.1
Requires-Dist: chromadb>=1.0.11
Requires-Dist: dependency-injector==4.48.1
Requires-Dist: fastapi==0.115.9
Requires-Dist: flask>=3.1.1
Requires-Dist: jsonpickle==4.1.1
Requires-Dist: markdown>=3.8.2
Requires-Dist: openai>=1.82.0
Requires-Dist: pandas>=2.3.1
Requires-Dist: passlib>=1.7.4
Requires-Dist: psutil>=7.0.0
Requires-Dist: pydantic-settings>=2.10.1
Requires-Dist: pydantic==2.11.5
Requires-Dist: pyodbc>=5.2.0
Requires-Dist: python-dotenv>=1.0.1
Requires-Dist: python-jose>=3.5.0
Requires-Dist: structlog==25.4.0
Requires-Dist: tiktoken>=0.9.0
Requires-Dist: typer==0.16.0
Requires-Dist: uvicorn>=0.35.0
Provides-Extra: ai
Requires-Dist: autogen-agentchat==0.5.7; extra == 'ai'
Requires-Dist: autogen-ext[openai]==0.5.7; extra == 'ai'
Requires-Dist: openai==1.82.0; extra == 'ai'
Provides-Extra: auth
Requires-Dist: bcrypt==4.3.0; extra == 'auth'
Requires-Dist: passlib==1.7.4; extra == 'auth'
Requires-Dist: python-jose[cryptography]==3.5.0; extra == 'auth'
Provides-Extra: azure
Requires-Dist: azure-core==1.34.0; extra == 'azure'
Requires-Dist: azure-cosmos==4.9.0; extra == 'azure'
Requires-Dist: azure-identity==1.17.1; extra == 'azure'
Requires-Dist: azure-keyvault==4.2.0; extra == 'azure'
Requires-Dist: azure-search-documents==11.5.2; extra == 'azure'
Requires-Dist: azure-storage-blob==12.25.1; extra == 'azure'
Provides-Extra: azure-full
Requires-Dist: aiosqlite==0.21.0; extra == 'azure-full'
Requires-Dist: autogen-agentchat==0.5.7; extra == 'azure-full'
Requires-Dist: autogen-ext[openai]==0.5.7; extra == 'azure-full'
Requires-Dist: azure-core==1.34.0; extra == 'azure-full'
Requires-Dist: azure-cosmos==4.9.0; extra == 'azure-full'
Requires-Dist: azure-identity==1.17.1; extra == 'azure-full'
Requires-Dist: azure-keyvault==4.2.0; extra == 'azure-full'
Requires-Dist: azure-search-documents==11.5.2; extra == 'azure-full'
Requires-Dist: azure-storage-blob==12.25.1; extra == 'azure-full'
Requires-Dist: bcrypt==4.3.0; extra == 'azure-full'
Requires-Dist: fastapi-cli==0.0.7; extra == 'azure-full'
Requires-Dist: flask==3.1.1; extra == 'azure-full'
Requires-Dist: jinja2==3.1.6; extra == 'azure-full'
Requires-Dist: openai==1.82.0; extra == 'azure-full'
Requires-Dist: passlib==1.7.4; extra == 'azure-full'
Requires-Dist: psutil==7.0.0; extra == 'azure-full'
Requires-Dist: pyodbc==5.2.0; extra == 'azure-full'
Requires-Dist: python-dotenv==1.0.1; extra == 'azure-full'
Requires-Dist: python-jose[cryptography]==3.5.0; extra == 'azure-full'
Provides-Extra: core
Requires-Dist: aiosqlite==0.21.0; extra == 'core'
Requires-Dist: fastapi-cli==0.0.7; extra == 'core'
Requires-Dist: jinja2==3.1.6; extra == 'core'
Requires-Dist: python-dotenv==1.0.1; extra == 'core'
Provides-Extra: database
Requires-Dist: psutil==7.0.0; extra == 'database'
Requires-Dist: pyodbc==5.2.0; extra == 'database'
Provides-Extra: dataprep
Requires-Dist: backoff==2.2.0; extra == 'dataprep'
Requires-Dist: python-dotenv==1.0.1; extra == 'dataprep'
Requires-Dist: scrapfly-sdk==0.8.23; extra == 'dataprep'
Provides-Extra: development
Requires-Dist: ipython==9.2.0; extra == 'development'
Provides-Extra: document-advanced
Requires-Dist: pdfminer-six==20250506; extra == 'document-advanced'
Requires-Dist: unstructured[all-docs]==0.17.2; extra == 'document-advanced'
Provides-Extra: document-processing
Requires-Dist: azure-ai-documentintelligence==1.0.2; extra == 'document-processing'
Requires-Dist: psutil==7.0.0; extra == 'document-processing'
Requires-Dist: pymupdf==1.26.1; extra == 'document-processing'
Provides-Extra: full
Requires-Dist: aiosqlite==0.21.0; extra == 'full'
Requires-Dist: autogen-agentchat==0.5.7; extra == 'full'
Requires-Dist: autogen-ext[openai]==0.5.7; extra == 'full'
Requires-Dist: azure-ai-documentintelligence==1.0.2; extra == 'full'
Requires-Dist: azure-core==1.34.0; extra == 'full'
Requires-Dist: azure-cosmos==4.9.0; extra == 'full'
Requires-Dist: azure-identity==1.17.1; extra == 'full'
Requires-Dist: azure-keyvault==4.2.0; extra == 'full'
Requires-Dist: azure-search-documents==11.5.2; extra == 'full'
Requires-Dist: azure-storage-blob==12.25.1; extra == 'full'
Requires-Dist: backoff==2.2.0; extra == 'full'
Requires-Dist: bcrypt==4.3.0; extra == 'full'
Requires-Dist: chromadb==1.0.11; extra == 'full'
Requires-Dist: fastapi-cli==0.0.7; extra == 'full'
Requires-Dist: flask==3.1.1; extra == 'full'
Requires-Dist: jinja2==3.1.6; extra == 'full'
Requires-Dist: matplotlib==3.10.3; extra == 'full'
Requires-Dist: openai==1.82.0; extra == 'full'
Requires-Dist: passlib==1.7.4; extra == 'full'
Requires-Dist: psutil==7.0.0; extra == 'full'
Requires-Dist: pymupdf==1.26.1; extra == 'full'
Requires-Dist: pyodbc==5.2.0; extra == 'full'
Requires-Dist: python-dotenv==1.0.1; extra == 'full'
Requires-Dist: python-jose[cryptography]==3.5.0; extra == 'full'
Requires-Dist: scrapfly-sdk==0.8.23; extra == 'full'
Requires-Dist: seaborn==0.13.2; extra == 'full'
Requires-Dist: sentence-transformers==5.0.0; extra == 'full'
Provides-Extra: knowledge-base
Requires-Dist: aiosqlite==0.21.0; extra == 'knowledge-base'
Requires-Dist: autogen-agentchat==0.5.7; extra == 'knowledge-base'
Requires-Dist: autogen-ext[openai]==0.5.7; extra == 'knowledge-base'
Requires-Dist: chromadb==1.0.11; extra == 'knowledge-base'
Requires-Dist: fastapi-cli==0.0.7; extra == 'knowledge-base'
Requires-Dist: jinja2==3.1.6; extra == 'knowledge-base'
Requires-Dist: openai==1.82.0; extra == 'knowledge-base'
Requires-Dist: python-dotenv==1.0.1; extra == 'knowledge-base'
Requires-Dist: sentence-transformers==5.0.0; extra == 'knowledge-base'
Provides-Extra: minimal
Provides-Extra: ml
Requires-Dist: chromadb==1.0.11; extra == 'ml'
Requires-Dist: sentence-transformers==5.0.0; extra == 'ml'
Provides-Extra: standard
Requires-Dist: aiosqlite==0.21.0; extra == 'standard'
Requires-Dist: autogen-agentchat==0.5.7; extra == 'standard'
Requires-Dist: autogen-ext[openai]==0.5.7; extra == 'standard'
Requires-Dist: bcrypt==4.3.0; extra == 'standard'
Requires-Dist: fastapi-cli==0.0.7; extra == 'standard'
Requires-Dist: jinja2==3.1.6; extra == 'standard'
Requires-Dist: openai==1.82.0; extra == 'standard'
Requires-Dist: passlib==1.7.4; extra == 'standard'
Requires-Dist: psutil==7.0.0; extra == 'standard'
Requires-Dist: pyodbc==5.2.0; extra == 'standard'
Requires-Dist: python-dotenv==1.0.1; extra == 'standard'
Requires-Dist: python-jose[cryptography]==3.5.0; extra == 'standard'
Provides-Extra: ui
Requires-Dist: flask==3.1.1; extra == 'ui'
Provides-Extra: visualization
Requires-Dist: matplotlib==3.10.3; extra == 'visualization'
Requires-Dist: seaborn==0.13.2; extra == 'visualization'
Description-Content-Type: text/markdown

# Insight Ingenious

[![Version](https://img.shields.io/badge/version-0.2.2-blue.svg)](https://github.com/Insight-Services-APAC/ingenious)
[![Python](https://img.shields.io/badge/python-3.13+-green.svg)](https://www.python.org/downloads/)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/Insight-Services-APAC/ingenious)
[![License](https://img.shields.io/badge/license-MIT-purple.svg)](LICENSE)

An enterprise-grade Python library for quickly setting up APIs to interact with AI Agents. Features multi-agent conversation flows using Microsoft's AutoGen, JWT authentication, and comprehensive Azure service integrations with support for both cloud and local implementations.

## Quick Start

Get up and running in 5 minutes with Azure OpenAI!

### Prerequisites
- Python 3.13 or higher (required - earlier versions are not supported)
- Azure OpenAI API credentials
- [uv package manager](https://docs.astral.sh/uv/)

### 5-Minute Setup

1. **Install and Initialize**:
    ```bash
    # Navigate to your desired project directory first
    cd /path/to/your/project

    # Set up the uv project
    uv init

    # Choose installation based on features needed
    uv add ingenious[standard] # Most common: includes SQL agent support (core, auth, ai, database)
    # OR
    uv add ingenious[azure-full] # Full Azure integration (core, auth, azure, ai, database, ui)
    # OR
    uv add ingenious # Minimal installation (base dependencies only)

    # Initialize project in the current directory
    uv run ingen init
    ```

2. **Configure Credentials**:
    Create a `.env` file with your Azure OpenAI credentials:
    ```bash
    # Create .env file in current directory
    touch .env

    # Edit .env file with your actual credentials
    ```

    **Required configuration (add to .env file)**:
    ```bash
    # Model Configuration (only INGENIOUS_* variables are used by the system)
    INGENIOUS_MODELS__0__MODEL=gpt-4.1-nano
    INGENIOUS_MODELS__0__API_TYPE=rest
    INGENIOUS_MODELS__0__API_VERSION=2024-12-01-preview
    INGENIOUS_MODELS__0__DEPLOYMENT=your-gpt4-deployment-name
    INGENIOUS_MODELS__0__API_KEY=your-actual-api-key-here
    INGENIOUS_MODELS__0__BASE_URL=https://your-resource.openai.azure.com/

    # Basic required settings
    INGENIOUS_CHAT_SERVICE__TYPE=multi_agent
    INGENIOUS_CHAT_HISTORY__DATABASE_TYPE=sqlite
    INGENIOUS_CHAT_HISTORY__DATABASE_PATH=./.tmp/chat_history.db
    INGENIOUS_CHAT_HISTORY__MEMORY_PATH=./.tmp

    # Optional: Authentication settings (enabled by default)
    # INGENIOUS_WEB_CONFIGURATION__ENABLE_AUTHENTICATION=false  # To disable auth
    ```

3. **Validate Configuration**:
    ```bash
    uv run ingen validate  # Check configuration before starting
    ```

    **If validation fails with port conflicts**:
    ```bash
    # Check if validation passes with different port
    INGENIOUS_WEB_CONFIGURATION__PORT=8001 uv run ingen validate

    # Or update your .env file before validating:
    echo "INGENIOUS_WEB_CONFIGURATION__PORT=8001" >> .env
    uv run ingen validate
    ```

    > **⚠️ BREAKING CHANGE**: Ingenious now uses **pydantic-settings** for configuration via environment variables. Legacy YAML configuration files (`config.yml`, `profiles.yml`) are **no longer supported** and must be migrated to environment variables with `INGENIOUS_` prefixes. Use the migration script:
    > ```bash
    > uv run python scripts/migrate_config.py --yaml-file config.yml --output .env
    > uv run python scripts/migrate_config.py --yaml-file profiles.yml --output .env.profiles
    > ```

4. **Start the Server**:
    ```bash
    # Start server on port 8000 (recommended for development)
    uv run ingen serve --port 8000

    # Additional options:
    # --host 0.0.0.0         # Bind host (default: 0.0.0.0)
    # --port                 # Port to bind (default: 80 or $WEB_PORT env var)
    # --config config.yml    # Legacy config file (deprecated - use environment variables)
    # --profile production   # Legacy profile (deprecated - use environment variables)
    ```

5. **Verify Health**:
    ```bash
    # Check server health
    curl http://localhost:8000/api/v1/health
    ```

### Common Issues

#### Port Conflicts
If you encounter "Address already in use" or validation fails with port conflicts:

1. **Check what's using the port**:
   ```bash
   lsof -i :8000  # Check if port 8000 is in use
   ```

2. **Use a different port**:
   ```bash
   uv run ingen serve --port 8001  # Try port 8001 instead
   ```

3. **Set port via environment variable** (recommended):
   ```bash
   # Add to your .env file
   INGENIOUS_WEB_CONFIGURATION__PORT=8001
   ```

4. **Update your test commands accordingly**:
   ```bash
   # Update health check
   curl http://localhost:8001/api/v1/health

   # Update workflow tests (use the new port in all examples below)
   ```

6. **Test with Core Workflows**:

    Create test files to avoid JSON escaping issues:
    ```bash
    # Create test files for each workflow
    echo '{"user_prompt": "Analyze this customer feedback: Great product", "conversation_flow": "classification-agent"}' > test_classification.json
    echo '{"user_prompt": "Search for documentation about setup", "conversation_flow": "knowledge-base-agent"}' > test_knowledge.json
    echo '{"user_prompt": "Show me all tables in the database", "conversation_flow": "sql-manipulation-agent"}' > test_sql.json

    # Test each workflow
    curl -X POST http://localhost:8000/api/v1/chat -H "Content-Type: application/json" -d @test_classification.json
    curl -X POST http://localhost:8000/api/v1/chat -H "Content-Type: application/json" -d @test_knowledge.json
    curl -X POST http://localhost:8000/api/v1/chat -H "Content-Type: application/json" -d @test_sql.json
    ```

**Expected Responses**:
- **Successful classification-agent response**: JSON with message analysis and categories
- **Successful knowledge-base-agent response**: JSON with relevant information retrieved (may indicate empty knowledge base initially)
- **Successful sql-manipulation-agent response**: JSON with query results or confirmation

**If you see error responses**, check the troubleshooting section above or the detailed [troubleshooting guide](docs/getting-started/troubleshooting.md).

That's it! You should see a JSON response with AI analysis of the input.

**Next Steps - Test Additional Workflows**:

7. **Test bike-insights Workflow (Requires `ingen init` first)**:

    The `bike-insights` workflow is part of the project template and must be initialized first:
    ```bash
    # First initialize project to get bike-insights workflow
    uv run ingen init

    # Create bike-insights test data file
    # IMPORTANT: bike-insights requires JSON data in the user_prompt field (double-encoded JSON)
    # Method 1: Use printf for precise formatting (recommended)
    printf '%s\n' '{
      "user_prompt": "{\"revision_id\": \"test-v1\", \"identifier\": \"test-001\", \"stores\": [{\"name\": \"Test Store\", \"location\": \"NSW\", \"bike_sales\": [{\"product_code\": \"MB-TREK-2021-XC\", \"quantity_sold\": 2, \"sale_date\": \"2023-04-01\", \"year\": 2023, \"month\": \"April\", \"customer_review\": {\"rating\": 4.5, \"comment\": \"Great bike\"}}], \"bike_stock\": []}]}",
      "conversation_flow": "bike-insights"
    }' > test_bike_insights.json

    # Method 2: Alternative using echo (simpler but watch for shell differences)
    echo '{
      "user_prompt": "{\"revision_id\": \"test-v1\", \"identifier\": \"test-001\", \"stores\": [{\"name\": \"Test Store\", \"location\": \"NSW\", \"bike_sales\": [{\"product_code\": \"MB-TREK-2021-XC\", \"quantity_sold\": 2, \"sale_date\": \"2023-04-01\", \"year\": 2023, \"month\": \"April\", \"customer_review\": {\"rating\": 4.5, \"comment\": \"Great bike\"}}], \"bike_stock\": []}]}",
      "conversation_flow": "bike-insights"
    }' > test_bike_insights.json

    # Method 3: If heredoc is preferred, ensure proper EOF placement
    cat > test_bike_insights.json << 'EOF'
    {
    "user_prompt": "{\"revision_id\": \"test-v1\", \"identifier\": \"test-001\", \"stores\": [{\"name\": \"Test Store\", \"location\": \"NSW\", \"bike_sales\": [{\"product_code\": \"MB-TREK-2021-XC\", \"quantity_sold\": 2, \"sale_date\": \"2023-04-01\", \"year\": 2023, \"month\": \"April\", \"customer_review\": {\"rating\": 4.5, \"comment\": \"Great bike\"}}], \"bike_stock\": []}]}",
    "conversation_flow": "bike-insights"
    }
    EOF

    # Test bike-insights workflow
    curl -X POST http://localhost:8000/api/v1/chat -H "Content-Type: application/json" -d @test_bike_insights.json
    ```

    **Expected bike-insights response**: JSON with comprehensive bike sales analysis from multiple agents (fiscal analysis, customer sentiment, summary, and bike lookup).

**Important Notes**:
- **Core Library Workflows** (`classification-agent`, `knowledge-base-agent`, `sql-manipulation-agent`) are always available and accept simple text prompts
- **Template Workflows** like `bike-insights` require JSON-formatted data with specific fields and are only available after running `ingen init`
- The `bike-insights` workflow is the recommended "Hello World" example for new users

## Workflow Categories

Insight Ingenious provides multiple conversation workflows with different configuration requirements:

### Core Library Workflows (Always Available)
These workflows are built into the Ingenious library and available immediately:

- `classification-agent` - Simple text classification and routing to categories (minimal config required)
- `knowledge-base-agent` - Search and retrieve information from knowledge bases (requires Azure Search or uses local ChromaDB by default)
- `sql-manipulation-agent` - Execute SQL queries based on natural language (requires Azure SQL or uses local SQLite by default)

> **Note**: Core workflows support both hyphenated (`classification-agent`) and underscored (`classification_agent`) naming formats for backward compatibility.

### Template Workflows (Created by `ingen init`)
These workflows are provided as examples in the project template when you run `ingen init`:

- `bike-insights` - Comprehensive bike sales analysis showcasing multi-agent coordination (**ONLY available after `ingen init`** - not included in the core library)

> **Important**: The `bike-insights` workflow is NOT part of the core library. It's a template example that's created when you initialize a new project with `ingen init`. This is the recommended "Hello World" example for learning how to build custom workflows.

### Configuration Requirements by Workflow
- **Minimal setup** (Azure OpenAI only): `classification-agent`, `bike-insights` (after `ingen init`)
- **Local implementations**: `knowledge-base-agent` (ChromaDB), `sql-manipulation-agent` (SQLite) - stable and work out-of-the-box
- **Azure integrations**: Azure Search for knowledge base, Azure SQL for database queries - fully supported with proper configuration

> **Note**: Both local (ChromaDB, SQLite) and Azure (Azure Search, Azure SQL) implementations are production-ready. Choose based on your infrastructure requirements. Use `uv run ingen workflows` to check configuration requirements for each workflow.

## Troubleshooting

For common issues like port conflicts, configuration errors, or workflow problems, see the [detailed troubleshooting guide](docs/getting-started/troubleshooting.md).

**Quick fixes for common issues**:
- **Port conflicts**: Use `--port 8001` or set `INGENIOUS_WEB_CONFIGURATION__PORT=8001` in .env
- **JSON escaping errors**: Use file-based approach with heredoc as shown in bike-insights example above
- **Validation failures**: Check the troubleshooting guide for specific error solutions
- **Workflow not found**: Ensure you've run `uv run ingen init` for template workflows like bike-insights
- **Azure OpenAI connection issues**: Verify your API key, endpoint, and deployment name in .env file

## Documentation

For detailed documentation, see the [docs](https://insight-services-apac.github.io/ingenious/).

## Contributing

Contributions are welcome! Please see [CONTRIBUTING.md](https://github.com/Insight-Services-APAC/ingenious/blob/main/CONTRIBUTING.md) for guidelines.

## License

This project is licensed under the terms specified in the [LICENSE](https://github.com/Insight-Services-APAC/ingenious/blob/main/LICENSE) file.
