✨feature: First push to git
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
import { ExtractedLink } from '../parsing/types.js';
|
||||
|
||||
export interface LlmProvider {
|
||||
categorize(link: ExtractedLink, categories: string[]): Promise<string | undefined>;
|
||||
}
|
||||
|
||||
interface ProviderOptions {
|
||||
apiKey?: string;
|
||||
baseUrl?: string | null;
|
||||
model: string;
|
||||
}
|
||||
|
||||
async function postJson(url: string, apiKey: string | undefined, body: unknown): Promise<any> {
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
...(apiKey ? { authorization: `Bearer ${apiKey}` } : {})
|
||||
},
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`LLM request failed: ${response.status}`);
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
function prompt(link: ExtractedLink, categories: string[]): string {
|
||||
return `Choose the best newsletter category from ${categories.join(', ')} for: ${link.title} ${link.url}. Return only the category.`;
|
||||
}
|
||||
|
||||
export class OpenAiCompatibleProvider implements LlmProvider {
|
||||
public constructor(private readonly options: ProviderOptions) {}
|
||||
|
||||
public async categorize(link: ExtractedLink, categories: string[]): Promise<string | undefined> {
|
||||
const data = await postJson(
|
||||
`${this.options.baseUrl ?? 'https://api.openai.com/v1'}/chat/completions`,
|
||||
this.options.apiKey,
|
||||
{
|
||||
model: this.options.model,
|
||||
messages: [{ role: 'user', content: prompt(link, categories) }],
|
||||
temperature: 0
|
||||
}
|
||||
);
|
||||
return data.choices?.[0]?.message?.content?.trim();
|
||||
}
|
||||
}
|
||||
|
||||
export class OpenAiProvider extends OpenAiCompatibleProvider {}
|
||||
|
||||
export class LocalProvider extends OpenAiCompatibleProvider {}
|
||||
|
||||
export class AnthropicProvider implements LlmProvider {
|
||||
public constructor(private readonly options: ProviderOptions) {}
|
||||
|
||||
public async categorize(link: ExtractedLink, categories: string[]): Promise<string | undefined> {
|
||||
const response = await fetch(
|
||||
`${this.options.baseUrl ?? 'https://api.anthropic.com'}/v1/messages`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
'x-api-key': this.options.apiKey ?? '',
|
||||
'anthropic-version': '2023-06-01'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: this.options.model,
|
||||
max_tokens: 64,
|
||||
messages: [{ role: 'user', content: prompt(link, categories) }]
|
||||
})
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Anthropic request failed: ${response.status}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
return data.content?.[0]?.text?.trim();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user