mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 17:30:23 +08:00
Merge remote-tracking branch 'upstream/aether-rust-pioneer' into codex/user-groups-default-permissions
This commit is contained in:
@@ -1,39 +1,78 @@
|
||||
import apiClient from './client'
|
||||
|
||||
// 异步任务状态
|
||||
export type AsyncTaskStatus = 'pending' | 'submitted' | 'queued' | 'processing' | 'completed' | 'failed' | 'cancelled'
|
||||
export type AsyncTaskStatus =
|
||||
| 'queued'
|
||||
| 'running'
|
||||
| 'retrying'
|
||||
| 'succeeded'
|
||||
| 'failed'
|
||||
| 'cancelled'
|
||||
| 'skipped'
|
||||
| 'pending'
|
||||
| 'submitted'
|
||||
| 'processing'
|
||||
| 'completed'
|
||||
|
||||
// 异步任务类型
|
||||
export type AsyncTaskType = 'video'
|
||||
export type AsyncTaskKind = 'scheduled' | 'daemon' | 'on_demand' | 'fire_and_forget'
|
||||
export type AsyncTaskType = AsyncTaskKind | 'video'
|
||||
|
||||
// 异步任务列表项
|
||||
export interface AsyncTaskItem {
|
||||
id: string
|
||||
external_task_id: string
|
||||
user_id: string
|
||||
username: string
|
||||
task_type: AsyncTaskType
|
||||
model: string
|
||||
prompt: string
|
||||
status: AsyncTaskStatus
|
||||
progress_percent: number
|
||||
progress_message: string | null
|
||||
provider_id: string
|
||||
provider_name: string
|
||||
duration_seconds: number
|
||||
resolution: string
|
||||
aspect_ratio: string
|
||||
video_url: string | null
|
||||
error_code: string | null
|
||||
error_message: string | null
|
||||
poll_count: number
|
||||
max_poll_count: number
|
||||
created_at: string
|
||||
completed_at: string | null
|
||||
submitted_at: string | null
|
||||
export interface AsyncTaskDefinition {
|
||||
task_key: string
|
||||
kind: AsyncTaskKind
|
||||
trigger: string
|
||||
max_attempts: number
|
||||
singleton: boolean
|
||||
persist_history: boolean
|
||||
}
|
||||
|
||||
export interface AsyncTaskItem {
|
||||
id: string
|
||||
task_key?: string
|
||||
kind?: AsyncTaskKind
|
||||
trigger?: string
|
||||
task_type?: AsyncTaskType
|
||||
external_task_id?: string
|
||||
user_id?: string
|
||||
username?: string
|
||||
model?: string
|
||||
prompt?: string
|
||||
status: AsyncTaskStatus
|
||||
attempt?: number
|
||||
max_attempts?: number
|
||||
owner_instance?: string | null
|
||||
progress_percent: number
|
||||
progress_message: string | null
|
||||
payload?: unknown
|
||||
result?: unknown
|
||||
error_message: string | null
|
||||
cancel_requested?: boolean
|
||||
created_by?: string | null
|
||||
provider_id?: string
|
||||
provider_name?: string
|
||||
duration_seconds?: number
|
||||
resolution?: string
|
||||
aspect_ratio?: string
|
||||
video_url?: string | null
|
||||
error_code?: string | null
|
||||
poll_count?: number
|
||||
max_poll_count?: number
|
||||
created_at: string
|
||||
started_at?: string | null
|
||||
updated_at?: string | null
|
||||
finished_at?: string | null
|
||||
completed_at?: string | null
|
||||
submitted_at?: string | null
|
||||
}
|
||||
|
||||
export interface AsyncTaskEvent {
|
||||
id: string
|
||||
run_id: string
|
||||
event_type: string
|
||||
message: string
|
||||
payload: unknown
|
||||
created_at: string
|
||||
}
|
||||
|
||||
// 候选 Key 信息
|
||||
export interface CandidateKeyInfo {
|
||||
index: number
|
||||
provider_id: string
|
||||
@@ -47,7 +86,6 @@ export interface CandidateKeyInfo {
|
||||
selected?: boolean
|
||||
}
|
||||
|
||||
// 请求元数据
|
||||
export interface AsyncTaskRequestMetadata {
|
||||
candidate_keys: CandidateKeyInfo[]
|
||||
selected_key_id: string
|
||||
@@ -56,111 +94,118 @@ export interface AsyncTaskRequestMetadata {
|
||||
user_agent: string
|
||||
request_id: string
|
||||
request_headers?: Record<string, string>
|
||||
poll_raw_response?: unknown // 轮询完成时的原始响应
|
||||
billing_snapshot?: unknown // 计费快照
|
||||
poll_raw_response?: unknown
|
||||
billing_snapshot?: unknown
|
||||
}
|
||||
|
||||
// 异步任务详情
|
||||
export interface AsyncTaskDetail extends AsyncTaskItem {
|
||||
api_key_id: string
|
||||
endpoint_id: string
|
||||
key_id: string
|
||||
client_api_format: string
|
||||
provider_api_format: string
|
||||
format_converted: boolean
|
||||
original_request_body: unknown
|
||||
converted_request_body: unknown
|
||||
size: string | null
|
||||
video_urls: string[] | null
|
||||
thumbnail_url: string | null
|
||||
video_size_bytes: number | null
|
||||
video_duration_seconds: number | null // 实际视频时长(秒)
|
||||
video_expires_at: string | null
|
||||
stored_video_path: string | null
|
||||
storage_provider: string | null
|
||||
retry_count: number
|
||||
max_retries: number
|
||||
poll_interval_seconds: number
|
||||
next_poll_at: string | null
|
||||
updated_at: string | null
|
||||
endpoint: {
|
||||
api_key_id?: string
|
||||
endpoint_id?: string
|
||||
key_id?: string
|
||||
client_api_format?: string
|
||||
provider_api_format?: string
|
||||
format_converted?: boolean
|
||||
original_request_body?: unknown
|
||||
converted_request_body?: unknown
|
||||
size?: string | null
|
||||
video_urls?: string[] | null
|
||||
thumbnail_url?: string | null
|
||||
video_size_bytes?: number | null
|
||||
video_duration_seconds?: number | null
|
||||
video_expires_at?: string | null
|
||||
stored_video_path?: string | null
|
||||
storage_provider?: string | null
|
||||
retry_count?: number
|
||||
max_retries?: number
|
||||
poll_interval_seconds?: number
|
||||
next_poll_at?: string | null
|
||||
endpoint?: {
|
||||
id: string
|
||||
base_url: string
|
||||
api_format: string
|
||||
} | null
|
||||
request_metadata: AsyncTaskRequestMetadata | null
|
||||
request_metadata?: AsyncTaskRequestMetadata | null
|
||||
}
|
||||
|
||||
// 异步任务列表响应
|
||||
export interface AsyncTaskListResponse {
|
||||
items: AsyncTaskItem[]
|
||||
total: number
|
||||
page: number
|
||||
page_size: number
|
||||
pages: number
|
||||
definitions?: AsyncTaskDefinition[]
|
||||
}
|
||||
|
||||
// 异步任务统计响应
|
||||
export interface AsyncTaskStatsResponse {
|
||||
total: number
|
||||
by_status: Record<AsyncTaskStatus, number>
|
||||
by_model: Record<string, number>
|
||||
today_count: number
|
||||
active_users?: number // 仅管理员
|
||||
processing_count?: number // 仅管理员
|
||||
running_count?: number
|
||||
registered_tasks?: number
|
||||
by_status: Partial<Record<AsyncTaskStatus, number>>
|
||||
by_kind?: Partial<Record<AsyncTaskKind, number>>
|
||||
by_model?: Record<string, number>
|
||||
today_count?: number
|
||||
active_users?: number
|
||||
processing_count?: number
|
||||
}
|
||||
|
||||
// 异步任务查询参数
|
||||
export interface AsyncTaskQueryParams {
|
||||
status?: AsyncTaskStatus
|
||||
kind?: AsyncTaskKind
|
||||
task_type?: AsyncTaskType
|
||||
task_key?: string
|
||||
trigger?: string
|
||||
user_id?: string
|
||||
model?: string
|
||||
page?: number
|
||||
page_size?: number
|
||||
}
|
||||
|
||||
function normalizeStatus(status: AsyncTaskStatus): AsyncTaskStatus {
|
||||
if (status === 'processing') return 'running'
|
||||
if (status === 'submitted' || status === 'pending') return 'queued'
|
||||
if (status === 'completed') return 'succeeded'
|
||||
return status
|
||||
}
|
||||
|
||||
export const asyncTasksApi = {
|
||||
/**
|
||||
* 获取异步任务列表
|
||||
*/
|
||||
async list(params: AsyncTaskQueryParams = {}): Promise<AsyncTaskListResponse> {
|
||||
const searchParams = new URLSearchParams()
|
||||
if (params.status) searchParams.append('status', params.status)
|
||||
if (params.task_type) searchParams.append('task_type', params.task_type)
|
||||
if (params.user_id) searchParams.append('user_id', params.user_id)
|
||||
if (params.model) searchParams.append('model', params.model)
|
||||
if (params.status) searchParams.append('status', normalizeStatus(params.status))
|
||||
if (params.kind) searchParams.append('kind', params.kind)
|
||||
if (params.task_type && params.task_type !== 'video') searchParams.append('kind', params.task_type)
|
||||
if (params.task_key) searchParams.append('task_key', params.task_key)
|
||||
if (params.trigger) searchParams.append('trigger', params.trigger)
|
||||
if (params.page) searchParams.append('page', params.page.toString())
|
||||
if (params.page_size) searchParams.append('page_size', params.page_size.toString())
|
||||
|
||||
const query = searchParams.toString()
|
||||
// 后端 API 路径保持不变,前端抽象为异步任务
|
||||
const url = query ? `/api/admin/video-tasks?${query}` : '/api/admin/video-tasks'
|
||||
const url = query ? `/api/admin/tasks?${query}` : '/api/admin/tasks'
|
||||
const response = await apiClient.get(url)
|
||||
return response.data
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取异步任务统计
|
||||
*/
|
||||
async getStats(): Promise<AsyncTaskStatsResponse> {
|
||||
const response = await apiClient.get('/api/admin/video-tasks/stats')
|
||||
const response = await apiClient.get('/api/admin/tasks/stats')
|
||||
return response.data
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取异步任务详情
|
||||
*/
|
||||
async getDetail(taskId: string): Promise<AsyncTaskDetail> {
|
||||
const response = await apiClient.get(`/api/admin/video-tasks/${taskId}`)
|
||||
const response = await apiClient.get(`/api/admin/tasks/${taskId}`)
|
||||
return response.data
|
||||
},
|
||||
|
||||
async getEvents(taskId: string): Promise<{ items: AsyncTaskEvent[] }> {
|
||||
const response = await apiClient.get(`/api/admin/tasks/${taskId}/events`)
|
||||
return response.data
|
||||
},
|
||||
|
||||
/**
|
||||
* 取消异步任务
|
||||
*/
|
||||
async cancel(taskId: string): Promise<{ id: string; status: string; message: string }> {
|
||||
const response = await apiClient.post(`/api/admin/video-tasks/${taskId}/cancel`)
|
||||
const response = await apiClient.post(`/api/admin/tasks/${taskId}/cancel`)
|
||||
return response.data
|
||||
},
|
||||
|
||||
async trigger(taskKey: string, payload: Record<string, unknown> = {}): Promise<{ run_id: string; status: string }> {
|
||||
const response = await apiClient.post(`/api/admin/tasks/${taskKey}/trigger`, payload)
|
||||
return response.data
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user