diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..3273495 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,64 @@ +# Contributing to Dograh AI + +First off β€” thank you for considering contributing! πŸŽ‰ +Dograh AI is open source because we believe the future of voice AI should stay in the hands of developers and the community. + +For now, this guide will get you started. Future documentation will be more comprehensive and is under progress. +πŸ‘‰ Join us β†’ [Dograh Community Slack](https://join.slack.com/t/dograh-community/shared_invite/zt-3czr47sw5-MSg1J0kJ7IMPOCHF~03auQ) + + + +## πŸ™Œ How You Can Contribute + +- πŸ› **Report bugs** via GitHub Issues +- πŸ’‘ **Suggest features** +- πŸ”§ **Submit pull requests** +- πŸ“– **Improve documentation** β€” even fixing typos helps! +- πŸ’¬ **Join the Slack community** β€” the cornerstone of our collaboration + + + +## 🧰 Issue Types + +On our [GitHub Issues page](../../issues), you’ll find these categories: + +- πŸ“„ **Documentation change request** +- ✨ **Feature request** +- 🐞 **Bug report** +- ❓ **General questions** +- πŸ”’ **Security vulnerability report** + +πŸ‘‰ A great place to start is with issues tagged **`good first issue`**. + + + +## πŸ›  Development Guidelines + +- Keep PRs focused and scoped. +- Follow Python best practices (PEP8). +- Please **link the issue** in your PR description using: fixes # + +This auto-closes the issue when merged. + + + +## πŸš€ Getting Started +- Fork the repository +- Create your feature branch (git checkout -b feature/AmazingFeature) +- Commit your changes (git commit -m 'Add some AmazingFeature') +- Push to the branch (git push origin feature/AmazingFeature) +Open a Pull Request πŸŽ‰ + + + +## πŸ’¬ Community & Contribution Hub +Our Slack community is not just for support β€” it’s the cornerstone of Dograh AI contributions. Here, you can: +- Connect with maintainers and other contributors +- Discuss issues and features before coding +- Get help with setup and debugging +- Stay up to date with contribution sprints + + +πŸ‘‰ Join us β†’ [Dograh Community Slack](https://join.slack.com/t/dograh-community/shared_invite/zt-3czr47sw5-MSg1J0kJ7IMPOCHF~03auQ) + +Thank you for helping us keep Dograh AI open and thriving! πŸ’œ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c7bcf29 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +BSD 2-Clause License + +Copyright (c) 2025, Zansat Technologies Private Limited + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..d4494ce --- /dev/null +++ b/README.md @@ -0,0 +1,158 @@ + + + +# Dograh AI + + + + +

+ + License: BSD 2-Clause + + + Slack Community + + + Docker Ready + +

+ +The fastest way to build voice bots - get started with any voice AI use case in under 2 minutes (our hard SLA standards). +Build voice agents in just one line or drag-and-drop, then test them using AI personas that mimic real customer calls. It's 100% open source, self-hosted if you want, and never hides a line of code- ever. The project has a strong commitment to **100% open source** and every line of code is released in the open. +Maintained by YC alumni and exit founders, we're making sure the future of voice AI stays open, not monopolized. + +## πŸŽ₯ Demo Video +πŸ“Ί [Watch 1-min demo video](#) *(coming soon)* + +## πŸš€ Quickstart + +### Prerequisites + +To run Dograh AI locally, make sure you have the following installed: + +- [Docker](https://docs.docker.com/get-docker/) +- [Docker Compose](https://docs.docker.com/compose/install/) +- [curl](https://curl.se/download.html) – usually preinstalled on macOS/Linux + + +> **Note** +> Make sure Docker Desktop (or your system’s Docker service) is running before you begin. + +## πŸš€ Get Started + +The only commands you need to run: + +```bash +curl -o docker-compose.yml https://raw.githubusercontent.com/Flagsmith/flagsmith/main/docker-compose.yml +docker-compose -f docker-compose.yml up +```` + +> **Note** +> Open your browser at http://localhost:3000 and create your first AI voice assistant for the usecase you want! + +### πŸŽ™οΈ Your First Voice Bot + +1. **Open Dashboard**: Launch [http://localhost:3000](http://localhost:3000) on your browser +2. **Choose Call Type**: Select **Inbound** or **Outbound** calling. +3. **Name Your Bot**: Use a short two-word name (e.g., *Lead Qualification*). +4. **Describe Use Case**: In 5–10 words (e.g., *Screen insurance form submissions for purchase intent*). +5. **Launch**: Your bot is ready! Open the bot and click **Web Call** to talk to it. +6. **No API Keys Needed**: We auto-generate Dograh API keys so you can start immediately. You can switch to your own keys anytime. +7. **Default Access**: Includes Dograh’s own LLMs, STT, and TTS stack by default. +8. **Bring Your Own Keys**: Optionally connect your own API keys for LLMs, STT, TTS, or telephony providers like Twilio. + +## Quick Summary +⚑ 2-Minute Setup: Hard SLA standards - from zero to working voice bot in under 2 minutes +- πŸ”§ Minimal setup: Just [run docker command](#get-started) and you're live +- πŸ€– AI Testing Personas: Test your bots with LoopTalk AI that mimics real customer interactions +- πŸ”“ 100% Open Source: Every line of code is open - no hidden logic, no black boxes +- πŸ”„ Flexible Integration: Bring your own LLM, TTS, or STT - or use Dograh’s API’s +- ☁️ Self-Host or Cloud: Run locally or use our hosted version at app.dograh.com + + +## Features +### Voice Capabilities +- Telephony: Built-in Twilio integration (easily add others) +- Languages: English support (expandable to other languages) +- Custom Models: Bring your own TTS/STT models +- Real-time Processing: Low-latency voice interactions + +### Developer Experience +- Zero Config Start: Auto-generated API keys for instant testing +- Python-Based: Built on Python for easy customization +- Docker-First: Containerized for consistent deployments +- Modular Architecture: Swap components as needed + +### Testing & Quality +- LoopTalk (Beta): Create AI personas to test your voice agents +- Workflow Testing: Test specific workflow IDs with automated calls +- Real-world Simulation: AI personas that mimic actual customer behavior + +## Configuration +Dograh automatically generates API keys on first run, but you can use your own keys. + - OPENAI_API_KEY=your_key_here + - TWILIO_ACCOUNT_SID=your_sid_here + - TWILIO_AUTH_TOKEN=your_token_here + +## Architecture +Architecture diagram *(coming soon)* + +## Deployment Options +### Local Development +Refer [prerequisites](#Prerequisites) and [first steps](#get-started) + +### Production (Self-Hosted) +Production guide coming soon. [Drop in a message](https://join.slack.com/t/dograh-community/shared_invite/zt-3czr47sw5-MSg1J0kJ7IMPOCHF~03auQ) for assistance. + +### Cloud Version +Visit [https://www.dograh.com](https://www.dograh.com/) for our managed cloud offering. + +## πŸ“šDocumentation +Full documentation is in progress. For now, this README will get you started. + +## 🀝Community & Support +- GitHub Issues: Report bugs or request features +- Slack: Our Slack community is not just for support β€” it’s the cornerstone of Dograh AI contributions. Here, you can: + - Connect with maintainers and other contributors + - Discuss issues and features before coding + - Get help with setup and debugging + - Stay up to date with contribution sprints + + +πŸ‘‰ Join us β†’ Dograh Community Slack +## Tech Stack +- FastAPI +- Pipecat +- LiveKit +- PostgreSQL +- Next.js +- XYFlow React +- Inbuilt Twilio integration +- Flexible back-end: switch to any LLM, TTS, or STT + +## πŸ™Œ Contributing +We love contributions! Dograh AI is 100% open source and we intend to keep it that way. + +### Getting Started +- Fork the repository +- Create your feature branch (git checkout -b feature/AmazingFeature) +- Commit your changes (git commit -m 'Add some AmazingFeature') +- Push to the branch (git push origin feature/AmazingFeature) +- Open a Pull Request + +## πŸ“„ License +Dograh AI is licensed under the [BSD 2-Clause License](LICENSE)- the same license as projects that were used in building Dograh AI, ensuring compatibility and freedom to use, modify, and distribute. + +## 🏒 About +Built with ❀️ by **Dograh** (Zansat Technologies Private Limited) +Founded by YC alumni and exit founders committed to keeping voice AI open and accessible to everyone. + +


+ +

+ ⭐ Star us on GitHub | + ☁️ Try Cloud Version | + πŸ’¬ Join Slack +

+ diff --git a/api/db/workflow_run_client.py b/api/db/workflow_run_client.py index d71984f..db44e04 100644 --- a/api/db/workflow_run_client.py +++ b/api/db/workflow_run_client.py @@ -14,6 +14,7 @@ from api.db.models import ( WorkflowModel, WorkflowRunModel, ) +from api.enums import StorageBackend from api.schemas.workflow import WorkflowRunResponseSchema @@ -67,6 +68,9 @@ class WorkflowRunClient(BaseDBClient): ) current_def = current_def_result.scalars().first() + # Get the current storage backend based on ENABLE_AWS_S3 flag + current_backend = StorageBackend.get_current_backend() + new_run = WorkflowRunModel( name=name, workflow=workflow, @@ -75,6 +79,7 @@ class WorkflowRunClient(BaseDBClient): initial_context=initial_context or workflow.template_context_variables, campaign_id=campaign_id, queued_run_id=queued_run_id, + storage_backend=current_backend.value, ) session.add(new_run) try: diff --git a/api/services/filesystem/minio.py b/api/services/filesystem/minio.py index bdc0154..9051d2d 100644 --- a/api/services/filesystem/minio.py +++ b/api/services/filesystem/minio.py @@ -1,9 +1,11 @@ import asyncio -from datetime import timedelta +from datetime import datetime, timedelta, timezone from typing import Any, BinaryIO, Dict, Optional +from loguru import logger from minio import Minio from minio.error import S3Error +import json from .base import BaseFileSystem @@ -42,12 +44,29 @@ class MinioFileSystem(BaseFileSystem): endpoint, access_key=access_key, secret_key=secret_key, secure=secure ) - # Ensure bucket exists (using internal client) + # Ensure bucket exists and configure anonymous access (using internal client) try: if not self.client.bucket_exists(self.bucket_name): self.client.make_bucket(self.bucket_name) + + # Set anonymous download policy for local development + # This allows unsigned URLs to work + policy = { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": {"AWS": "*"}, + "Action": ["s3:GetObject"], + "Resource": [f"arn:aws:s3:::{self.bucket_name}/*"] + } + ] + } + + self.client.set_bucket_policy(self.bucket_name, json.dumps(policy)) except Exception as e: # Bucket might already exist or we might be in a restricted environment + logger.debug(f"Bucket setup note: {e}") pass async def acreate_file(self, file_path: str, content: BinaryIO) -> bool: @@ -82,39 +101,14 @@ class MinioFileSystem(BaseFileSystem): self, file_path: str, expiration: int = 3600, force_inline: bool = False ) -> Optional[str]: try: - - def _presign(): - response_headers = None - if force_inline and file_path.endswith(".txt"): - response_headers = { - "response-content-type": "text/plain", - "response-content-disposition": "inline", - } - - # Generate URL with the main client - url = self.client.presigned_get_object( - self.bucket_name, - file_path, - expires=timedelta(seconds=expiration), - response_headers=response_headers, - ) - - # If we have different public endpoint, replace it in the URL - if self.endpoint != self.public_endpoint: - # Simple string replacement since presigned URLs are just strings - # Replace the endpoint in the URL - url = url.replace( - f"://{self.endpoint}/", f"://{self.public_endpoint}/" - ) - url = url.replace( - f"Host={self.endpoint}", f"Host={self.public_endpoint}" - ) - - return url - - url = await asyncio.to_thread(_presign) + # For MinIO in local development, return unsigned URLs + # This avoids signature mismatch issues when endpoint differs + # MinIO must be configured to allow anonymous read access + protocol = "https" if self.secure else "http" + url = f"{protocol}://{self.public_endpoint}/{self.bucket_name}/{file_path}" return url - except S3Error: + except Exception as e: + logger.error(f"Error generating MinIO URL: {e}") return None async def aget_file_metadata(self, file_path: str) -> Optional[Dict[str, Any]]: diff --git a/docker-compose.yaml b/docker-compose.yaml index 2182153..b322941 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -59,7 +59,7 @@ services: - app-network api: - image: chewieee/dograh-api:v7 + image: dograhai/dograh-api:v1 volumes: - shared-tmp:/tmp environment: @@ -122,7 +122,7 @@ services: - app-network arq-worker: - image: chewieee/dograh-api:v7 + image: dograhai/dograh-api:v1 volumes: - shared-tmp:/tmp environment: @@ -149,16 +149,23 @@ services: # Sentry ENABLE_SETRY: "false" SENTRY_DSN: "" + command: > + bash -c " + cd /app/api && + python -m arq api.tasks.arq.WorkerSettings + " depends_on: postgres: condition: service_healthy redis: condition: service_healthy + minio: + condition: service_healthy networks: - app-network ui: - image: chewieee/dograh-ui:v10 + image: dograhai/dograh-ui:v1 environment: NEXT_PUBLIC_NODE_ENV: "local" NEXT_PUBLIC_AUTH_PROVIDER: "local"