Hướng Dẫn Chi Tiết: Tạo Ảnh ➔ Tạo Video (R2V & I2V)
⚡ Tự động Chuyển Tài Khoản & Re-upload (Cross-Account Auto Re-upload): Bạn có thể tạo ảnh ở bất kỳ tài khoản nào (hoặc dùng URL ảnh từ nguồn bên ngoài). Khi gửi tạo Video sang Tài khoản Ultra / Video, hệ thống sẽ tự động tra cứu URL ảnh ➔ Tải về ➔ Re-upload ngầm sang tài khoản Ultra. Giúp tạo video 100% thành công không bị lỗi HTTP 404 (Media ID Not Found) do khác tài khoản.
📊 Phân Biệt 2 Kiểu Tạo Video Từ Ảnh qua API:
1. Kiểu I2V (Image-to-Video — Ảnh đầu/khung hình ➔ Video): Dùng khi muốn biến 1 bức ảnh tĩnh thành khung hình bắt đầu của Video. Truyền tham số start_media_id (hoặc start_media_path).
2. Kiểu R2V (Reference-to-Video — Ảnh tham chiếu phong cách ➔ Video): Dùng khi muốn giữ phong cách/nhân vật từ 1 hoặc nhiều bức ảnh mẫu. Truyền mảng media_ids (hoặc ref_image_urls).
GUIDE Flow hoàn chỉnh & Hướng dẫn I2V vs R2V Bấm để xem chi tiết

Bước 0: Lấy Danh Sách Tài Khoản (Tùy chọn)

Bên thứ 3 có thể lấy danh sách tài khoản nếu muốn chỉ định tài khoản cụ thể. Nếu bỏ trống account_id, hệ thống tự động xoay vòng tài khoản active.

Gửi request GET /api/accounts hoặc GET /api/user/accounts.

Bước 1: Tạo Ảnh Hoặc Upload Ảnh

Gọi POST /api/generate để tạo ảnh từ prompt, hoặc POST /api/upload_image để upload ảnh từ máy. API trả về media_id (UUID) và url.

// Response từ POST /api/generate:
{
  "success": true,
  "images": [
    {
      "index": 1,
      "url": "https://flow-content.google/image/b42c6ab5-...",
      "media_id": "b42c6ab5-982f-41bd-8c84-b35bfe2a4a5f"  // ← UUID ảnh vừa tạo
    }
  ],
  "account_id": "user_AccountA_101"
}

Bước 2A: Gọi API kiểu I2V (Image-to-Video — Ảnh làm khung hình đầu ở Tài Khoản Video/ULTRA)

Truyền start_media_id lấy từ Bước 1. Bạn có thể chọn bất kỳ **Tài Khoản Video / ULTRA** nào ở account_id. Hệ thống sẽ tự động tìm URL ảnh và re-upload ngầm sang tài khoản Video đó mà không bị lỗi 404.

POST /api/generate_video
{
  "prompt": "cô gái mỉm cười, tóc bay nhẹ trong gió, camera slow motion",
  "aspect_ratio": "VIDEO_ASPECT_RATIO_LANDSCAPE",
  "start_media_id": "b42c6ab5-982f-41bd-8c84-b35bfe2a4a5f", // ← UUID ảnh tạo từ Tài khoản A
  "model": "veo_3_1_i2v_lite_low_priority",                 // ← Model I2V
  "use_own_account": true,
  "account_id": "user_AccountB_ULTRA_202"                  // ← BẤT KỲ TÀI KHOẢN VIDEO/ULTRA NÀO! (Server tự re-upload)
}

Bước 2B: Gọi API kiểu R2V (Reference-to-Video — Ảnh làm tham chiếu phong cách)

Truyền mảng media_ids (hoặc ref_image_urls). Tương tự, bạn có thể truyền bất kỳ account_id tài khoản Video/ULTRA nào.

POST /api/generate_video
{
  "prompt": "nhân vật đi dạo trên phố ban đêm, ánh đèn neon",
  "aspect_ratio": "VIDEO_ASPECT_RATIO_LANDSCAPE",
  "media_ids": ["b42c6ab5-982f-41bd-8c84-b35bfe2a4a5f"],       // ← Mảng UUID ảnh tạo từ Tài khoản A
  "model": "veo_3_1_r2v_lite_low_priority",                 // ← Model R2V
  "use_own_account": true,
  "account_id": "user_AccountB_ULTRA_202"                  // ← TÀI KHOẢN VIDEO/ULTRA BẤT KỲ
}

Bước 2C: Gọi API truyền URL trực tiếp (Dành cho ảnh bên ngoài)

Nếu bạn đã có sẵn URL ảnh công khai (từ trang web khác hoặc server riêng), hãy truyền trực tiếp vào mảng ref_image_urls. Server sẽ tự động download và upload sang tài khoản video hiện tại.

POST /api/generate_video
{
  "prompt": "chú mèo chạy trên bãi cỏ, cinematic",
  "aspect_ratio": "VIDEO_ASPECT_RATIO_LANDSCAPE",
  "ref_image_urls": ["https://example.com/sample_cat.jpg"] // ← URL ảnh bất kỳ
}
Lưu ý kỹ thuật quan trọng:
start_media_id ➔ Kích hoạt chế độ **I2V** (Image-to-Video).
media_ids ➔ Kích hoạt chế độ **R2V** (Reference-to-Video).
ref_image_urls ➔ Dùng khi ảnh đến từ URL bên ngoài hoặc muốn hệ thống re-upload tự động.
• Khi chuyển tài khoản giữa Tạo Ảnh và Tạo Video, hệ thống tự động tìm URL trong DB để re-upload ➔ **Tuyệt đối không bị lỗi HTTP 404**.

Ví dụ Code Python Hoàn Chỉnh — Chuyển Tài Khoản Tự Động (Tạo ảnh Tk A ➔ Tạo Video Tk B/ULTRA)

import requests, time
 
BASE = "http://YOUR_SERVER:5000"
IMAGE_ACCOUNT = "user_AccountA_101"         # Tài khoản A dùng để tạo ảnh
ULTRA_VIDEO_ACCOUNT = "user_AccountB_202"    # Tài khoản B (ULTRA) dùng để tạo video
 
# ===== Bước 1: Tạo ảnh bằng Tài khoản A =====
print("🎨 Đang tạo ảnh bằng Tài khoản A...")
img_resp = requests.post(f"{BASE}/api/generate", json={
    "prompt": "quả táo đỏ trên bàn gỗ, manga style",
    "count": 1,
    "aspect_ratio": "IMAGE_ASPECT_RATIO_LANDSCAPE",
    "model": "GEM_PIX_2",
    "use_own_account": True,           # Sử dụng tài khoản riêng
    "account_id": IMAGE_ACCOUNT,       # Chỉ định Tài khoản A
    "for_video": True
}, timeout=120).json()
 
if not img_resp["success"]:
    print(f"❌ Lỗi tạo ảnh: {img_resp.get('error')}")
    exit()
 
image = img_resp["images"][0]
media_id_a = image["media_id"]        # UUID từ Tài khoản A
print(f"✅ Ảnh tạo từ Tk A thành công:")
print(f"   URL: {image['url']}")
print(f"   Media ID A: {media_id_a}")
 
# ===== Bước 2: Tạo video bằng Tài khoản B (ULTRA) từ Media ID của Tài khoản A =====
# (Server tự động tra cứu URL ➔ Download ➔ Re-upload ngầm sang Tk B ➔ 0 lỗi 404!)
print("\n🎬 Đang tạo video bằng Tài khoản B (ULTRA)...")
vid_resp = requests.post(f"{BASE}/api/generate_video", json={
    "prompt": "quả táo lăn trên bàn gỗ, camera slow motion",
    "start_media_id": media_id_a,        # Pass Media ID từ Tài khoản A (Kiểu I2V)
    "use_own_account": True,
    "account_id": ULTRA_VIDEO_ACCOUNT,   # Tài khoản B khác biệt hoàn toàn!
    "aspect_ratio": "VIDEO_ASPECT_RATIO_LANDSCAPE"
}, timeout=600).json()  # 10 phút timeout
 
if vid_resp["success"]:
    for v in vid_resp["videos"]:
        print(f"🎉 SUCCESS! Video tạo từ Tk B: {v['url']}")
else:
    print(f"❌ Lỗi tạo video: {vid_resp.get('error')}")

Chạy Thử Trực Tiếp: Tạo Ảnh Tk A ➔ Tạo Video Tk B (ULTRA)

LIVE INTERACTIVE TEST

Bạn có thể chọn 2 tài khoản khác nhau bên dưới (Tài khoản A tạo ảnh & Tài khoản B ULTRA tạo video) để kiểm tra tính năng Re-upload ngầm tự động ngay trên trang này.

BƯỚC 1 🎨 Tạo Ảnh trên Tài Khoản A
BƯỚC 2 🎬 Tạo Video từ Ảnh trên Tài Khoản B (ULTRA)
Xác Thực Đăng Nhập (Authentication)
Cơ chế xác thực mặc định: API sử dụng cơ chế session cookie của Flask. Khi gọi API từ ứng dụng ngoài, bạn cần thực hiện đăng nhập qua POST /api/auth/login để lấy cookie, sau đó đính kèm cookie session vào header trong các request tiếp theo.
POST /api/auth/login Đăng nhập tài khoản

Gửi tài khoản mật khẩu để lấy session cookie.

Parameters (JSON)

FieldTypeMô tả
username*stringTên đăng nhập
password*stringMật khẩu
is_extensionboolĐặt false (mặc định)

Response Headers

Set-Cookie: session=ey...; Path=/; HttpOnly; SameSite=Lax

Kiểm Thử Đăng Nhập

🔓 Tắt Xác Thực Đăng Nhập & Gọi API Tự Do (No-Auth Mode):
Bạn có thể kích hoạt chế độ gọi API không cần đăng nhập bằng 1 trong 2 cách:
Cách 1 (Giao diện Admin): Vào trang Admin UI ➔ phần Cấu Hình Admin & CSDL SQLite ➔ Tích chọn "Tắt Xác Thực Đăng Nhập & API". Hệ thống sẽ lưu trạng thái vào CSDL SQLite (`disable_auth_mode = true`).
Cách 2 (File Cấu hình .env): Đặt REQUIRE_API_AUTH=false trong file .env ở thư mục gốc.

⚡ Cơ chế Đa Luồng Đa Tài Khoản khi Tắt Xác Thực:
- Khi bật No-Auth Mode, **mọi API** (Tạo Ảnh `/api/generate`, Tạo Video `/api/generate_video`, Upload Ảnh `/api/upload_image`, Refresh Link `/api/refresh_media`, Hàng Chờ Queue...) đều cho phép các ứng dụng/script bên thứ ba gọi trực tiếp 100% không cần truyền Cookie hay Session.
- Server tự động gán session Admin mặc định và **luân chuyển luồng đa tài khoản (AccountManager)** song song dựa theo dung lượng `max_slots` và `max_video_slots` của từng tài khoản.
- Tất cả kịch bản, lịch sử kết quả công việc, và nhật ký đều được tự động lưu trữ và đồng bộ tức thì vào **CSDL SQLite (`database.db`)**.
Xác Thực API Key Cho Bên Thứ Ba (API Key Manager)
🔑 Tích hợp API Key cho thương mại hóa hoặc App bên thứ ba:
Admin có thể tạo các API Key dạng veo_live_abc123... trên Admin Panel kèm theo Hạn ngạch Quota (Ngày/Tháng). Ứng dụng bên thứ ba không cần gọi API Đăng nhập lấy cookie mà chỉ cần gửi Header:
Header 1: X-API-Key: veo_live_xxx
Header 2: Authorization: Bearer veo_live_xxx
HEADER X-API-Key: veo_live_a1b2c3d4... Đính kèm Header trong mọi request API

Ví dụ cURL với API Key

curl -X POST "http://127.0.0.1:5000/api/generate_video" \
  -H "X-API-Key: veo_live_a1b2c3d4e5f67890..." \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "chú mèo nhảy múa trong mưa, 4k",
    "aspect_ratio": "VIDEO_ASPECT_RATIO_LANDSCAPE"
  }'

Ví dụ Code Python với API Key

import requests

API_KEY = "veo_live_a1b2c3d4e5f67890..."
headers = {
    "X-API-Key": API_KEY,
    "Content-Type": "application/json"
}

resp = requests.post("http://127.0.0.1:5000/api/generate_video", json={
    "prompt": "cô gái mặc áo dài truyền thống Việt Nam",
    "aspect_ratio": "VIDEO_ASPECT_RATIO_PORTRAIT"
}, headers=headers).json()

print(resp)
Webhook Callback Thông Báo Cho Bên Thứ Ba
🔔 Cơ chế Webhook Callback Không Cần Chờ (Async Non-Blocking):
Khi ứng dụng bên thứ ba gửi yêu cầu tạo video/ảnh, ứng dụng có thể đính kèm tham số webhook_url (ví dụ: https://app-cua-khach.com/api/callback).
Khi server render xong video/ảnh, server sẽ tự động gửi một HTTP POST request chứa toàn bộ kết quả về webhook_url đó. Bên thứ 3 không cần giữ kết nối chờ đợi.
POST CALLBACK https://your-domain.com/api/callback Cấu trúc Webhook Payload & Signature

Tham Số Khởi Tạo Request

Trong request POST /api/generate_video hoặc POST /api/generate, bổ sung 2 trường:

FieldTypeMô tả
webhook_urlstringURL Server bên thứ ba nhận callback kết quả (ví dụ: https://app.domain.com/webhook)
webhook_secretstring (optional)Mã bí mật dùng để kiểm tra chữ ký xác thực HMAC-SHA256 trong Header X-Webhook-Signature

Cấu Trúc Payload Server Gửi Trả Về Webhook URL

{
  "success": true,
  "videos": [
    {
      "url": "http://127.0.0.1:5000/outputs/video_abc123.mp4",
      "media_id": "video_abc123",
      "index": 1,
      "name": "operations/eb4a58ba-..."
    }
  ],
  "total_generated": 1,
  "prompt": "chú mèo nhảy múa trong mưa, 4k",
  "account_id": "user_AccountA_101"
}

Ví dụ Code Server Bên Thứ Ba (Node.js / Express) Kiểm Tra Chữ Ký Webhook Signature

const express = require('express');
const crypto = require('crypto');
const app = express();

app.use(express.json());

const WEBHOOK_SECRET = "my_webhook_secret_key";

app.post('/api/callback', (req, res) => {
    const signature = req.headers['x-webhook-signature'];
    
    if (WEBHOOK_SECRET && signature) {
        const expectedSig = crypto
            .createHmac('sha256', WEBHOOK_SECRET)
            .update(JSON.stringify(req.body))
            .digest('hex');
            
        if (signature !== expectedSig) {
            console.error("❌ Webhook Signature Invalid!");
            return res.status(401).send("Invalid signature");
        }
    }

    console.log("🎉 Nhận kết quả Video thành công từ Veo Server:", req.body);
    // Xử lý lưu database hoặc gửi thông báo cho client của bạn ở đây...
    
    res.status(200).send("OK");
});

app.listen(3000, () => console.log('Webhook Listener running on port 3000'));
Tạo Ảnh (Generate Image)
POST /api/generate Tạo ảnh từ prompt — Synchronous ~15-20s

Gửi prompt tạo ảnh. API trả về URL ảnh khi hoàn thành (đồng bộ). Hỗ trợ ảnh tham chiếu bằng media_ids.

Parameters

FieldTypeMô tả
prompt*stringNội dung mô tả ảnh muốn tạo
countintSố ảnh (mặc định: 1, tối đa: 4)
aspect_ratiostringIMAGE_ASPECT_RATIO_LANDSCAPE (16:9), ..._PORTRAIT (9:16), ..._SQUARE (1:1)
modelstringGEM_PIX_2 (Nano Banana Pro), NARWHAL (Nano Banana 2) hoặc HARBOR_SEAL (Nano Banana 2 Lite)
for_videoboolƯu tiên tài khoản "both" (hỗ trợ cả ảnh + video) để dùng cho I2V
media_idsarrayMảng Media ID ảnh tham chiếu (cho ảnh→ảnh, tối đa 10 ảnh)
account_idstringTài khoản đã upload ảnh tham chiếu (bắt buộc nếu có media_ids)

Response

{
  "success": true,
  "images": [
    {
      "index": 1,
      "url": "https://flow-content.google/image/b42c6ab5-...",
      "media_id": "b42c6ab5-982f-41bd-8c84-b35bfe2a4a5f"  // UUID
    }
  ],
  "total_generated": 1,
  "account_id": "Maimaicodn",    // Tài khoản đã tạo
  "project_id": "0ffa648a-...",  // Project ID
  "acc_type": "both"             // Loại tài khoản
}
// → Lưu media_id + account_id → dùng cho /api/generate_video

Kiểm Thử Trực Tiếp

Upload Ảnh (Get Media ID)
POST /api/upload_image Upload ảnh → nhận media_id cho I2V

Upload ảnh lên Google qua multipart/form-data. Trả về media_id dùng làm ảnh tham chiếu hoặc khung hình đầu cho Video (I2V).

Request (Form-Data)

FieldTypeMô tả
file*FileFile ảnh (PNG, JPG, WEBP)

cURL

curl -X POST http://127.0.0.1:5000/api/upload_image \
  -F "file=@/path/to/image.jpg"

Response

{
  "success": true,
  "media_id": "projects/.../media/123456789"
}

Kiểm Thử Upload

Click hoặc kéo thả ảnh vào đây

Tạo Video (Text-to-Video & Image-to-Video)
Video mất 2-5 phút. API giữ kết nối HTTP mở. Client nên set timeout ≥ 10 phút.
POST /api/generate_video T2V + I2V — Async ~2-5 phút

Tạo video qua Google Veo. Text-to-Video (T2V): chỉ cần prompt. Image-to-Video (I2V / R2V): truyền ref_image_urls (URL ảnh) hoặc start_media_path (file ảnh local).

⚡ Tự động Re-upload ngầm sang Tài khoản Ultra: Bạn có thể dùng ảnh tạo từ bất kỳ đâu (Tài khoản riêng, Tài khoản chỉ tạo ảnh, hoặc URL ngoài). Server sẽ tự động download và re-upload ngầm ảnh đó lên Tài khoản Ultra / Video để sinh video thành công mà không bao giờ bị lỗi 400 / 500!

Parameters

FieldTypeMô tả
prompt*stringMô tả nội dung video muốn tạo
start_media_idstring(I2V — Ảnh đầu ➔ Video) UUID của ảnh muốn dùng làm khung hình bắt đầu cho video.
media_idsarray(R2V — Ảnh tham chiếu ➔ Video) Mảng UUID ảnh tham chiếu phong cách/nhân vật (tối đa 3 ảnh).
ref_image_urlsarray(I2V/R2V) Mảng URL ảnh ngoài. Server tự động download & re-upload sang tài khoản Video hiện tại.
start_media_pathstring(I2V) Đường dẫn file ảnh local trên máy server.
aspect_ratiostringVIDEO_ASPECT_RATIO_LANDSCAPE (16:9), ..._PORTRAIT (9:16), ..._SQUARE (1:1)
modelstringTự động nhận diện: veo_3_1_i2v_lite_low_priority (cho I2V), veo_3_1_r2v_lite_low_priority (cho R2V), hoặc veo_3_1_t2v_lite_low_priority (cho T2V)
account_idstring(Tùy chọn) ID tài khoản chỉ định. Nếu khác tài khoản tạo ảnh, hệ thống tự động re-upload ngầm.
countintSố video muốn tạo (mặc định: 1)

Ví dụ Python — Tạo ảnh bằng Nano Model rồi tạo video bằng Tài khoản Ultra

import requests

BASE = "http://YOUR_SERVER:5000"

# Bước 1: Tạo ảnh bằng bất kỳ Model Nano nào (Nano Pro, Nano 2, Nano 2 Lite)
img_res = requests.post(f"{BASE}/api/generate", json={
    "prompt": "một chú mèo dễ thương",
    "model": "GEM_PIX_2"  # GEM_PIX_2 (Nano Pro), NARWHAL (Nano 2) hoặc HARBOR_SEAL (Nano 2 Lite)
}, timeout=120).json()

img_url = img_res["images"][0]["url"]

# Bước 2: Tạo video bằng Tài khoản Ultra (Server tự động re-upload ngầm sang Ultra Account)
vid_res = requests.post(f"{BASE}/api/generate_video", json={
    "prompt": "chú mèo di chuyển linh hoạt, camera xoay quanh",
    "model": "veo_3_1_r2v_lite_low_priority",
    "ref_image_urls": [img_url]  # Truyền URL ảnh → Server tự động re-upload sang Ultra Account!
}, timeout=600).json()

print("Link Video Ultra:", vid_res["videos"][0]["url"])

Kiểm Thử Tạo Video

Làm Mới Link Media (Refresh Link)
Lưu ý: Link ảnh và video trả về từ Google thường hết hạn sau 2-4 giờ. API này giúp lấy lại link mới nhất thông qua media_idaccount_id mà không cần render lại.
POST /api/refresh_media_url Lấy URL mới cho ảnh/video đã hết hạn

Hồi sinh link media bằng cách lấy redirect URL mới từ Google.

Parameters

FieldTypeMô tả
media_id*stringUUID của media (ảnh hoặc video) cần refresh
account_id*stringTài khoản sở hữu media_id này
is_videobooltrue nếu là video, false nếu là ảnh
project_idstring(Tùy chọn) Project ID liên kết với media

Kiểm Thử Trực Tiếp

Server Status
GET /api/status Kiểm tra trạng thái server

Trả về trạng thái hoạt động, số tài khoản, hàng chờ.

Quản Lý Tài Khoản
GET /api/accounts Danh sách tài khoản

Lấy danh sách tất cả tài khoản đã đăng ký và trạng thái hoạt động.

POST /api/accounts Thêm/cập nhật tài khoản bằng Cookies

Request Body

{
  "id": "email@gmail.com",
  "cookies": [
    {"name":"__Secure-1PSID","value":"...","domain":".google.com"},
    {"name":"__Secure-1PSIDTS","value":"..."}
  ]
}
Hàng Chờ (Queue)
GET /api/queue Danh sách hàng chờ (List Queue)

Lấy danh sách kịch bản đang chờ chạy, đang chạy hoặc tạm dừng.

POST /api/queue/add Thêm kịch bản vào hàng chờ (Add to Queue)

Thêm một hoặc nhiều tác vụ kịch bản vào cuối hàng chờ để xử lý tuần tự.

Parameters

FieldTypeMô tả
item hoặc itemsobject / arrayNội dung tác vụ kịch bản
POST /api/queue/action Điều khiển hàng chờ (Start/Pause/Clear)

Thay đổi trạng thái hoạt động của hàng chờ (bắt đầu chạy, tạm dừng, xóa hàng chờ, v.v.).

Parameters

FieldTypeMô tả
action*stringGiá trị có thể: start, pause, clear, clear_errors, retry_errors
PUT/DEL /api/queue/<index> Cập nhật hoặc xóa tác vụ theo Index

Sử dụng PUT để cập nhật tác vụ tại vị trí index hoặc DELETE để xóa tác vụ đó khỏi hàng chờ.

GET /api/queue/results Lấy kết quả hàng chờ

Xem danh sách kết quả các tác vụ đã hoàn thành hoặc thất bại.

Analytics Dashboard API
GET /api/analytics/dashboard Báo cáo thống kê hiệu năng & hoạt động

Trả về thông số tổng quan hệ thống: Số lượng tạo ảnh/video, tỉ lệ thành công, tài khoản active và lượng tài nguyên đã sử dụng.

Quản Lý CSDL SQLite (`database.db`)
Bạn có thể thao tác trực tiếp qua giao diện UI tại /sqlite_admin.html hoặc gọi các REST API bên dưới.
GET /api/admin/db/tables Lấy danh sách các bảng & số bản ghi

Trả về danh sách tất cả các bảng trong CSDL SQLite và số lượng dòng hiện có.

GET /api/admin/db/download Tải về file database.db nguyên bản

Tải trực tiếp file CSDL database.db về máy tính để sao lưu hoặc kiểm tra offline.

POST /api/admin/db/vacuum Tối ưu hóa & nén dung lượng CSDL (VACUUM)

Dọn dẹp các ô nhớ trống và giải phóng dung lượng đĩa cho file database.db.

Cấu Hình System Admin & Bypass Auth
GET POST /api/admin/auth-settings Đọc/Thay đổi cấu hình Tắt Xác Thực (No-Auth Mode)

Đọc hoặc thay đổi trạng thái disable_auth_mode (Cho phép gọi API không cần Cookie/Xác thực).

POST Request Body

{ "disable_auth_mode": true }
Logs Hệ Thống
GET /api/logs 200 dòng log gần nhất

Lấy logs realtime để hiển thị trạng thái trên ứng dụng của bạn.