From 8580148dd5182213dc2a8c643f360cfd6c142890 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 26 May 2025 19:18:09 +0000 Subject: [PATCH] feat: Integrate Google Gemini API support Adds support for using the Google Gemini API via an API key. Key changes include: - Configuration: - Added `geminiApiKey` to `defaultConfig` in `src/config/index.mjs`. - Defined `geminiApiModelKeys` and added 'Gemini (API, Pro)' to `Models` and `ModelGroups`. - Added 'geminiApiPro' to the default `activeApiModes`. - API Client: - Created `src/services/apis/gemini-api.mjs` with logic to connect to the Gemini API using the configured API key. Includes placeholder for the exact API endpoint and payload structure. - User Interface: - Added an input field in `src/popup/sections/GeneralPart.jsx` for you to enter your Gemini API key. This field is conditionally displayed when a Gemini API model is active. - Integration: - Updated `src/background/index.mjs` to route requests to the `generateAnswersWithGeminiApi` client when a Gemini model is selected. Manual testing with a valid Gemini API key is required to fully verify the functionality. --- src/background/index.mjs | 4 ++ src/config/index.mjs | 13 ++++++ src/popup/sections/GeneralPart.jsx | 13 ++++++ src/services/apis/gemini-api.mjs | 73 ++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+) create mode 100644 src/services/apis/gemini-api.mjs diff --git a/src/background/index.mjs b/src/background/index.mjs index 6fde2d48..bd0f87ee 100644 --- a/src/background/index.mjs +++ b/src/background/index.mjs @@ -33,6 +33,7 @@ import { isUsingClaudeWebModel, isUsingMoonshotApiModel, isUsingMoonshotWebModel, + isUsingGeminiApiModel, } from '../config/index.mjs' import '../_locales/i18n' import { openUrl } from '../utils/open-url' @@ -49,6 +50,7 @@ import { generateAnswersWithBardWebApi } from '../services/apis/bard-web.mjs' import { generateAnswersWithClaudeWebApi } from '../services/apis/claude-web.mjs' import { generateAnswersWithMoonshotCompletionApi } from '../services/apis/moonshot-api.mjs' import { generateAnswersWithMoonshotWebApi } from '../services/apis/moonshot-web.mjs' +import { generateAnswersWithGeminiApi } from '../services/apis/gemini-api.mjs' // Added import import { isUsingModelName } from '../utils/model-name-convert.mjs' function setPortProxy(port, proxyTabId) { @@ -140,6 +142,8 @@ async function executeApi(session, port, config) { session, config.moonshotApiKey, ) + } else if (isUsingGeminiApiModel(session)) { // Added Gemini condition + await generateAnswersWithGeminiApi(port, session.question, session) } else if (isUsingChatGLMApiModel(session)) { await generateAnswersWithChatGLMApi(port, session.question, session) } else if (isUsingOllamaApiModel(session)) { diff --git a/src/config/index.mjs b/src/config/index.mjs index 1322216d..dee243bd 100644 --- a/src/config/index.mjs +++ b/src/config/index.mjs @@ -88,6 +88,7 @@ export const poeWebModelKeys = [ 'poeAiWeb_Llama_2_70b', ] export const moonshotApiModelKeys = ['moonshot_v1_8k', 'moonshot_v1_32k', 'moonshot_v1_128k'] +export const geminiApiModelKeys = ['geminiApiPro'] export const AlwaysCustomGroups = [ 'ollamaApiModelKeys', @@ -130,6 +131,10 @@ export const ModelGroups = { value: moonshotApiModelKeys, desc: 'Kimi.Moonshot (API)', }, + geminiApiModelKeys: { + value: geminiApiModelKeys, + desc: 'Gemini (API)', + }, chatglmApiModelKeys: { value: chatglmApiModelKeys, desc: 'ChatGLM (API)', @@ -267,6 +272,8 @@ export const Models = { value: 'moonshot-v1-128k', desc: 'Kimi.Moonshot (128k)', }, + + geminiApiPro: { value: 'gemini-pro', desc: 'Gemini (API, Pro)' }, } for (const modelName in Models) { @@ -317,6 +324,7 @@ export const defaultConfig = { claudeApiKey: '', chatglmApiKey: '', moonshotApiKey: '', + geminiApiKey: '', customApiKey: '', @@ -366,6 +374,7 @@ export const defaultConfig = { 'bingFree4', 'moonshotWebFree', 'moonshot_v1_8k', + 'geminiApiPro', // Added Gemini API model 'chatglmTurbo', 'customModel', 'azureOpenAi', @@ -508,6 +517,10 @@ export function isUsingMoonshotApiModel(configOrSession) { return isInApiModeGroup(moonshotApiModelKeys, configOrSession) } +export function isUsingGeminiApiModel(configOrSession) { + return isInApiModeGroup(geminiApiModelKeys, configOrSession) +} + export function isUsingChatGLMApiModel(configOrSession) { return isInApiModeGroup(chatglmApiModelKeys, configOrSession) } diff --git a/src/popup/sections/GeneralPart.jsx b/src/popup/sections/GeneralPart.jsx index 3db270ce..1e791ad0 100644 --- a/src/popup/sections/GeneralPart.jsx +++ b/src/popup/sections/GeneralPart.jsx @@ -21,6 +21,7 @@ import { ThemeMode, TriggerMode, isUsingMoonshotApiModel, + isUsingGeminiApiModel, // Added import Models, } from '../../config/index.mjs' import Browser from 'webextension-polyfill' @@ -331,6 +332,18 @@ export function GeneralPart({ config, updateConfig, setTabIndex }) { )} )} + {isUsingGeminiApiModel(config) && ( + { + const apiKey = e.target.value + updateConfig({ geminiApiKey: apiKey }) + }} + /> + )} {isUsingSpecialCustomModel(config) && ( ({ message: response.statusText })); + console.error('Gemini API error:', errorData); + port.postMessage({ error: `Gemini API error: ${errorData.error?.message || errorData.message || 'Unknown error'}`, done: true, session }); + return; + } + + const responseData = await response.json(); + + // Extract the answer from the responseData + // This is a placeholder and needs to be verified against actual Gemini API response structure + // Expected structure: responseData.candidates[0].content.parts[0].text + let answer = 'No response from Gemini API.'; + if (responseData.candidates && responseData.candidates[0] && responseData.candidates[0].content && responseData.candidates[0].content.parts && responseData.candidates[0].content.parts[0]) { + answer = responseData.candidates[0].content.parts[0].text; + } else { + console.error('Unexpected Gemini API response structure:', responseData); + } + + pushRecord(session, question, answer); + // console.debug('Gemini conversation history', { content: session.conversationRecords }); + port.postMessage({ answer: answer, done: true, session: session }); + + } catch (err) { + console.error('Error in generateAnswersWithGeminiApi:', err); + port.postMessage({ error: err.message || 'Failed to communicate with Gemini API.', done: true, session }); + } +}