{"id":43812104,"url":"https://github.com/grepory/ragu","last_synced_at":"2026-02-05T23:33:48.880Z","repository":{"id":305746585,"uuid":"1023809230","full_name":"grepory/ragu","owner":"grepory","description":"RAGU - RAG Utility for interrogating documents","archived":false,"fork":false,"pushed_at":"2025-08-17T16:45:38.000Z","size":280,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-17T17:34:36.827Z","etag":null,"topics":["ai","claude-code","llm"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/grepory.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-07-21T18:17:15.000Z","updated_at":"2025-08-17T16:45:41.000Z","dependencies_parsed_at":"2025-07-21T20:49:01.205Z","dependency_job_id":"5145d472-19d6-4e15-bd3b-d6aa4049f216","html_url":"https://github.com/grepory/ragu","commit_stats":null,"previous_names":["grepory/ragu"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/grepory/ragu","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grepory%2Fragu","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grepory%2Fragu/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grepory%2Fragu/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grepory%2Fragu/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/grepory","download_url":"https://codeload.github.com/grepory/ragu/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grepory%2Fragu/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29138375,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-05T23:14:48.546Z","status":"ssl_error","status_checked_at":"2026-02-05T23:14:35.724Z","response_time":65,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","claude-code","llm"],"created_at":"2026-02-05T23:33:48.790Z","updated_at":"2026-02-05T23:33:48.862Z","avatar_url":"https://github.com/grepory.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# RAGU: Retrieval-Augmented Generation Utility\n\nRAGU is a complete RAG (Retrieval-Augmented Generation) management and interrogation system built with FastAPI and ChromaDB. It provides a powerful API for document management, vector storage, and LLM-powered chat functionality with support for multiple LLM providers.\n\n## Features\n\n- **Document Management**: Upload, process, and manage documents in vector collections\n- **Document Tagging**: Add tags to documents for better organization and filtering\n- **Vector Database**: ChromaDB integration for efficient semantic search\n- **LLM Integration**: Support for multiple LLM providers:\n  - Ollama with local or remote models (including nomic-embed-text)\n  - Anthropic with Claude models (including haiku)\n  - OpenAI with GPT models (including 4o)\n- **Conversational UI**: Interactive chat interface with conversation history and context awareness\n- **WebSocket Chat**: Real-time, streaming chat interface with RAG capabilities\n- **REST API**: Comprehensive REST API for all operations\n- **Document Processing**: Support for various document types (PDF, DOCX, CSV, text)\n\n## Installation\n\n### Prerequisites\n\n- Python 3.8+\n- [Optional] Virtual environment (recommended)\n\n### Setup\n\n1. Clone the repository:\n   ```bash\n   git clone https://github.com/grepory/ragu.git\n   cd ragu\n   ```\n\n2. Create and activate a virtual environment (optional but recommended):\n   ```bash\n   python -m venv venv\n   source venv/bin/activate  # On Windows: venv\\Scripts\\activate\n   ```\n\n3. Install dependencies:\n   ```bash\n   pip install -r requirements.txt\n   ```\n\n4. Copy the `.env.example` file to `.env` in the project root and update it with your LLM provider configuration:\n   ```bash\n   cp .env.example .env\n   # Then edit the .env file with your preferred text editor\n   ```\n   \n   The `.env.example` file contains all the necessary environment variables with default values and explanatory comments. You only need to configure the providers you plan to use.\n\n## Running the Application\n\nStart the server with:\n\n```bash\npython run_app.py\n```\n\nThis will:\n- Start the server on the configured port (default 8000)\n- Display clear URLs for accessing the application\n- Automatically open your default web browser to the frontend\n\nAlternatively, you can start the server manually with:\n\n```bash\nuvicorn app.main:app --reload --host 0.0.0.0 --port 8000\n```\n\nThe API will be available at http://localhost:8000, and the API documentation at http://localhost:8000/docs.\n\n## Configuration\n\nRAGU can be configured through environment variables in the `.env` file:\n\n### Server Configuration\n\n- `PORT=8000` - Port for the FastAPI server\n- `ROOT_PATH=/ragu` - Root path prefix for reverse proxy setup (e.g., for hosting at http://example.com/ragu/)\n\n### LLM Provider Configuration\n\nConfigure your preferred LLM providers in the `.env` file:\n\n## API Documentation\n\n### Collections API\n\nCollections are used to organize documents in the vector database.\n\n#### Create a Collection\n\n```http\nPOST /api/v1/collections/\nContent-Type: application/json\n\n{\n  \"name\": \"my_collection\",\n  \"description\": \"My first collection\"\n}\n```\n\n#### List Collections\n\n```http\nGET /api/v1/collections/\n```\n\n#### Get Collection\n\n```http\nGET /api/v1/collections/{collection_name}\n```\n\n#### Delete Collection\n\n```http\nDELETE /api/v1/collections/{collection_name}\n```\n\n### Documents API\n\nDocuments are the core content stored in the vector database.\n\n#### Upload a Document\n\n```http\nPOST /api/v1/documents/upload\nContent-Type: multipart/form-data\n\nfile: [file]\ncollection_name: my_collection\ntags: personal,house,important\nadditional_metadata: {\"source\": \"website\", \"author\": \"John Doe\"}\n```\n\nThe `tags` parameter is optional and should be a comma-separated list of tags to associate with the document.\n\n#### Add Text Directly\n\n```http\nPOST /api/v1/documents/text\nContent-Type: application/json\n\n{\n  \"text\": \"This is some text to add to the vector database.\",\n  \"collection_name\": \"my_collection\",\n  \"tags\": [\"personal\", \"notes\", \"important\"],\n  \"metadata\": {\"source\": \"direct_input\", \"author\": \"Jane Smith\"}\n}\n```\n\nThe `tags` parameter is optional and should be an array of strings representing tags to associate with the document.\n\n#### Get Document\n\n```http\nGET /api/v1/documents/{collection_name}/{document_id}\n```\n\n#### Delete Document\n\n```http\nDELETE /api/v1/documents/{collection_name}/{document_id}\n```\n\n#### Query Documents\n\n```http\nPOST /api/v1/documents/query\nContent-Type: application/json\n\n{\n  \"collection_name\": \"my_collection\",\n  \"query_text\": \"What is retrieval-augmented generation?\",\n  \"n_results\": 5,\n  \"where\": {\n    \"tags\": {\"$in\": [\"personal\", \"important\"]}\n  }\n}\n```\n\nThe `where` parameter is optional and can be used to filter documents by metadata fields, including tags. In the example above, the query will only return documents that have either the \"personal\" or \"important\" tag. You can use other operators like `$eq` for exact match or `$contains` for substring match.\n\n### Chat API\n\nThe Chat API provides both REST and WebSocket interfaces for interacting with the LLM.\n\n#### Model Selection\n\nYou can specify which LLM provider and model to use by setting the `model` parameter in your requests. The format is:\n\n```\nprovider:model\n```\n\nFor example:\n- `ollama:llama2` - Use Ollama with the llama2 model\n- `anthropic:claude-3-haiku-20240307` - Use Anthropic with the Claude 3 Haiku model\n- `openai:gpt-4o` - Use OpenAI with the GPT-4o model\n\nIf you don't specify a provider, the default provider from your configuration will be used. If you don't specify a model, the default model for the selected provider will be used.\n\n#### REST Chat Endpoint\n\n```http\nPOST /api/v1/chat/\nContent-Type: application/json\n\n{\n  \"collection_name\": \"my_collection\",\n  \"query\": \"What is retrieval-augmented generation?\",\n  \"history\": [\n    {\"role\": \"user\", \"content\": \"Hello\"},\n    {\"role\": \"assistant\", \"content\": \"Hi there! How can I help you?\"}\n  ],\n  \"model\": \"llama2\"\n}\n```\n\n#### WebSocket Chat\n\nConnect to the WebSocket endpoint at `/api/v1/chat/ws` and send JSON messages with the following format:\n\n```json\n{\n  \"type\": \"chat\",\n  \"collection_name\": \"my_collection\",\n  \"query\": \"What is retrieval-augmented generation?\",\n  \"history\": [\n    {\"role\": \"user\", \"content\": \"Hello\"},\n    {\"role\": \"assistant\", \"content\": \"Hi there! How can I help you?\"}\n  ],\n  \"model\": \"llama2\"\n}\n```\n\nThe server will respond with messages in the following formats:\n\n1. Start message:\n```json\n{\n  \"type\": \"start\",\n  \"content\": \"Generating response...\"\n}\n```\n\n2. Token messages (streaming):\n```json\n{\n  \"type\": \"token\",\n  \"content\": \"piece of text\"\n}\n```\n\n3. Complete message:\n```json\n{\n  \"type\": \"complete\",\n  \"content\": {\n    \"answer\": \"The complete answer...\",\n    \"sources\": [\n      {\n        \"id\": \"document_id\",\n        \"text\": \"Snippet of the source document...\",\n        \"metadata\": {\"source\": \"document.pdf\", \"page\": 1}\n      }\n    ],\n    \"history\": [\n      {\"role\": \"user\", \"content\": \"What is RAG?\"},\n      {\"role\": \"assistant\", \"content\": \"The complete answer...\"}\n    ]\n  }\n}\n```\n\n4. Error message:\n```json\n{\n  \"type\": \"error\",\n  \"content\": \"Error message\"\n}\n```\n\n## Web Interface\n\nRAGU provides a responsive web interface that works seamlessly on desktop and mobile devices. The interface includes:\n\n### Document Upload\n\n- Upload files using the upload button\n- Add tags to organize your documents  \n- View upload progress and status\n\n### Conversational Chat Interface\n\nThe chat interface allows you to have natural conversations with the AI about your documents:\n\n- **Conversation History**: The system maintains the full conversation history, allowing for contextual follow-up questions\n- **Conversation Sidebar**: Browse and manage your chat history with a collapsible sidebar\n- **Enter Key Support**: Press Enter to send your message (use Shift+Enter for new lines)  \n- **Visual Distinction**: User and assistant messages are visually distinct for easy reading\n- **Source Citations**: The system displays the source documents used to generate responses\n- **Mobile Responsive**: Optimized interface for mobile devices with touch-friendly controls\n- **Tag-based Filtering**: Filter conversations and documents by tags with advanced search capabilities\n\nTo use the conversational interface:\n\n1. Select a a set of tags from the dropdown (or choose to search all tags)\n2. (Optional) Select a specific LLM model and provider\n3. Type your question in the message box\n4. Press Enter or click \"Send Message\"\n5. View the AI's response and the sources used\n6. Continue the conversation with follow-up questions\n\nThe system will maintain context between questions, allowing for a more natural conversation flow. On mobile devices, the conversation sidebar can be toggled using the sidebar button in the top navigation.\n\n## Examples\n\n### Python Client Example\n\nHere's a simple Python client for interacting with the API:\n\n```python\nimport requests\nimport websockets\nimport json\nimport asyncio\n\nBASE_URL = \"http://localhost:8000/api/v1\"\n\n# Create a collection\ndef create_collection(name, description=None):\n    response = requests.post(\n        f\"{BASE_URL}/collections/\",\n        json={\"name\": name, \"description\": description}\n    )\n    return response.json()\n\n# Upload a document\ndef upload_document(file_path, collection_name, tags=None, metadata=None):\n    files = {\"file\": open(file_path, \"rb\")}\n    data = {\"collection_name\": collection_name}\n    if tags:\n        data[\"tags\"] = \",\".join(tags)\n    if metadata:\n        data[\"additional_metadata\"] = json.dumps(metadata)\n    \n    response = requests.post(\n        f\"{BASE_URL}/documents/upload\",\n        files=files,\n        data=data\n    )\n    return response.json()\n\n# Query documents\ndef query_documents(collection_name, query_text, n_results=5, tags=None):\n    query_data = {\n        \"collection_name\": collection_name,\n        \"query_text\": query_text,\n        \"n_results\": n_results\n    }\n    \n    # Add tag filtering if specified\n    if tags:\n        query_data[\"where\"] = {\"tags\": {\"$in\": tags}}\n    \n    response = requests.post(\n        f\"{BASE_URL}/documents/query\",\n        json=query_data\n    )\n    return response.json()\n\n# WebSocket chat client\nasync def chat_websocket(query, tags=None, history=None, model=None, include_untagged=True):\n    uri = f\"ws://localhost:8000/api/v1/chat/ws\"\n    async with websockets.connect(uri) as websocket:\n        # Send chat message\n        message = {\n            \"type\": \"chat\",\n            \"query\": query,\n            \"history\": history or [],\n            \"include_untagged\": include_untagged\n        }\n        if tags:\n            message[\"tags\"] = tags\n        if model:\n            message[\"model\"] = model\n            \n        await websocket.send(json.dumps(message))\n        \n        # Process responses\n        full_response = \"\"\n        while True:\n            response = await websocket.recv()\n            data = json.loads(response)\n            \n            if data[\"type\"] == \"token\":\n                # Print token as it arrives\n                print(data[\"content\"], end=\"\", flush=True)\n                full_response += data[\"content\"]\n            \n            elif data[\"type\"] == \"complete\":\n                # Chat complete\n                print(\"\\n\\nSources:\")\n                for i, source in enumerate(data[\"content\"][\"sources\"]):\n                    print(f\"{i+1}. {source['text']} (ID: {source['id']})\")\n                \n                return data[\"content\"]\n            \n            elif data[\"type\"] == \"error\":\n                # Error occurred\n                print(f\"\\nError: {data['content']}\")\n                return None\n\n# Example usage\nif __name__ == \"__main__\":\n    # Create a collection\n    create_collection(\"my_docs\", \"My documents collection\")\n    \n    # Upload a document with tags\n    upload_document(\n        \"path/to/document.pdf\", \n        \"my_docs\", \n        tags=[\"house\", \"important\", \"insurance\"],\n        metadata={\"source\": \"local\", \"author\": \"Insurance Company\"}\n    )\n    \n    # Upload another document with different tags\n    upload_document(\n        \"path/to/another_document.pdf\", \n        \"my_docs\", \n        tags=[\"personal\", \"important\", \"legal\"],\n        metadata={\"source\": \"local\", \"author\": \"Law Firm\"}\n    )\n    \n    # Query documents without tag filtering\n    results = query_documents(\"my_docs\", \"What is RAG?\")\n    \n    # Query documents with tag filtering (only \"house\" tagged documents)\n    house_results = query_documents(\"my_docs\", \"What is RAG?\", tags=[\"house\"])\n    \n    # Query documents with multiple tag filtering (documents tagged as either \"important\" or \"personal\")\n    important_results = query_documents(\"my_docs\", \"What is RAG?\", tags=[\"important\", \"personal\"])\n    \n    # Chat with WebSocket - Single query\n    asyncio.run(chat_websocket(\"Explain RAG in simple terms.\"))\n    \n    # Chat with WebSocket - Query with tag filtering\n    asyncio.run(chat_websocket(\n        \"What can you tell me about my house documents?\", \n        tags=[\"house\", \"important\"]\n    ))\n    \n    # Chat with WebSocket - Conversation with history\n    async def conversation_example():\n        # First query\n        print(\"\\n--- Starting conversation ---\")\n        response = await chat_websocket(\"Explain RAG in simple terms.\")\n        \n        # Get the updated history from the response\n        conversation_history = response[\"history\"]\n        \n        # Follow-up query using the conversation history with tag filtering\n        print(\"\\n--- Follow-up question with tag filtering ---\")\n        response = await chat_websocket(\n            \"What are the main benefits compared to traditional approaches?\",\n            tags=[\"important\", \"personal\"],\n            history=conversation_history\n        )\n        \n        # Continue the conversation with another follow-up\n        conversation_history = response[\"history\"]\n        print(\"\\n--- Another follow-up question ---\")\n        await chat_websocket(\n            \"Can you give me a simple code example?\",\n            history=conversation_history\n        )\n    \n    # Run the conversation example\n    asyncio.run(conversation_example())\n```\n\n## License\n\nMIT\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrepory%2Fragu","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgrepory%2Fragu","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrepory%2Fragu/lists"}