| @@ -0,0 +1,164 @@ | |||
| # Video Pricing Table Testing | |||
| This guide verifies task video billing with model-level pricing tables. | |||
| ## Prerequisites | |||
| - Admin session cookie for `/api/option/model_pricing`. | |||
| - API token for `/v1/videos`. | |||
| - A usable Hailuo channel for `hailuo-video`. | |||
| - A usable Seedance/Doubao channel for `seedance-2`; for deterministic usage billing, point it at a mock upstream that returns `usage.total_tokens`. | |||
| - `QuotaPerUnit = 500000` unless your environment overrides it. | |||
| Set shell variables: | |||
| ```bash | |||
| BASE_URL=http://127.0.0.1:3000 | |||
| ADMIN_COOKIE='session=...' | |||
| API_TOKEN='sk-...' | |||
| ``` | |||
| ## Hailuo Per Call | |||
| Configure an exact per-call matrix: | |||
| ```bash | |||
| curl -sS -X PUT "$BASE_URL/api/option/model_pricing/hailuo-video" \ | |||
| -H "Cookie: $ADMIN_COOKIE" \ | |||
| -H 'Content-Type: application/json' \ | |||
| -d '{ | |||
| "schema_version": 1, | |||
| "scope": "model", | |||
| "billing_unit": "per_call", | |||
| "preconsume_strategy": "exact", | |||
| "dimensions": [ | |||
| {"key": "resolution", "source": "request.resolution", "type": "string", "default": null}, | |||
| {"key": "duration", "source": "request.duration", "type": "number", "default": null} | |||
| ], | |||
| "table": [ | |||
| {"resolution": "768P", "duration": 10, "price": 0.04, "source": "manual"} | |||
| ], | |||
| "fallback": {"strategy": "reject"} | |||
| }' | |||
| ``` | |||
| Submit a matched request: | |||
| ```bash | |||
| curl -sS -X POST "$BASE_URL/v1/videos" \ | |||
| -H "Authorization: Bearer $API_TOKEN" \ | |||
| -H 'Content-Type: application/json' \ | |||
| -d '{ | |||
| "model": "hailuo-video", | |||
| "prompt": "a pricing smoke test", | |||
| "resolution": "768P", | |||
| "duration": 10 | |||
| }' | |||
| ``` | |||
| Expected quota: | |||
| ```text | |||
| actual_quota = price_usd * QuotaPerUnit * group_ratio | |||
| = 0.04 * 500000 * 1 | |||
| = 20000 | |||
| ``` | |||
| Submit an unsupported row and expect HTTP 400 with no quota change: | |||
| ```bash | |||
| curl -i -X POST "$BASE_URL/v1/videos" \ | |||
| -H "Authorization: Bearer $API_TOKEN" \ | |||
| -H 'Content-Type: application/json' \ | |||
| -d '{ | |||
| "model": "hailuo-video", | |||
| "prompt": "a pricing reject test", | |||
| "resolution": "1080P", | |||
| "duration": 10 | |||
| }' | |||
| ``` | |||
| ## Seedance Per 1M Tokens | |||
| Configure a usage matrix: | |||
| ```bash | |||
| curl -sS -X PUT "$BASE_URL/api/option/model_pricing/seedance-2" \ | |||
| -H "Cookie: $ADMIN_COOKIE" \ | |||
| -H 'Content-Type: application/json' \ | |||
| -d '{ | |||
| "schema_version": 1, | |||
| "scope": "model", | |||
| "billing_unit": "per_1m_tokens", | |||
| "preconsume_strategy": "minimum", | |||
| "dimensions": [ | |||
| {"key": "resolution", "source": "request.resolution", "type": "string", "default": null} | |||
| ], | |||
| "table": [ | |||
| {"resolution": "720P", "price": 0.5, "source": "manual"} | |||
| ], | |||
| "fallback": {"strategy": "reject"} | |||
| }' | |||
| ``` | |||
| Submit: | |||
| ```bash | |||
| curl -sS -X POST "$BASE_URL/v1/videos" \ | |||
| -H "Authorization: Bearer $API_TOKEN" \ | |||
| -H 'Content-Type: application/json' \ | |||
| -d '{ | |||
| "model": "seedance-2", | |||
| "prompt": "a usage pricing smoke test", | |||
| "resolution": "720P", | |||
| "duration": 5 | |||
| }' | |||
| ``` | |||
| Fetch until complete: | |||
| ```bash | |||
| TASK_ID=task_xxx | |||
| curl -sS "$BASE_URL/v1/videos/$TASK_ID" \ | |||
| -H "Authorization: Bearer $API_TOKEN" | |||
| ``` | |||
| When the upstream completion response contains `usage.total_tokens = 1000`, expected final quota is: | |||
| ```text | |||
| actual_quota = total_tokens * token_unit_price_usd / 1_000_000 * QuotaPerUnit * group_ratio | |||
| = 1000 * 0.5 / 1_000_000 * 500000 * 1 | |||
| = 250 | |||
| ``` | |||
| The settlement must use the frozen `token_unit_price_usd` stored on the task billing context. Changing or deleting the current `ModelPricingRules` option after submit must not affect the completion calculation for that task. | |||
| ## Delete Config And Legacy Fallback | |||
| Delete a matrix config: | |||
| ```bash | |||
| curl -sS -X DELETE "$BASE_URL/api/option/model_pricing/hailuo-video" \ | |||
| -H "Cookie: $ADMIN_COOKIE" | |||
| curl -sS -X DELETE "$BASE_URL/api/option/model_pricing/seedance-2" \ | |||
| -H "Cookie: $ADMIN_COOKIE" | |||
| ``` | |||
| After deletion, requests for that model return to the legacy `ModelPrice` path. The `ModelPrice` option itself is not removed or modified by the model pricing table API. | |||
| ## Smoke Script | |||
| The same flow can be run with: | |||
| ```bash | |||
| "C:/Users/28221/.conda/envs/py312/python.exe" test-scripts/test_video_pricing.py | |||
| ``` | |||
| Required environment: | |||
| ```bash | |||
| NEW_API_BASE_URL=http://127.0.0.1:3000 | |||
| NEW_API_ADMIN_USERNAME=root | |||
| NEW_API_ADMIN_PASSWORD=123456 | |||
| NEW_API_TOKEN=sk-... | |||
| ``` | |||