Gemini added

This commit is contained in:
Piyu-Pika 2024-10-29 18:05:07 +05:30
parent 0f0719c596
commit 0c8a185df7
4 changed files with 105 additions and 10 deletions

View file

@ -7,6 +7,9 @@
"": {
"name": "void",
"version": "0.0.1",
"dependencies": {
"@google/generative-ai": "^0.21.0"
},
"devDependencies": {
"@anthropic-ai/sdk": "^0.29.2",
"@eslint/js": "^9.9.1",
@ -737,6 +740,15 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@google/generative-ai": {
"version": "0.21.0",
"resolved": "https://registry.npmjs.org/@google/generative-ai/-/generative-ai-0.21.0.tgz",
"integrity": "sha512-7XhUbtnlkSEZK15kN3t+tzIMxsbKm/dSkKBFalj+20NvPKe1kBY7mR2P7vuijEn+f06z5+A8bVGKO0v39cr6Wg==",
"license": "Apache-2.0",
"engines": {
"node": ">=18.0.0"
}
},
"node_modules/@humanwhocodes/config-array": {
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
@ -6013,6 +6025,14 @@
"node": ">=10"
}
},
"node_modules/monaco-editor": {
"version": "0.52.0",
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.0.tgz",
"integrity": "sha512-OeWhNpABLCeTqubfqLMXGsqf6OmPU6pHM85kF3dhy6kq5hnhuVS1p3VrEW/XhWHc71P2tHyS5JFySD8mgs1crw==",
"dev": true,
"license": "MIT",
"peer": true
},
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",

View file

@ -151,5 +151,8 @@
"typescript": "5.5.4",
"typescript-eslint": "^8.3.0",
"uuid": "^10.0.0"
},
"dependencies": {
"@google/generative-ai": "^0.21.0"
}
}

View file

@ -1,6 +1,7 @@
import Anthropic from '@anthropic-ai/sdk';
import OpenAI from 'openai';
import { Ollama } from 'ollama/browser'
import { GoogleGenerativeAI } from '@google/generative-ai';
import { VoidConfig } from '../webviews/common/contextForConfig'
export type AbortRef = { current: (() => void) | null }
@ -37,8 +38,6 @@ type SendLLMMessageFnTypeExternal = (params: {
abortRef: AbortRef,
}) => void
const parseMaxTokensStr = (maxTokensStr: string) => {
// parse the string but only if the full string is a valid number, eg parseInt('100abc') should return NaN
let int = isNaN(Number(maxTokensStr)) ? undefined : parseInt(maxTokensStr)
@ -103,8 +102,72 @@ const sendAnthropicMsg: SendLLMMessageFnTypeInternal = ({ messages, onText, onFi
return { abort }
};
// Gemini
const sendGeminiMsg: SendLLMMessageFnTypeInternal = async ({ messages, onText, onFinalMessage, onError, voidConfig, abortRef }) => {
let didAbort = false
let fullText = ''
abortRef.current = () => {
didAbort = true
}
try {
const genAI = new GoogleGenerativeAI(voidConfig.gemini.apikey);
// Force the model to be exactly what's configured
const modelName = voidConfig.gemini.model;
const model = genAI.getGenerativeModel({ model: modelName });
// Combine system messages with the first user message
let systemContent = messages
.filter(msg => msg.role === 'system')
.map(msg => msg.content)
.join('\n');
// Filter out system messages and modify first user message if needed
let geminiMessages = messages.filter(msg => msg.role !== 'system');
if (systemContent && geminiMessages.length > 0 && geminiMessages[0].role === 'user') {
geminiMessages[0] = {
...geminiMessages[0],
content: `${systemContent}\n\n${geminiMessages[0].content}`
};
}
// Convert remaining messages to Gemini format
const history = geminiMessages.map(msg => ({
role: msg.role === 'assistant' ? 'model' : msg.role,
parts: [{ text: msg.content }]
}));
const chat = model.startChat({
history: history.slice(0, -1), // Exclude last message
generationConfig: {
maxOutputTokens: parseInt(voidConfig.default.maxTokens)
// Removed model from generationConfig since it's not a valid property
// Model is already set when creating the model instance above
}
});
const lastMessage = messages[messages.length - 1].content;
const result = await chat.sendMessageStream(lastMessage);
for await (const chunk of result.stream) {
if (didAbort) return;
const newText = chunk.text();
fullText += newText;
onText(newText, fullText);
}
onFinalMessage(fullText);
} catch (error: unknown) {
if (error instanceof Error && error.message?.includes('API key')) {
onError('Invalid API key.');
} else if (error instanceof Error) {
onError(error.message || 'Error connecting to Gemini');
} else {
onError('Error connecting to Gemini');
}
}
};
// OpenAI, OpenRouter, OpenAICompatible
const sendOpenAIMsg: SendLLMMessageFnTypeInternal = ({ messages, onText, onFinalMessage, onError, voidConfig, abortRef }) => {
@ -178,7 +241,6 @@ const sendOpenAIMsg: SendLLMMessageFnTypeInternal = ({ messages, onText, onFinal
};
// Ollama
export const sendOllamaMsg: SendLLMMessageFnTypeInternal = ({ messages, onText, onFinalMessage, onError, voidConfig, abortRef }) => {
@ -220,8 +282,6 @@ export const sendOllamaMsg: SendLLMMessageFnTypeInternal = ({ messages, onText,
};
// Greptile
// https://docs.greptile.com/api-reference/query
// https://docs.greptile.com/quickstart#sample-response-streamed
@ -236,7 +296,6 @@ const sendGreptileMsg: SendLLMMessageFnTypeInternal = ({ messages, onText, onFin
didAbort = true
}
fetch('https://api.greptile.com/v2/query', {
method: 'POST',
headers: {
@ -291,8 +350,6 @@ const sendGreptileMsg: SendLLMMessageFnTypeInternal = ({ messages, onText, onFin
}
export const sendLLMMessage: SendLLMMessageFnTypeExternal = ({ messages, onText, onFinalMessage, onError, voidConfig, abortRef }) => {
if (!voidConfig) return;
@ -310,6 +367,8 @@ export const sendLLMMessage: SendLLMMessageFnTypeExternal = ({ messages, onText,
return sendOllamaMsg({ messages, onText, onFinalMessage, onError, voidConfig, abortRef });
case 'greptile':
return sendGreptileMsg({ messages, onText, onFinalMessage, onError, voidConfig, abortRef });
case 'gemini':
return sendGeminiMsg({ messages, onText, onFinalMessage, onError, voidConfig, abortRef });
default:
onError(`Error: whichApi was ${voidConfig.default.whichApi}, which is not recognized!`)
}

View file

@ -25,7 +25,8 @@ export const configFields = [
'ollama',
'openRouter',
'openAICompatible',
'azure'
'azure',
'gemini'
] as const
@ -164,6 +165,19 @@ const voidConfigInfo: Record<
// }
// },
},
gemini: {
apikey: configString('Google API key.', ''),
model: configEnum(
'Gemini model to use.',
'gemini-1.5-flash',
[
"gemini-1.5-flash",
"gemini-1.5-pro",
"gemini-1.5-flash-8b",
"gemini-1.0-pro"
] as const
),
},
}
@ -273,4 +287,3 @@ export function useVoidConfig(): ConfigValueType {
}
return context
}