۱) مفاهیم کلیدی سرویس و Endpointها
– `method`
اعتبار خود را بهصورت ریالی شارژ کنید. (در بدو عضویت، مقداری اعتبار رایگان به عنوان هدیه به شما تعلق میگیرد)
۳) نمونه درخواستهای ساخت ویدیو (Create) متن به ویدیو (چند زبان)
۱-۳) ساخت ساده (بدون تصویر مرجع)
const ENDPOINT = 'https://platonia.co/wp-json/platonia-dev/v1/proxy';
const USER_KEY = 'pltn_xxx...'; // کلید پلاتونیا
async function createVideo(prompt) {
const payload = {
openai_path: 'videos', // معادل POST /v1/videos
method: 'POST',
model: 'sora-2', // یا 'sora-2-pro'
prompt,
size: '1280x720', // رزولوشن خروجی
seconds: '8' // طول ویدیو به ثانیه
};
const res = await fetch(ENDPOINT, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + USER_KEY
},
body: JSON.stringify(payload)
});
const data = await res.json();
if (!res.ok) {
throw new Error(data.message || (data.error && data.error.message) || 'Request failed');
}
// data شکل شیٔ ویدیوی OpenAI است
// { id, status, model, progress, seconds, size, ... }
return data;
}
// نمونه استفاده
createVideo('Wide shot of a teal coupe driving through a desert highway, cinematic, golden hour.')
.then(v => console.log('Video job started:', v.id, v.status))
.catch(console.error);
import requests
ENDPOINT = 'https://platonia.co/wp-json/platonia-dev/v1/proxy'
USER_KEY = 'pltn_xxx...'
payload = {
'openai_path': 'videos',
'method': 'POST',
'model': 'sora-2-pro',
'prompt': 'A cinematic shot of ocean waves at sunset, slow camera dolly.',
'size': '1280x720',
'seconds': '8'
}
r = requests.post(ENDPOINT, json=payload, headers={
'Authorization': f'Bearer {USER_KEY}'
})
data = r.json()
if not r.ok:
raise SystemExit(data.get('message') or (data.get('error') or {}).get('message') or 'Request failed')
print('Job started:', data['id'], data['status'])
curl -X POST https://platonia.co/wp-json/platonia-dev/v1/proxy \
-H "Authorization: Bearer pltn_xxx..." \
-H "Content-Type: application/json" \
-d '{
"openai_path": "videos",
"method": "POST",
"model": "sora-2",
"prompt": "A video of the words \"Thank you\" in sparkling letters",
"size": "1280x720",
"seconds": "8"
}'
```
پاسخ، آبجکت ویدیو با `id` و `status` (مثلاً `queued` یا `in_progress`) است.
---
۴) ساخت ویدیو با تصویر مرجع (Input Reference)
async function createVideoWithImage(prompt, file) {
// file: از input[type=file]
const arrayBuffer = await file.arrayBuffer();
const b64 = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)));
const payload = {
openai_path: 'videos',
method: 'POST',
model: 'sora-2-pro',
prompt,
size: '1280x720', // باید با رزولوشن تصویر همخوانی داشته باشد
seconds: '8',
input_reference_b64: b64,
input_reference_name: file.name,
input_reference_mime: file.type || 'image/jpeg'
};
const res = await fetch(ENDPOINT, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + USER_KEY
},
body: JSON.stringify(payload)
});
const data = await res.json();
if (!res.ok) {
throw new Error(data.message || (data.error && data.error.message) || 'Request failed');
}
return data;
}
```
۵) Polling وضعیت و پیشرفت (`GET /videos/{id}`)
async function getVideoStatus(videoId) {
const payload = {
openai_path: `videos/${videoId}`,
method: 'GET'
};
const res = await fetch(ENDPOINT, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + USER_KEY
},
body: JSON.stringify(payload)
});
const data = await res.json();
if (!res.ok) {
throw new Error(data.message || (data.error && data.error.message) || 'Request failed');
}
// data: { id, status, progress, model, seconds, size, ... }
return data;
}
async function pollUntilDone(videoId) {
let delay = 10_000; // 10 ثانیه
const maxDelay = 25_000; // حداکثر ~25 ثانیه
while (true) {
const v = await getVideoStatus(videoId);
console.log('Status:', v.status, 'Progress:', v.progress ?? '-');
if (v.status === 'completed') return v;
if (v.status === 'failed') throw new Error('Video failed: ' + (v.error?.message || ''));
await new Promise(r => setTimeout(r, delay));
delay = Math.min(maxDelay, Math.round(delay * 1.5));
}
}
۶) دانلود ویدیو و Assetها (`/videos/{id}/content`)
async function downloadVideoBlob(videoId, variant = 'video') {
const payload = {
openai_path: `videos/${videoId}/content`,
method: 'GET'
};
if (variant && variant !== 'video') payload.variant = variant;
const res = await fetch(ENDPOINT, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + USER_KEY
},
body: JSON.stringify(payload)
});
if (!res.ok) {
let err;
try { err = await res.json(); } catch (e) {}
throw new Error(err?.message || (err?.error && err.error.message) || 'Download failed');
}
const blob = await res.blob();
return blob;
}
// مثال: ذخیرهٔ ویدیو در مرورگر
downloadVideoBlob('video_abc123').then(blob => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'video.mp4';
a.click();
URL.revokeObjectURL(url);
}).catch(console.error);
import requests
ENDPOINT = 'https://platonia.co/wp-json/platonia-dev/v1/proxy'
USER_KEY = 'pltn_xxx...'
VIDEO_ID = 'video_abc123'
payload = {
'openai_path': f'videos/{VIDEO_ID}/content',
'method': 'GET',
'variant': 'video' # یا 'thumbnail' / 'spritesheet'
}
r = requests.post(ENDPOINT, json=payload, headers={
'Authorization': f'Bearer {USER_KEY}'
}, stream=True)
if not r.ok:
try:
data = r.json()
raise SystemExit(data.get('message') or (data.get('error') or {}).get('message') or 'Download failed')
except ValueError:
raise SystemExit('Download failed')
with open('video.mp4', 'wb') as f:
for chunk in r.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
print('Saved video.mp4')
۷) ریمیکس ویدیو (`POST /videos/{id}/remix`)
async function remixVideo(sourceId, prompt) {
const payload = {
openai_path: `videos/${sourceId}/remix`,
method: 'POST',
prompt
};
const res = await fetch(ENDPOINT, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + USER_KEY
},
body: JSON.stringify(payload)
});
const data = await res.json();
if (!res.ok) {
throw new Error(data.message || (data.error && data.error.message) || 'Remix failed');
}
// data.id ویدیوی جدید است
return data;
}
remixVideo('video_abc123', 'Shift the color palette to teal, sand, and rust, with a warm backlight.')
.then(v => console.log('Remix started:', v.id, v.status))
.catch(console.error);
۸) لیست و حذف ویدیوها
۱-۸) لیست (`GET /videos` – محلی روی گیتوی)
json
{
"openai_path": "videos",
"method": "GET",
"limit": 20,
"order": "desc"
}
میتوانید «لیست محلی» ویدیوهای آن کلید را دریافت کنید (بدون تماس با OpenAI):
JavaScript
async function listMyVideos(pageSize = 20) {
const payload = {
openai_path: 'videos',
method: 'GET',
limit: pageSize,
order: 'desc'
};
const res = await fetch(ENDPOINT, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + USER_KEY
},
body: JSON.stringify(payload)
});
const data = await res.json();
if (!res.ok) {
throw new Error(data.message || (data.error && data.error.message) || 'List failed');
}
// data.data → آرایهای از { id, object:'video', created_at, status:'unknown' }
return data.data;
}
۲-۸) حذف ویدیو (`DELETE /videos/{id}`)
JavaScript
async function deleteVideo(videoId) {
const payload = {
openai_path: `videos/${videoId}`,
method: 'DELETE'
};
const res = await fetch(ENDPOINT, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + USER_KEY
},
body: JSON.stringify(payload)
});
const data = await res.json();
if (!res.ok) {
throw new Error(data.message || (data.error && data.error.message) || 'Delete failed');
}
return true;
}
توجه: فقط صاحب همان کلید میتواند ویدیو را حذف کند؛ در غیر این صورت `403 video_forbidden` دریافت میشود.
۹) مدیریت خطا، کوئوتا و پایداری
async function withBackoff(fn, max = 5) {
let delay = 1000;
for (let i = 0; i < max; i++) {
try {
return await fn();
} catch (e) {
if (i === max - 1) throw e;
await new Promise(r => setTimeout(r, delay * (1 + Math.random())));
delay *= 2;
}
}
}
۱۰) امنیت، CORS و دامنههای مجاز
– برای محیط Production توصیه میشود:
– گیتوی:
۱۱) نکات مهم برای کار با Sora از طریق گیتوی
۱۲) افزونه وردپرسی PlatoniaVid