diff --git a/.env.example b/.env.example index dd79847..848d17a 100644 --- a/.env.example +++ b/.env.example @@ -3,6 +3,7 @@ IPS="420.69.247.365" NODE_ENV="development" OPENAI_API_KEY="DEEZ" CLAUDE_API_KEY="NUTZ" +DEEPSEEK_API_KEY="BALLZ" # notify NOTIFY_URL="https://notify.jaw.dev" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d5f4853..217f3d4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,7 @@ env: NODE_ENV: 'testing' OPENAI_API_KEY: 'DEEZ' CLAUDE_API_KEY: 'NUTZ' + DEEPSEEK_API_KEY: 'BALLZ' DISCORD_WEBHOOK_URL: 'x' jobs: diff --git a/.vscode/settings.json b/.vscode/settings.json index fec1d2c..4390697 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,10 +2,14 @@ "cSpell.words": [ "adminjs", "aicommit", + "BALLZ", "claudeai", + "deepseek", + "DEEZ", "fastq", "healthz", "nofollow", + "NUTZ", "openai", "pacman", "Tahoma", diff --git a/src/ai.ts b/src/ai.ts index adeebd3..5cd4cc2 100644 --- a/src/ai.ts +++ b/src/ai.ts @@ -142,10 +142,48 @@ export const claudeAI: AIService = { }, }; +export const deepseekAI: AIService = { + generate: async (diff: string, apiKey?: string) => { + try { + const API_KEY = apiKey ? apiKey : appConfig.DEEPSEEK_API_KEY; + const chatCompletion = await new OpenAI({ + baseURL: 'https://api.deepseek.com', + apiKey: API_KEY, + }).chat.completions.create({ + model: 'deepseek-chat', + temperature: 0.7, + max_tokens: 200, + stream: false, + messages: [ + { + role: 'system', + content: prompt, + }, + { + role: 'user', + content: diff, + }, + ], + }); + const messages = chatCompletion.choices + .filter((choice) => choice.message?.content) + .map((choice) => choice.message.content); + return getRandomElement(messages); + } catch (error: any) { + if (error?.error?.type === 'invalid_api_key') { + throw new UnauthorizedError(error.message); + } + throw error; + } + }, +}; + export function ai(type?: Provider): AIService { switch (type) { case 'claudeai': return claudeAI; + case 'deepseek': + return deepseekAI; case 'openai': default: return openAI; diff --git a/src/commit.sh b/src/commit.sh index d57023d..42cad93 100755 --- a/src/commit.sh +++ b/src/commit.sh @@ -32,7 +32,7 @@ show_help() { printf "${YELLOW}Options:${NC}\n" printf " ${GREEN}-dr, --dry-run${NC} Run the script without making any changes\n" printf " ${GREEN}-nv, --no-verify${NC} Skip message selection\n" - printf " ${GREEN}-ai, --ai-provider${NC} Specify AI provider (openai or claude, default: openai)\n" + printf " ${GREEN}-ai, --ai-provider${NC} Specify AI provider (openai, claude or deepseek, default: openai)\n" printf " ${GREEN}-k, --api-key${NC} Specify the API key for the AI provider\n" printf " ${GREEN}-v, --verbose${NC} Enable verbose logging\n" printf " ${GREEN}-h, --help${NC} Display this help message\n" @@ -71,7 +71,7 @@ parse_arguments() { -ai|--ai-provider) AI_PROVIDER=$2 log_verbose "AI provider set to: " "$AI_PROVIDER" - if [[ "$AI_PROVIDER" != "openai" && "$AI_PROVIDER" != "claudeai" ]]; then + if [[ "$AI_PROVIDER" != "openai" && "$AI_PROVIDER" != "claudeai" && "$AI_PROVIDER" != "deepseek" ]]; then log_verbose "Invalid AI provider specified" echo -e "${RED}Invalid AI provider. Please use 'openai' or 'claudeai'.${NC}\n" exit 1 diff --git a/src/config.ts b/src/config.ts index 1fdc289..f23d0cc 100644 --- a/src/config.ts +++ b/src/config.ts @@ -42,4 +42,9 @@ export const appConfig = validateConfig({ required: false, type: (value: any) => value as 'development' | 'production', }, + DEEPSEEK_API_KEY: { + value: process.env.DEEPSEEK_API_KEY, + required: true, + type: (value: any) => String(value), + }, }); diff --git a/src/handler.ts b/src/handler.ts index 47d9474..d050321 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -120,7 +120,7 @@ export function postGenerateCommitMessageHandler(ai: (type?: Provider) => AIServ throw new ValidationError('Diff must not be empty!'); } - if (provider && provider !== 'openai' && provider !== 'claudeai') { + if (provider && provider !== 'openai' && provider !== 'claudeai' && provider !== 'deepseek') { throw new ValidationError('Invalid provider specified!'); } diff --git a/src/types.ts b/src/types.ts index 8e92780..c9566f3 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,6 +1,6 @@ import { Request } from 'express'; -export type Provider = 'openai' | 'claudeai'; +export type Provider = 'openai' | 'claudeai' | 'deepseek'; export interface GenerateCommitMessageRequest extends Request { body: { @@ -27,7 +27,7 @@ export interface ConfigItem { readonly required: boolean; } -export interface Logger { +export interface LoggerType { debug: (...value: any) => void; error: (...value: any) => void; info: (...value: any) => void; diff --git a/src/util.ts b/src/util.ts index 6fe1e1a..48a47ee 100644 --- a/src/util.ts +++ b/src/util.ts @@ -2,7 +2,7 @@ import fastq from 'fastq'; import { Request } from 'express'; import { styleText } from 'node:util'; import { appConfig } from './config'; -import { CacheType, ConfigItem, Logger } from './types'; +import { CacheType, ConfigItem, LoggerType } from './types'; export const sendNotificationQueue = fastq.promise(sendNotification, 1); @@ -81,7 +81,7 @@ function Cache(): CacheType { export const cache = Cache(); -export const logger: Logger = { +export const logger: LoggerType = { debug: (...value: any) => { const timestamp = new Date().toLocaleString(); console.debug(styleText('red', `🐛 ${timestamp} ${value}`));