General Material Understanding
General material understanding (describe) is an asynchronous task API: submit images (base64 / file_id, mixed batches allowed) and get a task ID back immediately; the cloud vision-language model runs inference per image in the background, and polling the query endpoint returns a four-dimensional result per image — content description (desc), tags (tags), quality score (mark), and usability signals (usable_flags) — directly answering "what is in this material, how good is it, and is it usable".
It is the sibling capability of Material Embedding: embedding is the raw material for "finding similar" (send text / images, get vectors back, the matching is yours to do); understanding is the raw material for "knowing the content" (send images, get description / tags / quality / usability back, the judgment is yours to make). A typical combination: recall candidates with vector search first, then use this API to double-check "similar but unusable" materials (watermarks, burned-in subtitles, black borders, blur).
💡 Why asynchronous? Vision understanding is model inference — latency varies with batch size and model load. With the async form, a successful submission locks in the task: even if the network drops or your client exits, the task still completes and the result stays retrievable by task ID at any time — no more "waited forever, connection dropped, got charged but received nothing".
💡 For bulk indexing and search, use the gtrk CLI (submission and polling built in, integrated with internal workflows).
Submit an Understanding Task
Basics
| Item | Value |
|---|---|
| Method | POST |
| Path | /task/material_describe |
| Content-Type | application/json |
| Auth | Authorization header (raw API Key) |
| Response Mode | Asynchronous task (returns task_id immediately; poll the query endpoint for results) |
| Billing | 1 credit per image (pre-deducted on submission, settled on completion; failed tasks are fully refunded automatically) |
Request Body
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
input | array | Yes | — | Mixed-batch input array; each item is {"image": "<base64>"} or {"file_id": "<uploaded file id>"} (mutually exclusive — extra or missing keys raise a parameter error). Images only: {"text": "..."} items are rejected with an explicit message. Task results align with the input array by index. Limit 32 images per request (image and file_id forms counted together); over-limit requests are rejected as a whole with the limit stated — no partial processing |
input[] element (image / file_id, mutually exclusive)
| Field | Type | Description |
|---|---|---|
image | string | Base64 of the image file bytes (data URI form accepted); each image ≤ 1MB after decoding |
file_id | string | ID of an image file previously ingested via File Upload — no need to send base64 again. Must be uploaded by you and an image type (jpg / jpeg / png / bmp / webp): missing or not yours returns 6004 (same code, existence not disclosed); non-image type returns 6014. Each file ≤ 10MB (read from disk, no transfer cost — a separate limit from the 1MB base64 form), same rules as the embed API |
Request Example
curl -X POST https://api.ai-mcn.tv:10000/task/material_describe \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input": [
{"image": "iVBORw0KGgoAAAANSUhEUgAA..."},
{"file_id": "1954167xxxxxxxxxxxx"}
]
}'
Submission Response Example
{
"code": 200,
"msg": "success",
"data": {
"task_id": "1018322xxxxxxxxxxxx",
"task_type": "material_describe",
"status": "queued",
"created_at": "2026-08-12 21:30:00"
}
}
| Field | Type | Description |
|---|---|---|
task_id | string | Task ID (string form — exceeds the JS safe-integer range, do not cast to number); use it to poll for results |
status | string | Initial state queued |
Query Task Result
Basics
| Item | Value |
|---|---|
| Method | GET |
| Path | /task/material_describe/{task_id} |
| Auth | Authorization header (raw API Key; you can only query your own tasks) |
Polling advice: every ~5 seconds; completed / failed / cancelled are terminal states. A single-image task typically finishes in ten-odd seconds; a full 32-image batch takes about 1-3 minutes (depending on model load).
Response Example (completed)
{
"code": 200,
"msg": "success",
"data": {
"id": "1018322xxxxxxxxxxxx",
"status": "completed",
"progress": 100,
"output_result": {
"data": [
{
"index": 0,
"desc": "Aerial night cityscape, slow push-in; light trails on the main road and tower lighting on both sides create depth; overall cool tone.",
"tags": ["city", "night", "aerial", "traffic"],
"mark": 86,
"usable_flags": {
"watermark": false,
"text_overlay": false,
"black_border": false,
"blurry": false
}
},
{
"index": 1,
"desc": "Indoor interview medium shot; a platform watermark in the lower-right corner and burned-in subtitles at the bottom.",
"tags": ["people", "interview", "indoor"],
"mark": 42,
"usable_flags": {
"watermark": true,
"text_overlay": true,
"black_border": false,
"blurry": false
}
}
],
"usage": {"images": 2, "total": 2}
}
}
}
Response Fields
| Field | Type | Description |
|---|---|---|
status | string | Task state: queued / processing / completed / failed (auto-refunded) / cancelled (auto-refunded) |
progress | integer | Progress percentage (advances per image) |
output_result | object | Understanding result when completed (see below); error info when failed |
output_result.data | array | Per-item results aligned with the submitted input |
output_result.data[].index | integer | Index of the corresponding input item |
output_result.data[].desc | string | Content description, Simplified Chinese, ≤ 200 characters |
output_result.data[].tags | array | 3-8 search-oriented attribute tags (free text) |
output_result.data[].mark | number | Quality / aesthetic score, 0-100 (up to two decimals), higher is better |
output_result.data[].usable_flags | object | Usability signals (four booleans), see below |
output_result.usage.images | integer | Number of images in this task |
output_result.usage.total | integer | Total item count |
usable_flags object
| Field | Type | Description |
|---|---|---|
watermark | boolean | Visible watermark / station logo / brand badge |
text_overlay | boolean | Visible burned-in subtitles / overlaid text |
black_border | boolean | Visible top-bottom / left-right black borders |
blurry | boolean | Noticeably out of focus / motion-blurred |
ℹ️ Note:
usable_flagsare signals for your review, not hard gates — combine them withdescwhen judging; if the model omits a dimension, it defaults tofalse(permissive rather than over-blocking).
ℹ️ Privacy: frames transit Tonghe Cloud infrastructure temporarily (for the understanding model to access) and are discarded right after use — cleaned up when the task finishes, never retained.
⚠️ Note: video is not accepted — extract frames locally first, then submit the frames.
Billing
- 1 credit per image, pre-deducted on submission, settled on completion: the pre-deduction =
image count × 1credit, rounded half up, minimum 1 credit per task.image(base64) andfile_idforms are billed identically per image. - Full refund on failure: if the task fails (including any single image failing — no partial-success billing) or is cancelled, the pre-deducted credits are automatically refunded in full, no half-settled accounts.
- Tonghe Cloud internal members are exempt: accounts with
gc_member_type=internal(see User Management) are not billed. - Insufficient balance / quota fails the submission directly (HTTP
402) — rejected upfront, no task created, no half-settled accounts.
Error Codes
Submission endpoint (task not created, nothing charged):
| Code | HTTP Status | Description | Solution |
|---|---|---|---|
6013 | 400 | Missing required parameter (input) | Provide the required parameters |
6016 | 400 | Invalid business parameter (text form in input, non-exclusive element form, etc. — images only) | Fix per the parameter description |
6004 | 404 | file_id not found or not owned by you (same code, existence not disclosed) | Confirm the file_id comes from your own uploads and has not expired |
6014 | 400 | file_id points to a non-image file | Only image files (jpg / jpeg / png / bmp / webp) may be referenced |
6030 | 400 | Input over limit (more than 32 images), rejected as a whole | Split into batches |
6031 | 413 | Single image over the size limit: image form > 1MB after decoding, or file_id form > 10MB (separate limits; the error message states which form) | Compress / downscale and retry |
6032 | 429 | Per-key rate limit (30 requests/minute, configurable) | Slow down and retry |
6201 | 402 | Insufficient balance / quota (rejected upfront, no task created, nothing charged) | Buy a quota pack or top up |
6502 | 401 | Authentication failed | Check the Authorization header |
Task execution failures (not HTTP error codes): upstream model unavailability / timeouts during execution are retried automatically first; once retries are exhausted the task enters failed, the pre-deducted credits are refunded in full, and output_result records the error — after polling a failed state, simply resubmit if needed.
Limits
- Up to 32 images per request (
imageandfile_idforms counted together); 30 requests/minute per key (both configurable). - Separate size limits per form:
image(base64) ≤ 1MB after decoding;file_id≤ 10MB (references an uploaded file with no transfer cost, hence the looser cap). file_idmay only reference your own uploaded, unexpired image files (jpg / jpeg / png / bmp / webp).- Images only:
inputdoes not accept thetextform; extract frames from videos locally first. - Asynchronous task: poll after submitting (every ~5 seconds recommended); a single image typically takes ten-odd seconds, a full 32-image batch about 1-3 minutes.