vk_hackathon/doc/curl_api_test.md
q 1f976cf297 Add logviewer project and fix Docker imports
- Add logviewer/: Dozzle web UI (port 9999) + analyze.py CLI tool
- docker-compose.yml: add json-file logging with rotation and labels for index/search
- Fix Dockerfiles: COPY *.py . so all modules are included in image
- Convert all relative imports to flat absolute imports for Docker flat layout
- Rename index/schemas.py → index/index_schemas.py to avoid module name collision with search/schemas.py in test runner
- Update all tests to add service dir to sys.path and use flat imports

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 15:26:11 +03:00

366 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Curl API Test
## Sources
- Canonical contracts: `doc/ТЗа_хакатон_Индексация_и_поиск_по_сообщениям.pdf`
- Runnable examples and local launch notes: `README.md`
- Actual local wiring: `docker-compose.yml`
PDF gives the strict request/response schemas for `POST /index`, `POST /sparse_embedding`, and `POST /search`.
`README.md` adds ready curl examples for the minimal requests.
This file normalizes both into checks against the current local compose stack.
## Compose Wiring
- `index`: `http://localhost:8001`
- `search`: `http://localhost:8002`
- `qdrant`: `http://localhost:6334`
- Inside compose, services use `QDRANT_URL=http://qdrant:6333`
- Collection name from `.env`: `evaluation`
- Vector names from `.env`: `dense` and `sparse`
Note: current `docker-compose.yml` publishes Qdrant as `6334:6333`, while `README.md` still says `localhost:6333`. For local checks in this repo state, use `localhost:6334`.
## Extracted API Requests
### `GET /health`
Both services must answer `200 OK`.
```bash
curl -sS http://localhost:8001/health
curl -sS http://localhost:8002/health
```
Expected shape:
```json
{"status":"ok"}
```
### `POST /index`
Schema from the PDF:
- body root: `data`
- `data.chat`
- `data.overlap_messages[]`
- `data.new_messages[]`
Runnable request:
```bash
curl -sS -X POST http://localhost:8001/index \
-H 'Content-Type: application/json' \
-d '{
"data": {
"chat": {
"id": "chat-1",
"name": "Go Nova",
"sn": "chat-1@chat.agent",
"type": "channel",
"is_public": true
},
"overlap_messages": [
{
"id": "1",
"time": 1710000000,
"text": "Обсуждаем релиз Go",
"sender_id": "u1",
"file_snippets": "",
"parts": [],
"mentions": [],
"member_event": null,
"is_system": false,
"is_hidden": false,
"is_forward": false,
"is_quote": false
}
],
"new_messages": [
{
"id": "2",
"time": 1710000060,
"text": "Релиз Go перенесли на следующую неделю",
"sender_id": "u2",
"file_snippets": "",
"parts": [],
"mentions": [],
"member_event": null,
"is_system": false,
"is_hidden": false,
"is_forward": false,
"is_quote": false
}
]
}
}'
```
Observed response:
```json
{
"results": [
{
"page_content": "u1: Обсуждаем релиз Go\nu2: Релиз Go перенесли на следующую неделю",
"dense_content": "[2024-03-09 16:00] sender:u1\nОбсуждаем релиз Go\n[2024-03-09 16:01] sender:u2\nРелиз Go перенесли на следующую неделю",
"sparse_content": "u1 Обсуждаем релиз Go u2 Релиз Go перенесли на следующую неделю",
"message_ids": ["2"]
}
]
}
```
Note: overlap messages are used as context, but are not included in returned `message_ids`.
### `POST /sparse_embedding`
Schema from the PDF:
- body root: `texts: string[]`
Runnable request:
```bash
curl -sS -X POST http://localhost:8001/sparse_embedding \
-H 'Content-Type: application/json' \
-d '{
"texts": [
"Релиз Go перенесли на следующую неделю",
"VK GPT обсуждали в отдельном чате"
]
}'
```
Observed response:
```json
{
"vectors": [
{
"indices": [275068001, 108710752, 842257583, 1159207840, 2129888840, 703082301],
"values": [1.6652868125369606, 1.6652868125369606, 1.6652868125369606, 1.6652868125369606, 1.6652868125369606, 1.6652868125369606]
},
{
"indices": [73209461, 751565418, 59863655, 1856729543, 2036701913, 1943620510],
"values": [1.6652868125369606, 1.6652868125369606, 1.6652868125369606, 1.6652868125369606, 1.6652868125369606, 1.6652868125369606]
}
]
}
```
### `POST /search`
Minimal request from `README.md`:
```bash
curl -sS -X POST http://localhost:8002/search \
-H 'Content-Type: application/json' \
-d '{
"question": {
"text": "Что писали про релиз Go?"
}
}'
```
Full schema from the PDF:
```json
{
"question": {
"text": "Что писали про релиз Go?",
"asker": "u2",
"asked_on": "2024-03-09",
"variants": ["релиз go перенесли?", "обсуждение релиза go"],
"hyde": ["В чате пишут, что релиз Go перенесли на следующую неделю."],
"keywords": ["релиз", "Go", "перенесли"],
"entities": {
"people": ["u2"],
"emails": [],
"documents": [],
"names": ["Go"],
"links": []
},
"date_mentions": ["следующая неделя", "2024-03-09"],
"date_range": {
"from": "2024-03-09T00:00:00Z",
"to": "2024-03-10T00:00:00Z"
},
"search_text": "релиз Go перенесли на следующую неделю"
}
}
```
## Checks Run
### 1. Health checks
Commands:
```bash
curl -sS http://localhost:8001/health
curl -sS http://localhost:8002/health
```
Observed:
```json
{"status":"ok"}
{"status":"ok"}
```
### 2. Qdrant collection exists, but starts empty
Command:
```bash
curl -sS http://localhost:6334/collections/evaluation
```
Observed before manual insert:
- `points_count: 0`
- `indexed_vectors_count: 0`
This matches the README note that local compose creates the collection, but the template flow does not automatically upsert `/index` output into Qdrant.
### 3. `/index` works
Observed:
- HTTP request completed successfully
- service returned one chunk
- returned fields match the contract: `page_content`, `dense_content`, `sparse_content`, `message_ids`
### 4. `/sparse_embedding` works
Observed:
- HTTP request completed successfully
- response returned `vectors[]`
- each vector contains `indices[]` and `values[]`
### 5. `/search` on an empty collection returns an empty result
Command:
```bash
curl -sS -X POST http://localhost:8002/search \
-H 'Content-Type: application/json' \
-d '{"question":{"text":"Что писали про релиз Go?"}}'
```
Observed:
```json
{"results":[]}
```
This is expected while `evaluation` has no points.
### 6. Manual Qdrant upsert for end-to-end smoke test
To verify `/search` end-to-end, I inserted one synthetic point into local Qdrant with:
- point id `1001`
- dummy dense vector of size `1024`
- sparse vector under field `sparse`
- payload containing `page_content` and `metadata.message_ids=["2"]`
Command:
```bash
vec=$(awk 'BEGIN{for(i=0;i<1024;i++) printf "%s%d", (i?",":""), (i==0)}')
curl -sS -X PUT 'http://localhost:6334/collections/evaluation/points?wait=true' \
-H 'Content-Type: application/json' \
-d "{\"points\":[{\"id\":1001,\"vector\":{\"dense\":[${vec}],\"sparse\":{\"indices\":[1],\"values\":[1.0]}},\"payload\":{\"page_content\":\"u1: Обсуждаем релиз Go\\nu2: Релиз Go перенесли на следующую неделю\",\"metadata\":{\"message_ids\":[\"2\"],\"participants\":[\"u1\",\"u2\"],\"start\":\"2024-03-09T16:00:00Z\",\"end\":\"2024-03-09T16:01:00Z\",\"chat_id\":\"chat-1\",\"chat_name\":\"Go Nova\",\"chat_type\":\"channel\",\"chat_sn\":\"chat-1@chat.agent\"}}}]}"
```
Observed:
```json
{"result":{"operation_id":0,"status":"completed"},"status":"ok","time":0.008234969}
```
Collection state after insert:
- `points_count: 1`
- `indexed_vectors_count: 1`
### 7. `/search` works after one point is present
Minimal request:
```bash
curl -sS -X POST http://localhost:8002/search \
-H 'Content-Type: application/json' \
-d '{"question":{"text":"Что писали про релиз Go?"}}'
```
Observed:
```json
{"results":[{"message_ids":["2"]}]}
```
Enriched request without `date_range`:
```bash
curl -sS -X POST http://localhost:8002/search \
-H 'Content-Type: application/json' \
-d '{
"question": {
"text": "Что писали про релиз Go?",
"asker": "u2",
"asked_on": "2024-03-09",
"variants": ["релиз go перенесли?", "обсуждение релиза go"],
"hyde": ["В чате пишут, что релиз Go перенесли на следующую неделю."],
"keywords": ["релиз", "Go", "перенесли"],
"entities": {
"people": ["u2"],
"emails": [],
"documents": [],
"names": ["Go"],
"links": []
},
"date_mentions": ["следующая неделя", "2024-03-09"],
"search_text": "релиз Go перенесли на следующую неделю"
}
}'
```
Observed:
```json
{"results":[{"message_ids":["2"]}]}
```
### 8. Defect: `date_range` request currently fails
The full PDF-shaped request with ISO timestamps in `question.date_range` does not work in the current implementation.
Observed:
```json
{
"detail": "2 validation errors for Range\ngte\n Input should be a valid number, unable to parse string as a number [type=float_parsing, input_value='2024-03-09T00:00:00Z', input_type=str]\n For further information visit https://errors.pydantic.dev/2.12/v/float_parsing\nlte\n Input should be a valid number, unable to parse string as a number [type=float_parsing, input_value='2024-03-10T00:00:00Z', input_type=str]\n For further information visit https://errors.pydantic.dev/2.12/v/float_parsing"
}
```
Interpretation:
- the public request schema accepts ISO date strings
- current `search` code tries to pass them into a numeric `qdrant_client.models.Range`
- so `date_range` is a real runtime bug in the current local build
## Bottom Line
- `index /health`: OK
- `search /health`: OK
- `POST /index`: OK
- `POST /sparse_embedding`: OK
- `POST /search` on empty collection: OK, returns empty list
- `POST /search` after one test point is inserted: OK
- `POST /search` with enriched request excluding `date_range`: OK
- `POST /search` with `date_range` from the PDF schema: FAILS in current implementation