pandion-api 0.1.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.
- pandion_api-0.1.0/.gitignore +57 -0
- pandion_api-0.1.0/CHANGELOG.md +49 -0
- pandion_api-0.1.0/LICENSE +21 -0
- pandion_api-0.1.0/PKG-INFO +206 -0
- pandion_api-0.1.0/README.md +179 -0
- pandion_api-0.1.0/pyproject.toml +45 -0
- pandion_api-0.1.0/src/pandion_api/__init__.py +15 -0
- pandion_api-0.1.0/src/pandion_api/app.py +67 -0
- pandion_api-0.1.0/src/pandion_api/checks.py +92 -0
- pandion_api-0.1.0/src/pandion_api/credentials.py +58 -0
- pandion_api-0.1.0/src/pandion_api/deps.py +26 -0
- pandion_api-0.1.0/src/pandion_api/documents.py +206 -0
- pandion_api-0.1.0/src/pandion_api/errors.py +20 -0
- pandion_api-0.1.0/src/pandion_api/jobs.py +141 -0
- pandion_api-0.1.0/src/pandion_api/keycheck.py +68 -0
- pandion_api-0.1.0/src/pandion_api/limits.py +107 -0
- pandion_api-0.1.0/src/pandion_api/metrics.py +91 -0
- pandion_api-0.1.0/src/pandion_api/observability.py +200 -0
- pandion_api-0.1.0/src/pandion_api/pages.py +165 -0
- pandion_api-0.1.0/src/pandion_api/pipelines.py +108 -0
- pandion_api-0.1.0/src/pandion_api/policy.py +234 -0
- pandion_api-0.1.0/src/pandion_api/reports.py +116 -0
- pandion_api-0.1.0/src/pandion_api/routes/__init__.py +0 -0
- pandion_api-0.1.0/src/pandion_api/routes/ask.py +97 -0
- pandion_api-0.1.0/src/pandion_api/routes/chat.py +199 -0
- pandion_api-0.1.0/src/pandion_api/routes/conversations.py +72 -0
- pandion_api-0.1.0/src/pandion_api/routes/documents.py +221 -0
- pandion_api-0.1.0/src/pandion_api/routes/evaluations.py +330 -0
- pandion_api-0.1.0/src/pandion_api/routes/feedback.py +58 -0
- pandion_api-0.1.0/src/pandion_api/routes/health.py +15 -0
- pandion_api-0.1.0/src/pandion_api/routes/projects.py +213 -0
- pandion_api-0.1.0/src/pandion_api/routes/questions.py +486 -0
- pandion_api-0.1.0/src/pandion_api/routes/results.py +126 -0
- pandion_api-0.1.0/src/pandion_api/routes/runs.py +114 -0
- pandion_api-0.1.0/src/pandion_api/routes/serve_ask.py +71 -0
- pandion_api-0.1.0/src/pandion_api/routes/serve_health.py +46 -0
- pandion_api-0.1.0/src/pandion_api/routes/settings.py +47 -0
- pandion_api-0.1.0/src/pandion_api/routes/sort.py +38 -0
- pandion_api-0.1.0/src/pandion_api/routes/strategies.py +60 -0
- pandion_api-0.1.0/src/pandion_api/runs.py +323 -0
- pandion_api-0.1.0/src/pandion_api/serve.py +236 -0
- pandion_api-0.1.0/src/pandion_api/settings.py +27 -0
- pandion_api-0.1.0/src/pandion_api/version.py +3 -0
- pandion_api-0.1.0/tests/apihelpers.py +92 -0
- pandion_api-0.1.0/tests/conftest.py +11 -0
- pandion_api-0.1.0/tests/test_api_app.py +82 -0
- pandion_api-0.1.0/tests/test_api_ask.py +111 -0
- pandion_api-0.1.0/tests/test_api_boundary.py +163 -0
- pandion_api-0.1.0/tests/test_api_categories.py +112 -0
- pandion_api-0.1.0/tests/test_api_chat.py +309 -0
- pandion_api-0.1.0/tests/test_api_checks.py +65 -0
- pandion_api-0.1.0/tests/test_api_collection.py +65 -0
- pandion_api-0.1.0/tests/test_api_cost.py +181 -0
- pandion_api-0.1.0/tests/test_api_documents.py +162 -0
- pandion_api-0.1.0/tests/test_api_evaluations.py +566 -0
- pandion_api-0.1.0/tests/test_api_feedback.py +163 -0
- pandion_api-0.1.0/tests/test_api_generate_questions.py +231 -0
- pandion_api-0.1.0/tests/test_api_logs.py +93 -0
- pandion_api-0.1.0/tests/test_api_metrics.py +101 -0
- pandion_api-0.1.0/tests/test_api_metrics_port.py +91 -0
- pandion_api-0.1.0/tests/test_api_optional_imports.py +26 -0
- pandion_api-0.1.0/tests/test_api_otel.py +132 -0
- pandion_api-0.1.0/tests/test_api_packaging.py +130 -0
- pandion_api-0.1.0/tests/test_api_pages.py +128 -0
- pandion_api-0.1.0/tests/test_api_policy_serve.py +49 -0
- pandion_api-0.1.0/tests/test_api_projects.py +173 -0
- pandion_api-0.1.0/tests/test_api_questions.py +394 -0
- pandion_api-0.1.0/tests/test_api_results.py +141 -0
- pandion_api-0.1.0/tests/test_api_roles.py +51 -0
- pandion_api-0.1.0/tests/test_api_run_queue.py +247 -0
- pandion_api-0.1.0/tests/test_api_runs.py +346 -0
- pandion_api-0.1.0/tests/test_api_serve_app.py +96 -0
- pandion_api-0.1.0/tests/test_api_serve_ask.py +53 -0
- pandion_api-0.1.0/tests/test_api_serve_errors.py +116 -0
- pandion_api-0.1.0/tests/test_api_serve_exposure.py +52 -0
- pandion_api-0.1.0/tests/test_api_serve_keys.py +64 -0
- pandion_api-0.1.0/tests/test_api_serve_limits.py +118 -0
- pandion_api-0.1.0/tests/test_api_serve_memory_safety.py +54 -0
- pandion_api-0.1.0/tests/test_api_serve_policy_required.py +61 -0
- pandion_api-0.1.0/tests/test_api_serve_retention.py +96 -0
- pandion_api-0.1.0/tests/test_api_serve_store_url.py +21 -0
- pandion_api-0.1.0/tests/test_api_serve_user_data.py +116 -0
- pandion_api-0.1.0/tests/test_api_settings.py +102 -0
- pandion_api-0.1.0/tests/test_api_sort.py +152 -0
- pandion_api-0.1.0/tests/test_api_strategies.py +244 -0
- pandion_api-0.1.0/tests/test_api_trace_id.py +53 -0
- pandion_api-0.1.0/tests/test_api_url_documents.py +289 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
.remember/
|
|
2
|
+
|
|
3
|
+
# Python
|
|
4
|
+
.venv/
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.pyc
|
|
7
|
+
.pytest_cache/
|
|
8
|
+
.coverage
|
|
9
|
+
htmlcov/
|
|
10
|
+
*.egg-info/
|
|
11
|
+
dist/
|
|
12
|
+
build/
|
|
13
|
+
|
|
14
|
+
# Playground data — regenerable, sometimes large
|
|
15
|
+
artifacts/
|
|
16
|
+
sources/
|
|
17
|
+
runs/
|
|
18
|
+
graphs/
|
|
19
|
+
qa_sets/
|
|
20
|
+
embeddings/
|
|
21
|
+
|
|
22
|
+
# Secrets
|
|
23
|
+
.env
|
|
24
|
+
.env.*
|
|
25
|
+
!.env.example
|
|
26
|
+
|
|
27
|
+
# Node (phase 5)
|
|
28
|
+
node_modules/
|
|
29
|
+
playground/frontend/dist/
|
|
30
|
+
|
|
31
|
+
# Editors / OS
|
|
32
|
+
.vscode/
|
|
33
|
+
.idea/
|
|
34
|
+
.DS_Store
|
|
35
|
+
Thumbs.db
|
|
36
|
+
|
|
37
|
+
# Third-party agent skills (installed via `npx skills add`, not project source)
|
|
38
|
+
.agents/
|
|
39
|
+
.claude/skills/
|
|
40
|
+
|
|
41
|
+
# Browser-automation screenshots and traces
|
|
42
|
+
.playwright-mcp/
|
|
43
|
+
|
|
44
|
+
# Agent working notes, and the private plans, specs and design system (.superpowers/docs/)
|
|
45
|
+
.superpowers/
|
|
46
|
+
# Local launch-video output and the skill installer lock file
|
|
47
|
+
brag-output*/
|
|
48
|
+
skills-lock.json
|
|
49
|
+
# Agent worktrees
|
|
50
|
+
.claude/worktrees/
|
|
51
|
+
|
|
52
|
+
# The own-strategies example writes its index here
|
|
53
|
+
examples/pandion/own_strategies/work/
|
|
54
|
+
# The pandion command examples write their index here
|
|
55
|
+
examples/pandion/cli-index/
|
|
56
|
+
# The pandion-api example server keeps its files here
|
|
57
|
+
examples/pandion-api/pandion-data/
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Notable changes, newest release first, commits oldest first within a release. Releases with only housekeeping commits (docs, chore, test, ci, refactor) are not listed. A commit that touches several parts appears in each part's changelog.
|
|
4
|
+
|
|
5
|
+
Generated by git-cliff from Conventional Commit titles. See CONTRIBUTING.md to regenerate it.
|
|
6
|
+
|
|
7
|
+
## Unreleased
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- The REST package starts, with a Policy, and the playground becomes a pandion-api app (#111)
|
|
12
|
+
- Strategies, explain and pipeline validation, with a request's pipeline prepared safely (#112)
|
|
13
|
+
- Documents with the site's rules, and today's upload tests run on /api/v2 (#113)
|
|
14
|
+
- A document's file and pages, sharing the playground's pdfium lock; today's page tests run on /api/v2 (#114)
|
|
15
|
+
- Index runs and questions as runs, with progress, stop, keys and owners (#115)
|
|
16
|
+
- Results by id, clearing the cache, the miss trace and question sets (#116)
|
|
17
|
+
- Evaluations and comparisons as runs, and model key settings (#117)
|
|
18
|
+
- What the app and CLI need from Pandion: public extras, the pipeline file, and one-question comparisons (#119)
|
|
19
|
+
- Cap questions per run and runs per visitor on the demo (#135)
|
|
20
|
+
- Usage and cost in run JSON (#150)
|
|
21
|
+
- Cost of the varied step and after (#151)
|
|
22
|
+
- Write questions for a document as a run (#158)
|
|
23
|
+
- Read Word, PowerPoint, HTML, Markdown, text and images (#162)
|
|
24
|
+
- Llm_context adds a model-written context before embedding (#166)
|
|
25
|
+
- Filter a search by document, pages or section (#170)
|
|
26
|
+
- Add a document from a link, and non-PDF uploads (#173)
|
|
27
|
+
- Compare an evaluation with a baseline on the server (#178)
|
|
28
|
+
- Say which step and setting a refused pipeline is about (#179)
|
|
29
|
+
- Sum up a chunk set with pandion.chunk.stats (#180)
|
|
30
|
+
- Own-document scoring, totals by document, one set across documents (#184)
|
|
31
|
+
- One question set for a pipeline with several documents (#186)
|
|
32
|
+
- Compare recipes over several documents (#188)
|
|
33
|
+
- Categories, routes and sorting over REST (C6) (#215)
|
|
34
|
+
- Evaluate and compare name the index collection (T11) (#241)
|
|
35
|
+
- Stage and trace id on executor events (T17) (#243)
|
|
36
|
+
- Serve mode with streaming /chat, policy roles and limits (T15)
|
|
37
|
+
- Serve ask, conversations and memories routes (T15b)
|
|
38
|
+
- Json logs, trace id and otel spans for serve (T18)
|
|
39
|
+
- Fenced sources, unsourced links removed (T30a)
|
|
40
|
+
- Serve hardening, scrubbed errors, default limits (T29)
|
|
41
|
+
- Prometheus metrics on its own port (T19)
|
|
42
|
+
- Forget-user, sql url_env and retention sweep (T30b)
|
|
43
|
+
- POST /feedback and feedback_total metric (T26) (#265)
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- Find the gold passage with Pandion's own rule (#177)
|
|
48
|
+
- Refuse a PDF or image renamed as a text file before indexing (#191)
|
|
49
|
+
- A new question set replaces every older set it overlaps (#192)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Nadeem Khan
|
|
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,206 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: pandion-api
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Pandion's public API over HTTP, with one Policy object for a site's rules
|
|
5
|
+
Project-URL: Documentation, https://github.com/nadeem4/rag-playground/blob/main/docs/pandion-api/index.md
|
|
6
|
+
Project-URL: Source, https://github.com/nadeem4/rag-playground/tree/main/packages/pandion-api
|
|
7
|
+
Project-URL: Issues, https://github.com/nadeem4/rag-playground/issues
|
|
8
|
+
Author: Nadeem Khan
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: fastapi,pandion,rag,rest,retrieval
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
16
|
+
Requires-Python: <3.14,>=3.13
|
|
17
|
+
Requires-Dist: fastapi>=0.141.1
|
|
18
|
+
Requires-Dist: pandion[anthropic,openai,pdfium]<0.9,>=0.8.0
|
|
19
|
+
Requires-Dist: pillow>=12.3.0
|
|
20
|
+
Requires-Dist: python-multipart>=0.0.32
|
|
21
|
+
Provides-Extra: metrics
|
|
22
|
+
Requires-Dist: prometheus-client>=0.21; extra == 'metrics'
|
|
23
|
+
Provides-Extra: otel
|
|
24
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.27; extra == 'otel'
|
|
25
|
+
Requires-Dist: opentelemetry-sdk>=1.27; extra == 'otel'
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# pandion-api
|
|
29
|
+
|
|
30
|
+
pandion-api serves [Pandion](https://github.com/nadeem4/rag-playground/blob/main/packages/pandion/README.md) over REST. It is a FastAPI app factory:
|
|
31
|
+
`create_app` gives you a FastAPI app with Pandion's documents, runs, questions,
|
|
32
|
+
evaluations and comparisons as HTTP routes. RAG Playground mounts it at `/api/v2`.
|
|
33
|
+
|
|
34
|
+
Every route that takes a pipeline takes the pipeline file's shape as JSON, the same dict
|
|
35
|
+
`Pipeline.from_dict` reads. Everything a site wants to limit is one `Policy` object, and
|
|
36
|
+
the default allows everything.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install pandion-api
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
It needs Python 3.13 and works with the Pandion versions its `pyproject.toml` declares
|
|
45
|
+
(`pandion>=0.8.0,<0.9` today), which `pip` installs for you. The pipeline's store needs its extra, for example
|
|
46
|
+
`pip install pandion-api "pandion[lancedb]"`.
|
|
47
|
+
|
|
48
|
+
[docs/pandion-api/index.md](https://github.com/nadeem4/rag-playground/blob/main/docs/pandion-api/index.md) is the full reference.
|
|
49
|
+
[Changelog](https://github.com/nadeem4/rag-playground/blob/main/packages/pandion-api/CHANGELOG.md): what changed in each release.
|
|
50
|
+
|
|
51
|
+
## Run it
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
# serve.py
|
|
55
|
+
from pathlib import Path
|
|
56
|
+
|
|
57
|
+
from pandion_api import ApiSettings, create_app
|
|
58
|
+
|
|
59
|
+
app = create_app(ApiSettings(data_dir=Path("./pandion-data"), prefix="/api/v2"))
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
uvicorn serve:app
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
With no `prefix` the routes sit at the root, so once it runs, `curl http://127.0.0.1:8000/health`
|
|
67
|
+
(or `/api/v2/health` with the prefix above) is the first call. The reference has a
|
|
68
|
+
[step by step first run](https://github.com/nadeem4/rag-playground/blob/main/docs/pandion-api/index.md#a-first-run-step-by-step).
|
|
69
|
+
|
|
70
|
+
`ApiSettings` takes `data_dir`, the one folder every request runs under. It also takes
|
|
71
|
+
`models` (a `pandion.ModelSettings`), `prefix` (where the routes are mounted) and `title`.
|
|
72
|
+
Pass a `Policy` as the second argument to `create_app` to set your site's rules.
|
|
73
|
+
|
|
74
|
+
[examples/pandion-api/](https://github.com/nadeem4/rag-playground/blob/main/examples/pandion-api) has a server script, a Python client
|
|
75
|
+
that validates, uploads, indexes, asks and evaluates, the same steps as curl commands,
|
|
76
|
+
and a small Policy.
|
|
77
|
+
|
|
78
|
+
## Serve mode
|
|
79
|
+
|
|
80
|
+
For a site's own users, `create_app(settings, policy, mode="serve", pipeline="pipeline.yaml")`
|
|
81
|
+
loads one pipeline file once and answers `POST /chat`, as JSON or as server-sent events. Your
|
|
82
|
+
`Policy` says who is asking (`user_id`), which roles they have (`roles`) and whether they may
|
|
83
|
+
ask now (`limit`). Serve refuses to start without a Policy that overrides all three; pass
|
|
84
|
+
`Policy.anonymous()` to say on purpose that everyone is one user. Build the index first with
|
|
85
|
+
`pandion sync`.
|
|
86
|
+
|
|
87
|
+
Serve is hardened by default: generic errors with a trace id, model keys from the environment
|
|
88
|
+
only, public model endpoints only, a limit of 20 turns a minute and 2 active turns for each
|
|
89
|
+
user, a 64 KB request body, a 120 second turn, no `/docs` and no CORS. See
|
|
90
|
+
[Serve mode: hardened defaults](https://github.com/nadeem4/rag-playground/blob/main/docs/pandion-api/serve-mode.md#serve-mode-hardened-defaults).
|
|
91
|
+
[`serve_policy.py`](https://github.com/nadeem4/rag-playground/blob/main/examples/pandion-api/serve_policy.py) shows a Policy that checks a
|
|
92
|
+
signed gateway token.
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
curl -N http://127.0.0.1:8000/chat -H 'content-type: application/json' \
|
|
96
|
+
-d '{"messages": [{"role": "user", "content": "How long is the notice period?"}], "stream": true}'
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Serve also has `POST /ask` (one question, nothing stored), `GET /conversations`,
|
|
100
|
+
`GET` and `DELETE /conversations/{id}`, `GET /memories` and `DELETE /memories/{id}`, and
|
|
101
|
+
`POST /feedback` (up or down on a trace). A user
|
|
102
|
+
only ever sees their own; anything else is a 404.
|
|
103
|
+
|
|
104
|
+
[docs/pandion-api/serve-mode.md](https://github.com/nadeem4/rag-playground/blob/main/docs/pandion-api/serve-mode.md#serve-mode) has the request, the events and `/ready`.
|
|
105
|
+
|
|
106
|
+
Serve deletes conversations older than `ServeSettings(retention_days=90)` every day, and
|
|
107
|
+
`pandion forget-user` removes one user's data. See [Your users' data](https://github.com/nadeem4/rag-playground/blob/main/docs/pandion-api/serve-mode.md#your-users-data).
|
|
108
|
+
|
|
109
|
+
Serve mode logs one JSON line per request, step and failure, and sets an `X-Trace-Id` header.
|
|
110
|
+
For OpenTelemetry spans, install `pandion-api[otel]` and set `OTEL_EXPORTER_OTLP_ENDPOINT`.
|
|
111
|
+
See [Logs and traces](https://github.com/nadeem4/rag-playground/blob/main/docs/pandion-api/serve-mode.md#logs-and-traces).
|
|
112
|
+
For Prometheus metrics on their own port, install `pandion-api[metrics]` and set
|
|
113
|
+
`ServeSettings(metrics_port=9464)`. See [Metrics](https://github.com/nadeem4/rag-playground/blob/main/docs/pandion-api/serve-mode.md#metrics).
|
|
114
|
+
|
|
115
|
+
## The routes
|
|
116
|
+
|
|
117
|
+
Each path is under `prefix`.
|
|
118
|
+
|
|
119
|
+
| Route | What it does |
|
|
120
|
+
|---|---|
|
|
121
|
+
| `GET /health` | Says the server is up, with the Pandion and pandion-api versions. |
|
|
122
|
+
| `GET /strategies` | Lists every strategy by step, with its settings as a JSON schema. |
|
|
123
|
+
| `POST /explain` | Says in plain words what a strategy will do with given settings. |
|
|
124
|
+
| `POST /pipelines/validate` | Checks a pipeline and returns it as a YAML file, or the problems. |
|
|
125
|
+
| `GET /documents` | Lists the documents this caller may read. |
|
|
126
|
+
| `POST /documents` | Stores an uploaded file by its fingerprint. |
|
|
127
|
+
| `POST /documents/url` | Fetches one web page and stores it like an upload, with its link as `origin_url`. |
|
|
128
|
+
| `DELETE /documents/{id}` | Deletes a document, its record and its question set. |
|
|
129
|
+
| `GET /documents/{id}/file` | Returns the file's own bytes. |
|
|
130
|
+
| `GET /documents/{id}/pages` | Returns each page's size. |
|
|
131
|
+
| `GET /documents/{id}/pages/{n}` | Returns one page as a PNG image. |
|
|
132
|
+
| `GET /documents/{id}/pages/{n}/find` | Finds where a piece of text is on a page. |
|
|
133
|
+
| `POST /documents/{id}/questions` | Checks a question set against the document, and keeps it if the Policy says so. |
|
|
134
|
+
| `GET /documents/{id}/questions` | Returns the question set kept for a document. |
|
|
135
|
+
| `DELETE /documents/{id}/questions` | Removes that question set. |
|
|
136
|
+
| `POST /documents/{id}/questions/generate` | Has a model write test questions for a document, as a run. |
|
|
137
|
+
| `POST /questions` | Checks one question set against several documents, and keeps it if the Policy says so. |
|
|
138
|
+
| `GET /questions` | Returns the question sets kept against several documents, as one. |
|
|
139
|
+
| `POST /golds/find` | Says which piece first holds a gold passage, by the eval step's rule. |
|
|
140
|
+
| `POST /evaluations/against` | Compares a run with a baseline: questions newly missed and newly found, and which run is better. |
|
|
141
|
+
| `POST /pipelines/sort` | Shows which category each document would go to and why. Nothing runs. |
|
|
142
|
+
| `POST /projects/serve` | Writes the deployable serve project for a pipeline, its questions per category and where it will run, as a zip or (`?preview=1`) JSON. Sample questions are left out. |
|
|
143
|
+
| `POST /runs` | Starts a run that indexes documents, or stops after one step. |
|
|
144
|
+
| `GET /runs/{run_id}` | Returns a run's status, its events and its result. |
|
|
145
|
+
| `GET /runs/{run_id}/events` | Streams a run's events as server-sent events. |
|
|
146
|
+
| `POST /runs/{run_id}/cancel` | Stops a run between steps. |
|
|
147
|
+
| `POST /ask` | Searches the documents for a question, and answers it. |
|
|
148
|
+
| `POST /evaluations` | Checks whether each question's answer came back, and which step lost a miss. |
|
|
149
|
+
| `POST /comparisons` | Runs one step's variants side by side and names the best. |
|
|
150
|
+
| `GET /results/{id}` | Returns a stored result's type and details. |
|
|
151
|
+
| `GET /results/{id}/payload` | Returns the stored result itself. |
|
|
152
|
+
| `POST /chunk-stats` | Sums up several chunk sets, one chunker's over several documents, as one. |
|
|
153
|
+
| `DELETE /cache` | Removes every stored result and the embedding cache, and keeps the documents. |
|
|
154
|
+
| `GET /settings/models` | Says where the server's own key for each provider comes from, never the key. |
|
|
155
|
+
| `POST /settings/models/check` | Checks that the key a request would use works. |
|
|
156
|
+
| `POST /trace` | Follows one missed question step by step through a finished run. |
|
|
157
|
+
|
|
158
|
+
Every run's result carries `usage` on each step (the token counts and model ids of its
|
|
159
|
+
model call, or null) and `cost` on each report (seconds, tokens and estimated dollars).
|
|
160
|
+
[Speed and cost](https://github.com/nadeem4/rag-playground/blob/main/docs/pandion-api/index.md#speed-and-cost) lists the fields.
|
|
161
|
+
|
|
162
|
+
## The Policy
|
|
163
|
+
|
|
164
|
+
A site subclasses `pandion_api.Policy` and overrides only what it needs. A method refuses
|
|
165
|
+
by raising `fastapi.HTTPException`. These are the hooks, from `pandion_api/policy.py`:
|
|
166
|
+
|
|
167
|
+
- `dependencies()`: FastAPI dependencies to run on every route, such as one that sets a cookie.
|
|
168
|
+
- `can_read(sha, request)`: may this request read this document?
|
|
169
|
+
- `check_upload(file, request)`: read an upload and return its bytes, or refuse it.
|
|
170
|
+
- `check_document(data, filename, request)`: refuse a document's bytes, for an upload and a URL document alike.
|
|
171
|
+
- `check_fetch(url, request)`: refuse a link before it is fetched.
|
|
172
|
+
- `fetch_slot(request)`: a context manager the fetch runs inside, for example to limit fetches at once.
|
|
173
|
+
- `max_url_bytes(request)`: the largest page a link may fetch (20 MB by default).
|
|
174
|
+
- `on_uploaded(document, request)`: called right after an upload's record is written.
|
|
175
|
+
- `on_delete(sha, document, request)`: refuse a delete, or say whether to delete the file now.
|
|
176
|
+
- `describe(document, request)`: extra keys to add to a document in the list.
|
|
177
|
+
- `private(sha, request)`: is this document one caller's own, so its page images are cached privately?
|
|
178
|
+
- `keeps_question_sets(request)`: keep a checked question set, or only check it?
|
|
179
|
+
- `max_active_runs()`: how many runs may work at once.
|
|
180
|
+
- `strategies(catalog, request)`: the strategy list a caller is shown.
|
|
181
|
+
- `check_run(config, request)`: refuse a pipeline before it runs.
|
|
182
|
+
- `public_endpoints_only(request)`: accept only a public https address for a custom model endpoint?
|
|
183
|
+
- `max_variants(request)`: how many variants one comparison may run.
|
|
184
|
+
- `check_question_count(kind, count, request)`: refuse an evaluation or comparison with too many questions.
|
|
185
|
+
- `max_runs_per_owner(request)`: how many runs one owner may have at once.
|
|
186
|
+
- `run_owner(request)`: who a run belongs to.
|
|
187
|
+
- `check_clear_cache(request)`: refuse `DELETE /cache`.
|
|
188
|
+
- `server_key(provider)`: the key the server itself has for a provider, and where it came from.
|
|
189
|
+
- `key(provider, request)`: the key for this request, and where it came from.
|
|
190
|
+
- `credentials(request)`: the keys a run gets.
|
|
191
|
+
- `missing_key(provider)`: what a key check says when there is no key.
|
|
192
|
+
- `check_provider(provider, request)`: refuse a key check for a provider.
|
|
193
|
+
- `scrub(text)`: an error message as it may leave the server.
|
|
194
|
+
- `on_startup(app)` and `on_shutdown(app)`: called once as the server starts and stops.
|
|
195
|
+
|
|
196
|
+
A complete, tested example is [`policy_example.py`](https://github.com/nadeem4/rag-playground/blob/main/examples/pandion-api/policy_example.py): a `SizeLimitedPolicy` that changes only `check_document` to refuse a document over a size limit with a 413.
|
|
197
|
+
|
|
198
|
+
Two class attributes set wording: `not_readable` is the message for a document the caller
|
|
199
|
+
may not read, and `not_keeping_note` is what a question set report says when the set was
|
|
200
|
+
not kept.
|
|
201
|
+
|
|
202
|
+
## How the playground uses it
|
|
203
|
+
|
|
204
|
+
The playground's backend, in [playground/backend/](https://github.com/nadeem4/rag-playground/blob/main/playground/backend/README.md),
|
|
205
|
+
calls `create_app` with `ApiSettings(prefix="/api/v2")` and `PlaygroundPolicy`, the hosted
|
|
206
|
+
demo's rules. It then adds its own routes under `/api` and serves the web app.
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# pandion-api
|
|
2
|
+
|
|
3
|
+
pandion-api serves [Pandion](https://github.com/nadeem4/rag-playground/blob/main/packages/pandion/README.md) over REST. It is a FastAPI app factory:
|
|
4
|
+
`create_app` gives you a FastAPI app with Pandion's documents, runs, questions,
|
|
5
|
+
evaluations and comparisons as HTTP routes. RAG Playground mounts it at `/api/v2`.
|
|
6
|
+
|
|
7
|
+
Every route that takes a pipeline takes the pipeline file's shape as JSON, the same dict
|
|
8
|
+
`Pipeline.from_dict` reads. Everything a site wants to limit is one `Policy` object, and
|
|
9
|
+
the default allows everything.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install pandion-api
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
It needs Python 3.13 and works with the Pandion versions its `pyproject.toml` declares
|
|
18
|
+
(`pandion>=0.8.0,<0.9` today), which `pip` installs for you. The pipeline's store needs its extra, for example
|
|
19
|
+
`pip install pandion-api "pandion[lancedb]"`.
|
|
20
|
+
|
|
21
|
+
[docs/pandion-api/index.md](https://github.com/nadeem4/rag-playground/blob/main/docs/pandion-api/index.md) is the full reference.
|
|
22
|
+
[Changelog](https://github.com/nadeem4/rag-playground/blob/main/packages/pandion-api/CHANGELOG.md): what changed in each release.
|
|
23
|
+
|
|
24
|
+
## Run it
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
# serve.py
|
|
28
|
+
from pathlib import Path
|
|
29
|
+
|
|
30
|
+
from pandion_api import ApiSettings, create_app
|
|
31
|
+
|
|
32
|
+
app = create_app(ApiSettings(data_dir=Path("./pandion-data"), prefix="/api/v2"))
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
uvicorn serve:app
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
With no `prefix` the routes sit at the root, so once it runs, `curl http://127.0.0.1:8000/health`
|
|
40
|
+
(or `/api/v2/health` with the prefix above) is the first call. The reference has a
|
|
41
|
+
[step by step first run](https://github.com/nadeem4/rag-playground/blob/main/docs/pandion-api/index.md#a-first-run-step-by-step).
|
|
42
|
+
|
|
43
|
+
`ApiSettings` takes `data_dir`, the one folder every request runs under. It also takes
|
|
44
|
+
`models` (a `pandion.ModelSettings`), `prefix` (where the routes are mounted) and `title`.
|
|
45
|
+
Pass a `Policy` as the second argument to `create_app` to set your site's rules.
|
|
46
|
+
|
|
47
|
+
[examples/pandion-api/](https://github.com/nadeem4/rag-playground/blob/main/examples/pandion-api) has a server script, a Python client
|
|
48
|
+
that validates, uploads, indexes, asks and evaluates, the same steps as curl commands,
|
|
49
|
+
and a small Policy.
|
|
50
|
+
|
|
51
|
+
## Serve mode
|
|
52
|
+
|
|
53
|
+
For a site's own users, `create_app(settings, policy, mode="serve", pipeline="pipeline.yaml")`
|
|
54
|
+
loads one pipeline file once and answers `POST /chat`, as JSON or as server-sent events. Your
|
|
55
|
+
`Policy` says who is asking (`user_id`), which roles they have (`roles`) and whether they may
|
|
56
|
+
ask now (`limit`). Serve refuses to start without a Policy that overrides all three; pass
|
|
57
|
+
`Policy.anonymous()` to say on purpose that everyone is one user. Build the index first with
|
|
58
|
+
`pandion sync`.
|
|
59
|
+
|
|
60
|
+
Serve is hardened by default: generic errors with a trace id, model keys from the environment
|
|
61
|
+
only, public model endpoints only, a limit of 20 turns a minute and 2 active turns for each
|
|
62
|
+
user, a 64 KB request body, a 120 second turn, no `/docs` and no CORS. See
|
|
63
|
+
[Serve mode: hardened defaults](https://github.com/nadeem4/rag-playground/blob/main/docs/pandion-api/serve-mode.md#serve-mode-hardened-defaults).
|
|
64
|
+
[`serve_policy.py`](https://github.com/nadeem4/rag-playground/blob/main/examples/pandion-api/serve_policy.py) shows a Policy that checks a
|
|
65
|
+
signed gateway token.
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
curl -N http://127.0.0.1:8000/chat -H 'content-type: application/json' \
|
|
69
|
+
-d '{"messages": [{"role": "user", "content": "How long is the notice period?"}], "stream": true}'
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Serve also has `POST /ask` (one question, nothing stored), `GET /conversations`,
|
|
73
|
+
`GET` and `DELETE /conversations/{id}`, `GET /memories` and `DELETE /memories/{id}`, and
|
|
74
|
+
`POST /feedback` (up or down on a trace). A user
|
|
75
|
+
only ever sees their own; anything else is a 404.
|
|
76
|
+
|
|
77
|
+
[docs/pandion-api/serve-mode.md](https://github.com/nadeem4/rag-playground/blob/main/docs/pandion-api/serve-mode.md#serve-mode) has the request, the events and `/ready`.
|
|
78
|
+
|
|
79
|
+
Serve deletes conversations older than `ServeSettings(retention_days=90)` every day, and
|
|
80
|
+
`pandion forget-user` removes one user's data. See [Your users' data](https://github.com/nadeem4/rag-playground/blob/main/docs/pandion-api/serve-mode.md#your-users-data).
|
|
81
|
+
|
|
82
|
+
Serve mode logs one JSON line per request, step and failure, and sets an `X-Trace-Id` header.
|
|
83
|
+
For OpenTelemetry spans, install `pandion-api[otel]` and set `OTEL_EXPORTER_OTLP_ENDPOINT`.
|
|
84
|
+
See [Logs and traces](https://github.com/nadeem4/rag-playground/blob/main/docs/pandion-api/serve-mode.md#logs-and-traces).
|
|
85
|
+
For Prometheus metrics on their own port, install `pandion-api[metrics]` and set
|
|
86
|
+
`ServeSettings(metrics_port=9464)`. See [Metrics](https://github.com/nadeem4/rag-playground/blob/main/docs/pandion-api/serve-mode.md#metrics).
|
|
87
|
+
|
|
88
|
+
## The routes
|
|
89
|
+
|
|
90
|
+
Each path is under `prefix`.
|
|
91
|
+
|
|
92
|
+
| Route | What it does |
|
|
93
|
+
|---|---|
|
|
94
|
+
| `GET /health` | Says the server is up, with the Pandion and pandion-api versions. |
|
|
95
|
+
| `GET /strategies` | Lists every strategy by step, with its settings as a JSON schema. |
|
|
96
|
+
| `POST /explain` | Says in plain words what a strategy will do with given settings. |
|
|
97
|
+
| `POST /pipelines/validate` | Checks a pipeline and returns it as a YAML file, or the problems. |
|
|
98
|
+
| `GET /documents` | Lists the documents this caller may read. |
|
|
99
|
+
| `POST /documents` | Stores an uploaded file by its fingerprint. |
|
|
100
|
+
| `POST /documents/url` | Fetches one web page and stores it like an upload, with its link as `origin_url`. |
|
|
101
|
+
| `DELETE /documents/{id}` | Deletes a document, its record and its question set. |
|
|
102
|
+
| `GET /documents/{id}/file` | Returns the file's own bytes. |
|
|
103
|
+
| `GET /documents/{id}/pages` | Returns each page's size. |
|
|
104
|
+
| `GET /documents/{id}/pages/{n}` | Returns one page as a PNG image. |
|
|
105
|
+
| `GET /documents/{id}/pages/{n}/find` | Finds where a piece of text is on a page. |
|
|
106
|
+
| `POST /documents/{id}/questions` | Checks a question set against the document, and keeps it if the Policy says so. |
|
|
107
|
+
| `GET /documents/{id}/questions` | Returns the question set kept for a document. |
|
|
108
|
+
| `DELETE /documents/{id}/questions` | Removes that question set. |
|
|
109
|
+
| `POST /documents/{id}/questions/generate` | Has a model write test questions for a document, as a run. |
|
|
110
|
+
| `POST /questions` | Checks one question set against several documents, and keeps it if the Policy says so. |
|
|
111
|
+
| `GET /questions` | Returns the question sets kept against several documents, as one. |
|
|
112
|
+
| `POST /golds/find` | Says which piece first holds a gold passage, by the eval step's rule. |
|
|
113
|
+
| `POST /evaluations/against` | Compares a run with a baseline: questions newly missed and newly found, and which run is better. |
|
|
114
|
+
| `POST /pipelines/sort` | Shows which category each document would go to and why. Nothing runs. |
|
|
115
|
+
| `POST /projects/serve` | Writes the deployable serve project for a pipeline, its questions per category and where it will run, as a zip or (`?preview=1`) JSON. Sample questions are left out. |
|
|
116
|
+
| `POST /runs` | Starts a run that indexes documents, or stops after one step. |
|
|
117
|
+
| `GET /runs/{run_id}` | Returns a run's status, its events and its result. |
|
|
118
|
+
| `GET /runs/{run_id}/events` | Streams a run's events as server-sent events. |
|
|
119
|
+
| `POST /runs/{run_id}/cancel` | Stops a run between steps. |
|
|
120
|
+
| `POST /ask` | Searches the documents for a question, and answers it. |
|
|
121
|
+
| `POST /evaluations` | Checks whether each question's answer came back, and which step lost a miss. |
|
|
122
|
+
| `POST /comparisons` | Runs one step's variants side by side and names the best. |
|
|
123
|
+
| `GET /results/{id}` | Returns a stored result's type and details. |
|
|
124
|
+
| `GET /results/{id}/payload` | Returns the stored result itself. |
|
|
125
|
+
| `POST /chunk-stats` | Sums up several chunk sets, one chunker's over several documents, as one. |
|
|
126
|
+
| `DELETE /cache` | Removes every stored result and the embedding cache, and keeps the documents. |
|
|
127
|
+
| `GET /settings/models` | Says where the server's own key for each provider comes from, never the key. |
|
|
128
|
+
| `POST /settings/models/check` | Checks that the key a request would use works. |
|
|
129
|
+
| `POST /trace` | Follows one missed question step by step through a finished run. |
|
|
130
|
+
|
|
131
|
+
Every run's result carries `usage` on each step (the token counts and model ids of its
|
|
132
|
+
model call, or null) and `cost` on each report (seconds, tokens and estimated dollars).
|
|
133
|
+
[Speed and cost](https://github.com/nadeem4/rag-playground/blob/main/docs/pandion-api/index.md#speed-and-cost) lists the fields.
|
|
134
|
+
|
|
135
|
+
## The Policy
|
|
136
|
+
|
|
137
|
+
A site subclasses `pandion_api.Policy` and overrides only what it needs. A method refuses
|
|
138
|
+
by raising `fastapi.HTTPException`. These are the hooks, from `pandion_api/policy.py`:
|
|
139
|
+
|
|
140
|
+
- `dependencies()`: FastAPI dependencies to run on every route, such as one that sets a cookie.
|
|
141
|
+
- `can_read(sha, request)`: may this request read this document?
|
|
142
|
+
- `check_upload(file, request)`: read an upload and return its bytes, or refuse it.
|
|
143
|
+
- `check_document(data, filename, request)`: refuse a document's bytes, for an upload and a URL document alike.
|
|
144
|
+
- `check_fetch(url, request)`: refuse a link before it is fetched.
|
|
145
|
+
- `fetch_slot(request)`: a context manager the fetch runs inside, for example to limit fetches at once.
|
|
146
|
+
- `max_url_bytes(request)`: the largest page a link may fetch (20 MB by default).
|
|
147
|
+
- `on_uploaded(document, request)`: called right after an upload's record is written.
|
|
148
|
+
- `on_delete(sha, document, request)`: refuse a delete, or say whether to delete the file now.
|
|
149
|
+
- `describe(document, request)`: extra keys to add to a document in the list.
|
|
150
|
+
- `private(sha, request)`: is this document one caller's own, so its page images are cached privately?
|
|
151
|
+
- `keeps_question_sets(request)`: keep a checked question set, or only check it?
|
|
152
|
+
- `max_active_runs()`: how many runs may work at once.
|
|
153
|
+
- `strategies(catalog, request)`: the strategy list a caller is shown.
|
|
154
|
+
- `check_run(config, request)`: refuse a pipeline before it runs.
|
|
155
|
+
- `public_endpoints_only(request)`: accept only a public https address for a custom model endpoint?
|
|
156
|
+
- `max_variants(request)`: how many variants one comparison may run.
|
|
157
|
+
- `check_question_count(kind, count, request)`: refuse an evaluation or comparison with too many questions.
|
|
158
|
+
- `max_runs_per_owner(request)`: how many runs one owner may have at once.
|
|
159
|
+
- `run_owner(request)`: who a run belongs to.
|
|
160
|
+
- `check_clear_cache(request)`: refuse `DELETE /cache`.
|
|
161
|
+
- `server_key(provider)`: the key the server itself has for a provider, and where it came from.
|
|
162
|
+
- `key(provider, request)`: the key for this request, and where it came from.
|
|
163
|
+
- `credentials(request)`: the keys a run gets.
|
|
164
|
+
- `missing_key(provider)`: what a key check says when there is no key.
|
|
165
|
+
- `check_provider(provider, request)`: refuse a key check for a provider.
|
|
166
|
+
- `scrub(text)`: an error message as it may leave the server.
|
|
167
|
+
- `on_startup(app)` and `on_shutdown(app)`: called once as the server starts and stops.
|
|
168
|
+
|
|
169
|
+
A complete, tested example is [`policy_example.py`](https://github.com/nadeem4/rag-playground/blob/main/examples/pandion-api/policy_example.py): a `SizeLimitedPolicy` that changes only `check_document` to refuse a document over a size limit with a 413.
|
|
170
|
+
|
|
171
|
+
Two class attributes set wording: `not_readable` is the message for a document the caller
|
|
172
|
+
may not read, and `not_keeping_note` is what a question set report says when the set was
|
|
173
|
+
not kept.
|
|
174
|
+
|
|
175
|
+
## How the playground uses it
|
|
176
|
+
|
|
177
|
+
The playground's backend, in [playground/backend/](https://github.com/nadeem4/rag-playground/blob/main/playground/backend/README.md),
|
|
178
|
+
calls `create_app` with `ApiSettings(prefix="/api/v2")` and `PlaygroundPolicy`, the hosted
|
|
179
|
+
demo's rules. It then adds its own routes under `/api` and serves the web app.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "pandion-api"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Pandion's public API over HTTP, with one Policy object for a site's rules"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [{ name = "Nadeem Khan" }]
|
|
7
|
+
requires-python = ">=3.13,<3.14"
|
|
8
|
+
dependencies = [
|
|
9
|
+
# anthropic and openai: the key check (keycheck.py) calls each SDK.
|
|
10
|
+
"pandion[pdfium,anthropic,openai]>=0.8.0,<0.9",
|
|
11
|
+
"fastapi>=0.141.1",
|
|
12
|
+
"pillow>=12.3.0",
|
|
13
|
+
"python-multipart>=0.0.32",
|
|
14
|
+
]
|
|
15
|
+
license = "MIT"
|
|
16
|
+
license-files = ["LICENSE"]
|
|
17
|
+
keywords = ["retrieval", "rag", "rest", "fastapi", "pandion"]
|
|
18
|
+
classifiers = [
|
|
19
|
+
"Development Status :: 3 - Alpha",
|
|
20
|
+
"Intended Audience :: Developers",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.urls]
|
|
26
|
+
Documentation = "https://github.com/nadeem4/rag-playground/blob/main/docs/pandion-api/index.md"
|
|
27
|
+
Source = "https://github.com/nadeem4/rag-playground/tree/main/packages/pandion-api"
|
|
28
|
+
Issues = "https://github.com/nadeem4/rag-playground/issues"
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
# OpenTelemetry spans in serve mode (docs/pandion-api/serve-mode.md, "Logs and traces").
|
|
32
|
+
otel = ["opentelemetry-sdk>=1.27", "opentelemetry-exporter-otlp-proto-http>=1.27"]
|
|
33
|
+
# Prometheus metrics on their own port in serve mode (docs/pandion-api/serve-mode.md, "Metrics").
|
|
34
|
+
metrics = ["prometheus-client>=0.21"]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
[tool.uv.sources]
|
|
38
|
+
pandion = { workspace = true }
|
|
39
|
+
|
|
40
|
+
[build-system]
|
|
41
|
+
requires = ["hatchling"]
|
|
42
|
+
build-backend = "hatchling.build"
|
|
43
|
+
|
|
44
|
+
[tool.hatch.build.targets.wheel]
|
|
45
|
+
packages = ["src/pandion_api"]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""pandion-api: Pandion's public API over HTTP, with one Policy for a site's rules.
|
|
2
|
+
|
|
3
|
+
`create_app(ApiSettings(data_dir=...), policy)` gives a FastAPI app. Every
|
|
4
|
+
endpoint that takes a pipeline takes the pipeline file's shape as JSON.
|
|
5
|
+
`create_app(settings, policy, mode="serve", pipeline="pipeline.yaml")` instead
|
|
6
|
+
serves one fixed pipeline to a site's users. See docs/pandion-api/index.md.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from pandion_api.app import create_app
|
|
10
|
+
from pandion_api.policy import Policy
|
|
11
|
+
from pandion_api.serve import ServeSettings
|
|
12
|
+
from pandion_api.settings import ApiSettings
|
|
13
|
+
from pandion_api.version import VERSION as __version__
|
|
14
|
+
|
|
15
|
+
__all__ = ["ApiSettings", "Policy", "ServeSettings", "create_app", "__version__"]
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"""create_app: a FastAPI app over Pandion's public API, with a site's Policy."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from contextlib import asynccontextmanager
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from fastapi import FastAPI
|
|
10
|
+
|
|
11
|
+
from pandion_api.documents import DocumentStore
|
|
12
|
+
from pandion_api.policy import Policy
|
|
13
|
+
from pandion_api.routes import ask, documents, evaluations, health, projects, questions, results, sort, strategies
|
|
14
|
+
from pandion_api.routes import runs as run_routes
|
|
15
|
+
from pandion_api.routes import settings as settings_routes
|
|
16
|
+
from pandion_api.runs import RunManager
|
|
17
|
+
from pandion_api.settings import ApiSettings
|
|
18
|
+
|
|
19
|
+
#: Every router, in the order docs/pandion-api/index.md lists them.
|
|
20
|
+
ROUTERS = (
|
|
21
|
+
health.router, strategies.router, documents.router, questions.router, run_routes.router, sort.router, ask.router,
|
|
22
|
+
evaluations.router, results.router, settings_routes.router, projects.router,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def create_app(
|
|
27
|
+
settings: ApiSettings,
|
|
28
|
+
policy: Policy | None = None,
|
|
29
|
+
*,
|
|
30
|
+
mode: str = "lab",
|
|
31
|
+
pipeline: str | Path | None = None,
|
|
32
|
+
conversations: Any = None,
|
|
33
|
+
serve: Any = None,
|
|
34
|
+
) -> FastAPI:
|
|
35
|
+
"""The app. `policy` holds the site's rules; the default allows everything.
|
|
36
|
+
|
|
37
|
+
`mode="lab"` (the default) takes a pipeline with each request. `mode="serve"`
|
|
38
|
+
loads the one pipeline file at `pipeline` and answers POST /chat; it keeps
|
|
39
|
+
conversations in `conversations` (a Pandion conversation store, else SQL in
|
|
40
|
+
the data folder) and takes its chat settings from `serve` (`ServeSettings`).
|
|
41
|
+
See docs/pandion-api/serve-mode.md, "Serve mode"."""
|
|
42
|
+
if mode == "serve":
|
|
43
|
+
from pandion_api.serve import create_serve_app
|
|
44
|
+
|
|
45
|
+
return create_serve_app(settings, policy, pipeline, conversations, serve)
|
|
46
|
+
if mode != "lab":
|
|
47
|
+
raise ValueError(f"mode must be 'lab' or 'serve', not '{mode}'.")
|
|
48
|
+
policy = policy or Policy()
|
|
49
|
+
manager = RunManager(limit=policy.max_active_runs)
|
|
50
|
+
|
|
51
|
+
@asynccontextmanager
|
|
52
|
+
async def lifespan(app: FastAPI):
|
|
53
|
+
await policy.on_startup(app)
|
|
54
|
+
try:
|
|
55
|
+
yield
|
|
56
|
+
finally:
|
|
57
|
+
await manager.shutdown()
|
|
58
|
+
await policy.on_shutdown(app)
|
|
59
|
+
|
|
60
|
+
app = FastAPI(title=settings.title, lifespan=lifespan)
|
|
61
|
+
app.state.settings = settings
|
|
62
|
+
app.state.policy = policy
|
|
63
|
+
app.state.runs = manager
|
|
64
|
+
app.state.documents = DocumentStore(settings.sources)
|
|
65
|
+
for router in ROUTERS:
|
|
66
|
+
app.include_router(router, prefix=settings.prefix, dependencies=policy.dependencies())
|
|
67
|
+
return app
|