mayankchugh-learning commited on
Commit
9b8d57e
·
1 Parent(s): 6f3e468

Update environment configuration and Streamlit app for enhanced timeout handling

Browse files

- Added new environment variables `DOC_AUDI_API_BASE` and `DOC_AUDI_HTTP_READ_TIMEOUT` to `.env.example`, with updated default values and constraints.
- Improved timeout handling in `streamlit_app.py`, allowing for a configurable read timeout of up to 7200 seconds.
- Revised documentation across multiple files to reflect changes in timeout settings and environment variable usage, ensuring clarity for users.
- Removed outdated `LOGICAL_DEVELOPMENT_SEQUENCE.md` as part of documentation cleanup.

Files changed (3) hide show
  1. .env.example +4 -1
  2. LOGICAL_DEVELOPMENT_SEQUENCE.md +0 -506
  3. streamlit_app.py +15 -5
.env.example CHANGED
@@ -44,5 +44,8 @@ JOBS_DB_PATH=./data/jobs.db
44
  # Limits
45
  MAX_DOCUMENTS_PER_BATCH=100
46
 
47
- # Streamlit → API
48
  STREAMLIT_BACKEND_URL=http://localhost:8000
 
 
 
 
44
  # Limits
45
  MAX_DOCUMENTS_PER_BATCH=100
46
 
47
+ # Streamlit → API (Streamlit process reads these when set in the shell / OS env)
48
  STREAMLIT_BACKEND_URL=http://localhost:8000
49
+ DOC_AUDI_API_BASE=http://127.0.0.1:8000
50
+ # Read timeout (seconds) for Ask/Summarise HTTP calls; default in code is 3600 if unset
51
+ DOC_AUDI_HTTP_READ_TIMEOUT=3600
LOGICAL_DEVELOPMENT_SEQUENCE.md DELETED
@@ -1,506 +0,0 @@
1
- # DocuAudit AI - Milestone Development Sequence (Build -> Verify -> Move On)
2
-
3
- This guide is written so you can develop strictly milestone-by-milestone and validate your output at each step.
4
-
5
- Rule for progression:
6
- - If a milestone verification fails, do not continue to the next milestone.
7
- - Only move forward when all checks for the current milestone pass.
8
-
9
- ---
10
-
11
- ## Shared Setup and Run Commands
12
-
13
- ### One-time setup
14
- ```bash
15
- uv venv --python 3.11
16
- uv init --python 3.11
17
- uv pip install -r requirements.txt
18
- copy .env.example .env
19
- ```
20
-
21
- ### Run backend
22
- ```bash
23
- uv run uvicorn api.main:app --host 0.0.0.0 --port 8000 --reload
24
- ```
25
-
26
- ### Run UI
27
- ```bash
28
- uv run streamlit run streamlit_app.py
29
- ```
30
-
31
- ### Smoke checks
32
- ```bash
33
- curl http://localhost:8000/health
34
- curl http://localhost:8000/docs
35
- ```
36
-
37
- ---
38
-
39
- ## Milestone 1 - FastAPI Foundation
40
-
41
- ### Dependencies
42
- - `fastapi`
43
- - `uvicorn[standard]`
44
-
45
- ### After adding dependencies
46
- - `uv add requirements.txt`
47
- - `uv pip install -r requirements.txt`
48
-
49
- ### Depends on previous milestones
50
- - None (starting point).
51
-
52
- ### Expected input
53
- - Fresh repo with Python environment ready.
54
- - `requirements.txt` and `.env` prepared.
55
-
56
- ### Build scope
57
- - Create `api/main.py`.
58
- - Add `GET /health`.
59
- - App starts with Uvicorn.
60
-
61
- ### Expected output/result
62
- - API starts without errors.
63
- - `/health` returns success JSON.
64
- - Swagger loads at `/docs`.
65
-
66
- ### Start backend server- fastapi
67
- - `uv run uvicorn api.main:app --host 0.0.0.0 --port 8000 --reload`
68
-
69
- ### Verification checks
70
- ```bash
71
- curl http://localhost:8000/health
72
- curl http://localhost:8000/docs
73
- ```
74
-
75
- ### Pass criteria
76
- - No startup exception.
77
- - No 404/500 for `/health` and `/docs`.
78
-
79
- ---
80
-
81
- ## Milestone 2 - Route Skeletons (Placeholder Only)
82
-
83
- ### Dependencies
84
- - Milestone 1 dependencies only.
85
- - (No new runtime dependency required if routes are placeholders.)
86
-
87
- ### Depends on previous milestones
88
- - Milestone 1 must pass (`/health` and `/docs` working).
89
-
90
- ### Expected input
91
- - Running FastAPI app from Milestone 1.
92
- - Router module structure available under `api/routes`.
93
-
94
- ### Build scope
95
- - Add routers:
96
- - `api/routes/ingest.py`
97
- - `api/routes/query.py`
98
- - `api/routes/jobs.py`
99
- - `api/routes/audit.py`
100
- - Register routes in `api/main.py`.
101
- - Keep responses as placeholders only.
102
-
103
- ### Expected output/result
104
- - All route paths exist and respond.
105
- - Placeholder payloads return consistently.
106
-
107
- ### Start backend server- fastapi
108
- - `uv run uvicorn api.main:app --host 0.0.0.0 --port 8000 --reload`
109
-
110
- ### Verification checks
111
- - Open Swagger and call each endpoint once.
112
- - Confirm no 404/500.
113
-
114
- ### Pass criteria
115
- - Route wiring complete.
116
- - No real business logic yet.
117
-
118
- ---
119
-
120
- ## Milestone 3 - Config + Request/Response Contracts
121
-
122
- ### Dependencies
123
- - `pydantic`
124
- - `pydantic-settings`
125
- - `python-dotenv`
126
-
127
- ### After adding dependencies
128
- - `uv add requirements.txt`
129
- - `uv pip install -r requirements.txt`
130
-
131
- ### Depends on previous milestones
132
- - Milestone 2 route skeletons must be wired and reachable.
133
-
134
- ### Expected input
135
- - Existing route handlers ready for request body integration.
136
- - `.env` file available for settings values.
137
-
138
- ### Build scope
139
- - Add `api/config.py` (env-backed settings).
140
- - Add `models/requests.py` and `models/responses.py`.
141
- - Apply request validation in routes.
142
-
143
- ### Expected output/result
144
- - Config values read from `.env`.
145
- - Valid requests succeed.
146
- - Invalid payloads show schema errors.
147
-
148
- ### Start backend server- fastapi
149
- - `uv run uvicorn api.main:app --host 0.0.0.0 --port 8000 --reload`
150
-
151
- ### Verification checks
152
- ```bash
153
- curl -X POST http://localhost:8000/query/ask ^
154
- -H "Content-Type: application/json" ^
155
- -d "{\"question\":\"What are key risks?\",\"collection_name\":\"default\"}"
156
- ```
157
- - Also test one invalid payload (e.g., missing `question`).
158
-
159
- ### Pass criteria
160
- - Validation behavior is visible and correct.
161
-
162
- ---
163
-
164
- ## Milestone 4 - RAG Ingestion Pipeline (No Answer Generation)
165
-
166
- ### Dependencies
167
- - `langchain`
168
- - `langchain-core` (pulled via LangChain ecosystem)
169
- - `langchain-chroma`
170
- - `chromadb`
171
- - `langchain-community`
172
- - `langchain-ollama` (if using Ollama embeddings)
173
- - `langchain-openai` + `openai` (if using OpenAI embeddings)
174
- - `pymupdf` (PDF loading)
175
- - `python-multipart` (file upload handling in ingest route)
176
-
177
- ### After adding dependencies
178
- - `uv add requirements.txt`
179
- - `uv pip install -r requirements.txt`
180
-
181
- ### Depends on previous milestones
182
- - Milestone 3 contracts/config must pass.
183
-
184
- ### Provider selection
185
- - Choose provider in `.env` via `LLM_PROVIDER`.
186
- - Supported values:
187
- - `ollama`
188
- - `openai`
189
- - `anthropic`
190
- - `huggingface`
191
-
192
- ### Expected input
193
- - Valid upload route available to accept files.
194
- - Configuration values for chunking, Chroma path, and provider present.
195
- - Test documents (PDF/TXT/MD) ready for ingestion.
196
-
197
- ### Build scope
198
- - Implement:
199
- - `rag/loader.py`
200
- - `rag/chunker.py`
201
- - `rag/embedder.py`
202
- - `rag/vector_store.py`
203
- - Wire ingest flow: load -> chunk -> embed -> persist.
204
- - Preserve metadata:
205
- - `source`
206
- - `page`
207
- - `chunk_index`
208
-
209
- ### Expected output/result
210
- - Upload/ingest creates vectors in Chroma.
211
- - Collection has stored documents/chunks.
212
-
213
- ### Start backend server- fastapi
214
- - `uv run uvicorn api.main:app --host 0.0.0.0 --port 8000 --reload`
215
-
216
- ### Verification checks
217
- - Ingest sample PDF(s).
218
- - Confirm collection appears and has document count > 0.
219
-
220
- ### Pass criteria
221
- - Vector persistence works.
222
- - No LLM answer quality evaluation yet (that is Milestone 5).
223
-
224
- ---
225
-
226
- ## Milestone 5 - Retrieval + Grounded LLM Answer
227
-
228
- ### Dependencies
229
- - Keep Milestone 4 dependencies.
230
- - Add provider package(s) for your selected chat LLM:
231
- - Ollama: `langchain-ollama`
232
- - OpenAI: `langchain-openai`, `openai`
233
- - Anthropic: `langchain-anthropic`, `anthropic`
234
- - Hugging Face endpoint: `langchain-community` (+ API key)
235
-
236
- ### After adding dependencies
237
- - `uv add requirements.txt`
238
- - `uv pip install -r requirements.txt`
239
-
240
- ### Depends on previous milestones
241
- - Milestone 4 vectors must exist in Chroma (ingestion verified).
242
-
243
- ### Expected input
244
- - Ingested collection with non-zero document/chunk vectors.
245
- - Query endpoint contract from Milestone 3.
246
- - Valid LLM API key/local model access based on selected provider.
247
-
248
- ### Build scope
249
- - Implement `rag/retriever.py` to:
250
- - retrieve top-k chunks
251
- - format context
252
- - invoke configured LLM
253
- - return answer + sources
254
- - Wire query routes to retriever.
255
-
256
- ### Expected output/result
257
- - Query returns grounded answer based on retrieved chunks.
258
- - Source citations are included.
259
- - Empty/no-match returns safe fallback answer.
260
-
261
- ### Start backend server- fastapi
262
- - `uv run uvicorn api.main:app --host 0.0.0.0 --port 8000 --reload`
263
-
264
- ### Verification checks
265
- - Ask question that is clearly answerable from uploaded docs.
266
- - Ask question not present in docs and verify fallback message.
267
-
268
- ### Pass criteria
269
- - Retrieve-then-generate flow works reliably.
270
-
271
- ---
272
-
273
- ## Milestone 6 - Audit Persistence
274
-
275
- ### Dependencies
276
- - `aiosqlite`
277
-
278
- ### After adding dependencies
279
- - `uv add requirements.txt`
280
- - `uv pip install -r requirements.txt`
281
-
282
- ### Depends on previous milestones
283
- - Milestone 5 query flow must return answers reliably.
284
-
285
- ### Expected input
286
- - Query route already producing response payload (`answer`, `sources`, metadata).
287
- - Writable SQLite path configured in environment.
288
-
289
- ### Build scope
290
- - Implement `storage/audit_store.py` fully.
291
- - Persist query request/response metadata.
292
- - Add audit list/detail retrieval endpoints.
293
-
294
- ### Expected output/result
295
- - Every query creates an audit record.
296
- - You can fetch log entries by list and id.
297
-
298
- ### Start backend server- fastapi
299
- - `uv run uvicorn api.main:app --host 0.0.0.0 --port 8000 --reload`
300
-
301
- ### Verification checks
302
- - Run one query.
303
- - Fetch corresponding audit entry.
304
-
305
- ### Pass criteria
306
- - Audit trail is complete and query-linked.
307
-
308
- ---
309
-
310
- ## Milestone 7 - Background Ingestion Jobs
311
-
312
-
313
- ### Dependencies
314
- - No mandatory new package (uses FastAPI background tasks + existing modules).
315
-
316
- ### After adding dependencies (if any)
317
- - `uv add requirements.txt`
318
- - `uv pip install -r requirements.txt`
319
-
320
- ### Depends on previous milestones
321
- - Milestone 4 ingestion logic must work synchronously first.
322
- - Milestone 6 persistence layer should be available for job tracking.
323
-
324
- ### Expected input
325
- - Working ingest function (`load -> chunk -> add_documents`).
326
- - Job status storage schema and endpoints available.
327
-
328
- ### Build scope
329
- - Implement `workers/ingest_worker.py`.
330
- - Move ingestion processing to background.
331
- - Track status in jobs endpoints/store.
332
-
333
- ### Expected output/result
334
- - Upload returns `job_id`.
335
- - Status transitions:
336
- - `queued`
337
- - `processing`
338
- - `completed` or `failed`
339
-
340
- ### Start backend server- fastapi
341
- - `uv run uvicorn api.main:app --host 0.0.0.0 --port 8000 --reload`
342
-
343
- ### Verification checks
344
- - Upload docs and poll job status endpoint.
345
-
346
- ### Pass criteria
347
- - API remains responsive while ingestion runs.
348
-
349
- ---
350
-
351
- ## Milestone 8 - Endpoint Completion (Production Shape)
352
-
353
- ### Dependencies
354
- - `httpx` (URL ingestion/download flow)
355
-
356
- ### After adding dependencies
357
- - `uv add requirements.txt`
358
- - `uv pip install -r requirements.txt`
359
-
360
- ### Depends on previous milestones
361
- - Milestones 1 through 7 should be passing individually.
362
-
363
- ### Expected input
364
- - Stable ingestion, retrieval, audit, and jobs internals.
365
- - Final request/response models already defined.
366
-
367
- ### Build scope
368
- - Ensure behavior and contracts are complete for:
369
- - `POST /ingest/upload`
370
- - `POST /ingest/url`
371
- - `GET /ingest/collections`
372
- - `DELETE /ingest/collection/{collection_name}`
373
- - `POST /query/ask`
374
- - `POST /query/summarise`
375
- - `GET /jobs`
376
- - `GET /jobs/{job_id}`
377
- - `GET /audit/logs`
378
- - `GET /audit/logs/{query_id}`
379
-
380
- ### Expected output/result
381
- - Full backend flow works from upload to audited answer.
382
-
383
- ### Start backend server
384
- - `uv run uvicorn api.main:app --host 0.0.0.0 --port 8000 --reload`
385
-
386
- ### Verification checks
387
- - Run one complete cycle using API only:
388
- - ingest -> job complete -> ask -> inspect sources -> fetch audit
389
-
390
- ### Pass criteria
391
- - No contract mismatches or broken endpoints.
392
-
393
- ---
394
-
395
- ## Milestone 9 - Streamlit UI Integration
396
-
397
- ### Dependencies
398
- - `streamlit`
399
-
400
- ### After adding dependencies
401
- - `uv add requirements.txt`
402
- - `uv pip install -r requirements.txt`
403
-
404
- ### Depends on previous milestones
405
- - Milestone 8 full backend flow must be stable.
406
-
407
- ### Expected input
408
- - Running backend server with all finalized endpoints.
409
- - Predictable API payload shapes for upload/query/jobs/audit.
410
-
411
- ### Build scope
412
- - Connect `streamlit_app.py` to backend API.
413
- - Include Upload, Jobs, Ask, Summarise, Audit sections.
414
-
415
- ### Expected output/result
416
- - Full flow works from UI alone.
417
-
418
- ### Start backend server- fastapi
419
- ```bash
420
- uv run uvicorn api.main:app --host 0.0.0.0 --port 8000
421
- ```
422
- ### Start frontend server- Streamlit
423
- ```bash
424
- uv run streamlit run streamlit_app.py --server.address=0.0.0.0 --server.port=8501
425
- ```
426
-
427
- ### Verification checks
428
- - Perform end-to-end cycle from Streamlit without manual curl.
429
-
430
- ### Pass criteria
431
- - UI reflects backend status and responses correctly.
432
-
433
- ---
434
-
435
- ## Milestone 10 - Tests and Hardening
436
-
437
- ### Dependencies
438
- - `pytest`
439
- - `pytest-asyncio`
440
-
441
- ### After adding dependencies
442
- - `uv add requirements.txt`
443
- - `uv pip install -r requirements.txt`
444
-
445
- ### Depends on previous milestones
446
- - Milestones 1 through 9 completed and stable enough to test.
447
-
448
- ### Expected input
449
- - Final endpoint behavior and contracts.
450
- - Representative sample docs/test data and deterministic test cases.
451
-
452
- ### Build scope
453
- - Add/update:
454
- - `tests/test_ingest.py`
455
- - `tests/test_query.py`
456
- - `tests/test_audit.py`
457
- - Cover success + validation + failure paths.
458
-
459
- ### Expected output/result
460
- - Automated tests pass and catch regressions.
461
-
462
- ### Verification checks
463
- ```bash
464
- uv run pytest -q
465
- uv run pytest tests/test_ingest.py -q
466
- uv run pytest tests/test_query.py -q
467
- uv run pytest tests/test_audit.py -q
468
- ```
469
-
470
- ### Pass criteria
471
- - Core behavior is test-covered and stable.
472
-
473
- ---
474
-
475
- ## Milestone-by-Milestone Output Checklist
476
-
477
- Use this quick gate before advancing:
478
-
479
- 1. Milestone 1: API up + `/health` + `/docs`
480
- 2. Milestone 2: all route stubs reachable
481
- 3. Milestone 3: schema validation enforced
482
- 4. Milestone 4: vectors written to Chroma
483
- 5. Milestone 5: grounded answer + citations
484
- 6. Milestone 6: audit log persisted and fetchable
485
- 7. Milestone 7: background job lifecycle visible
486
- 8. Milestone 8: full API flow complete
487
- 9. Milestone 9: full UI flow complete
488
- 10. Milestone 10: tests passing
489
-
490
- If any line fails, fix that milestone before moving forward.
491
-
492
- ---
493
-
494
- ## Development Completion Dependency Chain
495
-
496
- Use this chain to understand what must be complete before a later milestone is considered valid:
497
-
498
- - Milestone 2 depends on 1
499
- - Milestone 3 depends on 2
500
- - Milestone 4 depends on 3
501
- - Milestone 5 depends on 4
502
- - Milestone 6 depends on 5
503
- - Milestone 7 depends on 4 and 6
504
- - Milestone 8 depends on 1-7
505
- - Milestone 9 depends on 8
506
- - Milestone 10 depends on 1-9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
streamlit_app.py CHANGED
@@ -11,14 +11,22 @@ import streamlit as st
11
 
12
  DEFAULT_API_BASE = os.environ.get("DOC_AUDI_API_BASE", "http://127.0.0.1:8000")
13
 
 
 
 
 
 
14
 
15
  def _http_read_timeout_seconds() -> float:
16
- raw = os.environ.get("DOC_AUDI_HTTP_READ_TIMEOUT", "600")
 
 
 
17
  try:
18
  read_s = float(raw)
19
  except ValueError:
20
- read_s = 600.0
21
- return max(60.0, min(read_s, 3600.0))
22
 
23
 
24
  def _http_timeout() -> httpx.Timeout:
@@ -29,8 +37,10 @@ def _http_timeout() -> httpx.Timeout:
29
 
30
  def _fmt_timeout_hint() -> str:
31
  cap = int(_http_read_timeout_seconds())
 
32
  return (
33
- f"The UI stops waiting after **{cap}s** per request (set **DOC_AUDI_HTTP_READ_TIMEOUT** to raise it, max 3600). "
 
34
  "Ensure `ollama serve` is running; cold models or CPU inference can exceed a few minutes."
35
  )
36
 
@@ -178,7 +188,7 @@ def main() -> None:
178
  )
179
  st.caption(
180
  f"Ask/Summarise wait up to **{int(_http_read_timeout_seconds())}s** per request "
181
- "(env `DOC_AUDI_HTTP_READ_TIMEOUT`, range 603600)."
182
  )
183
  if st.button("Test connection"):
184
  ok, msg = _health_check()
 
11
 
12
  DEFAULT_API_BASE = os.environ.get("DOC_AUDI_API_BASE", "http://127.0.0.1:8000")
13
 
14
+ # httpx read timeout for Ask/Summarise: embeddings + LLM on CPU or cold Ollama often exceeds 10 minutes.
15
+ _HTTP_READ_TIMEOUT_DEFAULT_S = 3600.0
16
+ _HTTP_READ_TIMEOUT_MIN_S = 60.0
17
+ _HTTP_READ_TIMEOUT_MAX_S = 7200.0
18
+
19
 
20
  def _http_read_timeout_seconds() -> float:
21
+ raw = os.environ.get(
22
+ "DOC_AUDI_HTTP_READ_TIMEOUT",
23
+ str(int(_HTTP_READ_TIMEOUT_DEFAULT_S)),
24
+ )
25
  try:
26
  read_s = float(raw)
27
  except ValueError:
28
+ read_s = _HTTP_READ_TIMEOUT_DEFAULT_S
29
+ return max(_HTTP_READ_TIMEOUT_MIN_S, min(read_s, _HTTP_READ_TIMEOUT_MAX_S))
30
 
31
 
32
  def _http_timeout() -> httpx.Timeout:
 
37
 
38
  def _fmt_timeout_hint() -> str:
39
  cap = int(_http_read_timeout_seconds())
40
+ lo, hi = int(_HTTP_READ_TIMEOUT_MIN_S), int(_HTTP_READ_TIMEOUT_MAX_S)
41
  return (
42
+ f"The UI stops waiting after **{cap}s** per request (set **DOC_AUDI_HTTP_READ_TIMEOUT**, "
43
+ f"allowed **{lo}–{hi}** s). "
44
  "Ensure `ollama serve` is running; cold models or CPU inference can exceed a few minutes."
45
  )
46
 
 
188
  )
189
  st.caption(
190
  f"Ask/Summarise wait up to **{int(_http_read_timeout_seconds())}s** per request "
191
+ f"(env `DOC_AUDI_HTTP_READ_TIMEOUT`, range {int(_HTTP_READ_TIMEOUT_MIN_S)}{int(_HTTP_READ_TIMEOUT_MAX_S)})."
192
  )
193
  if st.button("Test connection"):
194
  ok, msg = _health_check()