مستندات المطور UlazAI
وكيل البداية السريعة
تكامل نقطة واطلاق النار للوكلاء
استخدم هذه الصفحة عندما تريد مواقع ويب أخرى أو وكلاء الذكاء الاصطناعي أو أدوات التشغيل الآلي للاتصال بـ UlazAI مباشرة بدون ملفات تعريف الارتباط الخاصة بالجلسة أو معالجة CSRF.
Authorization: Bearer YOUR_ULAZAI_KEY على كل طلب.
مهارة قابلة للتثبيت + عملاء جاهزون
إذا كنت تستخدم Skills CLI، فقم بتثبيت مهارة UlazAI مباشرة من GitHub.
npx skills add https://github.com/smrht/ulazai-agent-skills --skill ulazai-point-and-shoot
إذا كان الريبو المصدر الخاص بك خاصًا، فاستخدم مستودع المهارات العامة (مستحسن) أو قم بالتثبيت من مسار محلي:
npx skills add /absolute/path/to/repo --skill ulazai-point-and-shoot
"""UlazAI point-and-shoot API client.
Minimal wrapper for:
- model discovery
- image generation/status/history
- video studio generation/status/history
- video studio tool endpoints
"""
from __future__ import annotations
import time
from typing import Any, Dict, Optional
import requests
class UlazAIAPIError(Exception):
"""Raised when the UlazAI API returns a non-success response."""
def __init__(
self,
*,
status_code: int,
message: str,
payload: Optional[Dict[str, Any]] = None,
) -> None:
super().__init__(f"HTTP {status_code}: {message}")
self.status_code = status_code
self.message = message
self.payload = payload or {}
class UlazAIClient:
def __init__(
self,
api_key: str,
*,
base_url: str = "https://ulazai.com",
timeout_seconds: int = 120,
session: Optional[requests.Session] = None,
) -> None:
if not api_key or not api_key.strip():
raise ValueError("api_key is required")
self.base_url = base_url.rstrip("/")
self.timeout_seconds = timeout_seconds
self.session = session or requests.Session()
self.session.headers.update(
{
"Authorization": f"Bearer {api_key.strip()}",
"Content-Type": "application/json",
"Accept": "application/json",
"User-Agent": "UlazAI-Python-Client/1.0",
}
)
def _request(
self,
method: str,
path: str,
*,
params: Optional[Dict[str, Any]] = None,
json_body: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
url = f"{self.base_url}{path}"
response = self.session.request(
method=method,
url=url,
params=params,
json=json_body,
timeout=self.timeout_seconds,
)
try:
payload = response.json()
except ValueError:
payload = {"success": False, "error": response.text or "Invalid JSON response"}
if response.ok:
return payload
error_message = (
str(payload.get("error") or payload.get("message") or response.reason)
if isinstance(payload, dict)
else response.reason
)
raise UlazAIAPIError(
status_code=response.status_code,
message=error_message,
payload=payload if isinstance(payload, dict) else None,
)
# Model discovery
def list_image_models(self) -> Dict[str, Any]:
return self._request("GET", "/api/v1/models/image/")
def list_video_models(self) -> Dict[str, Any]:
return self._request("GET", "/api/v1/models/video/")
# Images
def generate_image(
self,
*,
prompt: str,
model: str,
size: Optional[str] = None,
quality: Optional[str] = None,
google_search: Optional[bool] = None,
extra: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
payload: Dict[str, Any] = {"prompt": prompt, "model": model}
if size:
payload["size"] = size
if quality:
payload["quality"] = quality
if google_search is not None:
payload.setdefault("input", {})["google_search"] = bool(google_search)
if extra:
payload.update(extra)
return self._request("POST", "/api/v1/generate/", json_body=payload)
def get_image_status(self, generation_id: str) -> Dict[str, Any]:
return self._request("GET", f"/api/v1/generate/{generation_id}/")
def list_image_history(self, *, page: int = 1, limit: int = 20) -> Dict[str, Any]:
return self._request("GET", "/api/v1/generate/history/", params={"page": page, "limit": limit})
def wait_for_image(
self,
generation_id: str,
*,
timeout_seconds: int = 300,
poll_interval_seconds: float = 2.0,
) -> Dict[str, Any]:
deadline = time.time() + timeout_seconds
while time.time() < deadline:
payload = self.get_image_status(generation_id)
status_value = str(
payload.get("status")
or payload.get("data", {}).get("status")
or payload.get("generation", {}).get("status")
or ""
).lower()
if status_value in {"completed", "failed"}:
return payload
time.sleep(poll_interval_seconds)
raise TimeoutError(f"Image generation timed out after {timeout_seconds}s")
# Videos
def generate_video(
self,
*,
model_slug: str,
prompt: str,
aspect_ratio: Optional[str] = None,
duration_seconds: Optional[int] = None,
quality_mode: Optional[str] = None,
extra: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
payload: Dict[str, Any] = {"model_slug": model_slug, "prompt": prompt}
if aspect_ratio:
payload["aspect_ratio"] = aspect_ratio
if duration_seconds:
payload["duration_seconds"] = duration_seconds
if quality_mode:
payload["quality_mode"] = quality_mode
if extra:
payload.update(extra)
return self._request("POST", "/api/v1/video-studio/generate/", json_body=payload)
def get_video_status(self, job_id: str) -> Dict[str, Any]:
return self._request("GET", f"/api/v1/video-studio/status/{job_id}/")
def list_video_history(self, *, limit: int = 20) -> Dict[str, Any]:
return self._request("GET", "/api/v1/video-studio/history/", params={"limit": limit})
def wait_for_video(
self,
job_id: str,
*,
timeout_seconds: int = 600,
poll_interval_seconds: float = 3.0,
) -> Dict[str, Any]:
deadline = time.time() + timeout_seconds
while time.time() < deadline:
payload = self.get_video_status(job_id)
job = payload.get("job", {}) if isinstance(payload, dict) else {}
status_value = str(job.get("status") or payload.get("status") or "").lower()
if status_value in {"completed", "failed"}:
return payload
time.sleep(poll_interval_seconds)
raise TimeoutError(f"Video generation timed out after {timeout_seconds}s")
# Video tools
def generate_street_interview(self, payload: Dict[str, Any]) -> Dict[str, Any]:
return self._request(
"POST",
"/api/v1/video-studio/tools/street-interview/generate/",
json_body=payload,
)
def generate_ugc_ad_quick(self, payload: Dict[str, Any]) -> Dict[str, Any]:
return self._request(
"POST",
"/api/v1/video-studio/tools/ugc-ad-quick/generate/",
json_body=payload,
)
def generate_video_remix(self, payload: Dict[str, Any]) -> Dict[str, Any]:
return self._request(
"POST",
"/api/v1/video-studio/tools/video-remix/generate/",
json_body=payload,
)
/**
* UlazAI point-and-shoot API client.
*
* Works in Node 18+ and modern browsers that support fetch.
*/
export class UlazAIAPIError extends Error {
constructor(statusCode, message, payload = {}) {
super(`HTTP ${statusCode}: ${message}`);
this.name = "UlazAIAPIError";
this.statusCode = statusCode;
this.payload = payload;
}
}
export class UlazAIClient {
constructor({ apiKey, baseUrl = "https://ulazai.com", timeoutMs = 120000 } = {}) {
if (!apiKey || !String(apiKey).trim()) {
throw new Error("apiKey is required");
}
this.apiKey = String(apiKey).trim();
this.baseUrl = String(baseUrl).replace(/\/+$/, "");
this.timeoutMs = timeoutMs;
}
async request(method, path, { params, body } = {}) {
const url = new URL(`${this.baseUrl}${path}`);
if (params) {
Object.entries(params).forEach(([key, value]) => {
if (value !== undefined && value !== null && value !== "") {
url.searchParams.set(key, String(value));
}
});
}
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), this.timeoutMs);
let response;
let payload;
try {
response = await fetch(url, {
method,
headers: {
Authorization: `Bearer ${this.apiKey}`,
"Content-Type": "application/json",
Accept: "application/json",
},
body: body ? JSON.stringify(body) : undefined,
signal: controller.signal,
});
const raw = await response.text();
try {
payload = raw ? JSON.parse(raw) : {};
} catch {
payload = { success: false, error: raw || "Invalid JSON response" };
}
} finally {
clearTimeout(timeout);
}
if (response.ok) {
return payload;
}
const message = payload?.error || payload?.message || response.statusText || "Request failed";
throw new UlazAIAPIError(response.status, message, payload);
}
// Model discovery
listImageModels() {
return this.request("GET", "/api/v1/models/image/");
}
listVideoModels() {
return this.request("GET", "/api/v1/models/video/");
}
// Images
generateImage({ prompt, model, size, quality, googleSearch, extra = {} }) {
const payload = { prompt, model, ...extra };
if (size) payload.size = size;
if (quality) payload.quality = quality;
if (googleSearch !== undefined) {
payload.input = { ...(payload.input || {}), google_search: Boolean(googleSearch) };
}
return this.request("POST", "/api/v1/generate/", { body: payload });
}
getImageStatus(generationId) {
return this.request("GET", `/api/v1/generate/${generationId}/`);
}
listImageHistory({ page = 1, limit = 20 } = {}) {
return this.request("GET", "/api/v1/generate/history/", { params: { page, limit } });
}
async waitForImage(generationId, { timeoutMs = 300000, pollMs = 2000 } = {}) {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const payload = await this.getImageStatus(generationId);
const status = String(
payload?.status || payload?.data?.status || payload?.generation?.status || ""
).toLowerCase();
if (status === "completed" || status === "failed") {
return payload;
}
await new Promise((resolve) => setTimeout(resolve, pollMs));
}
throw new Error(`Image generation timed out after ${timeoutMs}ms`);
}
// Videos
generateVideo({
modelSlug,
prompt,
aspectRatio,
durationSeconds,
qualityMode,
extra = {},
}) {
const payload = { model_slug: modelSlug, prompt, ...extra };
if (aspectRatio) payload.aspect_ratio = aspectRatio;
if (durationSeconds) payload.duration_seconds = durationSeconds;
if (qualityMode) payload.quality_mode = qualityMode;
return this.request("POST", "/api/v1/video-studio/generate/", { body: payload });
}
getVideoStatus(jobId) {
return this.request("GET", `/api/v1/video-studio/status/${jobId}/`);
}
listVideoHistory({ limit = 20 } = {}) {
return this.request("GET", "/api/v1/video-studio/history/", { params: { limit } });
}
async waitForVideo(jobId, { timeoutMs = 600000, pollMs = 3000 } = {}) {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const payload = await this.getVideoStatus(jobId);
const status = String(payload?.job?.status || payload?.status || "").toLowerCase();
if (status === "completed" || status === "failed") {
return payload;
}
await new Promise((resolve) => setTimeout(resolve, pollMs));
}
throw new Error(`Video generation timed out after ${timeoutMs}ms`);
}
// Video tools
generateStreetInterview(payload) {
return this.request("POST", "/api/v1/video-studio/tools/street-interview/generate/", {
body: payload,
});
}
generateUgcAdQuick(payload) {
return this.request("POST", "/api/v1/video-studio/tools/ugc-ad-quick/generate/", {
body: payload,
});
}
generateVideoRemix(payload) {
return this.request("POST", "/api/v1/video-studio/tools/video-remix/generate/", {
body: payload,
});
}
}
---
name: ulazai-point-and-shoot
description: UlazAI API skill for low-cost image and video generation across newest models (Nano Banana 2, Seedream 5.0 Lite, Wan 2.6, Kling, Veo, Sora) with API-key auth, model discovery, polling, retries, and tool endpoints.
---
# UlazAI Point-and-Shoot Skill
Use this skill when you need reliable UlazAI API integration in an external app,
automation, or white-label connector.
## Why UlazAI
Use this skill when you want strong production economics and broad model
coverage:
- low-cost endpoints for new image and video models
- one API surface for generation, status polling, and history
- fast rollout support for newly released model families
- agent-ready flow with predictable retries and guardrails
## Required auth
Send this header on every request:
- `Authorization: Bearer {{ULAZAI_API_KEY}}`
Base URL:
- `https://ulazai.com`
## API workflow
Follow this order for every integration:
1. Discover supported models first.
2. Create generation job.
3. Poll status endpoint until `completed` or `failed`.
4. Return output URLs and metadata.
### Model discovery
- Images: `GET /api/v1/models/image/`
- Videos: `GET /api/v1/models/video/`
### Image generation
- Create: `POST /api/v1/generate/`
- Poll: `GET /api/v1/generate/{generation_id}/`
- History: `GET /api/v1/generate/history/`
When the user asks for real-time grounded image generation on compatible
models, set `input.google_search=true` in the image payload.
### Video Studio generation
- Create: `POST /api/v1/video-studio/generate/`
- Poll: `GET /api/v1/video-studio/status/{job_id}/`
- History: `GET /api/v1/video-studio/history/`
### Video Studio tools
- Street interview:
`POST /api/v1/video-studio/tools/street-interview/generate/`
- UGC ad quick:
`POST /api/v1/video-studio/tools/ugc-ad-quick/generate/`
- Video remix:
`POST /api/v1/video-studio/tools/video-remix/generate/`
## Error behavior
- `401` or `403`: stop and request a valid API key.
- `402`: report insufficient credits.
- `429` and `5xx`: retry with exponential backoff.
- `400`: show validation error from response and let user fix input.
## Polling defaults
- Image jobs: poll every 2 seconds, timeout after 5 minutes.
- Video jobs: poll every 3 seconds, timeout after 10 minutes.
## Reusable clients in this skill
Use these files when code generation is requested:
- Python: `references/ulazai_client.py`
- JavaScript: `references/ulazai_client.js`
## Minimal cURL examples
```bash
curl -X GET https://ulazai.com/api/v1/models/image/ \
-H "Authorization: Bearer YOUR_ULAZAI_KEY"
```
```bash
curl -X POST https://ulazai.com/api/v1/generate/ \
-H "Authorization: Bearer YOUR_ULAZAI_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Premium product shot with cinematic lighting",
"model": "nano_banana_2",
"size": "16:9",
"quality": "2K"
}'
```
```bash
curl -X POST https://ulazai.com/api/v1/video-studio/generate/ \
-H "Authorization: Bearer YOUR_ULAZAI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model_slug": "wan_2_6",
"prompt": "Cinematic product teaser, smooth camera movement",
"aspect_ratio": "16:9",
"duration_seconds": 10,
"quality_mode": "1080p"
}'
```
عميل بايثون
"""UlazAI point-and-shoot API client.
Minimal wrapper for:
- model discovery
- image generation/status/history
- video studio generation/status/history
- video studio tool endpoints
"""
from __future__ import annotations
import time
from typing import Any, Dict, Optional
import requests
class UlazAIAPIError(Exception):
"""Raised when the UlazAI API returns a non-success response."""
def __init__(
self,
*,
status_code: int,
message: str,
payload: Optional[Dict[str, Any]] = None,
) -> None:
super().__init__(f"HTTP {status_code}: {message}")
self.status_code = status_code
self.message = message
self.payload = payload or {}
class UlazAIClient:
def __init__(
self,
api_key: str,
*,
base_url: str = "https://ulazai.com",
timeout_seconds: int = 120,
session: Optional[requests.Session] = None,
) -> None:
if not api_key or not api_key.strip():
raise ValueError("api_key is required")
self.base_url = base_url.rstrip("/")
self.timeout_seconds = timeout_seconds
self.session = session or requests.Session()
self.session.headers.update(
{
"Authorization": f"Bearer {api_key.strip()}",
"Content-Type": "application/json",
"Accept": "application/json",
"User-Agent": "UlazAI-Python-Client/1.0",
}
)
def _request(
self,
method: str,
path: str,
*,
params: Optional[Dict[str, Any]] = None,
json_body: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
url = f"{self.base_url}{path}"
response = self.session.request(
method=method,
url=url,
params=params,
json=json_body,
timeout=self.timeout_seconds,
)
try:
payload = response.json()
except ValueError:
payload = {"success": False, "error": response.text or "Invalid JSON response"}
if response.ok:
return payload
error_message = (
str(payload.get("error") or payload.get("message") or response.reason)
if isinstance(payload, dict)
else response.reason
)
raise UlazAIAPIError(
status_code=response.status_code,
message=error_message,
payload=payload if isinstance(payload, dict) else None,
)
# Model discovery
def list_image_models(self) -> Dict[str, Any]:
return self._request("GET", "/api/v1/models/image/")
def list_video_models(self) -> Dict[str, Any]:
return self._request("GET", "/api/v1/models/video/")
# Images
def generate_image(
self,
*,
prompt: str,
model: str,
size: Optional[str] = None,
quality: Optional[str] = None,
google_search: Optional[bool] = None,
extra: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
payload: Dict[str, Any] = {"prompt": prompt, "model": model}
if size:
payload["size"] = size
if quality:
payload["quality"] = quality
if google_search is not None:
payload.setdefault("input", {})["google_search"] = bool(google_search)
if extra:
payload.update(extra)
return self._request("POST", "/api/v1/generate/", json_body=payload)
def get_image_status(self, generation_id: str) -> Dict[str, Any]:
return self._request("GET", f"/api/v1/generate/{generation_id}/")
def list_image_history(self, *, page: int = 1, limit: int = 20) -> Dict[str, Any]:
return self._request("GET", "/api/v1/generate/history/", params={"page": page, "limit": limit})
def wait_for_image(
self,
generation_id: str,
*,
timeout_seconds: int = 300,
poll_interval_seconds: float = 2.0,
) -> Dict[str, Any]:
deadline = time.time() + timeout_seconds
while time.time() < deadline:
payload = self.get_image_status(generation_id)
status_value = str(
payload.get("status")
or payload.get("data", {}).get("status")
or payload.get("generation", {}).get("status")
or ""
).lower()
if status_value in {"completed", "failed"}:
return payload
time.sleep(poll_interval_seconds)
raise TimeoutError(f"Image generation timed out after {timeout_seconds}s")
# Videos
def generate_video(
self,
*,
model_slug: str,
prompt: str,
aspect_ratio: Optional[str] = None,
duration_seconds: Optional[int] = None,
quality_mode: Optional[str] = None,
extra: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
payload: Dict[str, Any] = {"model_slug": model_slug, "prompt": prompt}
if aspect_ratio:
payload["aspect_ratio"] = aspect_ratio
if duration_seconds:
payload["duration_seconds"] = duration_seconds
if quality_mode:
payload["quality_mode"] = quality_mode
if extra:
payload.update(extra)
return self._request("POST", "/api/v1/video-studio/generate/", json_body=payload)
def get_video_status(self, job_id: str) -> Dict[str, Any]:
return self._request("GET", f"/api/v1/video-studio/status/{job_id}/")
def list_video_history(self, *, limit: int = 20) -> Dict[str, Any]:
return self._request("GET", "/api/v1/video-studio/history/", params={"limit": limit})
def wait_for_video(
self,
job_id: str,
*,
timeout_seconds: int = 600,
poll_interval_seconds: float = 3.0,
) -> Dict[str, Any]:
deadline = time.time() + timeout_seconds
while time.time() < deadline:
payload = self.get_video_status(job_id)
job = payload.get("job", {}) if isinstance(payload, dict) else {}
status_value = str(job.get("status") or payload.get("status") or "").lower()
if status_value in {"completed", "failed"}:
return payload
time.sleep(poll_interval_seconds)
raise TimeoutError(f"Video generation timed out after {timeout_seconds}s")
# Video tools
def generate_street_interview(self, payload: Dict[str, Any]) -> Dict[str, Any]:
return self._request(
"POST",
"/api/v1/video-studio/tools/street-interview/generate/",
json_body=payload,
)
def generate_ugc_ad_quick(self, payload: Dict[str, Any]) -> Dict[str, Any]:
return self._request(
"POST",
"/api/v1/video-studio/tools/ugc-ad-quick/generate/",
json_body=payload,
)
def generate_video_remix(self, payload: Dict[str, Any]) -> Dict[str, Any]:
return self._request(
"POST",
"/api/v1/video-studio/tools/video-remix/generate/",
json_body=payload,
)
تدفق 60 ثانية
| خطوة | نقطة النهاية | الغرض |
|---|---|---|
| 1 | /api/v1/models/image/ / /api/v1/models/video/ |
اكتشاف صالح model و model_slug القيم |
| 2 | /api/v1/generate/ أو /api/v1/video-studio/generate/ |
إنشاء وظيفة إنشاء صورة أو فيديو |
| 3 | /api/v1/generate/{generation_id}/ أو /api/v1/video-studio/status/{job_id}/ |
التصويت حتى completed وقراءة عناوين URL للنتائج |
الحد الأدنى من وصفات الضفيرة
اكتشاف نماذج الصور
curl -X GET https://ulazai.com/api/v1/models/image/ \
-H "Authorization: Bearer YOUR_ULAZAI_KEY"
إنشاء صورة (نقطة النهاية الموحدة)
curl -X POST https://ulazai.com/api/v1/generate/ \
-H "Authorization: Bearer YOUR_ULAZAI_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Premium running shoe hero shot, dramatic studio light",
"model": "nano_banana_2",
"size": "16:9",
"quality": "2K"
}'
إنشاء فيديو (جميع نماذج الفيديو)
curl -X POST https://ulazai.com/api/v1/video-studio/generate/ \
-H "Authorization: Bearer YOUR_ULAZAI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model_slug": "wan_2_6",
"prompt": "Cinematic product teaser with smooth dolly motion",
"aspect_ratio": "16:9",
"duration_seconds": 10,
"quality_mode": "1080p"
}'
حالة الفيديو الاستطلاع
curl -X GET https://ulazai.com/api/v1/video-studio/status/YOUR_JOB_ID/ \
-H "Authorization: Bearer YOUR_ULAZAI_KEY"
مهارة وكيل النسخ واللصق
قم بلصق هذه الكتلة في نظام الوكيل الخاص بك prompt أو تكوين المهارات.
# UlazAI Point-and-Shoot Skill
Base URL: https://ulazai.com
Auth: Authorization: Bearer
1) Model discovery
- Images: GET /api/v1/models/image/
- Videos: GET /api/v1/models/video/
2) Image tasks
- Create: POST /api/v1/generate/
- Poll: GET /api/v1/generate/{generation_id}/
- History: GET /api/v1/generate/history/
3) Video tasks (all video model_slugs)
- Create: POST /api/v1/video-studio/generate/
- Poll: GET /api/v1/video-studio/status/{job_id}/
- History: GET /api/v1/video-studio/history/
4) Tool flows (video)
- Street interview: POST /api/v1/video-studio/tools/street-interview/generate/
- UGC ad quick: POST /api/v1/video-studio/tools/ugc-ad-quick/generate/
- Video remix: POST /api/v1/video-studio/tools/video-remix/generate/
5) Guardrails
- Always discover models first and validate requested slug.
- Retry 429/5xx with backoff.
- Stop immediately on 401/403 and request a valid key.
- On 402, report insufficient credits clearly.
البنية الموصى بها لتطبيقات العلامة البيضاء
- احتفظ بمفاتيح UlazAI من جانب الخادم فقط. لا تكشف أبدًا عن المفاتيح الأولية في كود الواجهة الأمامية العامة.
- قم بإنشاء محول خلفي واحد بتنسيق طلب واحد لتطبيقك الخاص.
- قم بتعيين أسماء النماذج الداخلية الخاصة بك إلى معرفات نماذج UlazAI من نقاط نهاية الاكتشاف.
- استمر
generation_idوjob_idلذا فإن الاقتراع وإعادة المحاولة غير فعالين. - استجابات قدرة نموذج ذاكرة التخزين المؤقت لمدة 5-15 دقيقة لتقليل حركة البيانات التعريفية.