Files
gongxue-base/apps/server/src/ai-config/dto/ai-config.dto.ts

151 lines
3.2 KiB
TypeScript

import {
IsString,
IsBoolean,
IsOptional,
IsInt,
Min,
Max,
IsIn,
IsNotEmpty,
ValidateIf,
} from 'class-validator';
import { AiProvider } from '../ai-config.entity';
const PROVIDERS = [AiProvider.OPENAI, AiProvider.DEEPSEEK, AiProvider.OPENAI_COMPATIBLE] as const;
const DEFAULT_BASE_URLS: Record<AiProvider, string> = {
[AiProvider.OPENAI]: 'https://api.openai.com/v1',
[AiProvider.DEEPSEEK]: 'https://api.deepseek.com',
[AiProvider.OPENAI_COMPATIBLE]: '',
};
/** DTO for PUT /api/ai/config — all fields required or validated */
export class SaveAiConfigDto {
@IsIn(PROVIDERS)
provider!: AiProvider;
@ValidateIf((o: SaveAiConfigDto) => o.provider === AiProvider.OPENAI_COMPATIBLE || (o.baseUrl !== undefined && o.baseUrl !== ''))
@IsNotEmpty({ message: 'Base URL 不能为空' })
@IsString()
baseUrl?: string;
/** Raw API key — never returned by GET; empty / undefined = keep existing */
@IsOptional()
@IsString()
apiKey?: string;
@IsOptional()
@IsString()
defaultModel?: string;
@IsOptional()
@IsBoolean()
enabled?: boolean;
@IsOptional()
@IsBoolean()
supportsVision?: boolean;
@IsOptional()
@IsInt()
@Min(1000)
@Max(120000)
timeoutMs?: number;
}
/** DTO for POST /api/ai/config/test — all fields optional, validate only when provided */
export class TestAiConfigDto {
@IsOptional()
@IsIn(PROVIDERS)
provider?: AiProvider;
@IsOptional()
@IsString()
baseUrl?: string;
@IsOptional()
@IsString()
apiKey?: string;
@IsOptional()
@IsString()
defaultModel?: string;
@IsOptional()
@IsInt()
@Min(1000)
@Max(120000)
timeoutMs?: number;
}
/** Response shape for GET /api/ai/config — NEVER includes plaintext key */
export interface AiConfigResponseDto {
id: number;
provider: AiProvider;
baseUrl: string;
hasApiKey: boolean;
hasDatabaseKey: boolean;
maskedApiKey: string | null;
keySource: 'database' | 'environment' | 'none';
defaultModel: string | null;
enabled: boolean;
supportsVision: boolean;
timeoutMs: number;
verified: boolean;
lastTestedAt: string | null;
lastTestLatencyMs: number | null;
createdAt: string;
updatedAt: string;
}
/** Response shape for POST /api/ai/config/test */
export interface AiConfigTestResultDto {
success: boolean;
latencyMs: number | null;
modelCount: number | null;
modelAvailable: boolean;
testedAt: string;
message: string;
}
/** Server-only runtime config — NEVER exported via controller DTO */
export interface AiRuntimeConfig {
provider: AiProvider;
baseUrl: string;
apiKey: string;
defaultModel: string;
timeoutMs: number;
enabled: boolean;
supportsVision: boolean;
}
/** DTO for POST /api/ai/config/models — fetch available model list from provider */
export class FetchModelsDto {
@IsOptional()
@IsIn(PROVIDERS)
provider?: AiProvider;
@IsOptional()
@IsString()
baseUrl?: string;
@IsOptional()
@IsString()
apiKey?: string;
@IsOptional()
@IsInt()
@Min(1000)
@Max(120000)
timeoutMs?: number;
}
/** Response shape for POST /api/ai/config/models */
export interface FetchModelsResultDto {
success: boolean;
models: Array<{ id: string }>;
message?: string;
}
export { DEFAULT_BASE_URLS };