85 lines
2.8 KiB
TypeScript
85 lines
2.8 KiB
TypeScript
/**
|
|
* LLM(AI 검증) 앱 설정 (gc_app_settings.llm_settings_json)
|
|
*/
|
|
|
|
export interface LlmAppSettings {
|
|
/** LLM AI 검증 사용 여부 */
|
|
enabled: boolean;
|
|
/** LLM 서버 호스트 (IP 또는 도메인) */
|
|
host: string;
|
|
/** LLM 서버 포트 */
|
|
port: number;
|
|
/** HTTPS 사용 여부 */
|
|
useHttps: boolean;
|
|
/** OpenAI 호환 chat completions 경로 */
|
|
chatPath: string;
|
|
/** 모델 ID */
|
|
model: string;
|
|
/** 최대 생성 토큰 */
|
|
maxTokens: number;
|
|
/** temperature (0~2) */
|
|
temperature: number;
|
|
/** 요청 타임아웃 (ms) */
|
|
timeoutMs: number;
|
|
}
|
|
|
|
export const DEFAULT_LLM_APP_SETTINGS: LlmAppSettings = {
|
|
enabled: true,
|
|
host: '127.0.0.1',
|
|
port: 16000,
|
|
useHttps: false,
|
|
chatPath: '/v1/chat/completions',
|
|
model: 'mlx-community/Qwen2.5-7B-Instruct-4bit',
|
|
maxTokens: 1024,
|
|
temperature: 0.1,
|
|
timeoutMs: 120_000,
|
|
};
|
|
|
|
function clampInt(v: unknown, min: number, max: number, fallback: number): number {
|
|
const n = Number(v);
|
|
if (!Number.isFinite(n)) return fallback;
|
|
return Math.max(min, Math.min(max, Math.round(n)));
|
|
}
|
|
|
|
function clampFloat(v: unknown, min: number, max: number, fallback: number): number {
|
|
const n = Number(v);
|
|
if (!Number.isFinite(n)) return fallback;
|
|
return Math.max(min, Math.min(max, n));
|
|
}
|
|
|
|
export function resolveLlmAppSettings(
|
|
raw?: Partial<LlmAppSettings> | null,
|
|
): LlmAppSettings {
|
|
const d = DEFAULT_LLM_APP_SETTINGS;
|
|
if (!raw || typeof raw !== 'object') return { ...d };
|
|
const host = typeof raw.host === 'string' && raw.host.trim() ? raw.host.trim() : d.host;
|
|
const chatPath = typeof raw.chatPath === 'string' && raw.chatPath.trim()
|
|
? (raw.chatPath.startsWith('/') ? raw.chatPath.trim() : `/${raw.chatPath.trim()}`)
|
|
: d.chatPath;
|
|
const model = typeof raw.model === 'string' && raw.model.trim() ? raw.model.trim() : d.model;
|
|
return {
|
|
enabled: raw.enabled === undefined ? d.enabled : Boolean(raw.enabled),
|
|
host,
|
|
port: clampInt(raw.port, 1, 65535, d.port),
|
|
useHttps: raw.useHttps === undefined ? d.useHttps : Boolean(raw.useHttps),
|
|
chatPath,
|
|
model,
|
|
maxTokens: clampInt(raw.maxTokens, 64, 8192, d.maxTokens),
|
|
temperature: clampFloat(raw.temperature, 0, 2, d.temperature),
|
|
timeoutMs: clampInt(raw.timeoutMs, 5_000, 600_000, d.timeoutMs),
|
|
};
|
|
}
|
|
|
|
/** 설정 UI용 — host·port·프로토콜로 base URL 미리보기 */
|
|
export function buildLlmBaseUrl(settings: LlmAppSettings): string {
|
|
const scheme = settings.useHttps ? 'https' : 'http';
|
|
const omitPort = (settings.useHttps && settings.port === 443)
|
|
|| (!settings.useHttps && settings.port === 80);
|
|
if (omitPort) return `${scheme}://${settings.host}`;
|
|
return `${scheme}://${settings.host}:${settings.port}`;
|
|
}
|
|
|
|
export function buildLlmEndpointUrl(settings: LlmAppSettings): string {
|
|
return `${buildLlmBaseUrl(settings)}${settings.chatPath}`;
|
|
}
|