mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-03-21 00:11:27 -07:00
feat(ai): split shared provider config from Anki runtime
This commit is contained in:
@@ -13,7 +13,6 @@ export function applyAnkiConnectResolution(context: ResolveContext): void {
|
||||
const media = isObject(ac.media) ? (ac.media as Record<string, unknown>) : {};
|
||||
const metadata = isObject(ac.metadata) ? (ac.metadata as Record<string, unknown>) : {};
|
||||
const proxy = isObject(ac.proxy) ? (ac.proxy as Record<string, unknown>) : {};
|
||||
const aiSource = isObject(ac.ai) ? ac.ai : isObject(ac.openRouter) ? ac.openRouter : {};
|
||||
const legacyKeys = new Set([
|
||||
'audioField',
|
||||
'imageField',
|
||||
@@ -42,19 +41,11 @@ export function applyAnkiConnectResolution(context: ResolveContext): void {
|
||||
'autoUpdateNewCards',
|
||||
]);
|
||||
|
||||
if (ac.openRouter !== undefined) {
|
||||
context.warn(
|
||||
'ankiConnect.openRouter',
|
||||
ac.openRouter,
|
||||
context.resolved.ankiConnect.ai,
|
||||
'Deprecated key; use ankiConnect.ai instead.',
|
||||
);
|
||||
}
|
||||
|
||||
const { nPlusOne: _nPlusOneConfigFromAnkiConnect, ...ankiConnectWithoutNPlusOne } = ac as Record<
|
||||
string,
|
||||
unknown
|
||||
>;
|
||||
const {
|
||||
nPlusOne: _nPlusOneConfigFromAnkiConnect,
|
||||
ai: _ankiAiConfig,
|
||||
...ankiConnectWithoutNPlusOne
|
||||
} = ac as Record<string, unknown>;
|
||||
const ankiConnectWithoutLegacy = Object.fromEntries(
|
||||
Object.entries(ankiConnectWithoutNPlusOne).filter(([key]) => !legacyKeys.has(key)),
|
||||
);
|
||||
@@ -70,10 +61,6 @@ export function applyAnkiConnectResolution(context: ResolveContext): void {
|
||||
? (ac.fields as (typeof context.resolved)['ankiConnect']['fields'])
|
||||
: {}),
|
||||
},
|
||||
ai: {
|
||||
...context.resolved.ankiConnect.ai,
|
||||
...(aiSource as (typeof context.resolved)['ankiConnect']['ai']),
|
||||
},
|
||||
media: {
|
||||
...context.resolved.ankiConnect.media,
|
||||
...(isObject(ac.media)
|
||||
@@ -219,6 +206,56 @@ export function applyAnkiConnectResolution(context: ResolveContext): void {
|
||||
);
|
||||
}
|
||||
|
||||
if (isObject(ac.ai)) {
|
||||
const aiEnabled = asBoolean(ac.ai.enabled);
|
||||
if (aiEnabled !== undefined) {
|
||||
context.resolved.ankiConnect.ai.enabled = aiEnabled;
|
||||
} else if (ac.ai.enabled !== undefined) {
|
||||
context.warn(
|
||||
'ankiConnect.ai.enabled',
|
||||
ac.ai.enabled,
|
||||
context.resolved.ankiConnect.ai.enabled,
|
||||
'Expected boolean.',
|
||||
);
|
||||
}
|
||||
|
||||
const aiModel = asString(ac.ai.model);
|
||||
if (aiModel !== undefined) {
|
||||
context.resolved.ankiConnect.ai.model = aiModel;
|
||||
} else if (ac.ai.model !== undefined) {
|
||||
context.warn(
|
||||
'ankiConnect.ai.model',
|
||||
ac.ai.model,
|
||||
context.resolved.ankiConnect.ai.model,
|
||||
'Expected string.',
|
||||
);
|
||||
}
|
||||
|
||||
const aiSystemPrompt = asString(ac.ai.systemPrompt);
|
||||
if (aiSystemPrompt !== undefined) {
|
||||
context.resolved.ankiConnect.ai.systemPrompt = aiSystemPrompt;
|
||||
} else if (ac.ai.systemPrompt !== undefined) {
|
||||
context.warn(
|
||||
'ankiConnect.ai.systemPrompt',
|
||||
ac.ai.systemPrompt,
|
||||
context.resolved.ankiConnect.ai.systemPrompt,
|
||||
'Expected string.',
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const aiEnabled = asBoolean(ac.ai);
|
||||
if (aiEnabled !== undefined) {
|
||||
context.resolved.ankiConnect.ai.enabled = aiEnabled;
|
||||
} else if (ac.ai !== undefined) {
|
||||
context.warn(
|
||||
'ankiConnect.ai',
|
||||
ac.ai,
|
||||
context.resolved.ankiConnect.ai.enabled,
|
||||
'Expected boolean or object.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (Array.isArray(ac.tags)) {
|
||||
const normalizedTags = ac.tags
|
||||
.filter((entry): entry is string => typeof entry === 'string')
|
||||
|
||||
@@ -4,6 +4,46 @@ import { asBoolean, asNumber, asString, isObject } from './shared';
|
||||
export function applyIntegrationConfig(context: ResolveContext): void {
|
||||
const { src, resolved, warn } = context;
|
||||
|
||||
if (isObject(src.ai)) {
|
||||
const booleanKeys = ['enabled'] as const;
|
||||
for (const key of booleanKeys) {
|
||||
const value = asBoolean(src.ai[key]);
|
||||
if (value !== undefined) {
|
||||
resolved.ai[key] = value;
|
||||
} else if (src.ai[key] !== undefined) {
|
||||
warn(`ai.${key}`, src.ai[key], resolved.ai[key], 'Expected boolean.');
|
||||
}
|
||||
}
|
||||
|
||||
const stringKeys = ['apiKey', 'apiKeyCommand', 'baseUrl', 'model', 'systemPrompt'] as const;
|
||||
for (const key of stringKeys) {
|
||||
const value = asString(src.ai[key]);
|
||||
if (value !== undefined) {
|
||||
resolved.ai[key] = value;
|
||||
} else if (src.ai[key] !== undefined) {
|
||||
warn(`ai.${key}`, src.ai[key], resolved.ai[key], 'Expected string.');
|
||||
}
|
||||
}
|
||||
|
||||
const requestTimeoutMs = asNumber(src.ai.requestTimeoutMs);
|
||||
if (
|
||||
requestTimeoutMs !== undefined &&
|
||||
Number.isInteger(requestTimeoutMs) &&
|
||||
requestTimeoutMs > 0
|
||||
) {
|
||||
resolved.ai.requestTimeoutMs = requestTimeoutMs;
|
||||
} else if (src.ai.requestTimeoutMs !== undefined) {
|
||||
warn(
|
||||
'ai.requestTimeoutMs',
|
||||
src.ai.requestTimeoutMs,
|
||||
resolved.ai.requestTimeoutMs,
|
||||
'Expected positive integer.',
|
||||
);
|
||||
}
|
||||
} else if (src.ai !== undefined) {
|
||||
warn('ai', src.ai, resolved.ai, 'Expected object.');
|
||||
}
|
||||
|
||||
if (isObject(src.anilist)) {
|
||||
const enabled = asBoolean(src.anilist.enabled);
|
||||
if (enabled !== undefined) {
|
||||
|
||||
Reference in New Issue
Block a user