mirror of
https://git.jabber.space/devs/cproof.git
synced 2026-07-19 05:26:21 +00:00
fix(ai): improve API error parsing and fallback
Add early return for empty responses and fallback to console output when the AI window is closed or invalid. Implement JSON error parsing to extract readable messages from API failures, improving debugging and user feedback.
This commit is contained in:
@@ -121,18 +121,27 @@ _aiwin_display_error(gpointer user_data, const gchar* error_msg)
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a response message in the AI window (thread-safe).
|
||||
* Display a response message. If aiwin is provided and valid, display in AI window.
|
||||
* Otherwise, display in console (for commands run from console).
|
||||
* @param user_data The original user_data pointer (may be NULL)
|
||||
* @param response The response message to display
|
||||
*/
|
||||
static void
|
||||
_aiwin_display_response(gpointer user_data, const gchar* response)
|
||||
{
|
||||
ProfAiWin* aiwin = _aiwin_validate(user_data);
|
||||
if (!aiwin) {
|
||||
log_warning("[AI-THREAD] Cannot display response: aiwin is invalid or window was closed");
|
||||
if (!response || strlen(response) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Try to display in AI window if available */
|
||||
ProfAiWin* aiwin = _aiwin_validate(user_data);
|
||||
if (!aiwin) {
|
||||
pthread_mutex_lock(&lock);
|
||||
cons_show("%s", response);
|
||||
pthread_mutex_unlock(&lock);
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&lock);
|
||||
aiwin_display_response(aiwin, response);
|
||||
pthread_mutex_unlock(&lock);
|
||||
@@ -1270,6 +1279,64 @@ _parse_ai_response(const gchar* response_json)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract error message from an API error JSON response.
|
||||
* Handles format: {"error":{"message":"...","type":"...","code":...}}
|
||||
*/
|
||||
static gchar*
|
||||
_parse_error_response(const gchar* error_json)
|
||||
{
|
||||
if (!error_json || strlen(error_json) == 0)
|
||||
return NULL;
|
||||
|
||||
/* Look for "message":"..." inside "error" object */
|
||||
const gchar* error_obj = strstr(error_json, "\"error\":");
|
||||
if (!error_obj)
|
||||
return NULL;
|
||||
|
||||
const gchar* message_key = strstr(error_obj, "\"message\":\"");
|
||||
if (!message_key)
|
||||
return NULL;
|
||||
|
||||
message_key += strlen("\"message\":\"");
|
||||
const gchar* msg_start = message_key;
|
||||
const gchar* p = msg_start;
|
||||
while (*p) {
|
||||
if (*p == '\\' && *(p + 1) == '"') {
|
||||
p += 2;
|
||||
continue;
|
||||
}
|
||||
if (*p == '"') {
|
||||
gsize len = p - msg_start;
|
||||
gchar* result = g_new0(gchar, len + 1);
|
||||
gchar* out = result;
|
||||
const gchar* in = msg_start;
|
||||
while (in < p) {
|
||||
if (*in == '\\' && *(in + 1) == '"') {
|
||||
*out++ = '"';
|
||||
in += 2;
|
||||
} else if (*in == '\\' && *(in + 1) == 'n') {
|
||||
*out++ = '\n';
|
||||
in += 2;
|
||||
} else if (*in == '\\' && *(in + 1) == '\\') {
|
||||
*out++ = '\\';
|
||||
in += 2;
|
||||
} else if (*in == '\\' && *(in + 1) == 't') {
|
||||
*out++ = '\t';
|
||||
in += 2;
|
||||
} else {
|
||||
*out++ = *in++;
|
||||
}
|
||||
}
|
||||
*out = '\0';
|
||||
return result;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
_ai_request_thread(gpointer data)
|
||||
{
|
||||
@@ -1328,7 +1395,11 @@ _ai_request_thread(gpointer data)
|
||||
log_debug("[AI-THREAD] API Request URL: %s", request_url);
|
||||
log_debug("[AI-THREAD] Model: %s", session->model);
|
||||
|
||||
/* Execute request with POST fields */
|
||||
/* Set URL and execute request */
|
||||
curl_easy_setopt(curl, CURLOPT_URL, request_url);
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _write_callback);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_payload);
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 60L);
|
||||
|
||||
@@ -1348,8 +1419,9 @@ _ai_request_thread(gpointer data)
|
||||
/* Handle HTTP errors */
|
||||
log_debug("[AI-THREAD] HTTP error response body (%zu bytes): %s",
|
||||
response.size, response.data ? response.data : "NULL");
|
||||
auto_gchar gchar* error_msg = g_strdup_printf("HTTP %ld: %s", http_code,
|
||||
response.data ? response.data : "Unknown error");
|
||||
/* Try to extract the actual error message from the JSON response */
|
||||
auto_gchar gchar* parsed_error = _parse_error_response(response.data);
|
||||
auto_gchar gchar* error_msg = parsed_error ? g_strdup_printf("HTTP %ld: %s", http_code, parsed_error) : g_strdup_printf("HTTP %ld: %s", http_code, response.data && strlen(response.data) > 0 ? response.data : "Unknown error");
|
||||
log_error("AI request failed for %s/%s: %s", session->provider_name, session->model, error_msg);
|
||||
_aiwin_display_error(user_data, error_msg);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user