Batch API supports both the
kimi-k2.6 and kimi-k2.5 models. The temperature, top_p, and other parameters cannot be modified for these models — do not include them in the request body.Create Batch
Upload a JSONL file and create a batch task
List Batches
List batch tasks for your organization
Retrieve Batch
Get status and details for a specific batch task
Cancel Batch
Cancel an in-progress batch task
Workflow
This guide walks through a complete text classification example using the Batch API:1. Build the Input File
Each line in the JSONL file is an independent JSON object representing a single inference request:{"custom_id": "request-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "kimi-k2.6", "messages": [{"role": "system", "content": "You are a text classification assistant."}, {"role": "user", "content": "Classify this text: AI is transforming the world"}]}}
| Field | Required | Description |
|---|---|---|
custom_id | Yes | Custom request identifier for tracking results, must be unique within the file |
method | Yes | Request method, must be POST |
url | Yes | Request endpoint, must be /v1/chat/completions |
body | Yes | Request body, same parameters as the Chat Completions API |
The
model in body must be either kimi-k2.6 or kimi-k2.5. The temperature, top_p, n, presence_penalty, and frequency_penalty parameters cannot be modified for these models. Do not include these parameters in the body.Input file requirements:
- File must be in
.jsonlformat, non-empty, and no larger than 100MB - Each line must be a valid JSON object containing
custom_id,method,url, andbodyfields custom_idmust be unique within the file- All lines must use the same
model— only one model per batch is allowed methodmust bePOST,urlmust be/v1/chat/completions- The specified model must exist and the user must have access to it
2. Upload the File
Upload the JSONL file via the Upload File endpoint withpurpose set to "batch".
import os
from openai import OpenAI
from openai.types import FileObject
client = OpenAI(
api_key=os.environ.get("MOONSHOT_API_KEY"),
base_url=os.environ.get("MOONSHOT_BASE_URL", "https://api.moonshot.ai/v1"),
)
file_object: FileObject = client.files.create(
file=open("batch_requests.jsonl", "rb"),
purpose="batch",
)
print(file_object.id) # Save file_id for the next step
curl ${MOONSHOT_BASE_URL:-https://api.moonshot.ai/v1}/files \
-H "Authorization: Bearer $MOONSHOT_API_KEY" \
-F purpose="batch" \
-F file="@batch_requests.jsonl"
const OpenAI = require("openai");
const fs = require("fs");
const client = new OpenAI({
apiKey: process.env.MOONSHOT_API_KEY,
baseURL: process.env.MOONSHOT_BASE_URL || "https://api.moonshot.ai/v1",
});
async function main() {
const fileObject = await client.files.create({
file: fs.createReadStream("batch_requests.jsonl"),
purpose: "batch"
});
console.log(fileObject.id); // Save file_id for the next step
}
main();
3. Create the Task
Call the Create Batch endpoint withinput_file_id and completion_window. We recommend setting a generous time window for larger datasets.
import os
from openai import OpenAI
from openai.types import Batch
client = OpenAI(
api_key=os.environ.get("MOONSHOT_API_KEY"),
base_url=os.environ.get("MOONSHOT_BASE_URL", "https://api.moonshot.ai/v1"),
)
batch: Batch = client.batches.create(
input_file_id="your_file_id",
endpoint="/v1/chat/completions",
completion_window="24h",
)
print(batch.id) # Save batch_id for polling
curl ${MOONSHOT_BASE_URL:-https://api.moonshot.ai/v1}/batches \
-H "Authorization: Bearer $MOONSHOT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"input_file_id": "your_file_id",
"endpoint": "/v1/chat/completions",
"completion_window": "24h"
}'
const OpenAI = require("openai");
const client = new OpenAI({
apiKey: process.env.MOONSHOT_API_KEY,
baseURL: process.env.MOONSHOT_BASE_URL || "https://api.moonshot.ai/v1",
});
async function main() {
const batch = await client.batches.create({
input_file_id: "your_file_id",
endpoint: "/v1/chat/completions",
completion_window: "24h"
});
console.log(batch.id); // Save batch_id for polling
}
main();
4. Wait for Completion
After creation, the task entersvalidating status for input validation. Once validated, it moves to in_progress. Use the Retrieve Batch endpoint to poll for status updates.
import os
import time
from openai import OpenAI
from openai.types import Batch
client = OpenAI(
api_key=os.environ.get("MOONSHOT_API_KEY"),
base_url=os.environ.get("MOONSHOT_BASE_URL", "https://api.moonshot.ai/v1"),
)
while True:
batch: Batch = client.batches.retrieve("your_batch_id")
completed: int = batch.request_counts.completed if batch.request_counts else 0
total: int = batch.request_counts.total if batch.request_counts else 0
print(f"Status: {batch.status} ({completed}/{total})")
if batch.status == "completed":
break
elif batch.status in ("failed", "expired", "cancelled"):
print(f"Task terminated: {batch.status}")
break
time.sleep(10)
curl ${MOONSHOT_BASE_URL:-https://api.moonshot.ai/v1}/batches/your_batch_id \
-H "Authorization: Bearer $MOONSHOT_API_KEY"
const OpenAI = require("openai");
const client = new OpenAI({
apiKey: process.env.MOONSHOT_API_KEY,
baseURL: process.env.MOONSHOT_BASE_URL || "https://api.moonshot.ai/v1",
});
async function main() {
let batch = await client.batches.retrieve("your_batch_id");
while (!["completed", "failed", "expired", "cancelled"].includes(batch.status)) {
await new Promise(r => setTimeout(r, 10000));
batch = await client.batches.retrieve("your_batch_id");
console.log(`Status: ${batch.status} (${batch.request_counts.completed}/${batch.request_counts.total})`);
}
}
main();
5. Process Results
When complete,output_file_id contains the results file ID. Download it via the Get File Content endpoint. If any requests failed, error_file_id contains the error details.
import json
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ.get("MOONSHOT_API_KEY"),
base_url=os.environ.get("MOONSHOT_BASE_URL", "https://api.moonshot.ai/v1"),
)
output = client.files.content("your_output_file_id")
for line in output.text.strip().split("\n"):
result: dict = json.loads(line)
custom_id: str = result["custom_id"]
content: str = result["response"]["body"]["choices"][0]["message"]["content"]
print(f"{custom_id}: {content}")
curl ${MOONSHOT_BASE_URL:-https://api.moonshot.ai/v1}/files/your_output_file_id/content \
-H "Authorization: Bearer $MOONSHOT_API_KEY" \
-o results.jsonl
const OpenAI = require("openai");
const client = new OpenAI({
apiKey: process.env.MOONSHOT_API_KEY,
baseURL: process.env.MOONSHOT_BASE_URL || "https://api.moonshot.ai/v1",
});
async function main() {
const output = await client.files.content("your_output_file_id");
const text = await output.text();
for (const line of text.trim().split("\n")) {
const data = JSON.parse(line);
console.log(`${data.custom_id}: ${data.response.body.choices[0].message.content}`);
}
}
main();
{
"id": "request-1",
"custom_id": "request-1",
"response": {
"status_code": 200,
"request_id": "",
"body": {
"id": "chatcmpl-xxx",
"object": "chat.completion",
"created": 1711475054,
"model": "kimi-k2.6",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "This text belongs to the Technology category."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 30,
"completion_tokens": 10,
"total_tokens": 40
}
}
},
"error": null
}
Complete Code Examples
Complete scripts combining all steps above — copy and run directly:import json
import os
import time
from pathlib import Path
from openai import OpenAI
MODEL = "kimi-k2.6"
client = OpenAI(
api_key=os.environ.get("MOONSHOT_API_KEY"),
base_url=os.environ.get("MOONSHOT_BASE_URL", "https://api.moonshot.ai/v1"),
)
def create_input_jsonl() -> Path:
"""Build a JSONL input file with classification requests."""
texts: list[str] = [
"Hamlet is one of Shakespeare's most famous tragedies",
"Scientists discover new potentially habitable planet",
"2024 Artificial Intelligence Development Report",
"How to make a delicious braised pork dish",
"Latest iPhone launch event details",
]
requests: list[dict] = []
for i, text in enumerate(texts):
requests.append({
"custom_id": f"text_{i}",
"method": "POST",
"url": "/v1/chat/completions",
"body": {
"model": MODEL,
"messages": [
{"role": "system", "content": "You are a text classification expert. Classify texts into: Literature/News/Academic/Technology/Lifestyle"},
{"role": "user", "content": f"Please classify the following text: {text}"},
],
},
})
output_path = Path("classification_requests.jsonl")
with output_path.open("w", encoding="utf-8") as f:
for req in requests:
f.write(json.dumps(req, ensure_ascii=False) + "\n")
return output_path
# 1. Build input file
input_file: Path = create_input_jsonl()
# 2. Upload file
file_object = client.files.create(file=input_file, purpose="batch")
print(f"File uploaded: {file_object.id}")
# 3. Create batch task
batch = client.batches.create(
input_file_id=file_object.id,
endpoint="/v1/chat/completions",
completion_window="24h",
)
print(f"Batch created: {batch.id}")
# 4. Poll for completion
while True:
batch = client.batches.retrieve(batch.id)
print(f"Status: {batch.status} ({batch.request_counts.completed}/{batch.request_counts.total})")
if batch.status == "completed":
break
elif batch.status in ("failed", "expired", "cancelled"):
print(f"Task terminated: {batch.status}")
exit(1)
time.sleep(10)
# 5. Process results
output = client.files.content(batch.output_file_id)
for line in output.text.strip().split("\n"):
data: dict = json.loads(line)
print(f"{data['custom_id']}: {data['response']['body']['choices'][0]['message']['content']}")
const OpenAI = require("openai");
const fs = require("fs");
const MODEL = "kimi-k2.6";
const client = new OpenAI({
apiKey: process.env.MOONSHOT_API_KEY,
baseURL: process.env.MOONSHOT_BASE_URL || "https://api.moonshot.ai/v1",
});
// 1. Build input file
const texts = [
"Hamlet is one of Shakespeare's most famous tragedies",
"Scientists discover new potentially habitable planet",
"2024 Artificial Intelligence Development Report",
"How to make a delicious braised pork dish",
"Latest iPhone launch event details"
];
const lines = texts.map((text, i) => JSON.stringify({
custom_id: `text_${i}`,
method: "POST",
url: "/v1/chat/completions",
body: {
model: MODEL,
messages: [
{ role: "system", content: "You are a text classification expert. Classify texts into: Literature/News/Academic/Technology/Lifestyle" },
{ role: "user", content: `Please classify the following text: ${text}` }
]
}
}));
fs.writeFileSync("classification_requests.jsonl", lines.join("\n") + "\n");
async function main() {
// 2. Upload file
const fileObject = await client.files.create({
file: fs.createReadStream("classification_requests.jsonl"),
purpose: "batch"
});
console.log(`File uploaded: ${fileObject.id}`);
// 3. Create batch task
const batch = await client.batches.create({
input_file_id: fileObject.id,
endpoint: "/v1/chat/completions",
completion_window: "24h"
});
console.log(`Batch created: ${batch.id}`);
// 4. Poll for completion
let current = batch;
while (!["completed", "failed", "expired", "cancelled"].includes(current.status)) {
await new Promise(r => setTimeout(r, 10000));
current = await client.batches.retrieve(batch.id);
console.log(`Status: ${current.status} (${current.request_counts.completed}/${current.request_counts.total})`);
}
if (current.status !== "completed") {
console.error(`Task terminated: ${current.status}`);
return;
}
// 5. Download and process results
const output = await client.files.content(current.output_file_id);
const text = await output.text();
for (const line of text.trim().split("\n")) {
const data = JSON.parse(line);
console.log(`${data.custom_id}: ${data.response.body.choices[0].message.content}`);
}
}
main();
Batch Status Reference
| Status | Description |
|---|---|
validating | Created, input data validation in progress |
failed | Data validation failed, batch terminated |
in_progress | Validation passed, execution in progress |
finalizing | Execution complete, preparing results |
completed | Results ready, batch complete |
expired | Did not complete within completion_window |
cancelling | Cancellation requested, pending |
cancelled | Cancellation complete, batch terminated |
Task Management
List Batches
Use the List Batches endpoint to view all batch tasks in your organization.import os
from openai import OpenAI
from openai.pagination import SyncCursorPage
from openai.types import Batch
client = OpenAI(
api_key=os.environ.get("MOONSHOT_API_KEY"),
base_url=os.environ.get("MOONSHOT_BASE_URL", "https://api.moonshot.ai/v1"),
)
batches: SyncCursorPage[Batch] = client.batches.list(limit=10)
for batch in batches.data:
print(f"{batch.id} - {batch.status} ({batch.request_counts.completed}/{batch.request_counts.total})")
curl "${MOONSHOT_BASE_URL:-https://api.moonshot.ai/v1}/batches?limit=10" \
-H "Authorization: Bearer $MOONSHOT_API_KEY"
const OpenAI = require("openai");
const client = new OpenAI({
apiKey: process.env.MOONSHOT_API_KEY,
baseURL: process.env.MOONSHOT_BASE_URL || "https://api.moonshot.ai/v1",
});
async function main() {
const batches = await client.batches.list({ limit: 10 });
for (const batch of batches.data) {
console.log(`${batch.id} - ${batch.status} (${batch.request_counts.completed}/${batch.request_counts.total})`);
}
}
main();
Cancel a Batch
Use the Cancel Batch endpoint to cancel an in-progress task. Only tasks invalidating, in_progress, or finalizing status can be cancelled. After cancellation, the status changes to cancelling and then cancelled.
import os
from openai import OpenAI
from openai.types import Batch
client = OpenAI(
api_key=os.environ.get("MOONSHOT_API_KEY"),
base_url=os.environ.get("MOONSHOT_BASE_URL", "https://api.moonshot.ai/v1"),
)
batch: Batch = client.batches.cancel("your_batch_id")
print(f"Status: {batch.status}") # cancelling
curl -X POST ${MOONSHOT_BASE_URL:-https://api.moonshot.ai/v1}/batches/your_batch_id/cancel \
-H "Authorization: Bearer $MOONSHOT_API_KEY"
const OpenAI = require("openai");
const client = new OpenAI({
apiKey: process.env.MOONSHOT_API_KEY,
baseURL: process.env.MOONSHOT_BASE_URL || "https://api.moonshot.ai/v1",
});
async function main() {
const batch = await client.batches.cancel("your_batch_id");
console.log(`Status: ${batch.status}`); // cancelling
}
main();
Multi-modal Batch Tasks
The Batch API supports image and video content in the input file. The key difference from text tasks is in building the input file — the rest of the workflow (upload, create task, poll, process results) is identical.Image Batch Processing Example
Image Batch Processing Example
There are two ways to include images:
- Base64 inline: Encode images as base64 directly in the JSONL. Suitable for small images. Note that base64 inflates file size by ~33% — keep the 100MB file size limit in mind.
- File reference: Upload images first via the Files API (
purpose="image"), then reference them in the JSONL usingms://<file_id>. Better for large images or image reuse.
import base64
import json
import os
import time
from pathlib import Path
from openai import OpenAI
from openai.types import Batch, FileObject
client = OpenAI(
api_key=os.environ.get("MOONSHOT_API_KEY"),
base_url=os.environ.get("MOONSHOT_BASE_URL", "https://api.moonshot.ai/v1"),
)
MODEL = "kimi-k2.6"
PROMPT = "Classify this image: Landscape/Portrait/Food/Architecture/Other"
SYSTEM = "You are an image classification assistant."
def build_request_base64(custom_id: str, image_path: str) -> dict:
"""Method 1: Encode the image as base64 and embed it directly in the JSONL.
Best for small images — no extra upload step needed."""
with open(image_path, "rb") as f:
image_data: str = base64.b64encode(f.read()).decode("utf-8")
return {
"custom_id": custom_id,
"method": "POST",
"url": "/v1/chat/completions",
"body": {
"model": MODEL,
"messages": [
{"role": "system", "content": SYSTEM},
{
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": f"data:image/png;base64,{image_data}"}},
{"type": "text", "text": PROMPT},
],
},
],
},
}
def build_request_upload(custom_id: str, image_path: str) -> dict:
"""Method 2: Upload the image first, then reference it via ms://<file_id>.
Best for large images or when the same image is reused across requests."""
file_object: FileObject = client.files.create(
file=open(image_path, "rb"),
purpose="image",
)
print(f"Image uploaded: {image_path} -> {file_object.id}")
return {
"custom_id": custom_id,
"method": "POST",
"url": "/v1/chat/completions",
"body": {
"model": MODEL,
"messages": [
{"role": "system", "content": SYSTEM},
{
"role": "user",
"content": [
{"type": "image_url", "image_url": {"url": f"ms://{file_object.id}"}},
{"type": "text", "text": PROMPT},
],
},
],
},
}
# ====== Choose your build method here ======
build_request = build_request_base64 # or build_request_upload
# ============================================
# 1. Build input file
images: list[str] = ["image1.png", "image2.png", "image3.png"]
requests: list[dict] = [build_request(f"img-{i}", path) for i, path in enumerate(images)]
input_path = Path("image_batch_requests.jsonl")
with input_path.open("w", encoding="utf-8") as f:
for req in requests:
f.write(json.dumps(req, ensure_ascii=False) + "\n")
# 2. Upload JSONL and create task
file_object: FileObject = client.files.create(file=input_path, purpose="batch")
batch: Batch = client.batches.create(
input_file_id=file_object.id,
endpoint="/v1/chat/completions",
completion_window="24h",
)
print(f"Batch created: {batch.id}")
# 3. Poll for completion
while True:
batch = client.batches.retrieve(batch.id)
print(f"Status: {batch.status} ({batch.request_counts.completed}/{batch.request_counts.total})")
if batch.status == "completed":
break
elif batch.status in ("failed", "expired", "cancelled"):
print(f"Task terminated: {batch.status}")
exit(1)
time.sleep(10)
# 4. Process results
output = client.files.content(batch.output_file_id)
for line in output.text.strip().split("\n"):
data: dict = json.loads(line)
print(f"{data['custom_id']}: {data['response']['body']['choices'][0]['message']['content']}")
const OpenAI = require("openai");
const fs = require("fs");
const client = new OpenAI({
apiKey: process.env.MOONSHOT_API_KEY,
baseURL: process.env.MOONSHOT_BASE_URL || "https://api.moonshot.ai/v1",
});
const MODEL = "kimi-k2.6";
const PROMPT = "Classify this image: Landscape/Portrait/Food/Architecture/Other";
const SYSTEM = "You are an image classification assistant.";
/** Method 1: Encode the image as base64 and embed it directly in the JSONL.
* Best for small images — no extra upload step needed. */
function buildRequestBase64(customId, imagePath) {
const imageData = fs.readFileSync(imagePath).toString("base64");
return {
custom_id: customId,
method: "POST",
url: "/v1/chat/completions",
body: {
model: MODEL,
messages: [
{ role: "system", content: SYSTEM },
{
role: "user",
content: [
{ type: "image_url", image_url: { url: `data:image/png;base64,${imageData}` } },
{ type: "text", text: PROMPT },
],
},
],
},
};
}
/** Method 2: Upload the image first, then reference it via ms://<file_id>.
* Best for large images or when the same image is reused across requests. */
async function buildRequestUpload(customId, imagePath) {
const fileObject = await client.files.create({
file: fs.createReadStream(imagePath),
purpose: "image"
});
console.log(`Image uploaded: ${imagePath} -> ${fileObject.id}`);
return {
custom_id: customId,
method: "POST",
url: "/v1/chat/completions",
body: {
model: MODEL,
messages: [
{ role: "system", content: SYSTEM },
{
role: "user",
content: [
{ type: "image_url", image_url: { url: `ms://${fileObject.id}` } },
{ type: "text", text: PROMPT },
],
},
],
},
};
}
async function main() {
// ====== Choose your build method here ======
const useUpload = false; // set to true for file reference method
// ============================================
// 1. Build input file
const images = ["image1.png", "image2.png", "image3.png"];
const requests = [];
for (let i = 0; i < images.length; i++) {
const req = useUpload
? await buildRequestUpload(`img-${i}`, images[i])
: buildRequestBase64(`img-${i}`, images[i]);
requests.push(JSON.stringify(req));
}
fs.writeFileSync("image_batch_requests.jsonl", requests.join("\n") + "\n");
// 2. Upload JSONL and create task
const fileObject = await client.files.create({
file: fs.createReadStream("image_batch_requests.jsonl"),
purpose: "batch"
});
const batch = await client.batches.create({
input_file_id: fileObject.id,
endpoint: "/v1/chat/completions",
completion_window: "24h"
});
console.log(`Batch created: ${batch.id}`);
// 3. Poll for completion
let current = batch;
while (!["completed", "failed", "expired", "cancelled"].includes(current.status)) {
await new Promise(r => setTimeout(r, 10000));
current = await client.batches.retrieve(batch.id);
console.log(`Status: ${current.status} (${current.request_counts.completed}/${current.request_counts.total})`);
}
if (current.status !== "completed") {
console.error(`Task terminated: ${current.status}`);
return;
}
// 4. Process results
const output = await client.files.content(current.output_file_id);
const text = await output.text();
for (const line of text.trim().split("\n")) {
const data = JSON.parse(line);
console.log(`${data.custom_id}: ${data.response.body.choices[0].message.content}`);
}
}
main();
Video Batch Processing Example
Video Batch Processing Example
There are two ways to include videos:
- Base64 inline: Encode videos as base64 directly in the JSONL. Suitable for small videos. Note that base64 inflates file size by ~33% — keep the 100MB file size limit in mind.
- File reference: Upload videos first via the Files API (
purpose="video"), then reference them in the JSONL usingms://<file_id>. Better for large videos or video reuse.
import base64
import json
import os
import time
from pathlib import Path
from openai import OpenAI
from openai.types import Batch, FileObject
MODEL = "kimi-k2.6"
client = OpenAI(
api_key=os.environ.get("MOONSHOT_API_KEY"),
base_url=os.environ.get("MOONSHOT_BASE_URL", "https://api.moonshot.ai/v1"),
)
PROMPT = "Summarize the main content of this video."
SYSTEM = "You are a video content analysis assistant."
def build_request_base64(custom_id: str, video_path: str) -> dict:
"""Method 1: Encode the video as base64 and embed it directly in the JSONL.
Best for small videos — no extra upload step needed."""
with open(video_path, "rb") as f:
video_data: str = base64.b64encode(f.read()).decode("utf-8")
return {
"custom_id": custom_id,
"method": "POST",
"url": "/v1/chat/completions",
"body": {
"model": MODEL,
"messages": [
{"role": "system", "content": SYSTEM},
{
"role": "user",
"content": [
{"type": "video_url", "video_url": {"url": f"data:video/mp4;base64,{video_data}"}},
{"type": "text", "text": PROMPT},
],
},
],
},
}
def build_request_upload(custom_id: str, video_path: str) -> dict:
"""Method 2: Upload the video first, then reference it via ms://<file_id>.
Best for large videos or when the same video is reused across requests."""
file_object: FileObject = client.files.create(
file=open(video_path, "rb"),
purpose="video",
)
print(f"Video uploaded: {video_path} -> {file_object.id}")
return {
"custom_id": custom_id,
"method": "POST",
"url": "/v1/chat/completions",
"body": {
"model": MODEL,
"messages": [
{"role": "system", "content": SYSTEM},
{
"role": "user",
"content": [
{"type": "video_url", "video_url": {"url": f"ms://{file_object.id}"}},
{"type": "text", "text": PROMPT},
],
},
],
},
}
# ====== Choose your build method here ======
build_request = build_request_base64 # or build_request_upload
# ============================================
# 1. Build input file
videos: list[str] = ["video1.mp4", "video2.mp4", "video3.mp4"]
requests: list[dict] = [build_request(f"video-{i}", path) for i, path in enumerate(videos)]
input_path = Path("video_batch_requests.jsonl")
with input_path.open("w", encoding="utf-8") as f:
for req in requests:
f.write(json.dumps(req, ensure_ascii=False) + "\n")
# 2. Upload JSONL and create task
batch_file: FileObject = client.files.create(file=input_path, purpose="batch")
batch: Batch = client.batches.create(
input_file_id=batch_file.id,
endpoint="/v1/chat/completions",
completion_window="24h",
)
print(f"Batch created: {batch.id}")
# 3. Poll for completion
while True:
batch = client.batches.retrieve(batch.id)
print(f"Status: {batch.status} ({batch.request_counts.completed}/{batch.request_counts.total})")
if batch.status == "completed":
break
elif batch.status in ("failed", "expired", "cancelled"):
print(f"Task terminated: {batch.status}")
exit(1)
time.sleep(10)
# 4. Process results
output = client.files.content(batch.output_file_id)
for line in output.text.strip().split("\n"):
data: dict = json.loads(line)
print(f"{data['custom_id']}: {data['response']['body']['choices'][0]['message']['content']}")
const OpenAI = require("openai");
const fs = require("fs");
const client = new OpenAI({
apiKey: process.env.MOONSHOT_API_KEY,
baseURL: process.env.MOONSHOT_BASE_URL || "https://api.moonshot.ai/v1",
});
const MODEL = "kimi-k2.6";
const PROMPT = "Summarize the main content of this video.";
const SYSTEM = "You are a video content analysis assistant.";
/** Method 1: Encode the video as base64 and embed it directly in the JSONL.
* Best for small videos — no extra upload step needed. */
function buildRequestBase64(customId, videoPath) {
const videoData = fs.readFileSync(videoPath).toString("base64");
return {
custom_id: customId,
method: "POST",
url: "/v1/chat/completions",
body: {
model: MODEL,
messages: [
{ role: "system", content: SYSTEM },
{
role: "user",
content: [
{ type: "video_url", video_url: { url: `data:video/mp4;base64,${videoData}` } },
{ type: "text", text: PROMPT },
],
},
],
},
};
}
/** Method 2: Upload the video first, then reference it via ms://<file_id>.
* Best for large videos or when the same video is reused across requests. */
async function buildRequestUpload(customId, videoPath) {
const fileObject = await client.files.create({
file: fs.createReadStream(videoPath),
purpose: "video"
});
console.log(`Video uploaded: ${videoPath} -> ${fileObject.id}`);
return {
custom_id: customId,
method: "POST",
url: "/v1/chat/completions",
body: {
model: MODEL,
messages: [
{ role: "system", content: SYSTEM },
{
role: "user",
content: [
{ type: "video_url", video_url: { url: `ms://${fileObject.id}` } },
{ type: "text", text: PROMPT },
],
},
],
},
};
}
async function main() {
// ====== Choose your build method here ======
const useUpload = false; // set to true for file reference method
// ============================================
// 1. Build input file
const videos = ["video1.mp4", "video2.mp4", "video3.mp4"];
const requests = [];
for (let i = 0; i < videos.length; i++) {
const req = useUpload
? await buildRequestUpload(`video-${i}`, videos[i])
: buildRequestBase64(`video-${i}`, videos[i]);
requests.push(JSON.stringify(req));
}
fs.writeFileSync("video_batch_requests.jsonl", requests.join("\n") + "\n");
// 2. Upload JSONL and create task
const batchFile = await client.files.create({
file: fs.createReadStream("video_batch_requests.jsonl"),
purpose: "batch"
});
const batch = await client.batches.create({
input_file_id: batchFile.id,
endpoint: "/v1/chat/completions",
completion_window: "24h"
});
console.log(`Batch created: ${batch.id}`);
// 3. Poll for completion
let current = batch;
while (!["completed", "failed", "expired", "cancelled"].includes(current.status)) {
await new Promise(r => setTimeout(r, 10000));
current = await client.batches.retrieve(batch.id);
console.log(`Status: ${current.status} (${current.request_counts.completed}/${current.request_counts.total})`);
}
if (current.status !== "completed") {
console.error(`Task terminated: ${current.status}`);
return;
}
// 4. Process results
const output = await client.files.content(current.output_file_id);
const text = await output.text();
for (const line of text.trim().split("\n")) {
const data = JSON.parse(line);
console.log(`${data.custom_id}: ${data.response.body.choices[0].message.content}`);
}
}
main();
Best Practices
- Set
completion_windowbased on data volume — use3dor7dfor larger datasets - Poll every 10-60 seconds to avoid excessive requests
- Process results into databases or reports as needed
- For very large files, consider splitting into multiple batches