diff --git a/public/scripts/extensions/shared.js b/public/scripts/extensions/shared.js
index 6a73d1cf3..c68d6c575 100644
--- a/public/scripts/extensions/shared.js
+++ b/public/scripts/extensions/shared.js
@@ -180,13 +180,10 @@ function throwIfInvalidModel(useReverseProxy) {
throw new Error('Google Vertex AI API key is not set for Express mode.');
}
} else if (authMode === 'full') {
- // Full mode requires Service Account JSON and project settings
+ // Full mode requires Service Account JSON and region settings
if (!secret_state[SECRET_KEYS.VERTEXAI_SERVICE_ACCOUNT]) {
throw new Error('Service Account JSON is required for Vertex AI Full mode. Please validate and save your Service Account JSON.');
}
- if (!secret_state[SECRET_KEYS.VERTEXAI_PROJECT_ID]) {
- throw new Error('Project ID is required for Vertex AI Full mode.');
- }
if (!oai_settings.vertexai_region) {
throw new Error('Region is required for Vertex AI Full mode.');
}
diff --git a/public/scripts/openai.js b/public/scripts/openai.js
index d3c3edab0..23fbdeadd 100644
--- a/public/scripts/openai.js
+++ b/public/scripts/openai.js
@@ -3496,8 +3496,6 @@ function loadOpenAISettings(data, settings) {
$('#claude_use_sysprompt').prop('checked', oai_settings.claude_use_sysprompt);
$('#use_makersuite_sysprompt').prop('checked', oai_settings.use_makersuite_sysprompt);
$('#vertexai_auth_mode').val(oai_settings.vertexai_auth_mode);
- // Don't display Project ID in input - it's stored in backend secrets
- $('#vertexai_project_id').val('');
$('#vertexai_region').val(oai_settings.vertexai_region);
// Don't display Service Account JSON in textarea - it's stored in backend secrets
$('#vertexai_service_account_json').val('');
@@ -5015,19 +5013,7 @@ async function onConnectButtonClick(e) {
}
} else {
// Full version - use service account
- // Check if we have a saved project ID, otherwise use the input value
- const savedProjectId = secret_state[SECRET_KEYS.VERTEXAI_PROJECT_ID];
- const inputProjectId = String($('#vertexai_project_id').val()).trim();
-
- if (!savedProjectId && !inputProjectId) {
- toastr.error(t`Project ID is required for Vertex AI full version`);
- return;
- }
-
- // Save project ID to secrets if we have an input value
- if (inputProjectId.length) {
- await writeSecret(SECRET_KEYS.VERTEXAI_PROJECT_ID, inputProjectId);
- }
+ // Project ID will be extracted from the Service Account JSON
// Check if service account JSON is saved in backend
if (!secret_state[SECRET_KEYS.VERTEXAI_SERVICE_ACCOUNT]) {
diff --git a/public/scripts/secrets.js b/public/scripts/secrets.js
index b72beb46b..488acb22e 100644
--- a/public/scripts/secrets.js
+++ b/public/scripts/secrets.js
@@ -44,7 +44,6 @@ export const SECRET_KEYS = {
SERPER: 'api_key_serper',
FALAI: 'api_key_falai',
XAI: 'api_key_xai',
- VERTEXAI_PROJECT_ID: 'vertexai_project_id',
VERTEXAI_SERVICE_ACCOUNT: 'vertexai_service_account_json',
};
diff --git a/src/endpoints/backends/chat-completions.js b/src/endpoints/backends/chat-completions.js
index e7b2979f8..767125af3 100644
--- a/src/endpoints/backends/chat-completions.js
+++ b/src/endpoints/backends/chat-completions.js
@@ -43,7 +43,7 @@ import {
webTokenizers,
getWebTokenizer,
} from '../tokenizers.js';
-import { getVertexAIAuth } from '../google.js';
+import { getVertexAIAuth, getProjectIdFromServiceAccount } from '../google.js';
const API_OPENAI = 'https://api.openai.com/v1';
const API_CLAUDE = 'https://api.anthropic.com/v1';
@@ -528,10 +528,19 @@ async function sendMakerSuiteRequest(request, response) {
url = `${apiUrl.toString().replace(/\/$/, '')}/v1/publishers/google/models/${model}:${responseType}?key=${keyParam}${stream ? '&alt=sse' : ''}`;
} else if (authType === 'full') {
// For Full mode (service account authentication), use project-specific URL
- // Only use project ID from secrets
- const projectId = readSecret(request.user.directories, SECRET_KEYS.VERTEXAI_PROJECT_ID);
- if (!projectId) {
- console.warn('Vertex AI project ID is missing.');
+ // Get project ID from Service Account JSON
+ const serviceAccountJson = readSecret(request.user.directories, SECRET_KEYS.VERTEXAI_SERVICE_ACCOUNT);
+ if (!serviceAccountJson) {
+ console.warn('Vertex AI Service Account JSON is missing.');
+ return response.status(400).send({ error: true });
+ }
+
+ let projectId;
+ try {
+ const serviceAccount = JSON.parse(serviceAccountJson);
+ projectId = getProjectIdFromServiceAccount(serviceAccount);
+ } catch (error) {
+ console.error('Failed to extract project ID from Service Account JSON:', error);
return response.status(400).send({ error: true });
}
const region = request.body.vertexai_region || 'us-central1';
diff --git a/src/endpoints/google.js b/src/endpoints/google.js
index 9d06683c0..b0c24557f 100644
--- a/src/endpoints/google.js
+++ b/src/endpoints/google.js
@@ -107,6 +107,25 @@ export async function getAccessToken(jwtToken) {
return data.access_token;
}
+/**
+ * Extracts the project ID from a Service Account JSON object.
+ * @param {object} serviceAccount Service account JSON object
+ * @returns {string} Project ID
+ * @throws {Error} If project ID is not found in the service account
+ */
+export function getProjectIdFromServiceAccount(serviceAccount) {
+ if (!serviceAccount || typeof serviceAccount !== 'object') {
+ throw new Error('Invalid service account object');
+ }
+
+ const projectId = serviceAccount.project_id;
+ if (!projectId || typeof projectId !== 'string') {
+ throw new Error('Project ID not found in service account JSON');
+ }
+
+ return projectId;
+}
+
export const router = express.Router();
router.post('/caption-image', async (request, response) => {
@@ -133,9 +152,19 @@ router.post('/caption-image', async (request, response) => {
url = `${apiUrl.origin}/v1/publishers/google/models/${model}:generateContent?key=${keyParam}`;
} else if (authType === 'full') {
// Full mode: use project-specific URL with Authorization header
- const projectId = readSecret(request.user.directories, SECRET_KEYS.VERTEXAI_PROJECT_ID);
- if (!projectId) {
- console.warn('Vertex AI project ID is missing.');
+ // Get project ID from Service Account JSON
+ const serviceAccountJson = readSecret(request.user.directories, SECRET_KEYS.VERTEXAI_SERVICE_ACCOUNT);
+ if (!serviceAccountJson) {
+ console.warn('Vertex AI Service Account JSON is missing.');
+ return response.status(400).send({ error: true });
+ }
+
+ let projectId;
+ try {
+ const serviceAccount = JSON.parse(serviceAccountJson);
+ projectId = getProjectIdFromServiceAccount(serviceAccount);
+ } catch (error) {
+ console.error('Failed to extract project ID from Service Account JSON:', error);
return response.status(400).send({ error: true });
}
const region = request.body.vertexai_region || 'us-central1';
diff --git a/src/endpoints/secrets.js b/src/endpoints/secrets.js
index 237eda570..d1f015b42 100644
--- a/src/endpoints/secrets.js
+++ b/src/endpoints/secrets.js
@@ -54,7 +54,6 @@ export const SECRET_KEYS = {
DEEPSEEK: 'api_key_deepseek',
SERPER: 'api_key_serper',
XAI: 'api_key_xai',
- VERTEXAI_PROJECT_ID: 'vertexai_project_id',
VERTEXAI_SERVICE_ACCOUNT: 'vertexai_service_account_json',
};