ragdoll-ai 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Rui Xue
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,220 @@
1
+ Metadata-Version: 2.4
2
+ Name: ragdoll-ai
3
+ Version: 0.2.0
4
+ Summary: Retrieval-Augmented Generation Driven by Offline Local LLMs โ€” a fully-local RAG system for JIRA tickets, code, and PDFs, powered by Ollama.
5
+ Author-email: Rui Xue <rx.astro@gmail.com>
6
+ License: MIT
7
+ Requires-Python: >=3.11
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: chromadb>=0.6
11
+ Requires-Dist: pymupdf>=1.25
12
+ Requires-Dist: jira>=3.8
13
+ Requires-Dist: click>=8.1
14
+ Requires-Dist: rich>=13.0
15
+ Requires-Dist: pydantic-settings>=2.0
16
+ Requires-Dist: httpx>=0.27
17
+ Requires-Dist: pytest
18
+ Requires-Dist: fastapi
19
+ Requires-Dist: uvicorn
20
+ Requires-Dist: gradio
21
+ Requires-Dist: llama-index
22
+ Requires-Dist: llama-index-vector-stores-chroma
23
+ Requires-Dist: llama-index-llms-ollama
24
+ Requires-Dist: llama-index-embeddings-ollama
25
+ Requires-Dist: llama-index-readers-jira
26
+ Provides-Extra: docs
27
+ Requires-Dist: sphinx>=7.0; extra == "docs"
28
+ Requires-Dist: furo; extra == "docs"
29
+ Requires-Dist: myst-parser>=3.0; extra == "docs"
30
+ Requires-Dist: sphinx-autodoc-typehints; extra == "docs"
31
+ Dynamic: license-file
32
+
33
+ # ๐Ÿงถ Ragdoll
34
+
35
+ **Retrieval-Augmented Generation Driven by Offline Local LLMs**
36
+
37
+ A fully-local RAG system that ingests JIRA tickets, PDF documents, and Python
38
+ source code, indexes them for semantic search, and connects to a local LLM via
39
+ [Ollama](https://ollama.ai) for interactive Q&A, summarization, and chat.
40
+
41
+ > **Privacy-first:** All data stays on your machine โ€” nothing is sent to
42
+ > external services.
43
+
44
+ ## Prerequisites
45
+
46
+ - **Python 3.12+**
47
+ - **[Ollama](https://ollama.ai)** running locally with:
48
+ - An embedding model (e.g. `nomic-embed-text`)
49
+ - A chat model (e.g. `gpt-oss:20b`, `deepseek-r1:32b`)
50
+ - **[pixi](https://pixi.sh)** for environment management
51
+
52
+ ## Quick Start
53
+
54
+ ```bash
55
+ # Clone and enter the project
56
+ cd ragdoll
57
+
58
+ # Install with pixi (creates isolated env + editable install)
59
+ pixi install
60
+
61
+ # Set up user-level configuration
62
+ mkdir -p ~/.ragdoll && chmod 700 ~/.ragdoll
63
+ cat > ~/.ragdoll/config.toml << 'EOF'
64
+ jira_url = "https://your-jira.example.com"
65
+ jira_user = "your.user"
66
+ jira_token = "YOUR_PAT_TOKEN"
67
+ jira_auth_method = "pat" # "pat" for JIRA Data Center, "basic" for Cloud
68
+ EOF
69
+ chmod 600 ~/.ragdoll/config.toml
70
+
71
+ # Check everything is connected
72
+ pixi run ragdoll status
73
+ ```
74
+
75
+ ## Usage
76
+
77
+ ### Ingest Data
78
+
79
+ ```bash
80
+ # Ingest PDF files or directories
81
+ pixi run ragdoll ingest pdf ./docs/technical_handbook.pdf
82
+ pixi run ragdoll ingest pdf ./reports/
83
+
84
+ # Ingest JIRA issues via JQL
85
+ pixi run ragdoll ingest jira --jql "project = CAS AND updated >= -30d"
86
+ pixi run ragdoll ingest jira --jql "project = PIPE AND updated >= -60d" --max-results 100
87
+
88
+ # Ingest from a different JIRA instance (multi-site)
89
+ pixi run ragdoll ingest jira \
90
+ --url https://other-jira.example.com \
91
+ --token OTHER_PAT \
92
+ --jql "project = EXT AND updated >= -30d"
93
+
94
+ # Ingest Python source code (AST-parsed per function/class)
95
+ pixi run ragdoll ingest code ./src/
96
+ pixi run ragdoll ingest code ./path/to/project/
97
+ ```
98
+
99
+ #### Reingesting Data (LlamaIndex Update)
100
+ If you are upgrading from an older version of `ragdoll` to the LlamaIndex-backed version, your existing ChromaDB data is fully backward compatible. However, it is highly recommended to wipe the old index and reingest your data to take advantage of LlamaIndex's superior semantic chunking (which splits by sentences instead of fixed character limits).
101
+
102
+ To clear your database and start fresh:
103
+ ```bash
104
+ # Delete the old ChromaDB collection
105
+ rm -rf ~/.ragdoll/data/chroma
106
+
107
+ # Re-run your ingestion commands
108
+ pixi run ragdoll ingest jira --jql "project = CAS AND updated >= -30d"
109
+ pixi run ragdoll ingest pdf ./docs/
110
+ ```
111
+
112
+ ### Search
113
+
114
+ ```bash
115
+ # Semantic search across all ingested data
116
+ pixi run ragdoll search "tclean performance regression"
117
+ pixi run ragdoll search "AsdmStMan lazy import" --source jira
118
+ pixi run ragdoll search "calibration pipeline" --source pdf -n 5
119
+ pixi run ragdoll search "embedding function" --source code
120
+ ```
121
+
122
+ ### Summarize
123
+
124
+ ```bash
125
+ # Summarize a topic from ingested data
126
+ pixi run ragdoll summarize "What are the known issues with AsdmStMan?"
127
+ pixi run ragdoll summarize "tclean parallelization" --source jira
128
+ ```
129
+
130
+ ### Interactive Chat
131
+
132
+ ```bash
133
+ # Start an interactive RAG chat session
134
+ pixi run ragdoll chat
135
+ pixi run ragdoll chat --source jira # only use JIRA context
136
+ pixi run ragdoll chat --source code # only use source code context
137
+ ```
138
+
139
+ Chat features:
140
+ - **Persistent history** โ€” arrow-up recalls previous questions across sessions
141
+ (stored in `~/.ragdoll/chat_history`)
142
+ - **Line editing** โ€” full readline support (backspace, arrows, Home/End)
143
+ - **Multi-turn** โ€” context accumulates within a session
144
+
145
+ ## Configuration
146
+
147
+ Ragdoll uses a **4-layer precedence** configuration strategy:
148
+
149
+ | Priority | Source | Purpose |
150
+ |----------|--------|---------|
151
+ | 1 (highest) | `RAGDOLL_*` environment variables | CI/ephemeral overrides |
152
+ | 2a | `./ragdoll.toml` in the project directory | Project-level settings |
153
+ | 2b | `./.env` in the project directory | Project-level secrets |
154
+ | 3 | `~/.ragdoll/config.toml` | User-level defaults & credentials |
155
+ | 4 (lowest) | Package defaults | Hardcoded fallbacks |
156
+
157
+ ### Settings Reference
158
+
159
+ | Variable / TOML key | Default | Description |
160
+ |---------------------|---------|-------------|
161
+ | `jira_url` | โ€” | JIRA server URL |
162
+ | `jira_user` | โ€” | JIRA username |
163
+ | `jira_token` | โ€” | JIRA API token or PAT |
164
+ | `jira_auth_method` | `pat` | `"pat"` for Data Center, `"basic"` for Cloud |
165
+ | `jira_batch_size` | `50` | Issues per API request |
166
+ | `ollama_host` | `http://localhost:11434` | Ollama API endpoint |
167
+ | `embed_model` | `nomic-embed-text` | Embedding model |
168
+ | `chat_model` | `gpt-oss:20b` | Chat / generation model |
169
+ | `temperature` | `0.3` | LLM sampling temperature |
170
+ | `data_dir` | `~/.ragdoll/data` | ChromaDB storage directory |
171
+ | `collection_name` | `ragdoll` | ChromaDB collection name |
172
+ | `chunk_size` | `1000` | Characters per chunk |
173
+ | `chunk_overlap` | `200` | Overlap between consecutive chunks |
174
+ | `top_k` | `20` | Default retrieval count |
175
+
176
+ ## Architecture
177
+
178
+ ```
179
+ Source Data Pipeline Storage
180
+ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€
181
+ PDF files โ”€โ”
182
+ JIRA tickets โ”€โ”ผโ”€โ†’ Ingestor โ†’ Chunker โ†’ Embedder โ†’ ChromaDB
183
+ Python code โ”€โ”˜ (AST-aware) (Ollama) (local)
184
+ โ†‘
185
+ Query Flow โ”‚
186
+ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚
187
+ CLI / Chat โ†’ Embed query โ†’ Retriever โ†โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
188
+ โ†“
189
+ LLM (Ollama) โ†’ Streamed answer
190
+ ```
191
+
192
+ ### Data Sources
193
+
194
+ | Source | Module | Strategy |
195
+ |--------|--------|----------|
196
+ | **PDF** | `ragdoll.ingest.pdf` | PyMuPDF text extraction โ†’ recursive character splitter |
197
+ | **JIRA** | `ragdoll.ingest.jira` | REST API with JQL โ†’ structured text per issue |
198
+ | **Code** | `ragdoll.ingest.code` | AST parsing โ†’ one Document per function/class/module docstring |
199
+
200
+ ### Key Components
201
+
202
+ - **Config** (`ragdoll.config`) โ€” Pydantic Settings with 4-layer precedence
203
+ - **Chunker** (`ragdoll.ingest.chunker`) โ€” Recursive character text splitter
204
+ - **Embedder** (`ragdoll.llm.ollama`) โ€” Ollama HTTP client for embeddings and generation
205
+ - **Vector Store** (`ragdoll.store.vectordb`) โ€” ChromaDB with cosine similarity
206
+ - **Retriever** (`ragdoll.query.retriever`) โ€” Semantic search with source filtering
207
+ - **RAG Chain** (`ragdoll.query.rag`) โ€” Context-augmented generation and chat
208
+ - **CLI** (`ragdoll.cli`) โ€” Click-based interface with Rich formatting
209
+
210
+ ## Documentation
211
+
212
+ Full documentation is available under `docs/` and can be built with Sphinx:
213
+
214
+ ```bash
215
+ pixi run docs
216
+ ```
217
+
218
+ ## License
219
+
220
+ MIT
@@ -0,0 +1,188 @@
1
+ # ๐Ÿงถ Ragdoll
2
+
3
+ **Retrieval-Augmented Generation Driven by Offline Local LLMs**
4
+
5
+ A fully-local RAG system that ingests JIRA tickets, PDF documents, and Python
6
+ source code, indexes them for semantic search, and connects to a local LLM via
7
+ [Ollama](https://ollama.ai) for interactive Q&A, summarization, and chat.
8
+
9
+ > **Privacy-first:** All data stays on your machine โ€” nothing is sent to
10
+ > external services.
11
+
12
+ ## Prerequisites
13
+
14
+ - **Python 3.12+**
15
+ - **[Ollama](https://ollama.ai)** running locally with:
16
+ - An embedding model (e.g. `nomic-embed-text`)
17
+ - A chat model (e.g. `gpt-oss:20b`, `deepseek-r1:32b`)
18
+ - **[pixi](https://pixi.sh)** for environment management
19
+
20
+ ## Quick Start
21
+
22
+ ```bash
23
+ # Clone and enter the project
24
+ cd ragdoll
25
+
26
+ # Install with pixi (creates isolated env + editable install)
27
+ pixi install
28
+
29
+ # Set up user-level configuration
30
+ mkdir -p ~/.ragdoll && chmod 700 ~/.ragdoll
31
+ cat > ~/.ragdoll/config.toml << 'EOF'
32
+ jira_url = "https://your-jira.example.com"
33
+ jira_user = "your.user"
34
+ jira_token = "YOUR_PAT_TOKEN"
35
+ jira_auth_method = "pat" # "pat" for JIRA Data Center, "basic" for Cloud
36
+ EOF
37
+ chmod 600 ~/.ragdoll/config.toml
38
+
39
+ # Check everything is connected
40
+ pixi run ragdoll status
41
+ ```
42
+
43
+ ## Usage
44
+
45
+ ### Ingest Data
46
+
47
+ ```bash
48
+ # Ingest PDF files or directories
49
+ pixi run ragdoll ingest pdf ./docs/technical_handbook.pdf
50
+ pixi run ragdoll ingest pdf ./reports/
51
+
52
+ # Ingest JIRA issues via JQL
53
+ pixi run ragdoll ingest jira --jql "project = CAS AND updated >= -30d"
54
+ pixi run ragdoll ingest jira --jql "project = PIPE AND updated >= -60d" --max-results 100
55
+
56
+ # Ingest from a different JIRA instance (multi-site)
57
+ pixi run ragdoll ingest jira \
58
+ --url https://other-jira.example.com \
59
+ --token OTHER_PAT \
60
+ --jql "project = EXT AND updated >= -30d"
61
+
62
+ # Ingest Python source code (AST-parsed per function/class)
63
+ pixi run ragdoll ingest code ./src/
64
+ pixi run ragdoll ingest code ./path/to/project/
65
+ ```
66
+
67
+ #### Reingesting Data (LlamaIndex Update)
68
+ If you are upgrading from an older version of `ragdoll` to the LlamaIndex-backed version, your existing ChromaDB data is fully backward compatible. However, it is highly recommended to wipe the old index and reingest your data to take advantage of LlamaIndex's superior semantic chunking (which splits by sentences instead of fixed character limits).
69
+
70
+ To clear your database and start fresh:
71
+ ```bash
72
+ # Delete the old ChromaDB collection
73
+ rm -rf ~/.ragdoll/data/chroma
74
+
75
+ # Re-run your ingestion commands
76
+ pixi run ragdoll ingest jira --jql "project = CAS AND updated >= -30d"
77
+ pixi run ragdoll ingest pdf ./docs/
78
+ ```
79
+
80
+ ### Search
81
+
82
+ ```bash
83
+ # Semantic search across all ingested data
84
+ pixi run ragdoll search "tclean performance regression"
85
+ pixi run ragdoll search "AsdmStMan lazy import" --source jira
86
+ pixi run ragdoll search "calibration pipeline" --source pdf -n 5
87
+ pixi run ragdoll search "embedding function" --source code
88
+ ```
89
+
90
+ ### Summarize
91
+
92
+ ```bash
93
+ # Summarize a topic from ingested data
94
+ pixi run ragdoll summarize "What are the known issues with AsdmStMan?"
95
+ pixi run ragdoll summarize "tclean parallelization" --source jira
96
+ ```
97
+
98
+ ### Interactive Chat
99
+
100
+ ```bash
101
+ # Start an interactive RAG chat session
102
+ pixi run ragdoll chat
103
+ pixi run ragdoll chat --source jira # only use JIRA context
104
+ pixi run ragdoll chat --source code # only use source code context
105
+ ```
106
+
107
+ Chat features:
108
+ - **Persistent history** โ€” arrow-up recalls previous questions across sessions
109
+ (stored in `~/.ragdoll/chat_history`)
110
+ - **Line editing** โ€” full readline support (backspace, arrows, Home/End)
111
+ - **Multi-turn** โ€” context accumulates within a session
112
+
113
+ ## Configuration
114
+
115
+ Ragdoll uses a **4-layer precedence** configuration strategy:
116
+
117
+ | Priority | Source | Purpose |
118
+ |----------|--------|---------|
119
+ | 1 (highest) | `RAGDOLL_*` environment variables | CI/ephemeral overrides |
120
+ | 2a | `./ragdoll.toml` in the project directory | Project-level settings |
121
+ | 2b | `./.env` in the project directory | Project-level secrets |
122
+ | 3 | `~/.ragdoll/config.toml` | User-level defaults & credentials |
123
+ | 4 (lowest) | Package defaults | Hardcoded fallbacks |
124
+
125
+ ### Settings Reference
126
+
127
+ | Variable / TOML key | Default | Description |
128
+ |---------------------|---------|-------------|
129
+ | `jira_url` | โ€” | JIRA server URL |
130
+ | `jira_user` | โ€” | JIRA username |
131
+ | `jira_token` | โ€” | JIRA API token or PAT |
132
+ | `jira_auth_method` | `pat` | `"pat"` for Data Center, `"basic"` for Cloud |
133
+ | `jira_batch_size` | `50` | Issues per API request |
134
+ | `ollama_host` | `http://localhost:11434` | Ollama API endpoint |
135
+ | `embed_model` | `nomic-embed-text` | Embedding model |
136
+ | `chat_model` | `gpt-oss:20b` | Chat / generation model |
137
+ | `temperature` | `0.3` | LLM sampling temperature |
138
+ | `data_dir` | `~/.ragdoll/data` | ChromaDB storage directory |
139
+ | `collection_name` | `ragdoll` | ChromaDB collection name |
140
+ | `chunk_size` | `1000` | Characters per chunk |
141
+ | `chunk_overlap` | `200` | Overlap between consecutive chunks |
142
+ | `top_k` | `20` | Default retrieval count |
143
+
144
+ ## Architecture
145
+
146
+ ```
147
+ Source Data Pipeline Storage
148
+ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€
149
+ PDF files โ”€โ”
150
+ JIRA tickets โ”€โ”ผโ”€โ†’ Ingestor โ†’ Chunker โ†’ Embedder โ†’ ChromaDB
151
+ Python code โ”€โ”˜ (AST-aware) (Ollama) (local)
152
+ โ†‘
153
+ Query Flow โ”‚
154
+ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚
155
+ CLI / Chat โ†’ Embed query โ†’ Retriever โ†โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
156
+ โ†“
157
+ LLM (Ollama) โ†’ Streamed answer
158
+ ```
159
+
160
+ ### Data Sources
161
+
162
+ | Source | Module | Strategy |
163
+ |--------|--------|----------|
164
+ | **PDF** | `ragdoll.ingest.pdf` | PyMuPDF text extraction โ†’ recursive character splitter |
165
+ | **JIRA** | `ragdoll.ingest.jira` | REST API with JQL โ†’ structured text per issue |
166
+ | **Code** | `ragdoll.ingest.code` | AST parsing โ†’ one Document per function/class/module docstring |
167
+
168
+ ### Key Components
169
+
170
+ - **Config** (`ragdoll.config`) โ€” Pydantic Settings with 4-layer precedence
171
+ - **Chunker** (`ragdoll.ingest.chunker`) โ€” Recursive character text splitter
172
+ - **Embedder** (`ragdoll.llm.ollama`) โ€” Ollama HTTP client for embeddings and generation
173
+ - **Vector Store** (`ragdoll.store.vectordb`) โ€” ChromaDB with cosine similarity
174
+ - **Retriever** (`ragdoll.query.retriever`) โ€” Semantic search with source filtering
175
+ - **RAG Chain** (`ragdoll.query.rag`) โ€” Context-augmented generation and chat
176
+ - **CLI** (`ragdoll.cli`) โ€” Click-based interface with Rich formatting
177
+
178
+ ## Documentation
179
+
180
+ Full documentation is available under `docs/` and can be built with Sphinx:
181
+
182
+ ```bash
183
+ pixi run docs
184
+ ```
185
+
186
+ ## License
187
+
188
+ MIT
@@ -0,0 +1,68 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "ragdoll-ai"
7
+ version = "0.2.0"
8
+ description = "Retrieval-Augmented Generation Driven by Offline Local LLMs โ€” a fully-local RAG system for JIRA tickets, code, and PDFs, powered by Ollama."
9
+ authors = [{name = "Rui Xue", email = "rx.astro@gmail.com"}]
10
+ requires-python = ">= 3.11"
11
+ license = {text = "MIT"}
12
+ readme = "README.md"
13
+ dependencies = [
14
+ "chromadb >= 0.6",
15
+ "pymupdf >= 1.25",
16
+ "jira >= 3.8",
17
+ "click >= 8.1",
18
+ "rich >= 13.0",
19
+ "pydantic-settings >= 2.0",
20
+ "httpx >= 0.27",
21
+ "pytest",
22
+ "fastapi",
23
+ "uvicorn",
24
+ "gradio", "llama-index", "llama-index-vector-stores-chroma", "llama-index-llms-ollama", "llama-index-embeddings-ollama", "llama-index-readers-jira",
25
+ ]
26
+
27
+ [project.optional-dependencies]
28
+ docs = [
29
+ "sphinx >= 7.0",
30
+ "furo",
31
+ "myst-parser >= 3.0",
32
+ "sphinx-autodoc-typehints",
33
+ ]
34
+
35
+ [project.scripts]
36
+ ragdoll = "ragdoll.cli:cli"
37
+
38
+
39
+
40
+ [tool.setuptools.packages.find]
41
+ where = ["src"]
42
+
43
+ [tool.pixi.workspace]
44
+ channels = ["conda-forge"]
45
+ platforms = ["linux-64", "osx-arm64"]
46
+
47
+ [tool.pixi.pypi-dependencies]
48
+ ragdoll = { path = ".", editable = true }
49
+ sphinx = ">=7.0"
50
+ furo = "*"
51
+ myst-parser = ">=3.0"
52
+ sphinx-autodoc-typehints = "*"
53
+
54
+ [tool.pixi.tasks]
55
+ ragdoll = "ragdoll"
56
+ ingest-pdf = { cmd = "ragdoll ingest pdf", description = "Ingest PDF documents" }
57
+ search = { cmd = "ragdoll search", description = "Semantic search" }
58
+ chat = { cmd = "ragdoll chat", description = "Interactive RAG chat" }
59
+ docs = { cmd = "sphinx-build -b html docs docs/_build/html", description = "Build Sphinx documentation" }
60
+
61
+ [tool.pixi.dependencies]
62
+ python = ">=3.12"
63
+ gradio = "*"
64
+ fastapi = "*"
65
+ uvicorn = "*"
66
+
67
+ [tool.pytest.ini_options]
68
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,6 @@
1
+ """Ragdoll โ€” Retrieval-Augmented Generative Discovery over Linked Logs.
2
+
3
+ A fully-local RAG system for JIRA tickets and PDF documents, powered by Ollama.
4
+ """
5
+
6
+ __version__ = "0.1.0"
@@ -0,0 +1,57 @@
1
+ import json
2
+ from fastapi import FastAPI, Request
3
+ from fastapi.responses import StreamingResponse
4
+
5
+ from ragdoll.query.rag import chat_with_context
6
+
7
+ app = FastAPI(title="Ragdoll API", description="OpenAI-compatible local RAG API")
8
+
9
+ @app.get("/v1/models")
10
+ async def list_models():
11
+ """Returns a dummy model list so Open WebUI can populate its model dropdown."""
12
+ return {
13
+ "object": "list",
14
+ "data": [
15
+ {
16
+ "id": "ragdoll-context-engine",
17
+ "object": "model",
18
+ "created": 1700000000,
19
+ "owned_by": "ragdoll",
20
+ }
21
+ ]
22
+ }
23
+
24
+ @app.post("/v1/chat/completions")
25
+ async def chat_completions(request: Request):
26
+ """OpenAI-compatible endpoint for chat completions.
27
+
28
+ Allows drop-in integration with Open WebUI and other AI frontends.
29
+
30
+ Args:
31
+ request (Request): The incoming FastAPI request object containing the JSON payload with messages.
32
+
33
+ Returns:
34
+ StreamingResponse: An SSE streaming response containing the generated text chunks.
35
+ """
36
+ body = await request.json()
37
+ messages = body.get("messages", [])
38
+
39
+ # We only support streaming for now, to provide the best UX
40
+ # If the client didn't request a stream, we could collect it, but streaming is standard for Web UIs.
41
+
42
+ def token_generator():
43
+ # Chat_with_context expects standard OpenAI message format
44
+ for chunk in chat_with_context(messages, stream=True):
45
+ # Format the output as an OpenAI-compatible SSE stream
46
+ response_obj = {
47
+ "choices": [{"delta": {"content": chunk}}]
48
+ }
49
+ yield f"data: {json.dumps(response_obj)}\n\n"
50
+ yield "data: [DONE]\n\n"
51
+
52
+ return StreamingResponse(token_generator(), media_type="text/event-stream")
53
+
54
+ def run_server(host: str = "0.0.0.0", port: int = 8000):
55
+ """Start the FastAPI uvicorn server."""
56
+ import uvicorn
57
+ uvicorn.run(app, host=host, port=port)