auto-claude: subtask-4-2 - Create Deepseek API client wrapper using OpenAI SDK
- Add Deepseek client using OpenAI SDK with custom baseURL - Implement createDeepseekClient() factory function with lazy initialization - Add ChatMessage type definitions for type safety - Include portfolio-specific system prompt for the chatbot - Support both streaming and non-streaming chat completions - Configure default model (deepseek-chat) and sensible defaults Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
import OpenAI from 'openai';
|
||||
|
||||
// Deepseek configuration constants
|
||||
const DEEPSEEK_BASE_URL = 'https://api.deepseek.com';
|
||||
const DEEPSEEK_DEFAULT_MODEL = 'deepseek-chat';
|
||||
|
||||
// Create Deepseek client using OpenAI SDK
|
||||
// The client is lazy-initialized to avoid issues during build time
|
||||
let deepseekClient: OpenAI | null = null;
|
||||
|
||||
export function createDeepseekClient(): OpenAI {
|
||||
if (!process.env.DEEPSEEK_API_KEY) {
|
||||
throw new Error('DEEPSEEK_API_KEY environment variable is not set');
|
||||
}
|
||||
|
||||
if (!deepseekClient) {
|
||||
deepseekClient = new OpenAI({
|
||||
baseURL: DEEPSEEK_BASE_URL,
|
||||
apiKey: process.env.DEEPSEEK_API_KEY,
|
||||
});
|
||||
}
|
||||
|
||||
return deepseekClient;
|
||||
}
|
||||
|
||||
// Type definitions for chat messages
|
||||
export type ChatRole = 'system' | 'user' | 'assistant';
|
||||
|
||||
export interface ChatMessage {
|
||||
role: ChatRole;
|
||||
content: string;
|
||||
}
|
||||
|
||||
// System prompt for the portfolio chatbot
|
||||
export const PORTFOLIO_SYSTEM_PROMPT = `You are a helpful AI assistant on Damjan Savić's portfolio website.
|
||||
Damjan is a full-stack web developer and AI specialist based in Vienna, Austria.
|
||||
You can help visitors learn about Damjan's skills, services, and experience.
|
||||
Be friendly, professional, and concise in your responses.
|
||||
If asked about topics unrelated to Damjan or web development, politely redirect the conversation.
|
||||
Respond in the same language the user writes to you (German, English, or Serbian).`;
|
||||
|
||||
// Chat completion options
|
||||
export interface ChatCompletionOptions {
|
||||
messages: ChatMessage[];
|
||||
model?: string;
|
||||
temperature?: number;
|
||||
maxTokens?: number;
|
||||
stream?: boolean;
|
||||
}
|
||||
|
||||
// Create a chat completion (non-streaming)
|
||||
export async function createChatCompletion(
|
||||
options: ChatCompletionOptions
|
||||
): Promise<string> {
|
||||
const client = createDeepseekClient();
|
||||
|
||||
const completion = await client.chat.completions.create({
|
||||
model: options.model ?? DEEPSEEK_DEFAULT_MODEL,
|
||||
messages: options.messages,
|
||||
temperature: options.temperature ?? 0.7,
|
||||
max_tokens: options.maxTokens ?? 1024,
|
||||
stream: false,
|
||||
});
|
||||
|
||||
return completion.choices[0]?.message?.content ?? '';
|
||||
}
|
||||
|
||||
// Create a streaming chat completion
|
||||
export async function createStreamingChatCompletion(
|
||||
options: Omit<ChatCompletionOptions, 'stream'>
|
||||
): Promise<AsyncIterable<OpenAI.Chat.Completions.ChatCompletionChunk>> {
|
||||
const client = createDeepseekClient();
|
||||
|
||||
const stream = await client.chat.completions.create({
|
||||
model: options.model ?? DEEPSEEK_DEFAULT_MODEL,
|
||||
messages: options.messages,
|
||||
temperature: options.temperature ?? 0.7,
|
||||
max_tokens: options.maxTokens ?? 1024,
|
||||
stream: true,
|
||||
});
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
// Default export for convenience
|
||||
export default {
|
||||
createClient: createDeepseekClient,
|
||||
createCompletion: createChatCompletion,
|
||||
createStreamingCompletion: createStreamingChatCompletion,
|
||||
SYSTEM_PROMPT: PORTFOLIO_SYSTEM_PROMPT,
|
||||
DEFAULT_MODEL: DEEPSEEK_DEFAULT_MODEL,
|
||||
};
|
||||
Reference in New Issue
Block a user