joel bot
This commit is contained in:
41
src/services/ai/index.ts
Normal file
41
src/services/ai/index.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* AI Service - Main entry point for AI functionality
|
||||
*/
|
||||
|
||||
import { createLogger } from "../../core/logger";
|
||||
import { ReplicateProvider } from "./replicate";
|
||||
import type { AiProvider, AiResponse } from "./types";
|
||||
|
||||
const logger = createLogger("AI:Service");
|
||||
|
||||
export class AiService {
|
||||
private provider: AiProvider;
|
||||
|
||||
constructor(provider?: AiProvider) {
|
||||
this.provider = provider ?? new ReplicateProvider();
|
||||
}
|
||||
|
||||
async health(): Promise<boolean> {
|
||||
return this.provider.health();
|
||||
}
|
||||
|
||||
async generateResponse(
|
||||
prompt: string,
|
||||
systemPrompt: string
|
||||
): Promise<AiResponse> {
|
||||
logger.debug("Generating response", { promptLength: prompt.length });
|
||||
return this.provider.ask({ prompt, systemPrompt });
|
||||
}
|
||||
}
|
||||
|
||||
// Singleton instance
|
||||
let aiService: AiService | null = null;
|
||||
|
||||
export function getAiService(): AiService {
|
||||
if (!aiService) {
|
||||
aiService = new AiService();
|
||||
}
|
||||
return aiService;
|
||||
}
|
||||
|
||||
export type { AiProvider, AiResponse } from "./types";
|
||||
63
src/services/ai/replicate.ts
Normal file
63
src/services/ai/replicate.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Replicate AI provider implementation
|
||||
*/
|
||||
|
||||
import Replicate from "replicate";
|
||||
import { config } from "../../core/config";
|
||||
import { createLogger } from "../../core/logger";
|
||||
import type { AiProvider, AiResponse, AskOptions } from "./types";
|
||||
|
||||
const logger = createLogger("AI:Replicate");
|
||||
|
||||
export class ReplicateProvider implements AiProvider {
|
||||
private client: Replicate;
|
||||
|
||||
constructor() {
|
||||
this.client = new Replicate({
|
||||
auth: config.ai.replicateApiToken,
|
||||
});
|
||||
}
|
||||
|
||||
async health(): Promise<boolean> {
|
||||
try {
|
||||
// Simple health check - just verify we can create a client
|
||||
return true;
|
||||
} catch (error) {
|
||||
logger.error("Health check failed", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async ask(options: AskOptions): Promise<AiResponse> {
|
||||
const { prompt, systemPrompt, maxTokens, temperature } = options;
|
||||
|
||||
try {
|
||||
const formattedPrompt = `<|im_start|>system
|
||||
${systemPrompt}<|im_end|>
|
||||
<|im_start|>user
|
||||
${prompt}<|im_end|>
|
||||
<|im_start|>assistant
|
||||
`;
|
||||
|
||||
const input = {
|
||||
prompt: formattedPrompt,
|
||||
temperature: temperature ?? config.ai.temperature,
|
||||
max_new_tokens: maxTokens ?? config.ai.maxTokens,
|
||||
};
|
||||
|
||||
let output = "";
|
||||
for await (const event of this.client.stream(config.ai.model as `${string}/${string}:${string}`, {
|
||||
input,
|
||||
})) {
|
||||
output += event;
|
||||
// Discord message limit safety
|
||||
if (output.length >= 1900) break;
|
||||
}
|
||||
|
||||
return { text: output.slice(0, 1900) };
|
||||
} catch (error: unknown) {
|
||||
logger.error("Failed to generate response", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
27
src/services/ai/types.ts
Normal file
27
src/services/ai/types.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* AI Provider interface
|
||||
* Allows swapping AI providers (Replicate, OpenAI, etc.) without changing business logic
|
||||
*/
|
||||
|
||||
export interface AiResponse {
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface AiProvider {
|
||||
/**
|
||||
* Generate a response to a prompt
|
||||
*/
|
||||
ask(options: AskOptions): Promise<AiResponse>;
|
||||
|
||||
/**
|
||||
* Check if the AI service is healthy
|
||||
*/
|
||||
health(): Promise<boolean>;
|
||||
}
|
||||
|
||||
export interface AskOptions {
|
||||
prompt: string;
|
||||
systemPrompt: string;
|
||||
maxTokens?: number;
|
||||
temperature?: number;
|
||||
}
|
||||
Reference in New Issue
Block a user