{"id":51506856,"url":"https://github.com/derekhuynen/ai-rag-chat-bot","last_synced_at":"2026-07-08T01:02:53.238Z","repository":{"id":361317276,"uuid":"986750273","full_name":"derekhuynen/ai-rag-chat-bot","owner":"derekhuynen","description":"A serverless rag chatbot solution that uses Azure OpenAI, Azure AI Search, and Semantic Kernel to provide intelligent responses from your own data sources with accurate citations.","archived":false,"fork":false,"pushed_at":"2026-05-30T04:30:56.000Z","size":458,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-05-30T06:14:49.916Z","etag":null,"topics":["azure","azure-ai-search","azure-functions-v4","azure-openai","bicep","chatbot","cosmosdb","csharp","dotnet-core","llm","managed-identity","openai","rag","react","retrieval-augmented-generation","semantic-kernel","serverless","streaming","typescript","vector-search"],"latest_commit_sha":null,"homepage":"","language":"C#","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/derekhuynen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-05-20T04:33:06.000Z","updated_at":"2026-05-30T04:31:00.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/derekhuynen/ai-rag-chat-bot","commit_stats":null,"previous_names":["derekhuynen/ai_rag_chat_bot"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/derekhuynen/ai-rag-chat-bot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derekhuynen%2Fai-rag-chat-bot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derekhuynen%2Fai-rag-chat-bot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derekhuynen%2Fai-rag-chat-bot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derekhuynen%2Fai-rag-chat-bot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/derekhuynen","download_url":"https://codeload.github.com/derekhuynen/ai-rag-chat-bot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/derekhuynen%2Fai-rag-chat-bot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35247742,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-07T02:00:07.222Z","response_time":90,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["azure","azure-ai-search","azure-functions-v4","azure-openai","bicep","chatbot","cosmosdb","csharp","dotnet-core","llm","managed-identity","openai","rag","react","retrieval-augmented-generation","semantic-kernel","serverless","streaming","typescript","vector-search"],"created_at":"2026-07-08T01:02:52.301Z","updated_at":"2026-07-08T01:02:53.230Z","avatar_url":"https://github.com/derekhuynen.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# AI RAG Chat Bot\n\n### Streaming AI chat with image understanding and retrieval-augmented generation over your own documents: keyless Azure, one-command deploy\n\n[![CI](https://github.com/derekhuynen/ai-rag-chat-bot/actions/workflows/ci.yml/badge.svg)](https://github.com/derekhuynen/ai-rag-chat-bot/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)\n![.NET 10](https://img.shields.io/badge/.NET-10-512BD4?logo=dotnet\u0026logoColor=white)\n![React 19](https://img.shields.io/badge/React-19-61DAFB?logo=react\u0026logoColor=white)\n![Azure Functions](https://img.shields.io/badge/Azure-Functions-0078D4?logo=microsoftazure\u0026logoColor=white)\n[![Stars](https://img.shields.io/github/stars/derekhuynen/ai-rag-chat-bot?style=social)](https://github.com/derekhuynen/ai-rag-chat-bot/stargazers)\n\n![Streaming chat grounded in your own documents](docs/images/chat-streaming.png)\n\n\u003c/div\u003e\n\nA production-grade reference app: **Azure Functions (.NET 10) + React**, Semantic Kernel, and Azure AI Search, wired up keyless with Managed Identity and deployable to a cheap, scale-to-zero Azure environment in a single command.\n\n_Built for fun: a personal project exploring how far a fully keyless, scale-to-zero RAG stack on Azure can go. It is a demo and portfolio piece, not a commercial product, but everything here actually runs._\n\n---\n\n## Why you might like this\n\n- **Keyless, end to end.** Cosmos DB, Azure OpenAI, Azure AI Search, and Storage all auth via `DefaultAzureCredential`: Managed Identity in the cloud, `az login` locally. No API keys or connection strings anywhere.\n- **Real-time streaming chat** over Server-Sent Events, with multi-turn history persisted in Cosmos DB and one-click regenerate.\n- **Hybrid RAG** (keyword + vector) over your own `.txt`/`.md` docs, with clickable citations back to the source.\n- **Image understanding**: paste, drag-and-drop, or upload images straight into the chat.\n- **Cheap by design**: Flex Consumption Functions, serverless Cosmos, Free-tier AI Search, Storage static website. Scales to zero; ~$0 at idle.\n- **One command up, one command down**: Bicep IaC with `deploy.ps1` / `teardown.ps1`, plus OIDC-based GitHub Actions CI/CD (no stored cloud secrets).\n- **Tested and CI-gated**: xUnit (backend) + Vitest/RTL (frontend) run on every push.\n\n\u003cdetails\u003e\n\u003csummary\u003eMore screenshots\u003c/summary\u003e\n\n![Admin dashboard: users, conversations, and message stats](docs/images/admin-dashboard.png)\n![Markdown and code rendering with clickable citations](docs/images/markdown-rendering.png)\n![RAG answer with a summary table and clickable source citations](docs/images/rag-citations.png)\n![Document library: upload, chunk, and index .txt and .md files](docs/images/admin-documents.png)\n\n\u003c/details\u003e\n\n---\n\n## Tech stack\n\n| Layer | Tech |\n|-------|------|\n| **Backend** | Azure Functions v4, **.NET 10** isolated worker, Semantic Kernel |\n| **Frontend** | **React 19** + TypeScript (Vite), MUI, TanStack Query, react-hook-form + Zod |\n| **AI** | Azure OpenAI (GPT-4.1 chat + `text-embedding-3-small`) |\n| **Data / Search** | Azure Cosmos DB · Azure AI Search (hybrid) · Azure Blob Storage |\n| **Infra** | Bicep · Key Vault · Managed Identity · GitHub Actions (OIDC) |\n\n---\n\n## Quick start\n\n### Option A: Deploy to Azure (cheap, one command)\n\nInfrastructure lives in [`infra/`](infra/README.md) (Bicep + `az`). Spin up a full, cheap environment: Free AI Search, serverless Cosmos, Flex Consumption Functions, a Storage static website for the SPA, and Azure OpenAI (S0):\n\n```powershell\ncd infra\n./deploy.ps1 -Location eastus2 -ResourceGroupName rg-ragchat -SearchSku free\n```\n\nLoad the bundled sample documents (`demo/documents/`) so the chat has something to ground answers on:\n\n```powershell\ncd infra\n./seed-demo.ps1 -ApiBaseUrl \u003cAPI base URL from deploy.ps1\u003e -AdminPassword (Read-Host \"Admin password\" -AsSecureString)\n```\n\nTear it all back down (the whole resource group) with:\n\n```powershell\ncd infra\n./teardown.ps1 -ResourceGroupName rg-ragchat\n```\n\nSee [`infra/README.md`](infra/README.md) for prerequisites, the one-time GitHub Actions OIDC setup, and cost/region caveats.\n\n### Option B: Run locally\n\n\u003e The app is **keyless** and talks to real Azure resources (no local emulators for AI Search / OpenAI), so you'll point at deployed services and authenticate with `az login`. The easiest path is to run `deploy.ps1 -DevPrincipalId \u003cyour-object-id\u003e` once, then run the app locally against those cheap resources.\n\n```bash\ngit clone https://github.com/derekhuynen/ai-rag-chat-bot.git\ncd ai-rag-chat-bot\n\n# 1) Backend\ncd backend\ncp local.settings.example.json local.settings.json   # Windows: copy\n#   fill in your endpoint URLs (no keys needed, it's keyless)\ndotnet restore\nfunc start                                            # → http://localhost:7071/api\n\n# 2) Frontend (new terminal)\ncd ../frontend\nnpm install\necho VITE_API_BASE_URL=http://localhost:7071/api \u003e .env\nnpm run dev                                           # → http://localhost:5173\n```\n\n---\n\n## Architecture\n\n```mermaid\nflowchart LR\n    user([User]) --\u003e spa[\"React SPA\u003cbr/\u003e(Storage static website)\"]\n    spa --\u003e|\"REST + SSE\u003cbr/\u003eJWT bearer\"| api[\"Azure Functions API\u003cbr/\u003e(.NET 10 isolated)\"]\n\n    api --\u003e|DefaultAzureCredential| cosmos[(Cosmos DB\u003cbr/\u003eai_chat)]\n    api --\u003e|DefaultAzureCredential| openai[\"Azure OpenAI\u003cbr/\u003echat + embeddings\"]\n    api --\u003e|DefaultAzureCredential| search[\"Azure AI Search\u003cbr/\u003ehybrid retrieval\"]\n    api --\u003e|user-delegation SAS| blob[\"Blob Storage\u003cbr/\u003eimages + documents\"]\n    api --\u003e|KeyVault refs| kv[\"Key Vault\u003cbr/\u003eJWT secret + admin pwd\"]\n\n    subgraph ingest [Document RAG ingestion]\n        blob --\u003e chunk[Chunk + summarize] --\u003e embed[Embed] --\u003e idx[Index in AI Search]\n    end\n```\n\nAll app-to-Azure calls are **keyless** (Managed Identity in Azure, `az login` locally via `DefaultAzureCredential`). The only stored secrets are the JWT signing key and the admin password, held in Key Vault.\n\n**Backend:** Azure Functions v4 / .NET 10 isolated · Cosmos DB (`ai_chat`) · Blob Storage (`ai-chat`) · Azure OpenAI (GPT-4.1 + `text-embedding-3-small`) · Azure AI Search (`ai-chat-documents`, hybrid) · JWT (HS256) auth.\n\n**Frontend:** React + TypeScript (Vite) · MUI dark theme · TanStack Query · react-hook-form + Zod · Axios for REST and native `fetch` for SSE streaming.\n\nDeeper dives: [backend architecture](documents/backend_architecture.md) · [frontend architecture](documents/frontend_architecture.md).\n\n\u003cdetails\u003e\n\u003csummary\u003eProject structure\u003c/summary\u003e\n\n```text\nai-rag-chat-bot/\n├── backend/                    # Azure Functions backend (.NET 10 isolated)\n│   ├── Functions/              # HTTP-triggered functions\n│   │   ├── AuthFunction.cs         # Auth endpoints (login, register, me)\n│   │   ├── AdminFunction.cs        # Admin dashboard endpoints\n│   │   ├── ConversationFunction.cs # Conversation CRUD\n│   │   ├── ChatFunction.cs         # Non-streaming chat (optional)\n│   │   ├── ChatStreamFunction.cs   # Streaming chat (SSE)\n│   │   ├── ImageUploadFunction.cs  # Image upload\n│   │   └── DocumentManagementFunction.cs # Admin document upload + RAG mgmt\n│   ├── Services/               # Business logic \u0026 integrations\n│   ├── Models/                 # Cosmos DB and API models\n│   ├── Setup/                  # Cosmos DB + admin bootstrap\n│   └── AzureFunctionApp.Tests/ # xUnit test suite\n├── frontend/                   # React + MUI frontend (Vitest tests)\n│   └── src/                    # components, pages, services, hooks, utils\n├── infra/                      # Bicep + deploy/teardown/seed scripts (cheap, keyless Azure)\n├── demo/                       # Fictional sample docs to seed RAG for the demo\n├── scripts/                    # Tooling (Playwright screenshot capture)\n└── documents/                  # Backend \u0026 frontend architecture docs\n```\n\n\u003c/details\u003e\n\n---\n\n## Security\n\n- **Keyless by default**: no service keys or connection strings stored anywhere; everything authenticates via `DefaultAzureCredential`.\n- The only application secrets are `Jwt:SecretKey` and `Admin:Password`: local in gitignored `local.settings.json`, in Azure stored in **Key Vault** and referenced from Function App settings.\n- JWTs are signed (HS256, ≥256-bit key enforced) and validated on every protected endpoint; admin role is re-checked against the database.\n- Cosmos queries are parameterized; Blob access uses short-lived **user-delegation SAS** (no account key).\n- `.env` and `local.settings.json` are gitignored: never commit secrets.\n\n\u003cdetails\u003e\n\u003csummary\u003eConfiguration reference (\u003ccode\u003elocal.settings.json\u003c/code\u003e)\u003c/summary\u003e\n\nThe app is keyless, so this file holds **endpoints and account names** plus the `Jwt` and `Admin` values: **not access keys**. Example (also at [`backend/local.settings.example.json`](backend/local.settings.example.json)):\n\n```json\n{\n  \"IsEncrypted\": false,\n  \"Values\": {\n    \"AzureWebJobsStorage\": \"UseDevelopmentStorage=true\",\n    \"FUNCTIONS_WORKER_RUNTIME\": \"dotnet-isolated\",\n    \"CosmosDb:Endpoint\": \"https://YOUR_COSMOS_ACCOUNT.documents.azure.com:443/\",\n    \"CosmosDb:DatabaseName\": \"ai_chat\",\n    \"AzureAI:Endpoint\": \"https://YOUR_AZURE_OPENAI.openai.azure.com/\",\n    \"AzureAI:DeploymentName\": \"gpt-4.1\",\n    \"AzureAI:AvailableModels\": \"gpt-4.1\",\n    \"AzureAI:EmbeddingDeployment\": \"text-embedding-3-small\",\n    \"AzureSearch:Endpoint\": \"https://YOUR_SEARCH_SERVICE.search.windows.net\",\n    \"AzureSearch:IndexName\": \"ai-chat-documents\",\n    \"AzureStorage:AccountName\": \"YOUR_STORAGE_ACCOUNT\",\n    \"AzureStorage:ContainerName\": \"ai-chat\",\n    \"AzureStorage:ImageFolder\": \"images\",\n    \"AzureStorage:DocumentFolder\": \"documents\",\n    \"AzureStorage:QueueName\": \"document-processing-queue\",\n    \"DocumentProcessing:ChunkSize\": \"800\",\n    \"DocumentProcessing:ChunkOverlap\": \"200\",\n    \"DocumentProcessing:MaxFileSize\": \"10485760\",\n    \"RAG:MinRelevanceScore\": \"0.7\",\n    \"RAG:MaxResults\": \"3\",\n    \"RAG:SemanticWeight\": \"0.7\",\n    \"Jwt:SecretKey\": \"CHANGE_ME_TO_A_SECURE_RANDOM_SECRET\",\n    \"Jwt:Issuer\": \"AIChatBot\",\n    \"Jwt:Audience\": \"AIChatBot\",\n    \"Jwt:ExpirationMinutes\": \"1440\",\n    \"Admin:Email\": \"admin@example.com\",\n    \"Admin:Password\": \"ChangeThisAdminPassword123!\",\n    \"Admin:Name\": \"Administrator\"\n  },\n  \"Host\": { \"CORS\": \"*\" }\n}\n```\n\nThe frontend reads the backend URL from `VITE_API_BASE_URL` (in `frontend/.env`); for local dev that's `http://localhost:7071/api`.\n\n\u003c/details\u003e\n\n---\n\n## Status and roadmap\n\n**Done:** streaming chat + history · admin dashboard · RAG ingestion (upload → chunk → embed → search) · markdown rendering \u0026 regenerate · keyless Managed-Identity auth · one-command cheap Azure deploy · OIDC CI/CD · automated tests.\n\n**Next:** model selection in the chat UI · user settings (theme, default model).\n\n---\n\n## Contributing and license\n\nContributions welcome: see [CONTRIBUTING.md](CONTRIBUTING.md) for local setup, the checks CI runs (build, lint, tests), and commit/branch conventions. Released under the [MIT License](LICENSE).\n\nIf this project helped or inspired you, a star is appreciated.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fderekhuynen%2Fai-rag-chat-bot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fderekhuynen%2Fai-rag-chat-bot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fderekhuynen%2Fai-rag-chat-bot/lists"}