forked from wangziqi/gongxue-base
117 lines
2.5 KiB
TypeScript
117 lines
2.5 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)
|
|
@IsNotEmpty({ message: 'OPENAI_COMPATIBLE 模式必须提供 baseUrl' })
|
|
@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()
|
|
@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;
|
|
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;
|
|
}
|
|
|
|
export { DEFAULT_BASE_URLS };
|