From 798d7e8f5bf2b49298a6ff6b932ca5fb352b473c Mon Sep 17 00:00:00 2001 From: Damjan Savic Date: Sun, 25 Jan 2026 00:49:33 +0100 Subject: [PATCH] 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 --- src/lib/deepseek.ts | 92 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 src/lib/deepseek.ts diff --git a/src/lib/deepseek.ts b/src/lib/deepseek.ts new file mode 100644 index 0000000..4f6ffd8 --- /dev/null +++ b/src/lib/deepseek.ts @@ -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 { + 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 +): Promise> { + 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, +};