Replace url.origin with trimTrailingSlash (#4118) * Replace url.origin with trimV1 * Replace url.origin with trimTrailingSlash
Signed| @@ -16,6 +16,7 @@ import { | |||
| 16 | mergeObjectWithYaml, | 16 | mergeObjectWithYaml, |
| 17 | excludeKeysByYaml, | 17 | excludeKeysByYaml, |
| 18 | color, | 18 | color, |
| 19 | trimTrailingSlash, | ||
| 19 | } from '../../util.js'; | 20 | } from '../../util.js'; |
| 20 | import { | 21 | import { |
| 21 | convertClaudeMessages, | 22 | convertClaudeMessages, |
| @@ -1094,11 +1095,11 @@ router.post('/status', async function (request, statusResponse) { | |||
| 1094 | headers = {}; | 1095 | headers = {}; |
| 1095 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.MAKERSUITE) { | 1096 | } else if (request.body.chat_completion_source === CHAT_COMPLETION_SOURCES.MAKERSUITE) { |
| 1096 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MAKERSUITE); | 1097 | apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MAKERSUITE); |
| 1097 | apiUrl = new URL(request.body.reverse_proxy || API_MAKERSUITE); | 1098 | apiUrl = trimTrailingSlash(request.body.reverse_proxy || API_MAKERSUITE); |
| 1098 | const apiVersion = getConfigValue('gemini.apiVersion', 'v1beta'); | 1099 | const apiVersion = getConfigValue('gemini.apiVersion', 'v1beta'); |
| 1099 | const modelsUrl = !apiKey && request.body.reverse_proxy | 1100 | const modelsUrl = !apiKey && request.body.reverse_proxy |
| 1100 | ? `${apiUrl.origin}/${apiVersion}/models` | 1101 | ? `${apiUrl}/${apiVersion}/models` |
| 1101 | : `${apiUrl.origin}/${apiVersion}/models?key=${apiKey}`; | 1102 | : `${apiUrl}/${apiVersion}/models?key=${apiKey}`; |
| 1102 | 1103 | ||
| 1103 | if (!apiKey && !request.body.reverse_proxy) { | 1104 | if (!apiKey && !request.body.reverse_proxy) { |
| 1104 | console.warn('Google AI Studio API key is missing.'); | 1105 | console.warn('Google AI Studio API key is missing.'); |
| @@ -6,6 +6,7 @@ import crypto from 'node:crypto'; | |||
| 6 | 6 | ||
| 7 | import { readSecret, SECRET_KEYS } from './secrets.js'; | 7 | import { readSecret, SECRET_KEYS } from './secrets.js'; |
| 8 | import { GEMINI_SAFETY } from '../constants.js'; | 8 | import { GEMINI_SAFETY } from '../constants.js'; |
| 9 | import { trimTrailingSlash } from '../util.js'; | ||
| 9 | 10 | ||
| 10 | const API_MAKERSUITE = 'https://generativelanguage.googleapis.com'; | 11 | const API_MAKERSUITE = 'https://generativelanguage.googleapis.com'; |
| 11 | const API_VERTEX_AI = 'https://us-central1-aiplatform.googleapis.com'; | 12 | const API_VERTEX_AI = 'https://us-central1-aiplatform.googleapis.com'; |
| @@ -148,8 +149,8 @@ router.post('/caption-image', async (request, response) => { | |||
| 148 | if (authType === 'express') { | 149 | if (authType === 'express') { |
| 149 | // Express mode: use API key parameter | 150 | // Express mode: use API key parameter |
| 150 | const keyParam = authHeader.replace('Bearer ', ''); | 151 | const keyParam = authHeader.replace('Bearer ', ''); |
| 151 | const apiUrl = new URL(request.body.reverse_proxy || API_VERTEX_AI); | 152 | const apiUrl = trimTrailingSlash(request.body.reverse_proxy || API_VERTEX_AI); |
| 152 | url = `${apiUrl.origin}/v1/publishers/google/models/${model}:generateContent?key=${keyParam}`; | 153 | url = `${apiUrl}/v1/publishers/google/models/${model}:generateContent?key=${keyParam}`; |
| 153 | } else if (authType === 'full') { | 154 | } else if (authType === 'full') { |
| 154 | // Full mode: use project-specific URL with Authorization header | 155 | // Full mode: use project-specific URL with Authorization header |
| 155 | // Get project ID from Service Account JSON | 156 | // Get project ID from Service Account JSON |
| @@ -177,15 +178,15 @@ router.post('/caption-image', async (request, response) => { | |||
| 177 | headers['Authorization'] = authHeader; | 178 | headers['Authorization'] = authHeader; |
| 178 | } else { | 179 | } else { |
| 179 | // Proxy mode: use Authorization header | 180 | // Proxy mode: use Authorization header |
| 180 | const apiUrl = new URL(request.body.reverse_proxy || API_VERTEX_AI); | 181 | const apiUrl = trimTrailingSlash(request.body.reverse_proxy || API_VERTEX_AI); |
| 181 | url = `${apiUrl.origin}/v1/publishers/google/models/${model}:generateContent`; | 182 | url = `${apiUrl}/v1/publishers/google/models/${model}:generateContent`; |
| 182 | headers['Authorization'] = authHeader; | 183 | headers['Authorization'] = authHeader; |
| 183 | } | 184 | } |
| 184 | } else { | 185 | } else { |
| 185 | // Google AI Studio | 186 | // Google AI Studio |
| 186 | const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MAKERSUITE); | 187 | const apiKey = request.body.reverse_proxy ? request.body.proxy_password : readSecret(request.user.directories, SECRET_KEYS.MAKERSUITE); |
| 187 | const apiUrl = new URL(request.body.reverse_proxy || API_MAKERSUITE); | 188 | const apiUrl = trimTrailingSlash(request.body.reverse_proxy || API_MAKERSUITE); |
| 188 | url = `${apiUrl.origin}/v1beta/models/${model}:generateContent?key=${apiKey}`; | 189 | url = `${apiUrl}/v1beta/models/${model}:generateContent?key=${apiKey}`; |
| 189 | } | 190 | } |
| 190 | const body = { | 191 | const body = { |
| 191 | contents: [{ | 192 | contents: [{ |
| @@ -659,6 +659,15 @@ export function trimV1(str) { | |||
| 659 | } | 659 | } |
| 660 | 660 | ||
| 661 | /** | 661 | /** |
| 662 | * Removes trailing slash from a string. | ||
| 663 | * @param {string} str Input string | ||
| 664 | * @returns {string} String with trailing slash removed | ||
| 665 | */ | ||
| 666 | export function trimTrailingSlash(str) { | ||
| 667 | return String(str ?? '').replace(/\/$/, ''); | ||
| 668 | } | ||
| 669 | |||
| 670 | /** | ||
| 662 | * Simple TTL memory cache. | 671 | * Simple TTL memory cache. |
| 663 | */ | 672 | */ |
| 664 | export class Cache { | 673 | export class Cache { |
| @@ -1,5 +1,6 @@ | |||
| 1 | import fetch from 'node-fetch'; | 1 | import fetch from 'node-fetch'; |
| 2 | import { SECRET_KEYS, readSecret } from '../endpoints/secrets.js'; | 2 | import { SECRET_KEYS, readSecret } from '../endpoints/secrets.js'; |
| 3 | import { trimTrailingSlash } from '../util.js'; | ||
| 3 | const API_MAKERSUITE = 'https://generativelanguage.googleapis.com'; | 4 | const API_MAKERSUITE = 'https://generativelanguage.googleapis.com'; |
| 4 | 5 | ||
| 5 | /** | 6 | /** |
| @@ -27,9 +28,9 @@ export async function getMakerSuiteVector(text, directories) { | |||
| 27 | throw new Error('No Google AI Studio key found'); | 28 | throw new Error('No Google AI Studio key found'); |
| 28 | } | 29 | } |
| 29 | 30 | ||
| 30 | const apiUrl = new URL(API_MAKERSUITE); | 31 | const apiUrl = trimTrailingSlash(API_MAKERSUITE); |
| 31 | const model = 'text-embedding-004'; | 32 | const model = 'text-embedding-004'; |
| 32 | const url = `${apiUrl.origin}/v1beta/models/${model}:embedContent?key=${key}`; | 33 | const url = `${apiUrl}/v1beta/models/${model}:embedContent?key=${key}`; |
| 33 | const body = { | 34 | const body = { |
| 34 | content: { | 35 | content: { |
| 35 | parts: [ | 36 | parts: [ |