feat(认证): 添加通过base64编码或文件路径加载OAuth凭证的功能
支持通过--oauth-creds-base64参数传入base64编码的凭证,或通过--oauth-creds-file指定凭证文件路径 更新README文档说明新的启动方式 在响应中添加usageMetadata字段传递token用量信息
This commit is contained in:
parent
0e799798bc
commit
4c2c9bde33
5 changed files with 127 additions and 25 deletions
20
README-EN.md
20
README-EN.md
|
|
@ -115,6 +115,14 @@ This project consists of three core files, each with its own specific function:
|
|||
```bash
|
||||
node gemini-api-server.js 0.0.0.0 --port 3001 --api-key your_secret_key --log-prompts file
|
||||
```
|
||||
* **Start with Base64 Encoded Credentials** (e.g., for Docker or CI/CD environments)
|
||||
```bash
|
||||
node gemini-api-server.js --oauth-creds-base64 "YOUR_BASE64_ENCODED_OAUTH_CREDS_JSON"
|
||||
```
|
||||
* **Start with Specified Credential File Path** (e.g., for custom credential location)
|
||||
```bash
|
||||
node gemini-api-server.js --oauth-creds-file "/path/to/your/oauth_creds.json"
|
||||
```
|
||||
|
||||
#### 💻 Call the API (Default API Key: `123456`)
|
||||
* **List Models**
|
||||
|
|
@ -123,7 +131,7 @@ This project consists of three core files, each with its own specific function:
|
|||
```
|
||||
* **Generate Content (with system prompt)**
|
||||
```bash
|
||||
curl "http://localhost:3000/v1beta/models/gemini-1.5-pro-latest:generateContent" \
|
||||
curl "http://localhost:3000/v1beta/models/gemini-2.5-pro:generateContent" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "x-goog-api-key: 123456" \
|
||||
-d '{
|
||||
|
|
@ -133,7 +141,7 @@ This project consists of three core files, each with its own specific function:
|
|||
```
|
||||
* **Stream Generate Content**
|
||||
```bash
|
||||
curl "http://localhost:3000/v1beta/models/gemini-1.5-flash-latest:streamGenerateContent?key=123456" \
|
||||
curl "http://localhost:3000/v1beta/models/gemini-2.5-flash:streamGenerateContent?key=123456" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"contents":[{"parts":[{"text":"Write a five-line poem about the universe"}]}]}'
|
||||
```
|
||||
|
|
@ -160,7 +168,7 @@ This project consists of three core files, each with its own specific function:
|
|||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer sk-your-key" \
|
||||
-d '{
|
||||
"model": "gemini-1.5-pro-latest",
|
||||
"model": "gemini-2.5-pro",
|
||||
"messages": [
|
||||
{"role": "system", "content": "You are a cat named Neko."},
|
||||
{"role": "user", "content": "Hello, what is your name?"}
|
||||
|
|
@ -173,7 +181,7 @@ This project consists of three core files, each with its own specific function:
|
|||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer sk-your-key" \
|
||||
-d '{
|
||||
"model": "gemini-1.5-flash-latest",
|
||||
"model": "gemini-2.5-flash",
|
||||
"messages": [
|
||||
{"role": "user", "content": "Write a five-line poem about the universe"}
|
||||
],
|
||||
|
|
@ -194,8 +202,6 @@ This project consists of three core files, each with its own specific function:
|
|||
* **Response Caching**: Add caching logic for frequently repeated questions to reduce API calls and improve response speed.
|
||||
* **Custom Content Filtering**: Add keyword filtering or content review logic before requests are sent or returned to meet compliance requirements.
|
||||
|
||||
* **⚖️ Multi-Account Load Balancing (Advanced Usage)**: Run multiple instances of `GeminiCli2API` (each authorized with a different Google account), and then use a load balancer like [gemini-balance](https://github.com/snailyp/gemini-balance/) to achieve load balancing. This can create a huge shared pool of free quota, ideal for teams or high-request scenarios.
|
||||
|
||||
---
|
||||
|
||||
## 📄 License
|
||||
|
|
@ -204,4 +210,4 @@ This project is licensed under the [**GNU General Public License v3 (GPLv3)**](h
|
|||
|
||||
## 🙏 Acknowledgements
|
||||
|
||||
The development of this project was greatly inspired by the official Google Gemini CLI, and it references some of the code implementation from its `gemini-cli.ts` (Cline 3.18.0 version). Sincere thanks to the official Google team for their excellent work!
|
||||
The development of this project was greatly inspired by the official Google Gemini CLI, and referenced some code implementations of Cline 3.18.0 version `gemini-cli.ts`. I would like to express my sincere gratitude to the Google official team and the Cline development team for their excellent work!
|
||||
|
|
|
|||
20
README.md
20
README.md
|
|
@ -115,6 +115,14 @@
|
|||
```bash
|
||||
node gemini-api-server.js 0.0.0.0 --port 3001 --api-key your_secret_key --log-prompts file
|
||||
```
|
||||
* **通过 base64 编码的凭证启动** (例如,用于 Docker 或 CI/CD 环境)
|
||||
```bash
|
||||
node gemini-api-server.js --oauth-creds-base64 "YOUR_BASE64_ENCODED_OAUTH_CREDS_JSON"
|
||||
```
|
||||
* **通过指定凭证文件路径启动** (例如,用于自定义凭证位置)
|
||||
```bash
|
||||
node gemini-api-server.js --oauth-creds-file "/path/to/your/oauth_creds.json"
|
||||
```
|
||||
|
||||
#### 💻 调用 API (默认 API Key: `123456`)
|
||||
* **列出模型**
|
||||
|
|
@ -123,7 +131,7 @@
|
|||
```
|
||||
* **生成内容 (带系统提示)**
|
||||
```bash
|
||||
curl "http://localhost:3000/v1beta/models/gemini-1.5-pro-latest:generateContent" \
|
||||
curl "http://localhost:3000/v1beta/models/gemini-2.5-pro:generateContent" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "x-goog-api-key: 123456" \
|
||||
-d '{
|
||||
|
|
@ -133,7 +141,7 @@
|
|||
```
|
||||
* **流式生成内容**
|
||||
```bash
|
||||
curl "http://localhost:3000/v1beta/models/gemini-1.5-flash-latest:streamGenerateContent?key=123456" \
|
||||
curl "http://localhost:3000/v1beta/models/gemini-2.5-flash:streamGenerateContent?key=123456" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"contents":[{"parts":[{"text":"写一首关于宇宙的五行短诗"}]}]}'
|
||||
```
|
||||
|
|
@ -160,7 +168,7 @@
|
|||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer sk-your-key" \
|
||||
-d '{
|
||||
"model": "gemini-1.5-pro-latest",
|
||||
"model": "gemini-2.5-pro",
|
||||
"messages": [
|
||||
{"role": "system", "content": "你是一只名叫 Neko 的猫。"},
|
||||
{"role": "user", "content": "你好,你叫什么名字?"}
|
||||
|
|
@ -173,7 +181,7 @@
|
|||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer sk-your-key" \
|
||||
-d '{
|
||||
"model": "gemini-1.5-flash-latest",
|
||||
"model": "gemini-2.5-flash",
|
||||
"messages": [
|
||||
{"role": "user", "content": "写一首关于宇宙的五行短诗"}
|
||||
],
|
||||
|
|
@ -194,8 +202,6 @@
|
|||
* **响应缓存**: 对高频重复问题添加缓存逻辑,降低 API 调用,提升响应速度。
|
||||
* **自定义内容过滤**: 在请求发送或返回前增加关键词过滤或内容审查逻辑,满足合规要求。
|
||||
|
||||
* **⚖️ 多账号负载均衡 (高级用法)**: 运行多个 `GeminiCli2API` 实例(每个使用不同 Google 账号授权),再通过[gemini-balance](https://github.com/snailyp/gemini-balance/) 等实现负载均衡。这能创建一个巨大的共享免费额度池,非常适合团队或高请求量场景。
|
||||
|
||||
---
|
||||
|
||||
## 📄 开源许可
|
||||
|
|
@ -204,4 +210,4 @@
|
|||
|
||||
## 🙏 致谢
|
||||
|
||||
本项目的开发受到了官方 Google Gemini CLI 的极大启发,并参考了其 `gemini-cli.ts` (Cline 3.18.0 版本) 的部分代码实现。在此对 Google 官方团队的卓越工作表示衷心的感谢!
|
||||
本项目的开发受到了官方 Google Gemini CLI 的极大启发,并参考了Cline 3.18.0 版本 `gemini-cli.ts` 的部分代码实现。在此对 Google 官方团队和 Cline 开发团队的卓越工作表示衷心的感谢!
|
||||
|
|
|
|||
|
|
@ -51,6 +51,12 @@
|
|||
* // 指定 API Key 和端口 (参数顺序无关)
|
||||
* node gemini-api-server-final.js --api-key your_secret_key --port 3001
|
||||
*
|
||||
* // 通过 base64 编码的凭证启动 (例如,用于 Docker 或 CI/CD 环境)
|
||||
* node gemini-api-server.js --oauth-creds-base64 "YOUR_BASE64_ENCODED_OAUTH_CREDS_JSON"
|
||||
*
|
||||
* // 通过指定凭证文件路径启动 (例如,用于自定义凭证位置)
|
||||
* node gemini-api-server.js --oauth-creds-file "/path/to/your/oauth_creds.json"
|
||||
*
|
||||
* 3. 调用 API 接口 (默认 API Key: 123456):
|
||||
*
|
||||
* // a) 列出可用模型 (GET 请求,密钥在 URL 参数中)
|
||||
|
|
@ -98,6 +104,8 @@ const PROMPT_LOG_BASE_NAME = 'prompts';
|
|||
let PROMPT_LOG_FILENAME = '';
|
||||
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
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const remainingArgs = [];
|
||||
|
|
@ -129,6 +137,20 @@ for (let i = 0; i < args.length; i++) {
|
|||
} else {
|
||||
console.warn(`[Config Warning] --port flag requires a value.`);
|
||||
}
|
||||
} else if (args[i] === '--oauth-creds-base64') {
|
||||
if (i + 1 < args.length) {
|
||||
OAUTH_CREDS_BASE64 = args[i + 1];
|
||||
i++; // Skip the value
|
||||
} else {
|
||||
console.warn(`[Config Warning] --oauth-creds-base64 flag requires a value.`);
|
||||
}
|
||||
} else if (args[i] === '--oauth-creds-file') {
|
||||
if (i + 1 < args.length) {
|
||||
OAUTH_CREDS_FILE_PATH = args[i + 1];
|
||||
i++; // Skip the value
|
||||
} else {
|
||||
console.warn(`[Config Warning] --oauth-creds-file flag requires a value.`);
|
||||
}
|
||||
} else {
|
||||
remainingArgs.push(args[i]);
|
||||
}
|
||||
|
|
@ -164,7 +186,7 @@ function isAuthorized(req, requestUrl) {
|
|||
let apiServiceInstance = null;
|
||||
async function getApiService() {
|
||||
if (!apiServiceInstance) {
|
||||
apiServiceInstance = new GeminiApiService(HOST);
|
||||
apiServiceInstance = new GeminiApiService(HOST, OAUTH_CREDS_BASE64, OAUTH_CREDS_FILE_PATH);
|
||||
await apiServiceInstance.initialize();
|
||||
} else if (!apiServiceInstance.isInitialized) {
|
||||
await apiServiceInstance.initialize();
|
||||
|
|
@ -184,6 +206,8 @@ async function handleStreamRequest(res, service, model, requestBody) {
|
|||
}
|
||||
process.stdout.write('\n');
|
||||
res.end();
|
||||
const expiryDate = service.authClient.credentials.expiry_date;
|
||||
console.log(`[Auth Token] Time until expiry: ${formatExpiryTime(expiryDate)}`);
|
||||
}
|
||||
async function handleUnaryRequest(res, service, model, requestBody) {
|
||||
const response = await service.generateContent(model, requestBody);
|
||||
|
|
@ -195,6 +219,8 @@ async function handleUnaryRequest(res, service, model, requestBody) {
|
|||
const responseString = JSON.stringify(response);
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
res.end(responseString);
|
||||
const expiryDate = service.authClient.credentials.expiry_date;
|
||||
console.log(`[Auth Token] Time until expiry: ${formatExpiryTime(expiryDate)}`);
|
||||
}
|
||||
function handleError(res, error) {
|
||||
console.error('\n[Server] Request failed:', error.stack);
|
||||
|
|
@ -218,12 +244,12 @@ async function requestHandler(req, res) {
|
|||
|
||||
try {
|
||||
const service = await getApiService();
|
||||
const expiryDate = service.authClient.credentials.expiry_date;
|
||||
console.log(`[Auth Token] Time until expiry: ${formatExpiryTime(expiryDate)}`);
|
||||
|
||||
if (req.method === 'GET' && requestUrl.pathname === '/v1beta/models') {
|
||||
const models = await service.listModels();
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
const expiryDate = service.authClient.credentials.expiry_date;
|
||||
console.log(`[Auth Token] Time until expiry: ${formatExpiryTime(expiryDate)}`);
|
||||
return res.end(JSON.stringify(models));
|
||||
}
|
||||
|
||||
|
|
@ -264,6 +290,7 @@ server.listen(SERVER_PORT, HOST, () => {
|
|||
console.log(` Port: ${SERVER_PORT}`);
|
||||
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(`--------------------------`);
|
||||
console.log(`\nGemini API Server (Final) running on http://${HOST}:${SERVER_PORT}`);
|
||||
console.log('Initializing service... This may take a moment.');
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ export function extractResponseText(responseObject) {
|
|||
function toGeminiApiResponse(codeAssistResponse) {
|
||||
if (!codeAssistResponse) return null;
|
||||
const compliantResponse = { candidates: codeAssistResponse.candidates };
|
||||
if (codeAssistResponse.usageMetadata) compliantResponse.usageMetadata = codeAssistResponse.usageMetadata;
|
||||
if (codeAssistResponse.promptFeedback) compliantResponse.promptFeedback = codeAssistResponse.promptFeedback;
|
||||
if (codeAssistResponse.automaticFunctionCallingHistory) compliantResponse.automaticFunctionCallingHistory = codeAssistResponse.automaticFunctionCallingHistory;
|
||||
return compliantResponse;
|
||||
|
|
@ -123,12 +124,14 @@ export async function getRequestBody(req) {
|
|||
|
||||
// --- Main Service Class ---
|
||||
export class GeminiApiService {
|
||||
constructor(host = 'localhost') {
|
||||
constructor(host = 'localhost', oauthCredsBase64 = null, oauthCredsFilePath = null) {
|
||||
this.authClient = new OAuth2Client(OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET);
|
||||
this.projectId = null;
|
||||
this.availableModels = [];
|
||||
this.isInitialized = false;
|
||||
this.host = host;
|
||||
this.oauthCredsBase64 = oauthCredsBase64;
|
||||
this.oauthCredsFilePath = oauthCredsFilePath;
|
||||
}
|
||||
|
||||
async initialize() {
|
||||
|
|
@ -142,7 +145,23 @@ export class GeminiApiService {
|
|||
|
||||
async initializeAuth(forceRefresh = false) {
|
||||
if (this.authClient.credentials.access_token && !forceRefresh) return;
|
||||
const credPath = path.join(os.homedir(), CREDENTIALS_DIR, CREDENTIALS_FILE);
|
||||
|
||||
if (this.oauthCredsBase64) {
|
||||
try {
|
||||
const decoded = Buffer.from(this.oauthCredsBase64, 'base64').toString('utf8');
|
||||
const credentials = JSON.parse(decoded);
|
||||
this.authClient.setCredentials(credentials);
|
||||
console.log('[Auth] Authentication configured successfully from base64 string.');
|
||||
// If using base64, we don't refresh and save to file automatically
|
||||
// as the source of truth is the provided string.
|
||||
return;
|
||||
} catch (error) {
|
||||
console.error('[Auth] Failed to parse base64 OAuth credentials:', error);
|
||||
throw new Error(`Failed to load OAuth credentials from base64 string.`);
|
||||
}
|
||||
}
|
||||
|
||||
const credPath = this.oauthCredsFilePath || path.join(os.homedir(), CREDENTIALS_DIR, CREDENTIALS_FILE);
|
||||
try {
|
||||
const data = await fs.readFile(credPath, "utf8");
|
||||
const credentials = JSON.parse(data);
|
||||
|
|
@ -157,7 +176,7 @@ export class GeminiApiService {
|
|||
}
|
||||
} catch (error) {
|
||||
if (error.code === 'ENOENT') {
|
||||
console.log(`[Auth] '${CREDENTIALS_FILE}' not found. Starting new authentication flow...`);
|
||||
console.log(`[Auth] Credentials file '${credPath}' not found. Starting new authentication flow...`);
|
||||
const newTokens = await this.getNewToken(credPath);
|
||||
this.authClient.setCredentials(newTokens);
|
||||
console.log('[Auth] New token obtained and loaded into memory.');
|
||||
|
|
|
|||
|
|
@ -61,6 +61,16 @@
|
|||
* node openai-api-server.js --port 8088 --api-key your_secret_key 0.0.0.0
|
||||
* ```
|
||||
*
|
||||
* - **通过 base64 编码的凭证启动** (例如,用于 Docker 或 CI/CD 环境)
|
||||
* ```bash
|
||||
* node openai-api-server.js --oauth-creds-base64 "YOUR_BASE64_ENCODED_OAUTH_CREDS_JSON"
|
||||
* ```
|
||||
*
|
||||
* - **通过指定凭证文件路径启动** (例如,用于自定义凭证位置)
|
||||
* ```bash
|
||||
* node openai-api-server.js --oauth-creds-file "/path/to/your/oauth_creds.json"
|
||||
* ```
|
||||
*
|
||||
* 4. 调用 API 接口 (假设 API Key: `your_secret_key`, 服务运行在 `localhost:8000`):
|
||||
*
|
||||
* - **a) 列出可用模型**
|
||||
|
|
@ -115,6 +125,8 @@ const PROMPT_LOG_BASE_NAME = 'prompts';
|
|||
let PROMPT_LOG_FILENAME = '';
|
||||
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
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const remainingArgs = [];
|
||||
|
|
@ -146,6 +158,20 @@ for (let i = 0; i < args.length; i++) {
|
|||
} else {
|
||||
console.warn(`[Config Warning] --log-prompts flag requires a value.`);
|
||||
}
|
||||
} else if (args[i] === '--oauth-creds-base64') {
|
||||
if (i + 1 < args.length) {
|
||||
OAUTH_CREDS_BASE64 = args[i + 1];
|
||||
i++; // Skip the value
|
||||
} else {
|
||||
console.warn(`[Config Warning] --oauth-creds-base64 flag requires a value.`);
|
||||
}
|
||||
} else if (args[i] === '--oauth-creds-file') {
|
||||
if (i + 1 < args.length) {
|
||||
OAUTH_CREDS_FILE_PATH = args[i + 1];
|
||||
i++; // Skip the value
|
||||
} else {
|
||||
console.warn(`[Config Warning] --oauth-creds-file flag requires a value.`);
|
||||
}
|
||||
} else {
|
||||
remainingArgs.push(args[i]);
|
||||
}
|
||||
|
|
@ -303,8 +329,12 @@ function toOpenAIChatCompletion(geminiResponse, model) {
|
|||
},
|
||||
finish_reason: "stop",
|
||||
}],
|
||||
usage: {
|
||||
prompt_tokens: 0, // Note: Gemini API doesn't provide token counts
|
||||
usage: geminiResponse.usageMetadata ? {
|
||||
prompt_tokens: geminiResponse.usageMetadata.promptTokenCount || 0,
|
||||
completion_tokens: geminiResponse.usageMetadata.candidatesTokenCount || 0,
|
||||
total_tokens: geminiResponse.usageMetadata.totalTokenCount || 0,
|
||||
} : {
|
||||
prompt_tokens: 0,
|
||||
completion_tokens: 0,
|
||||
total_tokens: 0,
|
||||
},
|
||||
|
|
@ -323,6 +353,15 @@ function toOpenAIStreamChunk(geminiChunk, model) {
|
|||
delta: { content: text },
|
||||
finish_reason: null,
|
||||
}],
|
||||
usage: geminiChunk.usageMetadata ? {
|
||||
prompt_tokens: geminiChunk.usageMetadata.promptTokenCount || 0,
|
||||
completion_tokens: geminiChunk.usageMetadata.candidatesTokenCount || 0,
|
||||
total_tokens: geminiChunk.usageMetadata.totalTokenCount || 0,
|
||||
} : {
|
||||
prompt_tokens: 0,
|
||||
completion_tokens: 0,
|
||||
total_tokens: 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -359,7 +398,7 @@ function isAuthorized(req, requestUrl) {
|
|||
let apiServiceInstance = null;
|
||||
async function getApiService() {
|
||||
if (!apiServiceInstance) {
|
||||
apiServiceInstance = new GeminiApiService(HOST);
|
||||
apiServiceInstance = new GeminiApiService(HOST, OAUTH_CREDS_BASE64, OAUTH_CREDS_FILE_PATH);
|
||||
await apiServiceInstance.initialize();
|
||||
} else if (!apiServiceInstance.isInitialized) { // Ensure re-initialization if not already initialized
|
||||
await apiServiceInstance.initialize();
|
||||
|
|
@ -396,6 +435,8 @@ async function handleStreamRequest(res, service, model, requestBody) {
|
|||
res.end();
|
||||
}
|
||||
}
|
||||
const expiryDate = service.authClient.credentials.expiry_date;
|
||||
console.log(`[Auth Token] Time until expiry: ${formatExpiryTime(expiryDate)}`);
|
||||
}
|
||||
|
||||
async function handleUnaryRequest(res, service, model, requestBody) {
|
||||
|
|
@ -409,6 +450,8 @@ async function handleUnaryRequest(res, service, model, requestBody) {
|
|||
process.stdout.write('\n');
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
res.end(JSON.stringify(openAIResponse));
|
||||
const expiryDate = service.authClient.credentials.expiry_date;
|
||||
console.log(`[Auth Token] Time until expiry: ${formatExpiryTime(expiryDate)}`);
|
||||
}
|
||||
|
||||
function handleError(res, error) {
|
||||
|
|
@ -433,13 +476,13 @@ async function requestHandler(req, res) {
|
|||
|
||||
try {
|
||||
const service = await getApiService();
|
||||
const expiryDate = service.authClient.credentials.expiry_date;
|
||||
console.log(`[Auth Token] Time until expiry: ${formatExpiryTime(expiryDate)}`);
|
||||
|
||||
if (req.method === 'GET' && requestUrl.pathname === '/v1/models') {
|
||||
const models = await service.listModels();
|
||||
const openAIModels = toOpenAIModelList(models.models.map(m => m.name.replace('models/', '')));
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' });
|
||||
const expiryDate = service.authClient.credentials.expiry_date;
|
||||
console.log(`[Auth Token] Time until expiry: ${formatExpiryTime(expiryDate)}`);
|
||||
return res.end(JSON.stringify(openAIModels));
|
||||
}
|
||||
|
||||
|
|
@ -478,6 +521,7 @@ server.listen(SERVER_PORT, HOST, () => {
|
|||
console.log(` Port: ${SERVER_PORT}`);
|
||||
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(`---------------------------------------------`);
|
||||
console.log(`\nServer running on http://${HOST}:${SERVER_PORT}`);
|
||||
console.log('Initializing backend service... This may take a moment.');
|
||||
|
|
|
|||
Loading…
Reference in a new issue