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

ItemValue
MethodPOST
Path/task/material_describe
Content-Typeapplication/json
AuthAuthorization header (raw API Key)
Response ModeAsynchronous task (returns task_id immediately; poll the query endpoint for results)
Billing1 credit per image (pre-deducted on submission, settled on completion; failed tasks are fully refunded automatically)

Request Body

FieldTypeRequiredDefaultDescription
inputarrayYesMixed-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)

FieldTypeDescription
imagestringBase64 of the image file bytes (data URI form accepted); each image ≤ 1MB after decoding
file_idstringID 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"
  }
}
FieldTypeDescription
task_idstringTask ID (string form — exceeds the JS safe-integer range, do not cast to number); use it to poll for results
statusstringInitial state queued

Query Task Result

Basics

ItemValue
MethodGET
Path/task/material_describe/{task_id}
AuthAuthorization 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

FieldTypeDescription
statusstringTask state: queued / processing / completed / failed (auto-refunded) / cancelled (auto-refunded)
progressintegerProgress percentage (advances per image)
output_resultobjectUnderstanding result when completed (see below); error info when failed
output_result.dataarrayPer-item results aligned with the submitted input
output_result.data[].indexintegerIndex of the corresponding input item
output_result.data[].descstringContent description, Simplified Chinese, ≤ 200 characters
output_result.data[].tagsarray3-8 search-oriented attribute tags (free text)
output_result.data[].marknumberQuality / aesthetic score, 0-100 (up to two decimals), higher is better
output_result.data[].usable_flagsobjectUsability signals (four booleans), see below
output_result.usage.imagesintegerNumber of images in this task
output_result.usage.totalintegerTotal item count

usable_flags object

FieldTypeDescription
watermarkbooleanVisible watermark / station logo / brand badge
text_overlaybooleanVisible burned-in subtitles / overlaid text
black_borderbooleanVisible top-bottom / left-right black borders
blurrybooleanNoticeably out of focus / motion-blurred

ℹ️ Note: usable_flags are signals for your review, not hard gates — combine them with desc when judging; if the model omits a dimension, it defaults to false (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 × 1 credit, rounded half up, minimum 1 credit per task. image (base64) and file_id forms 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):

CodeHTTP StatusDescriptionSolution
6013400Missing required parameter (input)Provide the required parameters
6016400Invalid business parameter (text form in input, non-exclusive element form, etc. — images only)Fix per the parameter description
6004404file_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
6014400file_id points to a non-image fileOnly image files (jpg / jpeg / png / bmp / webp) may be referenced
6030400Input over limit (more than 32 images), rejected as a wholeSplit into batches
6031413Single 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
6032429Per-key rate limit (30 requests/minute, configurable)Slow down and retry
6201402Insufficient balance / quota (rejected upfront, no task created, nothing charged)Buy a quota pack or top up
6502401Authentication failedCheck 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 (image and file_id forms counted together); 30 requests/minute per key (both configurable).
  • Separate size limits per form: image (base64) ≤ 1MB after decoding; file_id10MB (references an uploaded file with no transfer cost, hence the looser cap).
  • file_id may only reference your own uploaded, unexpired image files (jpg / jpeg / png / bmp / webp).
  • Images only: input does not accept the text form; 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.

Next Steps