LAST TRY
This commit is contained in:
@@ -334,11 +334,9 @@ export class OpenAIKeyChecker extends KeyCheckerBase<OpenAIKey> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the key has access to the gpt-image-1 model by making a small test request.
|
||||
* Returns true if the key has access, false otherwise.
|
||||
*
|
||||
* Ensures that the key can actually generate images by verifying the API response
|
||||
* contains the expected data structure for successful image generation.
|
||||
* Tests whether the key has access to the gpt-image-1 model by making a test request.
|
||||
* Returns true if the API accepts the request without specific access errors.
|
||||
* Does not wait for actual image generation to complete.
|
||||
*/
|
||||
public async testGptImageAccess(key: OpenAIKey): Promise<boolean> {
|
||||
this.log.info({ key: key.hash }, "Testing gpt-image-1 access");
|
||||
@@ -346,85 +344,96 @@ export class OpenAIKeyChecker extends KeyCheckerBase<OpenAIKey> {
|
||||
try {
|
||||
const payload = {
|
||||
model: "gpt-image-1",
|
||||
prompt: "A cute baby sea otter",
|
||||
prompt: "A simple test image",
|
||||
n: 1,
|
||||
size: "auto",
|
||||
quality: "low",
|
||||
};
|
||||
|
||||
// Make a real request to test access
|
||||
// Make a minimal request just to check access
|
||||
const response = await axios.post(
|
||||
POST_IMAGE_GENERATIONS_URL,
|
||||
payload,
|
||||
{
|
||||
headers: OpenAIKeyChecker.getHeaders(key),
|
||||
validateStatus: (status) => status >= 200 && status < 500, // Accept any non-server error response
|
||||
timeout: 200000, // 200 second timeout to allow for image generation
|
||||
signal: AbortSignal.timeout(200000)
|
||||
validateStatus: (status) => true, // Accept any status code to inspect errors
|
||||
timeout: 5000, // 5 second timeout
|
||||
signal: AbortSignal.timeout(5000)
|
||||
}
|
||||
);
|
||||
|
||||
// Status 200 means success, but we need to verify the response actually contains image data
|
||||
if (response.status === 200) {
|
||||
// Check if the response contains the expected data structure
|
||||
if (response.data &&
|
||||
response.data.data &&
|
||||
Array.isArray(response.data.data) &&
|
||||
response.data.data.length > 0 &&
|
||||
response.data.data[0].url) {
|
||||
this.log.info(
|
||||
{ key: key.hash, status: response.status },
|
||||
"Verified gpt-image-1 access: Successfully generated an image"
|
||||
);
|
||||
return true;
|
||||
} else {
|
||||
this.log.warn(
|
||||
{ key: key.hash, status: response.status, data: response.data },
|
||||
"Response status is 200 but received unexpected response format. Image may not have been generated."
|
||||
);
|
||||
return false;
|
||||
}
|
||||
// If we get a 200, 400, or 500 response, consider the key valid
|
||||
if (response.status === 200 || response.status === 400 || response.status === 500) {
|
||||
this.log.info(
|
||||
{ key: key.hash, status: response.status },
|
||||
`Verified gpt-image-1 access with status code ${response.status}`
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
// All other status codes indicate issues
|
||||
// Check for specific error responses that indicate no access
|
||||
const data = response.data as any;
|
||||
const errorMessage = data?.error?.message || '';
|
||||
|
||||
// Explicitly check for organization verification errors
|
||||
if (response.status === 403 && errorMessage.includes("organization must be verified")) {
|
||||
this.log.warn(
|
||||
{ key: key.hash, status: response.status, error: errorMessage },
|
||||
"Key does not have access to gpt-image-1: organization verification required"
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only 401/403/404 responses indicate the key doesn't have model access
|
||||
// (we're now considering 400 as valid)
|
||||
if (response.status === 401 || response.status === 403 || response.status === 404) {
|
||||
this.log.warn(
|
||||
{ key: key.hash, status: response.status, error: errorMessage },
|
||||
`Key does not have access to gpt-image-1: received ${response.status} response`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
// For other status codes, log the issue but assume no access
|
||||
this.log.warn(
|
||||
{ key: key.hash, status: response.status, error: data?.error?.message || 'Unknown error' },
|
||||
{ key: key.hash, status: response.status, error: errorMessage },
|
||||
"Unexpected response when testing gpt-image-1 access, assuming no access"
|
||||
);
|
||||
return false;
|
||||
|
||||
} catch (error) {
|
||||
// Handle network errors or request failures
|
||||
if (error instanceof AxiosError && error.response) {
|
||||
// Check for forbidden/unauthorized responses
|
||||
const status = error.response.status;
|
||||
const data = error.response.data as any;
|
||||
const errorMessage = data?.error?.message || 'Unknown error';
|
||||
|
||||
// Organization verification errors (403 forbidden)
|
||||
if (status === 403) {
|
||||
// Check for specific error messages related to access
|
||||
if (errorMessage.includes("organization must be verified") ||
|
||||
errorMessage.includes("does not have access") ||
|
||||
errorMessage.includes("not available")) {
|
||||
this.log.warn(
|
||||
{ key: key.hash, error: errorMessage },
|
||||
"Key does not have access to gpt-image-1: received 403 Forbidden response"
|
||||
{ key: key.hash, status, error: errorMessage },
|
||||
"Key does not have access to gpt-image-1 based on error message"
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Explicitly handle all status codes that indicate the key doesn't have access
|
||||
if (status === 401 || status === 404 || status === 400) {
|
||||
this.log.warn(
|
||||
// Status 400 or 500 indicates the API processed the request but had validation issues
|
||||
// This means the key is authorized to use the model
|
||||
if (status === 400 || status === 500) {
|
||||
this.log.info(
|
||||
{ key: key.hash, status, error: errorMessage },
|
||||
`Key does not have access to gpt-image-1: received ${status} response`
|
||||
`Verified gpt-image-1 access with error response ${status}`
|
||||
);
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Rate limit errors - we no longer assume these mean the key has access
|
||||
// since the rate limit could be happening before model validation
|
||||
if (status === 429) {
|
||||
// 401/403/404 responses indicate the key doesn't have proper access
|
||||
if (status === 401 || status === 403 || status === 404) {
|
||||
this.log.warn(
|
||||
{ key: key.hash, status, error: errorMessage },
|
||||
"Cannot verify gpt-image-1 access: key is rate limited. Assuming no access for safety."
|
||||
`Key does not have access to gpt-image-1: received ${status} error response`
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -433,7 +442,7 @@ export class OpenAIKeyChecker extends KeyCheckerBase<OpenAIKey> {
|
||||
// For all other errors, assume no access
|
||||
this.log.error(
|
||||
{ key: key.hash, error: error.message },
|
||||
"Unexpected error testing gpt-image-1 access. Assuming no access for safety."
|
||||
"Error testing gpt-image-1 access. Assuming no access for safety."
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user