93 lines
2.6 KiB
Markdown
93 lines
2.6 KiB
Markdown
# 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.
|