diff --git a/README-EN.md b/README-EN.md index 78a350b..e017e09 100644 --- a/README-EN.md +++ b/README-EN.md @@ -123,6 +123,10 @@ This project consists of three core files, each with its own specific function: ```bash node gemini-api-server.js --oauth-creds-file "/path/to/your/oauth_creds.json" ``` +* **Start with Specified Project ID** (e.g., for multi-project environments) + ```bash + node gemini-api-server.js --project-id your-gcp-project-id + ``` #### 💻 Call the API (Default API Key: `123456`) * **List Models** diff --git a/README.md b/README.md index ab15bbc..301e47a 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,10 @@ ```bash node gemini-api-server.js --oauth-creds-file "/path/to/your/oauth_creds.json" ``` +* **通过指定项目ID启动** (例如,用于多项目环境) + ```bash + node gemini-api-server.js --project-id your-gcp-project-id + ``` #### 💻 调用 API (默认 API Key: `123456`) * **列出模型** diff --git a/gemini-api-server.js b/gemini-api-server.js index 08e2165..581b940 100644 --- a/gemini-api-server.js +++ b/gemini-api-server.js @@ -57,6 +57,9 @@ * // 通过指定凭证文件路径启动 (例如,用于自定义凭证位置) * node gemini-api-server.js --oauth-creds-file "/path/to/your/oauth_creds.json" * + * // 通过指定项目ID启动 (例如,用于多项目环境) + * node gemini-api-server.js --project-id your-gcp-project-id + * * 3. 调用 API 接口 (默认 API Key: 123456): * * // a) 列出可用模型 (GET 请求,密钥在 URL 参数中) @@ -106,6 +109,7 @@ let REQUIRED_API_KEY = '123456'; // Default API Key let SERVER_PORT = 3000; // Default Port let OAUTH_CREDS_BASE64 = null; // New variable for base64 encoded OAuth credentials let OAUTH_CREDS_FILE_PATH = null; // New variable for OAuth credentials file path +let PROJECT_ID = null; // New variable for project ID const args = process.argv.slice(2); const remainingArgs = []; @@ -151,6 +155,13 @@ for (let i = 0; i < args.length; i++) { } else { console.warn(`[Config Warning] --oauth-creds-file flag requires a value.`); } + } else if (args[i] === '--project-id') { // New argument for project ID + if (i + 1 < args.length) { + PROJECT_ID = args[i + 1]; + i++; // Skip the value + } else { + console.warn(`[Config Warning] --project-id flag requires a value.`); + } } else { remainingArgs.push(args[i]); } @@ -186,7 +197,7 @@ function isAuthorized(req, requestUrl) { let apiServiceInstance = null; async function getApiService() { if (!apiServiceInstance) { - apiServiceInstance = new GeminiApiService(HOST, OAUTH_CREDS_BASE64, OAUTH_CREDS_FILE_PATH); + apiServiceInstance = new GeminiApiService(HOST, OAUTH_CREDS_BASE64, OAUTH_CREDS_FILE_PATH, PROJECT_ID); await apiServiceInstance.initialize(); } else if (!apiServiceInstance.isInitialized) { await apiServiceInstance.initialize(); @@ -291,6 +302,7 @@ server.listen(SERVER_PORT, HOST, () => { console.log(` Required API Key: ${REQUIRED_API_KEY}`); console.log(` Prompt Logging: ${PROMPT_LOG_MODE}${PROMPT_LOG_MODE === 'file' ? ` (to ${PROMPT_LOG_FILENAME})` : ''}`); console.log(` OAuth Creds File Path: ${OAUTH_CREDS_FILE_PATH || 'Default'}`); + console.log(` Project ID: ${PROJECT_ID || 'Auto-discovered'}`); // Log the project ID console.log(`--------------------------`); console.log(`\nGemini API Server (Final) running on http://${HOST}:${SERVER_PORT}`); console.log('Initializing service... This may take a moment.'); diff --git a/gemini-core.js b/gemini-core.js index 01ace83..f75dabe 100644 --- a/gemini-core.js +++ b/gemini-core.js @@ -124,9 +124,9 @@ export async function getRequestBody(req) { // --- Main Service Class --- export class GeminiApiService { - constructor(host = 'localhost', oauthCredsBase64 = null, oauthCredsFilePath = null) { + constructor(host = 'localhost', oauthCredsBase64 = null, oauthCredsFilePath = null, projectId = null) { this.authClient = new OAuth2Client(OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET); - this.projectId = null; + this.projectId = projectId; // Set projectId from constructor argument this.availableModels = []; this.isInitialized = false; this.host = host; @@ -138,7 +138,15 @@ export class GeminiApiService { if (this.isInitialized) return; console.log('[Service] Initializing Gemini API Service...'); await this.initializeAuth(); - this.projectId = await this.discoverProjectAndModels(); + // Only discover project ID if it's not already provided + if (!this.projectId) { + this.projectId = await this.discoverProjectAndModels(); + } else { + console.log(`[Service] Using provided Project ID: ${this.projectId}`); + // Still need to ensure models are set up even if project ID is provided + this.availableModels = ['gemini-2.5-pro', 'gemini-2.5-flash']; + console.log(`[Service] Using fixed models: [${this.availableModels.join(', ')}]`); + } this.isInitialized = true; console.log(`[Service] Initialization complete. Project ID: ${this.projectId}`); } @@ -239,7 +247,12 @@ export class GeminiApiService { } async discoverProjectAndModels() { - if (this.projectId) return this.projectId; + // If projectId is already set, return it directly + if (this.projectId) { + console.log(`[Service] Using pre-configured Project ID: ${this.projectId}`); + return this.projectId; + } + console.log('[Service] Discovering Project ID...'); this.availableModels = ['gemini-2.5-pro', 'gemini-2.5-flash']; console.log(`[Service] Using fixed models: [${this.availableModels.join(', ')}]`); @@ -249,7 +262,7 @@ export class GeminiApiService { return loadResponse.cloudaicompanionProject; } const defaultTier = loadResponse.allowedTiers?.find(tier => tier.isDefault); - const onboardRequest = { tierId: defaultTier?.id || 'free-tier', metadata: { pluginType: 'GEMINI' } }; + const onboardRequest = { tierId: defaultTier?.id || 'free-tier', metadata: { pluginType: 'GEMINI' } , cloudaicompanionProject: 'default',}; let lro = await this.callApi('onboardUser', onboardRequest); while (!lro.done) { await new Promise(resolve => setTimeout(resolve, 2000)); @@ -278,11 +291,14 @@ export class GeminiApiService { async callApi(method, body, isRetry = false) { try { + console.log(`${CODE_ASSIST_ENDPOINT}/${CODE_ASSIST_API_VERSION}:${method}`); + console.log(body); const res = await this.authClient.request({ url: `${CODE_ASSIST_ENDPOINT}/${CODE_ASSIST_API_VERSION}:${method}`, method: "POST", headers: { "Content-Type": "application/json" }, responseType: "json", body: JSON.stringify(body), }); + console.log(res.data); return res.data; } catch (error) { if (error.response?.status === 401 && !isRetry) { diff --git a/openai-api-server.js b/openai-api-server.js index 95b1230..d3a7e95 100644 --- a/openai-api-server.js +++ b/openai-api-server.js @@ -71,6 +71,11 @@ * node openai-api-server.js --oauth-creds-file "/path/to/your/oauth_creds.json" * ``` * + * - **通过指定项目ID启动** (例如,用于多项目环境) + * ```bash + * node openai-api-server.js --project-id your-gcp-project-id + * ``` + * * 4. 调用 API 接口 (假设 API Key: `your_secret_key`, 服务运行在 `localhost:8000`): * * - **a) 列出可用模型** @@ -127,6 +132,7 @@ let REQUIRED_API_KEY = '123456'; // Default API Key let SERVER_PORT = 8000; // Default Port let OAUTH_CREDS_BASE64 = null; // New variable for base64 encoded OAuth credentials let OAUTH_CREDS_FILE_PATH = null; // New variable for OAuth credentials file path +let PROJECT_ID = null; // New variable for project ID const args = process.argv.slice(2); const remainingArgs = []; @@ -172,6 +178,13 @@ for (let i = 0; i < args.length; i++) { } else { console.warn(`[Config Warning] --oauth-creds-file flag requires a value.`); } + } else if (args[i] === '--project-id') { // New argument for project ID + if (i + 1 < args.length) { + PROJECT_ID = args[i + 1]; + i++; // Skip the value + } else { + console.warn(`[Config Warning] --project-id flag requires a value.`); + } } else { remainingArgs.push(args[i]); } @@ -398,7 +411,7 @@ function isAuthorized(req, requestUrl) { let apiServiceInstance = null; async function getApiService() { if (!apiServiceInstance) { - apiServiceInstance = new GeminiApiService(HOST, OAUTH_CREDS_BASE64, OAUTH_CREDS_FILE_PATH); + apiServiceInstance = new GeminiApiService(HOST, OAUTH_CREDS_BASE64, OAUTH_CREDS_FILE_PATH, PROJECT_ID); await apiServiceInstance.initialize(); } else if (!apiServiceInstance.isInitialized) { // Ensure re-initialization if not already initialized await apiServiceInstance.initialize(); @@ -522,6 +535,7 @@ server.listen(SERVER_PORT, HOST, () => { console.log(` Required API Key: ${REQUIRED_API_KEY}`); console.log(` Prompt Logging: ${PROMPT_LOG_MODE}${PROMPT_LOG_MODE === 'file' ? ` (to ${PROMPT_LOG_FILENAME})` : ''}`); console.log(` OAuth Creds File Path: ${OAUTH_CREDS_FILE_PATH || 'Default'}`); + console.log(` Project ID: ${PROJECT_ID || 'Auto-discovered'}`); // Log the project ID console.log(`---------------------------------------------`); console.log(`\nServer running on http://${HOST}:${SERVER_PORT}`); console.log('Initializing backend service... This may take a moment.');