feat(web): 完善 API 文档与异步任务说明
This commit is contained in:
parent
2d6c16fec0
commit
cc3bbeccc2
@ -1,8 +1,10 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import {
|
||||
createResponse,
|
||||
deleteOIDCBrowserSession,
|
||||
GatewayApiError,
|
||||
gatewayErrorMessage,
|
||||
getAPITask,
|
||||
getCurrentUser,
|
||||
getOpsManagementSkillMetadata,
|
||||
OIDC_BROWSER_SESSION_CREDENTIAL,
|
||||
@ -96,3 +98,39 @@ describe('Public Agent resources', () => {
|
||||
expect(new Headers(init.headers).has('Authorization')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('API documentation runner transports', () => {
|
||||
afterEach(() => {
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
it('runs Responses against the public OpenAI-compatible endpoint', async () => {
|
||||
const fetchMock = vi.fn().mockResolvedValue(new Response(JSON.stringify({ id: 'resp-test', object: 'response' }), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}));
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
|
||||
await createResponse('sk-test', { model: 'gpt-test', input: 'hello', store: true, stream: false });
|
||||
|
||||
const [url, init] = fetchMock.mock.calls[0] as [string, RequestInit];
|
||||
expect(url).toContain('/v1/responses');
|
||||
expect(init.method).toBe('POST');
|
||||
expect(new Headers(init.headers).get('Authorization')).toBe('Bearer sk-test');
|
||||
expect(JSON.parse(String(init.body))).toMatchObject({ model: 'gpt-test', input: 'hello', store: true, stream: false });
|
||||
});
|
||||
|
||||
it('retrieves a task from the documented API path', async () => {
|
||||
const fetchMock = vi.fn().mockResolvedValue(new Response(JSON.stringify({ id: 'task-123', status: 'running' }), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}));
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
|
||||
await getAPITask('sk-test', 'task-123');
|
||||
|
||||
const [url, init] = fetchMock.mock.calls[0] as [string, RequestInit];
|
||||
expect(url).toContain('/api/v1/tasks/task-123');
|
||||
expect(init.method).toBe('GET');
|
||||
});
|
||||
});
|
||||
|
||||
@ -605,6 +605,26 @@ export async function createCompatibleChatCompletion(
|
||||
});
|
||||
}
|
||||
|
||||
export async function createResponse(
|
||||
token: string,
|
||||
input: {
|
||||
model: string;
|
||||
input: unknown;
|
||||
instructions?: string;
|
||||
previous_response_id?: string;
|
||||
runMode?: string;
|
||||
simulation?: boolean;
|
||||
store?: boolean;
|
||||
stream?: boolean;
|
||||
},
|
||||
): Promise<Record<string, unknown>> {
|
||||
return request<Record<string, unknown>>('/v1/responses', {
|
||||
body: input,
|
||||
method: 'POST',
|
||||
token,
|
||||
});
|
||||
}
|
||||
|
||||
export async function createEmbedding(
|
||||
token: string,
|
||||
input: { model: string; input: string | string[]; dimensions?: number; runMode?: string; simulation?: boolean },
|
||||
@ -818,6 +838,8 @@ export interface VideoGenerationParams {
|
||||
mode?: 'std' | 'pro';
|
||||
negative_prompt?: string;
|
||||
cfg_scale?: number;
|
||||
runMode?: string;
|
||||
simulation?: boolean;
|
||||
}
|
||||
|
||||
export async function createVideoGenerationTask(
|
||||
@ -881,6 +903,10 @@ export async function getTask(token: string, taskId: string): Promise<GatewayTas
|
||||
return request<GatewayTask>(`/api/workspace/tasks/${taskId}`, { token });
|
||||
}
|
||||
|
||||
export async function getAPITask(token: string, taskId: string): Promise<GatewayTask> {
|
||||
return request<GatewayTask>(`/api/v1/tasks/${taskId}`, { token });
|
||||
}
|
||||
|
||||
export async function listTaskParamPreprocessing(
|
||||
token: string,
|
||||
taskId: string,
|
||||
|
||||
@ -1,5 +1,14 @@
|
||||
import type { GatewayTask } from '@easyai-ai-gateway/contracts';
|
||||
import { createCompatibleChatCompletion, createEmbedding, createImageEditTask, createImageGenerationTask, createRerank } from '../api';
|
||||
import {
|
||||
createCompatibleChatCompletion,
|
||||
createEmbedding,
|
||||
createImageEditTask,
|
||||
createImageGenerationTask,
|
||||
createRerank,
|
||||
createResponse,
|
||||
createVideoGenerationTask,
|
||||
getAPITask,
|
||||
} from '../api';
|
||||
import type { TaskForm } from '../types';
|
||||
|
||||
export interface RunTaskResponse {
|
||||
@ -19,6 +28,19 @@ export async function runTask(token: string, task: TaskForm): Promise<RunTaskRes
|
||||
});
|
||||
return { localOnly: true, task: compatibleTask(task, result) };
|
||||
}
|
||||
if (task.kind === 'responses') {
|
||||
const result = await createResponse(token, {
|
||||
model: task.model,
|
||||
input: task.prompt,
|
||||
instructions: task.instructions,
|
||||
previous_response_id: task.previousResponseId,
|
||||
runMode: 'simulation',
|
||||
simulation: true,
|
||||
store: true,
|
||||
stream: false,
|
||||
});
|
||||
return { localOnly: true, task: compatibleTask(task, result) };
|
||||
}
|
||||
if (task.kind === 'embeddings') {
|
||||
const result = await createEmbedding(token, {
|
||||
model: task.model,
|
||||
@ -60,6 +82,24 @@ export async function runTask(token: string, task: TaskForm): Promise<RunTaskRes
|
||||
simulation: true,
|
||||
});
|
||||
}
|
||||
if (task.kind === 'videos.generations') {
|
||||
return createVideoGenerationTask(token, {
|
||||
model: task.model,
|
||||
content: [{ type: 'text', text: task.prompt }],
|
||||
aspect_ratio: task.aspectRatio ?? '16:9',
|
||||
resolution: task.resolution ?? '720p',
|
||||
duration: task.duration ?? 5,
|
||||
audio: task.outputAudio ?? true,
|
||||
runMode: 'simulation',
|
||||
simulation: true,
|
||||
});
|
||||
}
|
||||
if (task.kind === 'tasks.retrieve') {
|
||||
const taskId = task.taskId?.trim();
|
||||
if (!taskId) throw new Error('请输入要取回的 Task ID');
|
||||
const result = await getAPITask(token, taskId);
|
||||
return { localOnly: true, task: compatibleTask(task, result as unknown as Record<string, unknown>) };
|
||||
}
|
||||
throw new Error(`Unsupported task kind: ${task.kind}`);
|
||||
}
|
||||
|
||||
@ -83,6 +123,18 @@ function compatibleTask(task: TaskForm, result: Record<string, unknown>): Gatewa
|
||||
}
|
||||
|
||||
function requestSnapshot(task: TaskForm): Record<string, unknown> {
|
||||
if (task.kind === 'responses') {
|
||||
return {
|
||||
model: task.model,
|
||||
input: task.prompt,
|
||||
instructions: task.instructions,
|
||||
previous_response_id: task.previousResponseId,
|
||||
runMode: 'simulation',
|
||||
simulation: true,
|
||||
store: true,
|
||||
stream: false,
|
||||
};
|
||||
}
|
||||
if (task.kind === 'embeddings') {
|
||||
return {
|
||||
model: task.model,
|
||||
@ -102,6 +154,19 @@ function requestSnapshot(task: TaskForm): Record<string, unknown> {
|
||||
simulation: true,
|
||||
};
|
||||
}
|
||||
if (task.kind === 'videos.generations') {
|
||||
return {
|
||||
model: task.model,
|
||||
content: [{ type: 'text', text: task.prompt }],
|
||||
aspect_ratio: task.aspectRatio ?? '16:9',
|
||||
resolution: task.resolution ?? '720p',
|
||||
duration: task.duration ?? 5,
|
||||
audio: task.outputAudio ?? true,
|
||||
runMode: 'simulation',
|
||||
simulation: true,
|
||||
};
|
||||
}
|
||||
if (task.kind === 'tasks.retrieve') return { taskId: task.taskId };
|
||||
return {
|
||||
model: task.model,
|
||||
messages: [{ role: 'user', content: task.prompt }],
|
||||
@ -133,5 +198,7 @@ function modelTypeForKind(kind: TaskForm['kind']) {
|
||||
if (kind === 'reranks') return 'text_rerank';
|
||||
if (kind === 'images.generations') return 'image_generate';
|
||||
if (kind === 'images.edits') return 'image_edit';
|
||||
if (kind === 'videos.generations') return 'video_generate';
|
||||
if (kind === 'tasks.retrieve') return 'task';
|
||||
return 'text_generate';
|
||||
}
|
||||
|
||||
107
apps/web/src/pages/ApiDocsPage.test.tsx
Normal file
107
apps/web/src/pages/ApiDocsPage.test.tsx
Normal file
@ -0,0 +1,107 @@
|
||||
import { renderToStaticMarkup } from 'react-dom/server';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import type { ApiDocSection, TaskForm } from '../types';
|
||||
import { ApiDocsPage } from './ApiDocsPage';
|
||||
|
||||
describe('ApiDocsPage extended task documentation', () => {
|
||||
it.each([
|
||||
['guideBaseUrl', '前往创建 API Key'],
|
||||
['guideWebhook', 'TASK_PROGRESS_CALLBACK_ENABLED'],
|
||||
['guideErrors', '400 invalid_parameter'],
|
||||
['guideTesting', 'simulated=true'],
|
||||
] as const)('renders the clickable guide page %s', (section, expectedContent) => {
|
||||
const html = renderDocs(section, { kind: 'chat.completions', model: 'gpt-4o-mini', prompt: '你好' });
|
||||
|
||||
expect(html).toContain('data-active="true"');
|
||||
expect(html).toContain(expectedContent);
|
||||
expect(html).toContain('指南导航');
|
||||
expect(html).not.toContain('/v1/chat/completions');
|
||||
});
|
||||
|
||||
it('documents the OpenAI-compatible Responses request and continuity fields', () => {
|
||||
const html = renderDocs('responses', { kind: 'responses', model: 'gpt-4o-mini', prompt: '你好' });
|
||||
|
||||
expect(html).toContain('/v1/responses');
|
||||
expect(html).toContain('previous_response_id');
|
||||
expect(html).toContain('X-Async');
|
||||
expect(html).toContain('连续对话与状态归属');
|
||||
});
|
||||
|
||||
it('documents video generation parameters and async retrieval guidance', () => {
|
||||
const html = renderDocs('videoGeneration', { kind: 'videos.generations', model: '豆包Seedance-2.0', prompt: '雪山日出' });
|
||||
|
||||
expect(html).toContain('/api/v1/videos/generations');
|
||||
expect(html).toContain('aspect_ratio');
|
||||
expect(html).toContain('reference_image');
|
||||
expect(html).toContain('任务取回接口');
|
||||
});
|
||||
|
||||
it('documents async mode as a body-independent capability', () => {
|
||||
const html = renderDocs('asyncMode', { kind: 'chat.completions', model: 'gpt-4o-mini', prompt: '你好' });
|
||||
|
||||
expect(html).toContain('X-Async');
|
||||
expect(html).toContain('原请求 Header');
|
||||
expect(html).toContain('同步与异步的区别');
|
||||
expect(html).toContain('异步受理响应');
|
||||
expect(html).not.toContain('/api/v1/videos/generations');
|
||||
expect(html).not.toContain('Body 参数');
|
||||
expect(html).not.toContain('视频模型 ID');
|
||||
});
|
||||
|
||||
it.each(['chat', 'responses', 'embeddings', 'reranks', 'imageGeneration', 'imageEdit', 'videoGeneration'] as const)(
|
||||
'shows the shared X-Async switch on the %s task API',
|
||||
(section) => {
|
||||
const html = renderDocs(section, { kind: 'chat.completions', model: 'gpt-4o-mini', prompt: '你好' });
|
||||
|
||||
expect(html).toContain('X-Async');
|
||||
},
|
||||
);
|
||||
|
||||
it('renders nested objects and object arrays recursively', () => {
|
||||
const html = renderDocs('videoGeneration', { kind: 'videos.generations', model: '豆包Seedance-2.0', prompt: '雪山日出' });
|
||||
|
||||
expect(html).toContain('array<object>');
|
||||
expect(html).toContain('data-depth="1"');
|
||||
expect(html).toContain('data-depth="4"');
|
||||
expect(html).toContain('inline_element');
|
||||
expect(html).toContain('refer_images');
|
||||
expect(html).toContain('slot_key');
|
||||
});
|
||||
|
||||
it('renders task retrieval as GET with a path parameter instead of a request body', () => {
|
||||
const html = renderDocs('taskRetrieve', { kind: 'tasks.retrieve', model: 'task', prompt: '', taskId: 'task-123' });
|
||||
|
||||
expect(html).toContain('GET');
|
||||
expect(html).toContain('/api/v1/tasks/task-123');
|
||||
expect(html).toContain('Path 参数');
|
||||
expect(html).toContain('响应 Body');
|
||||
expect(html).toContain('result');
|
||||
expect(html).toContain('billingSummary');
|
||||
expect(html).toContain('attempts');
|
||||
expect(html).toContain('成功响应示例');
|
||||
expect(html).toContain('Task ID');
|
||||
expect(html).not.toContain('请求 Body');
|
||||
});
|
||||
});
|
||||
|
||||
function renderDocs(activeDocSection: ApiDocSection, taskForm: TaskForm) {
|
||||
return renderToStaticMarkup(
|
||||
<ApiDocsPage
|
||||
activeDocSection={activeDocSection}
|
||||
apiKeySecretsById={{}}
|
||||
apiKeys={[]}
|
||||
canRun
|
||||
coreMessage=""
|
||||
coreState="idle"
|
||||
selectedApiKeyId=""
|
||||
taskForm={taskForm}
|
||||
taskResult={null}
|
||||
onApiKeyChange={vi.fn()}
|
||||
onCreateApiKey={vi.fn()}
|
||||
onDocSectionChange={vi.fn()}
|
||||
onLogin={vi.fn()}
|
||||
onSubmitTask={vi.fn()}
|
||||
onTaskFormChange={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
27
apps/web/src/routing.test.ts
Normal file
27
apps/web/src/routing.test.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { parseAppRoute, pathForApiDocSection } from './routing';
|
||||
|
||||
describe('API documentation routes', () => {
|
||||
it.each([
|
||||
['guideBaseUrl', '/docs/auth'],
|
||||
['guideWebhook', '/docs/webhook'],
|
||||
['guideErrors', '/docs/errors'],
|
||||
['guideTesting', '/docs/testing'],
|
||||
['responses', '/docs/responses'],
|
||||
['videoGeneration', '/docs/videos/generations'],
|
||||
['asyncMode', '/docs/async'],
|
||||
['taskRetrieve', '/docs/tasks/retrieve'],
|
||||
] as const)('maps %s to a stable documentation URL', (section, path) => {
|
||||
expect(pathForApiDocSection(section)).toBe(path);
|
||||
expect(parseAppRoute(path).apiDocSection).toBe(section);
|
||||
});
|
||||
|
||||
it.each([
|
||||
['/docs/playground', 'guideTesting'],
|
||||
['/docs/api/responses', 'responses'],
|
||||
['/docs/api/videos', 'videoGeneration'],
|
||||
['/docs/api/tasks', 'taskRetrieve'],
|
||||
] as const)('keeps the legacy documentation URL %s working', (path, section) => {
|
||||
expect(parseAppRoute(path).apiDocSection).toBe(section);
|
||||
});
|
||||
});
|
||||
@ -43,11 +43,19 @@ const adminPaths: Record<AdminSection, string> = {
|
||||
};
|
||||
|
||||
const docsPaths: Record<ApiDocSection, string> = {
|
||||
guideBaseUrl: '/docs/auth',
|
||||
guideWebhook: '/docs/webhook',
|
||||
guideErrors: '/docs/errors',
|
||||
guideTesting: '/docs/testing',
|
||||
chat: '/docs/chat',
|
||||
responses: '/docs/responses',
|
||||
embeddings: '/docs/embeddings',
|
||||
reranks: '/docs/reranks',
|
||||
imageGeneration: '/docs/images/generations',
|
||||
imageEdit: '/docs/images/edits',
|
||||
videoGeneration: '/docs/videos/generations',
|
||||
asyncMode: '/docs/async',
|
||||
taskRetrieve: '/docs/tasks/retrieve',
|
||||
pricing: '/docs/pricing',
|
||||
files: '/docs/files',
|
||||
};
|
||||
@ -63,8 +71,9 @@ const adminSections = reverseMap(adminPaths);
|
||||
const docsSections = reverseMap(docsPaths);
|
||||
const playgroundSections = reverseMap(playgroundPaths);
|
||||
|
||||
export function parseAppRoute(input = `${window.location.pathname}${window.location.search}`): AppRouteState {
|
||||
const url = new URL(input, window.location.origin);
|
||||
export function parseAppRoute(input = currentLocationPath()): AppRouteState {
|
||||
const origin = typeof window === 'undefined' ? 'http://localhost' : window.location.origin;
|
||||
const url = new URL(input, origin);
|
||||
const path = normalizePath(url.pathname);
|
||||
const workspaceTaskQuery = parseWorkspaceTaskQuery(url.searchParams);
|
||||
if (path === '/') return { ...defaultRouteState };
|
||||
@ -84,6 +93,11 @@ export function parseAppRoute(input = `${window.location.pathname}${window.locat
|
||||
return { ...defaultRouteState };
|
||||
}
|
||||
|
||||
function currentLocationPath() {
|
||||
if (typeof window === 'undefined') return '/';
|
||||
return `${window.location.pathname}${window.location.search}`;
|
||||
}
|
||||
|
||||
export function pathForPage(page: PageKey, route: AppRouteState): string {
|
||||
if (page === 'playground') return pathForPlaygroundMode(route.playgroundMode);
|
||||
if (page === 'models') return '/models';
|
||||
@ -135,11 +149,14 @@ function parseAdminSection(path: string): AdminSection {
|
||||
|
||||
function parseDocSection(path: string): ApiDocSection {
|
||||
if (path === '/docs') return 'chat';
|
||||
if (path === '/docs/playground') return 'guideTesting';
|
||||
if (path === '/docs/api/chat') return 'chat';
|
||||
if (path === '/docs/api/responses') return 'responses';
|
||||
if (path === '/docs/api/embeddings') return 'embeddings';
|
||||
if (path === '/docs/api/reranks') return 'reranks';
|
||||
if (path === '/docs/api/media') return 'imageGeneration';
|
||||
if (path === '/docs/playground') return 'chat';
|
||||
if (path === '/docs/api/videos') return 'videoGeneration';
|
||||
if (path === '/docs/api/tasks') return 'taskRetrieve';
|
||||
return docsSections[path] ?? 'chat';
|
||||
}
|
||||
|
||||
|
||||
@ -218,6 +218,7 @@
|
||||
.paramRow {
|
||||
display: grid;
|
||||
grid-template-columns: 150px 110px minmax(0, 1fr) 50px;
|
||||
align-items: start;
|
||||
gap: 12px;
|
||||
padding: 13px 16px;
|
||||
border-bottom: 1px solid #f0f2f5;
|
||||
@ -225,11 +226,91 @@
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.paramRow[data-nested='true'] {
|
||||
background: #fbfcfe;
|
||||
}
|
||||
|
||||
.paramName {
|
||||
position: relative;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.paramName code {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.paramTreeMarker {
|
||||
position: absolute;
|
||||
top: -13px;
|
||||
width: 12px;
|
||||
height: 23px;
|
||||
border-bottom: 1px solid #cfd7e3;
|
||||
border-left: 1px solid #cfd7e3;
|
||||
border-radius: 0 0 0 4px;
|
||||
}
|
||||
|
||||
.paramRow em {
|
||||
color: #a16207;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.docsDetailContent {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
color: var(--text-soft);
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.docsDetailContent p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.docsDetailContent pre {
|
||||
overflow: auto;
|
||||
margin: 0;
|
||||
padding: 14px;
|
||||
border-radius: 8px;
|
||||
background: #f7f8fa;
|
||||
color: var(--text-normal);
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.docsSteps {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
margin: 0;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.docsGuideActions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.docsStatusGrid {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(190px, auto) minmax(0, 1fr);
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.docsStatusGrid > * {
|
||||
margin: 0;
|
||||
padding: 13px 16px;
|
||||
border-bottom: 1px solid #f0f2f5;
|
||||
color: var(--text-soft);
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.docsStatusGrid > code {
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.docsRunner {
|
||||
border-left: 1px solid var(--border);
|
||||
background: #fff;
|
||||
@ -241,6 +322,40 @@
|
||||
padding: 0 16px 16px;
|
||||
}
|
||||
|
||||
.docsRunnerUnavailable {
|
||||
padding: 14px;
|
||||
border: 1px dashed var(--border);
|
||||
border-radius: 8px;
|
||||
background: var(--surface-muted);
|
||||
color: var(--text-soft);
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.docsGuideAside header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-height: 58px;
|
||||
}
|
||||
|
||||
.docsGuideAside > div {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
padding: 18px 16px;
|
||||
color: var(--text-soft);
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.docsGuideAside span,
|
||||
.docsGuideAside p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.docsGuideAside strong {
|
||||
color: var(--text-normal);
|
||||
}
|
||||
|
||||
.runnerResult {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
@ -279,6 +394,10 @@
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.docsStatusGrid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.agentResourceCard {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
@ -1,10 +1,33 @@
|
||||
export type LoadState = 'idle' | 'loading' | 'ready' | 'error';
|
||||
export type AuthMode = 'login' | 'register' | 'external';
|
||||
export type TaskKind = 'chat.completions' | 'embeddings' | 'reranks' | 'images.generations' | 'images.edits';
|
||||
export type TaskKind =
|
||||
| 'chat.completions'
|
||||
| 'responses'
|
||||
| 'embeddings'
|
||||
| 'reranks'
|
||||
| 'images.generations'
|
||||
| 'images.edits'
|
||||
| 'videos.generations'
|
||||
| 'tasks.retrieve';
|
||||
export type PageKey = 'home' | 'playground' | 'models' | 'workspace' | 'admin' | 'docs';
|
||||
export type PlaygroundMode = 'chat' | 'image' | 'video';
|
||||
export type WorkspaceSection = 'overview' | 'billing' | 'apiKeys' | 'tasks' | 'transactions';
|
||||
export type ApiDocSection = 'chat' | 'embeddings' | 'reranks' | 'imageGeneration' | 'imageEdit' | 'pricing' | 'files';
|
||||
export type ApiDocSection =
|
||||
| 'guideBaseUrl'
|
||||
| 'guideWebhook'
|
||||
| 'guideErrors'
|
||||
| 'guideTesting'
|
||||
| 'chat'
|
||||
| 'responses'
|
||||
| 'embeddings'
|
||||
| 'reranks'
|
||||
| 'imageGeneration'
|
||||
| 'imageEdit'
|
||||
| 'videoGeneration'
|
||||
| 'asyncMode'
|
||||
| 'taskRetrieve'
|
||||
| 'pricing'
|
||||
| 'files';
|
||||
export type AdminSection =
|
||||
| 'overview'
|
||||
| 'globalModels'
|
||||
@ -37,10 +60,17 @@ export interface TaskForm {
|
||||
kind: TaskKind;
|
||||
model: string;
|
||||
prompt: string;
|
||||
aspectRatio?: string;
|
||||
dimensions?: number;
|
||||
documents?: string;
|
||||
duration?: number;
|
||||
image?: string;
|
||||
instructions?: string;
|
||||
mask?: string;
|
||||
outputAudio?: boolean;
|
||||
previousResponseId?: string;
|
||||
resolution?: string;
|
||||
taskId?: string;
|
||||
topN?: number;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user