mirror of https://github.com/ghostfolio/ghostfolio
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
136 lines
2.7 KiB
136 lines
2.7 KiB
const DEFAULT_GLM_MODEL = 'glm-5';
|
|
const DEFAULT_MINIMAX_MODEL = 'MiniMax-M2.5';
|
|
const DEFAULT_REQUEST_TIMEOUT_IN_MS = 15_000;
|
|
|
|
function extractTextFromResponsePayload(payload: unknown) {
|
|
const firstChoice = (payload as { choices?: unknown[] })?.choices?.[0] as
|
|
| { message?: { content?: unknown } }
|
|
| undefined;
|
|
const content = firstChoice?.message?.content;
|
|
|
|
if (typeof content === 'string') {
|
|
return content.trim();
|
|
}
|
|
|
|
if (Array.isArray(content)) {
|
|
const normalized = content
|
|
.map((item) => {
|
|
if (typeof item === 'string') {
|
|
return item;
|
|
}
|
|
|
|
if (
|
|
typeof item === 'object' &&
|
|
item !== null &&
|
|
'text' in item &&
|
|
typeof item.text === 'string'
|
|
) {
|
|
return item.text;
|
|
}
|
|
|
|
return '';
|
|
})
|
|
.join(' ')
|
|
.trim();
|
|
|
|
return normalized.length > 0 ? normalized : null;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
async function callChatCompletions({
|
|
apiKey,
|
|
model,
|
|
prompt,
|
|
signal,
|
|
url
|
|
}: {
|
|
apiKey: string;
|
|
model: string;
|
|
prompt: string;
|
|
signal?: AbortSignal;
|
|
url: string;
|
|
}) {
|
|
const providerTimeoutSignal = AbortSignal.timeout(DEFAULT_REQUEST_TIMEOUT_IN_MS);
|
|
const requestSignal = signal
|
|
? AbortSignal.any([providerTimeoutSignal, signal])
|
|
: providerTimeoutSignal;
|
|
|
|
const response = await fetch(url, {
|
|
body: JSON.stringify({
|
|
messages: [
|
|
{
|
|
content: 'You are a neutral financial assistant.',
|
|
role: 'system'
|
|
},
|
|
{
|
|
content: prompt,
|
|
role: 'user'
|
|
}
|
|
],
|
|
model
|
|
}),
|
|
headers: {
|
|
Authorization: `Bearer ${apiKey}`,
|
|
'Content-Type': 'application/json'
|
|
},
|
|
method: 'POST',
|
|
signal: requestSignal
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`provider request failed with status ${response.status}`);
|
|
}
|
|
|
|
const payload = (await response.json()) as unknown;
|
|
const text = extractTextFromResponsePayload(payload);
|
|
|
|
if (!text) {
|
|
throw new Error('provider returned no assistant text');
|
|
}
|
|
|
|
return {
|
|
text
|
|
};
|
|
}
|
|
|
|
export async function generateTextWithZAiGlm({
|
|
apiKey,
|
|
model,
|
|
prompt,
|
|
signal
|
|
}: {
|
|
apiKey: string;
|
|
model?: string;
|
|
prompt: string;
|
|
signal?: AbortSignal;
|
|
}) {
|
|
return callChatCompletions({
|
|
apiKey,
|
|
model: model ?? DEFAULT_GLM_MODEL,
|
|
prompt,
|
|
signal,
|
|
url: 'https://api.z.ai/api/paas/v4/chat/completions'
|
|
});
|
|
}
|
|
|
|
export async function generateTextWithMinimax({
|
|
apiKey,
|
|
model,
|
|
prompt,
|
|
signal
|
|
}: {
|
|
apiKey: string;
|
|
model?: string;
|
|
prompt: string;
|
|
signal?: AbortSignal;
|
|
}) {
|
|
return callChatCompletions({
|
|
apiKey,
|
|
model: model ?? DEFAULT_MINIMAX_MODEL,
|
|
prompt,
|
|
signal,
|
|
url: 'https://api.minimax.io/v1/chat/completions'
|
|
});
|
|
}
|
|
|