Update main.ts
Browse files
main.ts
CHANGED
|
@@ -38,22 +38,15 @@ class GoogleAIService {
|
|
| 38 |
|
| 39 |
constructor() {
|
| 40 |
this.apiKeys = [];
|
| 41 |
-
|
| 42 |
-
while (true) {
|
| 43 |
-
const key = Deno.env.get(`GOOGLE_AI_KEY_${i}`) ||
|
| 44 |
-
(i === 1 ? Deno.env.get("GOOGLE_AI_KEY") : null);
|
| 45 |
-
if (!key) break;
|
| 46 |
-
this.apiKeys.push(key);
|
| 47 |
-
i++;
|
| 48 |
-
}
|
| 49 |
-
|
| 50 |
if (this.apiKeys.length === 0) {
|
| 51 |
-
throw new Error("No Google AI API keys found in environment variables (e.g.,
|
| 52 |
}
|
| 53 |
}
|
| 54 |
|
| 55 |
private getNextApiKey(): string {
|
| 56 |
const key = this.apiKeys[this.currentKeyIndex];
|
|
|
|
| 57 |
this.currentKeyIndex = (this.currentKeyIndex + 1) % this.apiKeys.length;
|
| 58 |
return key;
|
| 59 |
}
|
|
@@ -129,8 +122,8 @@ class GoogleAIService {
|
|
| 129 |
}
|
| 130 |
|
| 131 |
public isVisionModel = (modelName: string): boolean => modelName.toLowerCase().includes('vision') || modelName.toLowerCase().includes('pro');
|
| 132 |
-
public isImageGenerationModel = (modelName: string): boolean => modelName.includes('image
|
| 133 |
-
public isImageEditingModel = (modelName: string): boolean => modelName.includes('image
|
| 134 |
public isDocumentModel = (modelName: string): boolean => modelName.toLowerCase().includes('gemini-1.5') || modelName.toLowerCase().includes('pro') || modelName.toLowerCase().includes('flash');
|
| 135 |
public isTTSModel = (modelName: string): boolean => modelName.toLowerCase().includes('tts');
|
| 136 |
|
|
@@ -463,22 +456,19 @@ class GoogleAIService {
|
|
| 463 |
tools: [{ googleSearch: {} }],
|
| 464 |
generationConfig: { temperature: 0.7, maxOutputTokens: maxTokens || 8192 }
|
| 465 |
};
|
| 466 |
-
|
| 467 |
const response = await fetch(
|
| 468 |
`https://generativelanguage.googleapis.com/v1beta/${fullModelName}:generateContent?key=${apiKey}`,
|
| 469 |
{ method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(requestBody) }
|
| 470 |
);
|
| 471 |
-
|
| 472 |
if (!response.ok) {
|
| 473 |
console.warn(`Google Search API failed: ${response.status}, trying alternative.`);
|
| 474 |
return await this.generateContentWithSearchPrompt(messages, modelName, maxTokens);
|
| 475 |
}
|
| 476 |
-
|
| 477 |
const data = await response.json();
|
| 478 |
if (!data.candidates || data.candidates.length === 0) {
|
| 479 |
return await this.generateContentWithSearchPrompt(messages, modelName, maxTokens);
|
| 480 |
}
|
| 481 |
-
|
| 482 |
const candidate = data.candidates[0];
|
| 483 |
if (candidate.finishReason === "SAFETY") {
|
| 484 |
throw new Error("Response blocked due to safety filters");
|
|
@@ -505,7 +495,7 @@ class GoogleAIService {
|
|
| 505 |
const result = await this.generateOrEditImageWithGemini(prompt, modelName, inputImage);
|
| 506 |
let response = "";
|
| 507 |
if (result.text) response += result.text + "\\\\n\\\\n";
|
| 508 |
-
if (result.imageUrl) response += `
|
| 509 |
return response || `Image processing complete.`;
|
| 510 |
} catch (error) {
|
| 511 |
return `Image processing failed: ${error.message}`;
|
|
@@ -601,17 +591,22 @@ class OpenAICompatibleServer {
|
|
| 601 |
const stream = body.stream || false;
|
| 602 |
const maxTokens = body.max_tokens || 1048576;
|
| 603 |
console.log(`Request for model: ${requestedModel}, stream: ${stream}, max_tokens: ${maxTokens}`);
|
| 604 |
-
|
| 605 |
const lastMessage = body.messages[body.messages.length - 1];
|
| 606 |
const content = typeof lastMessage.content === "string"
|
| 607 |
? lastMessage.content
|
| 608 |
: (Array.isArray(lastMessage.content) ? lastMessage.content.map(p => p.text || "").join(" ") : "");
|
| 609 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 610 |
const hasDocument = body.messages.some(msg =>
|
| 611 |
Array.isArray(msg.content) &&
|
| 612 |
msg.content.some(part => part.type === "document" || this.isDocumentContent(part.document?.url))
|
| 613 |
);
|
| 614 |
-
|
| 615 |
const hasImages = body.messages.some(msg => Array.isArray(msg.content) && msg.content.some(part => part.type === "image_url"));
|
| 616 |
|
| 617 |
let inputImages: any[] = [];
|
|
@@ -624,7 +619,6 @@ class OpenAICompatibleServer {
|
|
| 624 |
}
|
| 625 |
});
|
| 626 |
}
|
| 627 |
-
|
| 628 |
let responseText: string;
|
| 629 |
|
| 630 |
// Routing logic based on keywords and content types
|
|
|
|
| 38 |
|
| 39 |
constructor() {
|
| 40 |
this.apiKeys = [];
|
| 41 |
+
this.apiKeys = Deno.env.get(`GOOGLE_AI_KEYS`).split(',').map(s => s.trim());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
if (this.apiKeys.length === 0) {
|
| 43 |
+
throw new Error("No Google AI API keys found in environment variables (e.g., GOOGLE_AI_KEYS)");
|
| 44 |
}
|
| 45 |
}
|
| 46 |
|
| 47 |
private getNextApiKey(): string {
|
| 48 |
const key = this.apiKeys[this.currentKeyIndex];
|
| 49 |
+
console.log(key)
|
| 50 |
this.currentKeyIndex = (this.currentKeyIndex + 1) % this.apiKeys.length;
|
| 51 |
return key;
|
| 52 |
}
|
|
|
|
| 122 |
}
|
| 123 |
|
| 124 |
public isVisionModel = (modelName: string): boolean => modelName.toLowerCase().includes('vision') || modelName.toLowerCase().includes('pro');
|
| 125 |
+
public isImageGenerationModel = (modelName: string): boolean => modelName.includes('image') || modelName === 'gemini-2.0-flash-preview-image-generation' || modelName === 'gemini-2.5-flash-image-preview';
|
| 126 |
+
public isImageEditingModel = (modelName: string): boolean => modelName.includes('image') || modelName === 'gemini-2.0-flash-preview-image-generation' || modelName === 'gemini-2.5-flash-image-preview';
|
| 127 |
public isDocumentModel = (modelName: string): boolean => modelName.toLowerCase().includes('gemini-1.5') || modelName.toLowerCase().includes('pro') || modelName.toLowerCase().includes('flash');
|
| 128 |
public isTTSModel = (modelName: string): boolean => modelName.toLowerCase().includes('tts');
|
| 129 |
|
|
|
|
| 456 |
tools: [{ googleSearch: {} }],
|
| 457 |
generationConfig: { temperature: 0.7, maxOutputTokens: maxTokens || 8192 }
|
| 458 |
};
|
|
|
|
| 459 |
const response = await fetch(
|
| 460 |
`https://generativelanguage.googleapis.com/v1beta/${fullModelName}:generateContent?key=${apiKey}`,
|
| 461 |
{ method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(requestBody) }
|
| 462 |
);
|
|
|
|
| 463 |
if (!response.ok) {
|
| 464 |
console.warn(`Google Search API failed: ${response.status}, trying alternative.`);
|
| 465 |
return await this.generateContentWithSearchPrompt(messages, modelName, maxTokens);
|
| 466 |
}
|
|
|
|
| 467 |
const data = await response.json();
|
| 468 |
if (!data.candidates || data.candidates.length === 0) {
|
| 469 |
return await this.generateContentWithSearchPrompt(messages, modelName, maxTokens);
|
| 470 |
}
|
| 471 |
+
|
| 472 |
const candidate = data.candidates[0];
|
| 473 |
if (candidate.finishReason === "SAFETY") {
|
| 474 |
throw new Error("Response blocked due to safety filters");
|
|
|
|
| 495 |
const result = await this.generateOrEditImageWithGemini(prompt, modelName, inputImage);
|
| 496 |
let response = "";
|
| 497 |
if (result.text) response += result.text + "\\\\n\\\\n";
|
| 498 |
+
if (result.imageUrl) response += ``;
|
| 499 |
return response || `Image processing complete.`;
|
| 500 |
} catch (error) {
|
| 501 |
return `Image processing failed: ${error.message}`;
|
|
|
|
| 591 |
const stream = body.stream || false;
|
| 592 |
const maxTokens = body.max_tokens || 1048576;
|
| 593 |
console.log(`Request for model: ${requestedModel}, stream: ${stream}, max_tokens: ${maxTokens}`);
|
|
|
|
| 594 |
const lastMessage = body.messages[body.messages.length - 1];
|
| 595 |
const content = typeof lastMessage.content === "string"
|
| 596 |
? lastMessage.content
|
| 597 |
: (Array.isArray(lastMessage.content) ? lastMessage.content.map(p => p.text || "").join(" ") : "");
|
| 598 |
+
if (content == 'ping'){
|
| 599 |
+
const responsePayload = {
|
| 600 |
+
id: `chatcmpl-${Date.now()}`, object: "chat.completion", created: Math.floor(Date.now() / 1000), model: requestedModel,
|
| 601 |
+
choices: [{ index: 0, message: { role: "assistant", content: "pong" }, finish_reason: "stop" }],
|
| 602 |
+
usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 }
|
| 603 |
+
};
|
| 604 |
+
return new Response(JSON.stringify(responsePayload), { headers: { "Content-Type": "application/json" } });
|
| 605 |
+
}
|
| 606 |
const hasDocument = body.messages.some(msg =>
|
| 607 |
Array.isArray(msg.content) &&
|
| 608 |
msg.content.some(part => part.type === "document" || this.isDocumentContent(part.document?.url))
|
| 609 |
);
|
|
|
|
| 610 |
const hasImages = body.messages.some(msg => Array.isArray(msg.content) && msg.content.some(part => part.type === "image_url"));
|
| 611 |
|
| 612 |
let inputImages: any[] = [];
|
|
|
|
| 619 |
}
|
| 620 |
});
|
| 621 |
}
|
|
|
|
| 622 |
let responseText: string;
|
| 623 |
|
| 624 |
// Routing logic based on keywords and content types
|