Files
mediaplayer/sentence_api/README.md
2026-10-08 10:08:16 +08:00

148 lines
5.3 KiB
Markdown

# Oral Trainer Video Service
FastAPI service for the Android oral-training SDK. It provides:
- chunked video upload with SHA-256 calculation;
- files stored under `data/v/` and metadata stored in SQLite;
- after the first processing pass, videos can be uploaded automatically to
Volcano Engine Object Storage (TOS / 火山 OSS) and the catalog/share UI will
use that public URL;
- background sentence transcription through MOSS-Transcribe-Diarize;
- a browser-based administration page at `/admin`;
- video catalog and HTTP Range playback;
- sentence-boundary lookup compatible with the existing Android SDK;
- student recording upload and `asr-fluency-v1` assessment;
- signed-in user history for test results and dubbing shares, including deletion;
- AI sentence explanation for signed-in mobile users;
- the legacy JSON boundary index as a read-only fallback.
## Local Run
```bash
python3.12 -m venv .venv-sentence-api
. .venv-sentence-api/bin/activate
python -m pip install -r sentence_api/requirements.txt
export ADMIN_API_KEY=local-development-key
export MOSS_TRANSCRIBE_URL=http://127.0.0.1:8001/v1/audio/transcriptions
python -m uvicorn sentence_api.main:app --host 0.0.0.0 --port 8000
```
Open:
```text
http://127.0.0.1:8000/admin
http://127.0.0.1:8000/docs
```
When `MOSS_TRANSCRIBE_URL` is empty, uploaded videos still receive silence-based
boundaries, but no reference transcript is produced and assessment is disabled.
When all `VOLCANO_OSS_*` credentials in `.env.example` are configured, the first
processing pass saves sentence boundaries, uploads the source video, and only
then marks it ready. `stream_url` and the legacy `/content` endpoint then point
to the OSS/CDN URL. If the upload fails, the video is marked failed so clients
do not fall back to server-local playback.
## Main Endpoints
```text
GET /healthz
GET /api/v1/videos
GET /api/v1/videos/{sha256}
GET /api/v1/videos/{sha256}/content
GET /api/v1/videos/{sha256}/sentence-boundaries
POST /api/v1/audio/sentence-boundaries
POST /api/v1/sentences/explain
POST /api/v1/videos/{sha256}/sentences/{index}/assessments
POST /api/v1/admin/videos
PUT /api/v1/admin/videos/raw
POST /api/v1/admin/videos/{sha256}/process
GET /api/v1/admin/videos/{sha256}/subtitle-translation
POST /api/v1/admin/videos/{sha256}/subtitle-translation
PUT /api/v1/admin/videos/{sha256}/sentences/{index}
PUT /api/v1/admin/videos/{sha256}/sentences/{index}/split
PUT /api/v1/admin/videos/{sha256}/sentences/{index}/boundary
PUT /api/v1/admin/users/password
DELETE /api/v1/admin/videos/{sha256}
```
Admin endpoints use `X-Admin-Key` when `ADMIN_API_KEY` is configured. Assessment
requests use `X-Client-Key` when `CLIENT_API_KEY` is configured.
Administrators can set a local password for an SSO-linked account with:
```bash
curl -X PUT https://your-server/api/v1/admin/users/password \
-H "X-Admin-Key: $ADMIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{"username":"bobcoc","password":"new-password"}'
```
`POST /api/v1/audio/sentence-boundaries` accepts an audio file from an
authenticated client, generates boundaries in memory/temp storage only, and
returns a sentence document. It does not register or archive the uploaded
audio.
## AI Sentence Explanation
Configure an OpenAI-compatible chat-completions endpoint in `sentence_api/.env`.
A base URL ending in `/v1` is also accepted and is resolved to
`/v1/chat/completions`:
```dotenv
AI_API_URL=https://api.example.com/v1/chat/completions
AI_API_KEY=replace-with-your-ai-api-key
AI_MODEL=gpt-4o-mini
AI_TIMEOUT_SECONDS=45
```
The endpoint requires a signed-in user and accepts only the sentence and course
context. `AI_API_URL` and `AI_API_KEY` remain on the server and are never sent
to the mobile clients.
Chinese captions are stored on the course in the server database and shared by
every user. `GET /api/v1/videos/{sha256}/subtitle-translation` returns the saved
captions without calling the AI, including `complete` and `status` so clients can
poll long videos. `POST` starts missing-caption generation in the background and
returns quickly; it translates in small windows with neighboring context, runs
several windows in parallel, retries and splits a window if the model response is
invalid, and writes each finished window immediately so later viewers can reuse
it. English sentence edits clear the saved Chinese captions for that course.
Desktop playback of a local file can `POST` the same endpoint with the locally
generated English cues (`duration_ms`, `algorithm_version`, `sentences`). If that
SHA-256 is not already a course, the server stores the English subtitles and
translates them; later `GET`/`POST` calls poll and reuse the saved Chinese
captions. Official course sentences are never overwritten by a local upload.
## Assessment
```bash
curl -X POST \
http://127.0.0.1:8000/api/v1/videos/{sha256}/sentences/0/assessments \
-F audio=@student.wav \
-F language=en
```
The current score intentionally measures reading content and fluency:
```text
overall = content * 80% + fluency * 20%
fluency = duration * 35% + pauses * 40% + speech rate * 25%
```
`pronunciation_score` and `prosody_score` remain `null` until a phoneme/GOP
model is connected.
## Tests
```bash
python -m pytest sentence_api/tests -q
```
See [DEPLOYMENT.md](DEPLOYMENT.md) for Docker, MOSS/Whisper, Nginx HTTP 回源,
large-file
upload, backup, and production operation instructions.