add sentence service
This commit is contained in:
92
sentence_api/README.md
Normal file
92
sentence_api/README.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# Sentence Boundary API
|
||||
|
||||
This service looks up pre-generated sentence boundaries by the SHA-256 hash of
|
||||
the exact video bytes. It does not analyze media during an API request.
|
||||
|
||||
## Install
|
||||
|
||||
From the repository root:
|
||||
|
||||
```bash
|
||||
python3 -m venv .venv-sentence-api
|
||||
. .venv-sentence-api/bin/activate
|
||||
python -m pip install -r sentence_api/requirements.txt
|
||||
```
|
||||
|
||||
## Generate The Index
|
||||
|
||||
Generate boundaries with the same silence detector used by the desktop player:
|
||||
|
||||
```bash
|
||||
python -m sentence_api.generate_boundaries \
|
||||
"/path/to/lesson.mp4" \
|
||||
--index sentence_api/data/sentence_boundaries.json
|
||||
```
|
||||
|
||||
The command calculates the SHA-256 hash, detects boundaries, converts seconds
|
||||
to milliseconds, infers each `end_ms` from the next sentence start, and writes
|
||||
the result atomically into the JSON index. The last sentence ends at the media
|
||||
duration.
|
||||
|
||||
For a large course library, run this command in an ingestion worker and store
|
||||
the same document in a database or object storage instead of committing the
|
||||
JSON file to the application image.
|
||||
|
||||
## Run
|
||||
|
||||
```bash
|
||||
SENTENCE_BOUNDARIES_FILE=sentence_api/data/sentence_boundaries.json \
|
||||
python -m uvicorn sentence_api.main:app --host 0.0.0.0 --port 8000
|
||||
```
|
||||
|
||||
The interactive API documentation is available at `/docs`.
|
||||
|
||||
## Request
|
||||
|
||||
```http
|
||||
GET /api/v1/videos/{sha256}/sentence-boundaries
|
||||
```
|
||||
|
||||
Example using the demo record in the checked-in index:
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:8000/api/v1/videos/468a4d064f6ec49942b45e25ab93c500d31870f978c4f28ff8b3b408852326e0/sentence-boundaries
|
||||
```
|
||||
|
||||
The MP4 used during development is also indexed. Its hash is
|
||||
`b6631d5cf48f37fed0ecc623563dd48b7ed660689b4d25d2ebac7fecab807ddc`, and its
|
||||
generated index contains 244 boundaries.
|
||||
|
||||
The response is:
|
||||
|
||||
```json
|
||||
{
|
||||
"video_hash": "...",
|
||||
"duration_ms": 16000,
|
||||
"algorithm_version": "silence-rms-v1",
|
||||
"sentences": [
|
||||
{
|
||||
"index": 0,
|
||||
"start_ms": 0,
|
||||
"end_ms": 4230,
|
||||
"text": null
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Unknown hashes return `404`. A hash must be a 64-character hexadecimal
|
||||
SHA-256 digest; malformed values return `422`.
|
||||
|
||||
When testing from a physical Android phone, replace `127.0.0.1` with the
|
||||
computer's LAN IP address. `127.0.0.1` on the phone refers to the phone itself.
|
||||
For production, expose the API over HTTPS.
|
||||
|
||||
## Android Request Flow
|
||||
|
||||
The mobile app should calculate the hash from the selected `content://` URI in
|
||||
streaming chunks, request the endpoint, map the returned `sentences` to
|
||||
`SentenceBoundary`, and then call `controller.loadItem`. The hash must be
|
||||
calculated from the exact bytes of the same video served to the player. For
|
||||
HTTPS course videos, the course manifest can carry the hash and avoid hashing
|
||||
the entire remote file on every device.
|
||||
Reference in New Issue
Block a user