From 3ceb227507b11f27ddc5f676ec4b5e824def9389 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Wed, 18 Dec 2024 12:13:16 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20feat:=20Google=20Revers?= =?UTF-8?q?e=20Proxy=20support,=20`CIVIC=5FINTEGRITY`=20harm=20category=20?= =?UTF-8?q?(#5037)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🛡️ feat: Google Reverse Proxy support, `CIVIC_INTEGRITY` harm category * 🔧 chore: Update @langchain/google-vertexai to version 0.1.4 in package.json and package-lock.json * fix: revert breaking Vertex AI changes --------- Co-authored-by: KiGamji --- .env.example | 4 + api/app/clients/GoogleClient.js | 34 ++++-- api/package.json | 2 +- .../services/Endpoints/google/initialize.js | 9 +- package-lock.json | 102 ++++++++++-------- 5 files changed, 98 insertions(+), 53 deletions(-) diff --git a/.env.example b/.env.example index 989df12618..eaa9c478d5 100644 --- a/.env.example +++ b/.env.example @@ -138,7 +138,10 @@ BINGAI_TOKEN=user_provided #============# GOOGLE_KEY=user_provided + # GOOGLE_REVERSE_PROXY= +# Some reverse proxies do not support the X-goog-api-key header, uncomment to pass the API key in Authorization header instead. +# GOOGLE_AUTH_HEADER=true # Gemini API (AI Studio) # GOOGLE_MODELS=gemini-2.0-flash-exp,gemini-exp-1121,gemini-exp-1114,gemini-1.5-flash-latest,gemini-1.0-pro,gemini-1.0-pro-001,gemini-1.0-pro-latest,gemini-1.0-pro-vision-latest,gemini-1.5-pro-latest,gemini-pro,gemini-pro-vision @@ -167,6 +170,7 @@ GOOGLE_KEY=user_provided # GOOGLE_SAFETY_HATE_SPEECH=BLOCK_ONLY_HIGH # GOOGLE_SAFETY_HARASSMENT=BLOCK_ONLY_HIGH # GOOGLE_SAFETY_DANGEROUS_CONTENT=BLOCK_ONLY_HIGH +# GOOGLE_SAFETY_CIVIC_INTEGRITY=BLOCK_ONLY_HIGH #============# # OpenAI # diff --git a/api/app/clients/GoogleClient.js b/api/app/clients/GoogleClient.js index ab1094b776..15f2e6dc63 100644 --- a/api/app/clients/GoogleClient.js +++ b/api/app/clients/GoogleClient.js @@ -30,8 +30,7 @@ const BaseClient = require('./BaseClient'); const loc = process.env.GOOGLE_LOC || 'us-central1'; const publisher = 'google'; -const endpointPrefix = `https://${loc}-aiplatform.googleapis.com`; -// const apiEndpoint = loc + '-aiplatform.googleapis.com'; +const endpointPrefix = `${loc}-aiplatform.googleapis.com`; const tokenizersCache = {}; const settings = endpointSettings[EModelEndpoint.google]; @@ -58,6 +57,10 @@ class GoogleClient extends BaseClient { this.apiKey = creds[AuthKeys.GOOGLE_API_KEY]; + this.reverseProxyUrl = options.reverseProxyUrl; + + this.authHeader = options.authHeader; + if (options.skipSetOptions) { return; } @@ -66,7 +69,7 @@ class GoogleClient extends BaseClient { /* Google specific methods */ constructUrl() { - return `${endpointPrefix}/v1/projects/${this.project_id}/locations/${loc}/publishers/${publisher}/models/${this.modelOptions.model}:serverStreamingPredict`; + return `https://${endpointPrefix}/v1/projects/${this.project_id}/locations/${loc}/publishers/${publisher}/models/${this.modelOptions.model}:serverStreamingPredict`; } async getClient() { @@ -595,7 +598,21 @@ class GoogleClient extends BaseClient { createLLM(clientOptions) { const model = clientOptions.modelName ?? clientOptions.model; clientOptions.location = loc; - clientOptions.endpoint = `${loc}-aiplatform.googleapis.com`; + clientOptions.endpoint = endpointPrefix; + + let requestOptions = null; + if (this.reverseProxyUrl) { + requestOptions = { + baseUrl: this.reverseProxyUrl, + }; + + if (this.authHeader) { + requestOptions.customHeaders = { + Authorization: `Bearer ${this.apiKey}`, + }; + } + } + if (this.project_id && this.isTextModel) { logger.debug('Creating Google VertexAI client'); return new GoogleVertexAI(clientOptions); @@ -607,10 +624,7 @@ class GoogleClient extends BaseClient { return new ChatVertexAI(clientOptions); } else if (!EXCLUDED_GENAI_MODELS.test(model)) { logger.debug('Creating GenAI client'); - return new GenAI(this.apiKey).getGenerativeModel({ - ...clientOptions, - model, - }); + return new GenAI(this.apiKey).getGenerativeModel({ ...clientOptions, model }, requestOptions); } logger.debug('Creating Chat Google Generative AI client'); @@ -901,6 +915,10 @@ class GoogleClient extends BaseClient { threshold: process.env.GOOGLE_SAFETY_DANGEROUS_CONTENT || 'HARM_BLOCK_THRESHOLD_UNSPECIFIED', }, + { + category: 'HARM_CATEGORY_CIVIC_INTEGRITY', + threshold: process.env.GOOGLE_SAFETY_CIVIC_INTEGRITY || 'HARM_BLOCK_THRESHOLD_UNSPECIFIED', + }, ]; } diff --git a/api/package.json b/api/package.json index dc14a6db7d..a9220ad3c7 100644 --- a/api/package.json +++ b/api/package.json @@ -42,7 +42,7 @@ "@langchain/community": "^0.3.14", "@langchain/core": "^0.3.18", "@langchain/google-genai": "^0.1.4", - "@langchain/google-vertexai": "^0.1.2", + "@langchain/google-vertexai": "^0.1.4", "@langchain/textsplitters": "^0.1.0", "@librechat/agents": "^1.8.8", "axios": "^1.7.7", diff --git a/api/server/services/Endpoints/google/initialize.js b/api/server/services/Endpoints/google/initialize.js index 788375e1e7..f601c8e403 100644 --- a/api/server/services/Endpoints/google/initialize.js +++ b/api/server/services/Endpoints/google/initialize.js @@ -1,9 +1,15 @@ const { EModelEndpoint, AuthKeys } = require('librechat-data-provider'); const { getUserKey, checkUserKeyExpiry } = require('~/server/services/UserService'); const { GoogleClient } = require('~/app'); +const { isEnabled } = require('~/server/utils'); const initializeClient = async ({ req, res, endpointOption }) => { - const { GOOGLE_KEY, GOOGLE_REVERSE_PROXY, PROXY } = process.env; + const { + GOOGLE_KEY, + GOOGLE_REVERSE_PROXY, + GOOGLE_AUTH_HEADER, + PROXY, + } = process.env; const isUserProvided = GOOGLE_KEY === 'user_provided'; const { key: expiresAt } = req.body; @@ -46,6 +52,7 @@ const initializeClient = async ({ req, res, endpointOption }) => { req, res, reverseProxyUrl: GOOGLE_REVERSE_PROXY ?? null, + authHeader: isEnabled(GOOGLE_AUTH_HEADER) ?? null, proxy: PROXY ?? null, ...clientOptions, ...endpointOption, diff --git a/package-lock.json b/package-lock.json index 7735e8879b..e01dd0351d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,7 +51,7 @@ "@langchain/community": "^0.3.14", "@langchain/core": "^0.3.18", "@langchain/google-genai": "^0.1.4", - "@langchain/google-vertexai": "^0.1.2", + "@langchain/google-vertexai": "^0.1.4", "@langchain/textsplitters": "^0.1.0", "@librechat/agents": "^1.8.8", "axios": "^1.7.7", @@ -682,6 +682,20 @@ "@langchain/core": ">=0.3.17 <0.4.0" } }, + "api/node_modules/@langchain/google-vertexai": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@langchain/google-vertexai/-/google-vertexai-0.1.4.tgz", + "integrity": "sha512-x78wezYBOxmiMOPSatlCk4UOQd6RPxz2YVfGKLOzNV89xxHrEVX9JcyRUCx4L568S4kqZYkLvnqzZA9AF/TCaA==", + "dependencies": { + "@langchain/google-gauth": "~0.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@langchain/core": ">=0.2.21 <0.4.0" + } + }, "api/node_modules/@langchain/textsplitters": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@langchain/textsplitters/-/textsplitters-0.1.0.tgz", @@ -9835,6 +9849,48 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/@langchain/google-common": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@langchain/google-common/-/google-common-0.1.4.tgz", + "integrity": "sha512-EIpJYhat+BpGXRJiLSKKWlbBl88AJLnwGhLNOh85nNPtcqKqWTIJ/WGVNfFNsrAwHZ+f77gZeNfefeRIrChNZw==", + "dependencies": { + "uuid": "^10.0.0", + "zod-to-json-schema": "^3.22.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@langchain/core": ">=0.2.21 <0.4.0" + } + }, + "node_modules/@langchain/google-common/node_modules/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/@langchain/google-gauth": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@langchain/google-gauth/-/google-gauth-0.1.4.tgz", + "integrity": "sha512-g/yXfGCgBU5FkH/lW4L0E2HDvQ3JuS5/KZylixWwkV+hk9gSyYcMV3RnhMjp+zEY/68XALiqlwUyvfK5vToz4g==", + "dependencies": { + "@langchain/google-common": "~0.1.4", + "google-auth-library": "^8.9.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@langchain/core": ">=0.2.21 <0.4.0" + } + }, "node_modules/@langchain/google-genai": { "version": "0.0.11", "resolved": "https://registry.npmjs.org/@langchain/google-genai/-/google-genai-0.0.11.tgz", @@ -9931,6 +9987,8 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/@langchain/google-vertexai/-/google-vertexai-0.1.2.tgz", "integrity": "sha512-b8Di2AgSwlyyKl4A5qii+19Wj82I1KvtUXSDvJpDzhucuyrJjmnNb/0ClkaIQv6RyISajtxszxxSGHukPn3PJA==", + "optional": true, + "peer": true, "dependencies": { "@langchain/google-gauth": "~0.1.2" }, @@ -9941,48 +9999,6 @@ "@langchain/core": ">=0.2.21 <0.4.0" } }, - "node_modules/@langchain/google-vertexai/node_modules/@langchain/google-common": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@langchain/google-common/-/google-common-0.1.2.tgz", - "integrity": "sha512-3A7vUr2WObCFUusM/Wl0yZN7QGGXboXyparORkZdv0RnGngPm6tBmqbAyWYmT8R9aQNHqzBKDEQBiSRvTxao1w==", - "dependencies": { - "uuid": "^10.0.0", - "zod-to-json-schema": "^3.22.4" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@langchain/core": ">=0.2.21 <0.4.0" - } - }, - "node_modules/@langchain/google-vertexai/node_modules/@langchain/google-gauth": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@langchain/google-gauth/-/google-gauth-0.1.2.tgz", - "integrity": "sha512-5fPPaVcv4l2o/WdPuFLkIKFsfAeY8JD7zP/lFlTTeDvCbGbnsywwX08ZCqe9jgDIVBGcIoUqhiyBvwrpJMzMEw==", - "dependencies": { - "@langchain/google-common": "~0.1.2", - "google-auth-library": "^8.9.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@langchain/core": ">=0.2.21 <0.4.0" - } - }, - "node_modules/@langchain/google-vertexai/node_modules/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/@langchain/langgraph": { "version": "0.2.33", "resolved": "https://registry.npmjs.org/@langchain/langgraph/-/langgraph-0.2.33.tgz",