From 0ec7504e9270f73de6f0441deba78883fc0c42b4 Mon Sep 17 00:00:00 2001 From: wChenonly Date: Fri, 24 Jan 2025 11:29:19 +0800 Subject: [PATCH] feat: add deepseek --- bun.lockb | Bin 127927 -> 128560 bytes package.json | 12 +++-- setup.md | 2 +- src/args.ts | 9 ++-- src/common/model/AIModel.ts | 90 ++++++++++++++++++++++++++++-------- src/common/types.ts | 17 +++++-- src/review/constants.ts | 18 ++++++-- src/review/llm/askAI.ts | 7 ++- src/test/run/runTest.ts | 10 ++-- 9 files changed, 122 insertions(+), 43 deletions(-) diff --git a/bun.lockb b/bun.lockb index 3b16506c80b75f936883541e1600d26b8a7ab123..058c590a9b50db370a75580c96d20f8e95b595ee 100755 GIT binary patch delta 24115 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 delta 23675 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 F{{?4L4afih diff --git a/package.json b/package.json index 7d267f16..12d847a1 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,10 @@ "huggingface", "ai", "genai", - "llama" + "llama", + "deepseek", + "deepseek-chat", + "deepseek-R1" ], "author": "Matt Carey", "license": "MIT", @@ -55,7 +58,8 @@ "tinyglobby": "^0.2.10", "tslog": "^4.8.2", "yargs": "^17.7.2", - "zod": "^3.24.1" + "zod": "^3.24.1", + "openai": "^4.79.4" }, "devDependencies": { "@biomejs/biome": "^1.9.4", @@ -66,7 +70,5 @@ "npm-dts": "^1.3.12", "typescript": "^5.1.6" }, - "files": [ - "dist/*" - ] + "files": ["dist/*"] } diff --git a/setup.md b/setup.md index 6199ec94..647b78a0 100644 --- a/setup.md +++ b/setup.md @@ -103,7 +103,7 @@ You can now run `code-review-gpt review` in the root directory of any git-enable ### Options -- `--ci` - Used with the `review` command. Options are --ci=("github" | "gitlab"). Defaults to "github" if no option is specified. Runs the application in CI mode. This will use the BASE_SHA and GITHUB_SHA environment variables to determine which files to review. It will also use the GITHUB_TOKEN environment variable to create a comment on the pull request with the review results. +- `--ci` - Used with the `review` command. Options are --ci=("github" | "gitlab" | "azdev"). Defaults to "github" if no option is specified. Runs the application in CI mode. This will use the BASE_SHA and GITHUB_SHA environment variables to determine which files to review. It will also use the GITHUB_TOKEN environment variable to create a comment on the pull request with the review results. - `--reviewType` - Used with the 'review' command. The options are --reviewType=("changed" | "full" | "costOptimized). Defaults to "changed" if no option is specified. Specifies whether the review is for the full file or just the changed lines. costOptimized limits the context surrounding the changed lines to 5 lines. diff --git a/src/args.ts b/src/args.ts index b5a4420b..e4032670 100644 --- a/src/args.ts +++ b/src/args.ts @@ -2,7 +2,7 @@ import rawlist from '@inquirer/rawlist'; import dotenv from 'dotenv'; import yargs from 'yargs'; import { hideBin } from 'yargs/helpers'; - +import { modelsNames } from './review/constants'; import type { ReviewArgs } from './common/types'; dotenv.config(); @@ -22,7 +22,7 @@ const handleNoCommand = async (): Promise => { return command; }; -export const getYargs = async (): Promise => { +export const getYargs = async () => { return yargs(hideBin(process.argv)) .command('configure', 'Configure the tool') .command('review', 'Review code changes') @@ -49,6 +49,7 @@ export const getYargs = async (): Promise => { }) .option('model', { description: 'The model to use for generating the review.', + choices: modelsNames, type: 'string', default: 'gpt-4o-mini', }) @@ -82,10 +83,10 @@ export const getYargs = async (): Promise => { }) .option('provider', { description: 'Provider to use for AI', - choices: ['openai', 'azureai', 'bedrock'], + choices: ['openai', 'azureai', 'bedrock', 'deepseek'], type: 'string', default: 'openai', }) .help() - .parse(); + .parse() as ReviewArgs; }; diff --git a/src/common/model/AIModel.ts b/src/common/model/AIModel.ts index 7d8b2400..35dd6d34 100644 --- a/src/common/model/AIModel.ts +++ b/src/common/model/AIModel.ts @@ -1,20 +1,22 @@ import { ChatOpenAI, AzureChatOpenAI } from '@langchain/openai'; - +import { OpenAI as DeepSeekAI } from 'openai'; import type { ZodType } from 'zod'; import type { IFeedback } from '../types'; import { logger } from '../utils/logger'; +import type { AIModelName } from '../../review/constants'; +import type { ProviderOptions } from '../../common/types'; interface IAIModel { - modelName: string; - provider: string; + modelName: AIModelName; + provider: ProviderOptions; temperature: number; apiKey: string; retryCount?: number; - organization: string | undefined; + organization?: string; } export class AIModel { - private model: ChatOpenAI; + private model: ChatOpenAI | ReturnType; constructor(options: IAIModel) { switch (options.provider) { @@ -26,11 +28,19 @@ export class AIModel { modelName: options.modelName, }); break; - case "azureai": + case 'azureai': this.model = new AzureChatOpenAI({ temperature: options.temperature, }); break; + case 'deepseek': + this.model = createDeepSeekModel({ + apiKey: options.apiKey, + baseURL: 'https://api.deepseek.com', + temperature: options.temperature, + model: options.modelName as Extract, + }); + break; case 'bedrock': throw new Error('Bedrock provider not implemented'); default: @@ -39,25 +49,33 @@ export class AIModel { } public async callModel(prompt: string): Promise { - const message = await this.model.invoke(prompt); - return message.content[0] as string; + if ('callModel' in this.model) { + return this.model.callModel(prompt); + } else { + const message = await this.model.invoke(prompt); + return message.content[0] as string; + } } public async callStructuredModel(prompt: string, schema: ZodType): Promise { - const modelWithStructuredOutput = this.model.withStructuredOutput(schema, { - method: 'jsonSchema', - strict: true, - includeRaw: true, - }); - const res = await modelWithStructuredOutput.invoke(prompt); + if ('callStructuredModel' in this.model) { + return this.model.callStructuredModel(prompt); + } else { + const modelWithStructuredOutput = this.model.withStructuredOutput(schema, { + method: 'jsonSchema', + strict: true, + includeRaw: true, + }); + const res = await modelWithStructuredOutput.invoke(prompt); - logger.debug('LLm response', res); + logger.debug('LLm response', res); - if (res.parsed) { - return res.parsed; - } + if (res.parsed) { + return res.parsed; + } - return parseJson(res.raw.content[0] as string); + return parseJson(res.raw.content[0] as string); + } } } @@ -80,3 +98,37 @@ const parseJson = (json: string) => { logger.debug('Escaped JSON', jsonString); return JSON.parse(jsonString); }; + +interface DeepSeekOptions { + apiKey: string; + baseURL: string; + temperature: number; // https://api-docs.deepseek.com/quick_start/parameter_settings 0.0 | 1.0 | 1.3 | 1.5 + model: Extract; +} + +function createDeepSeekModel(options: DeepSeekOptions) { + const { apiKey, baseURL, temperature = 1.0, model } = options; + + const client = new DeepSeekAI({ baseURL, apiKey }); + + return { + callModel: async (prompt: string) => { + const completion = await client.chat.completions.create({ + messages: [{ role: 'user', content: prompt }], + model, + temperature, + }); + return completion.choices[0].message.content as string; + }, + + callStructuredModel: async (prompt: string): Promise => { + const completion = await client.chat.completions.create({ + messages: [{ role: 'user', content: prompt }], + model, + temperature, + }); + const content = completion.choices[0].message.content; + return parseJson(content as string); + }, + }; +} diff --git a/src/common/types.ts b/src/common/types.ts index 6e7fb8a3..41a42cbe 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -1,5 +1,6 @@ import type { z } from 'zod'; import type { feedbackSchema, reviewSchema } from '../review/prompt/schemas'; +import type { AIModelName } from '../review/constants'; export type AskAIResponse = { markdownReport: string; @@ -35,17 +36,23 @@ export enum PlatformOptions { AZDEV = 'azdev', } +export type CIOptions = 'github' | 'gitlab' | 'azdev'; + +export type ProviderOptions = 'openai' | 'azureai' | 'bedrock' | 'deepseek'; + +export type ReviewType = 'full' | 'changed' | 'costOptimized'; + export type ReviewArgs = { [x: string]: unknown; - ci: string | undefined; - setupTarget: string; + ci: CIOptions | undefined; + setupTarget: CIOptions; commentPerFile: boolean; - model: string; - reviewType: string; + model: AIModelName; + reviewType: ReviewType; reviewLanguage: string | undefined; org: string | undefined; remote: string | undefined; - provider: string; + provider: ProviderOptions; _: (string | number)[]; $0: string; }; diff --git a/src/review/constants.ts b/src/review/constants.ts index acfb1322..32992936 100644 --- a/src/review/constants.ts +++ b/src/review/constants.ts @@ -1,6 +1,8 @@ export const signOff = '#### Powered by [Code Review GPT](https://github.com/mattzcarey/code-review-gpt)'; +export type AIModelName = (typeof modelInfo)[number]['model']; + export const modelInfo = [ { model: 'gpt-4o-mini', @@ -34,9 +36,19 @@ export const modelInfo = [ model: 'gpt-3.5-turbo-16k', maxPromptLength: 45000, //16k tokens }, -]; // Response needs about 1k tokens ~= 3k characters + { + model: 'deepseek-chat', + maxPromptLength: 180000, //64k tokens + }, + { + model: 'deepseek-reasoner', + maxPromptLength: 180000, //64k tokens + }, +] as const; // Response needs about 1k tokens ~= 3k characters + +export const modelsNames = modelInfo.map((item) => item.model); -export const languageMap: { [key: string]: string } = { +export const languageMap = { '.js': 'JavaScript', '.ts': 'TypeScript', '.py': 'Python', @@ -61,7 +73,7 @@ export const languageMap: { [key: string]: string } = { '.tf': 'Terraform', '.hcl': 'Terraform', '.swift': 'Swift', -}; +} as const; export const supportedFiles = new Set(Object.keys(languageMap)); diff --git a/src/review/llm/askAI.ts b/src/review/llm/askAI.ts index e395d006..b3f8a063 100644 --- a/src/review/llm/askAI.ts +++ b/src/review/llm/askAI.ts @@ -3,13 +3,16 @@ import type { AskAIResponse } from '../../common/types'; import { logger } from '../../common/utils/logger'; import { processFeedbacks } from './feedbackProcessor'; import { markdownReport } from './generateMarkdownReport'; +import { AIModelName } from '../constants'; + +import type { ProviderOptions } from '../../common/types'; export const askAI = async ( prompts: string[], - modelName: string, + modelName: AIModelName, openAIApiKey: string, organization: string | undefined, - provider: string + provider: ProviderOptions ): Promise => { logger.info('Asking the experts...'); diff --git a/src/test/run/runTest.ts b/src/test/run/runTest.ts index 3b70aeda..db9e77c0 100644 --- a/src/test/run/runTest.ts +++ b/src/test/run/runTest.ts @@ -5,6 +5,8 @@ import { logger } from '../../common/utils/logger'; import { askAI } from '../../review/llm/askAI'; import { constructPromptsArray } from '../../review/prompt/constructPrompt/constructPrompt'; import type { TestCase } from '../types'; +import type { AIModelName } from '../../review/constants'; +import type { ReviewType } from '../../common/types'; import { generateTestReport, generateTestResultsSummary, @@ -25,10 +27,10 @@ import { const runTest = async ( openAIApiKey: string, testCase: TestCase, - modelName: string, + modelName: AIModelName, maxPromptLength: number, vectorStore: MemoryVectorStore, - reviewType: string, + reviewType: ReviewType, reviewLanguage?: string // eslint-disable-next-line max-params ): Promise => { @@ -88,10 +90,10 @@ const runTest = async ( export const runTests = async ( openAIApiKey: string, testCases: TestCase[], - modelName: string, + modelName: AIModelName, maxPromptLength: number, vectorStore: MemoryVectorStore, - reviewType: string, + reviewType: ReviewType, reviewLanguage?: string // eslint-disable-next-line max-params ): Promise => {