google is idiotic

This commit is contained in:
reanon
2025-07-23 23:19:54 +02:00
parent 6e02db4bd7
commit f114469057
2 changed files with 61 additions and 5 deletions
+36 -2
View File
@@ -15,6 +15,8 @@ const GENERATE_CONTENT_URL =
const PRO_MODEL_ID = "gemini-2.5-pro";
const GENERATE_PRO_CONTENT_URL =
`https://generativelanguage.googleapis.com/v1beta/models/${PRO_MODEL_ID}:generateContent?key=%KEY%`;
const IMAGEN_BILLING_TEST_URL =
"https://generativelanguage.googleapis.com/v1beta/models/imagen-3.0-generate-002:predict?key=%KEY%";
type ListModelsResponse = {
models: {
@@ -53,6 +55,9 @@ export class GoogleAIKeyChecker extends KeyCheckerBase<GoogleAIKey> {
// Always test flash model access (existing behaviour)
await this.testGenerateContent(key);
// Test if billing is enabled for this key
const billingEnabled = await this.testBillingEnabled(key);
// If key claims to support gemini-pro, perform a second layer test with a pro model.
let effectiveFamilies = [...provisionedModels];
if (effectiveFamilies.includes("gemini-pro")) {
@@ -66,10 +71,10 @@ export class GoogleAIKeyChecker extends KeyCheckerBase<GoogleAIKey> {
}
}
const updates = { modelFamilies: effectiveFamilies };
const updates = { modelFamilies: effectiveFamilies, billingEnabled };
this.updateKey(key.hash, updates);
this.log.info(
{ key: key.hash, models: effectiveFamilies, ids: key.modelIds?.length },
{ key: key.hash, models: effectiveFamilies, ids: key.modelIds?.length, billingEnabled },
"Checked key."
);
}
@@ -134,6 +139,35 @@ export class GoogleAIKeyChecker extends KeyCheckerBase<GoogleAIKey> {
}
}
private async testBillingEnabled(key: GoogleAIKey): Promise<boolean> {
const payload = {
instances: [{ prompt: "" }]
};
try {
const response = await axios.post(
IMAGEN_BILLING_TEST_URL.replace("%KEY%", key.key),
payload,
{ validateStatus: () => true } // Accept all status codes
);
if (response.status === 400) {
const errorMessage = response.data?.error?.message || "";
// If the error message contains the billing requirement, billing is NOT enabled
if (errorMessage.includes("Imagen API is only accessible to billed users at this time")) {
return false;
}
// Other 400 errors indicate billing IS enabled (following Python logic)
return true;
}
// For other status codes, assume no billing (conservative approach)
return false;
} catch (error: any) {
// Network errors or other issues - assume no billing
return false;
}
}
protected handleAxiosError(key: GoogleAIKey, error: AxiosError): void {
if (error.response && GoogleAIKeyChecker.errorIsGoogleAIError(error)) {
const httpStatus = error.response.status;
@@ -32,6 +32,8 @@ export interface GoogleAIKey extends Key {
isOverQuota?: boolean;
/** Model families that are over quota and need to be excluded. */
overQuotaFamilies?: GoogleAIModelFamily[];
/** Whether this key has billing enabled (required for preview models). */
billingEnabled?: boolean;
}
/**
@@ -46,6 +48,13 @@ const RATE_LIMIT_LOCKOUT = 2000;
*/
const KEY_REUSE_DELAY = 500;
/**
* Determines if a model is a preview model that requires billing-enabled keys.
*/
function isPreviewModel(model: string): boolean {
return model.includes("-preview");
}
export class GoogleAIKeyProvider implements KeyProvider<GoogleAIKey> {
readonly service = "google-ai";
@@ -84,6 +93,7 @@ export class GoogleAIKeyProvider implements KeyProvider<GoogleAIKey> {
tokenUsage: {}, // Initialize new tokenUsage field
modelIds: [],
overQuotaFamilies: [],
billingEnabled: false, // Will be determined during key checking
};
this.keys.push(newKey);
}
@@ -103,11 +113,23 @@ export class GoogleAIKeyProvider implements KeyProvider<GoogleAIKey> {
public get(model: string) {
const neededFamily = getGoogleAIModelFamily(model);
const availableKeys = this.keys.filter(
let availableKeys = this.keys.filter(
(k) => !k.isDisabled && k.modelFamilies.includes(neededFamily)
);
if (availableKeys.length === 0) {
throw new PaymentRequiredError("No Google AI keys available");
// For preview models, only use billing-enabled keys
if (isPreviewModel(model)) {
availableKeys = availableKeys.filter((k) => k.billingEnabled === true);
if (availableKeys.length === 0) {
throw new PaymentRequiredError(
"No billing-enabled Google AI keys available for preview models"
);
}
} else {
// For standard models, use any available key
if (availableKeys.length === 0) {
throw new PaymentRequiredError("No Google AI keys available");
}
}
const keysByPriority = prioritizeKeys(availableKeys);