recent changes
This commit is contained in:
@@ -4,49 +4,164 @@
|
||||
#include <string.h>
|
||||
#include <json-c/json.h>
|
||||
|
||||
/* forward declaration (defined later in this file) */
|
||||
/* forward declarations (defined later in this file) */
|
||||
static char *content_to_string(json_object *content);
|
||||
static const char *get_str(json_object *obj, const char *key);
|
||||
|
||||
static int count_content_tokens(json_object *content) {
|
||||
if (!content) return 0;
|
||||
enum json_type t = json_object_get_type(content);
|
||||
if (t == json_type_null) return 0;
|
||||
if (t == json_type_string)
|
||||
return tok_count(json_object_get_string(content),
|
||||
json_object_get_string_len(content));
|
||||
if (t == json_type_array) {
|
||||
int total = 0;
|
||||
int n = json_object_array_length(content);
|
||||
for (int i = 0; i < n; i++) {
|
||||
json_object *part = json_object_array_get_idx(content, i);
|
||||
if (!part) continue;
|
||||
enum json_type pt = json_object_get_type(part);
|
||||
if (pt == json_type_string) {
|
||||
total += tok_count(json_object_get_string(part),
|
||||
json_object_get_string_len(part));
|
||||
} else if (pt == json_type_object) {
|
||||
json_object *txt = NULL;
|
||||
if (json_object_object_get_ex(part, "text", &txt) &&
|
||||
json_object_get_type(txt) == json_type_string)
|
||||
total += tok_count(json_object_get_string(txt),
|
||||
json_object_get_string_len(txt));
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
const char *s = json_object_to_json_string(content);
|
||||
return s ? tok_count_str(s) : 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Token counting (embedded cl100k_base BPE) */
|
||||
/* ------------------------------------------------------------------ */
|
||||
int count_messages_tokens(void *req_obj) {
|
||||
json_object *req = (json_object *)req_obj;
|
||||
if (!req) return 0;
|
||||
int total = 0;
|
||||
|
||||
json_object *tools = NULL;
|
||||
if (json_object_object_get_ex(req, "tools", &tools) &&
|
||||
json_object_get_type(tools) == json_type_array &&
|
||||
json_object_array_length(tools) > 0) {
|
||||
const char *ts = json_object_to_json_string(tools);
|
||||
if (ts) total += tok_count_str(ts);
|
||||
}
|
||||
|
||||
json_object *messages = NULL;
|
||||
if (!json_object_object_get_ex(req, "messages", &messages) ||
|
||||
json_object_get_type(messages) != json_type_array)
|
||||
return 0;
|
||||
int total = 0;
|
||||
return total;
|
||||
|
||||
int n = json_object_array_length(messages);
|
||||
int sys_idx = -1;
|
||||
int last_nonsys_idx = -1;
|
||||
bool sys_has_content = false;
|
||||
for (int i = 0; i < n; i++) {
|
||||
json_object *m = json_object_array_get_idx(messages, i);
|
||||
if (!m) continue;
|
||||
const char *roleStr = get_str(m, "role");
|
||||
if (strcmp(roleStr, "system") == 0 && !sys_has_content) {
|
||||
sys_idx = i;
|
||||
if (count_content_tokens(json_object_object_get(m, "content")) > 0)
|
||||
sys_has_content = true;
|
||||
} else {
|
||||
last_nonsys_idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
json_object *m = json_object_array_get_idx(messages, i);
|
||||
if (!m) continue;
|
||||
const char *roleStr = get_str(m, "role");
|
||||
json_object *content = json_object_object_get(m, "content");
|
||||
char *cs = content_to_string(content);
|
||||
total += tok_count_str(cs);
|
||||
free(cs);
|
||||
json_object *rc = NULL;
|
||||
if (json_object_object_get_ex(m, "reasoning_content", &rc) &&
|
||||
json_object_get_type(rc) == json_type_string)
|
||||
total += tok_count_str(json_object_get_string(rc));
|
||||
json_object *tcs = NULL;
|
||||
if (json_object_object_get_ex(m, "tool_calls", &tcs) &&
|
||||
json_object_get_type(tcs) == json_type_array) {
|
||||
int tn = json_object_array_length(tcs);
|
||||
for (int j = 0; j < tn; j++) {
|
||||
json_object *tc = json_object_array_get_idx(tcs, j);
|
||||
if (!tc) continue;
|
||||
json_object *fn = NULL;
|
||||
if (json_object_object_get_ex(tc, "function", &fn) &&
|
||||
json_object_get_type(fn) == json_type_object) {
|
||||
json_object *nm = NULL, *ar = NULL;
|
||||
if (json_object_object_get_ex(fn, "name", &nm) &&
|
||||
json_object_get_type(nm) == json_type_string)
|
||||
total += tok_count_str(json_object_get_string(nm));
|
||||
if (json_object_object_get_ex(fn, "arguments", &ar) &&
|
||||
json_object_get_type(ar) == json_type_string)
|
||||
total += tok_count_str(json_object_get_string(ar));
|
||||
|
||||
if (i == sys_idx) {
|
||||
total += count_content_tokens(content);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i == last_nonsys_idx &&
|
||||
(strcmp(roleStr, "tool") == 0 || strcmp(roleStr, "function") == 0)) {
|
||||
const char *toolName = get_str(m, "name");
|
||||
if (toolName[0] == 0) toolName = get_str(m, "tool_call_id");
|
||||
if (toolName[0] != 0) {
|
||||
char *lastContent = content_to_string(content);
|
||||
const char *lc = lastContent ? lastContent : "";
|
||||
size_t need = strlen("Tool result for : ") + strlen(toolName) +
|
||||
strlen(lc) + 1;
|
||||
char *s = (char *)malloc(need);
|
||||
if (s) {
|
||||
snprintf(s, need, "Tool result for %s: %s", toolName, lc);
|
||||
total += tok_count_str(s);
|
||||
free(s);
|
||||
} else {
|
||||
total += tok_count_str(toolName) + count_content_tokens(content);
|
||||
}
|
||||
free(lastContent);
|
||||
} else {
|
||||
total += count_content_tokens(content);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
total += count_content_tokens(content);
|
||||
|
||||
if (strcmp(roleStr, "tool") == 0 || strcmp(roleStr, "function") == 0) {
|
||||
const char *toolID = get_str(m, "tool_call_id");
|
||||
const char *nm = get_str(m, "name");
|
||||
if (toolID[0] != 0) total += tok_count_str(toolID);
|
||||
if (nm[0] != 0) total += tok_count_str(nm);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(roleStr, "assistant") == 0) {
|
||||
json_object *rc = NULL;
|
||||
if (json_object_object_get_ex(m, "reasoning_content", &rc) &&
|
||||
json_object_get_type(rc) == json_type_string)
|
||||
total += tok_count(json_object_get_string(rc),
|
||||
json_object_get_string_len(rc));
|
||||
json_object *tcs = NULL;
|
||||
if (json_object_object_get_ex(m, "tool_calls", &tcs) &&
|
||||
json_object_get_type(tcs) == json_type_array) {
|
||||
int tn = json_object_array_length(tcs);
|
||||
for (int j = 0; j < tn; j++) {
|
||||
json_object *tc = json_object_array_get_idx(tcs, j);
|
||||
if (!tc) continue;
|
||||
json_object *fn = NULL;
|
||||
if (json_object_object_get_ex(tc, "function", &fn) &&
|
||||
json_object_get_type(fn) == json_type_object) {
|
||||
json_object *nm = NULL, *ar = NULL;
|
||||
if (json_object_object_get_ex(fn, "name", &nm) &&
|
||||
json_object_get_type(nm) == json_type_string)
|
||||
total += tok_count(json_object_get_string(nm),
|
||||
json_object_get_string_len(nm));
|
||||
if (json_object_object_get_ex(fn, "arguments", &ar) &&
|
||||
json_object_get_type(ar) == json_type_string)
|
||||
total += tok_count(json_object_get_string(ar),
|
||||
json_object_get_string_len(ar));
|
||||
}
|
||||
}
|
||||
}
|
||||
json_object *fc = NULL;
|
||||
if (json_object_object_get_ex(m, "function_call", &fc) &&
|
||||
json_object_get_type(fc) == json_type_object) {
|
||||
json_object *nm = NULL, *ar = NULL;
|
||||
if (json_object_object_get_ex(fc, "name", &nm) &&
|
||||
json_object_get_type(nm) == json_type_string)
|
||||
total += tok_count(json_object_get_string(nm),
|
||||
json_object_get_string_len(nm));
|
||||
if (json_object_object_get_ex(fc, "arguments", &ar) &&
|
||||
json_object_get_type(ar) == json_type_string)
|
||||
total += tok_count(json_object_get_string(ar),
|
||||
json_object_get_string_len(ar));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,11 +184,13 @@ int count_completion_tokens(const char *content, const char *reasoning,
|
||||
static char *content_to_string(json_object *content) {
|
||||
if (!content) return strdup("");
|
||||
enum json_type t = json_object_get_type(content);
|
||||
if (t == json_type_null) return strdup("");
|
||||
if (t == json_type_string)
|
||||
return strdup(json_object_get_string(content));
|
||||
if (t == json_type_array) {
|
||||
strbuf sb;
|
||||
sb_init(&sb);
|
||||
if (!sb.buf) return strdup("");
|
||||
int n = json_object_array_length(content);
|
||||
for (int i = 0; i < n; i++) {
|
||||
json_object *part = json_object_array_get_idx(content, i);
|
||||
@@ -88,9 +205,7 @@ static char *content_to_string(json_object *content) {
|
||||
sb_append_str(&sb, json_object_get_string(txt));
|
||||
}
|
||||
}
|
||||
char *r = strdup(sb.buf);
|
||||
sb_free(&sb);
|
||||
return r;
|
||||
return sb.buf;
|
||||
}
|
||||
const char *s = json_object_to_json_string(content);
|
||||
return s ? strdup(s) : strdup("");
|
||||
@@ -124,8 +239,7 @@ static double get_double(json_object *req, const char *key) {
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Build Gradio payload */
|
||||
/* ------------------------------------------------------------------ */
|
||||
char *build_gradio_payload(void *req_obj, const char *model_default) {
|
||||
(void)model_default;
|
||||
char *build_gradio_payload(void *req_obj) {
|
||||
json_object *req = (json_object *)req_obj;
|
||||
json_object *messages = NULL;
|
||||
if (!json_object_object_get_ex(req, "messages", &messages) ||
|
||||
@@ -133,19 +247,25 @@ char *build_gradio_payload(void *req_obj, const char *model_default) {
|
||||
return NULL;
|
||||
int n = json_object_array_length(messages);
|
||||
|
||||
char *system_str = strdup("");
|
||||
char *message_str = strdup("");
|
||||
int *nonSys = (int *)malloc(sizeof(int) * (size_t)(n > 0 ? n : 1));
|
||||
if (!nonSys) return NULL;
|
||||
json_object *history_arr = json_object_new_array();
|
||||
if (!history_arr) {
|
||||
free(nonSys);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *system_str = NULL;
|
||||
char *message_str = NULL;
|
||||
|
||||
/* First pass: pick first system message as system prompt, collect the
|
||||
* rest as non-system messages. */
|
||||
int *nonSys = (int *)malloc(sizeof(int) * (size_t)(n > 0 ? n : 1));
|
||||
int nonSysN = 0;
|
||||
for (int i = 0; i < n; i++) {
|
||||
json_object *m = json_object_array_get_idx(messages, i);
|
||||
if (!m) continue;
|
||||
const char *roleStr = get_str(m, "role");
|
||||
if (strcmp(roleStr, "system") == 0 && system_str[0] == 0) {
|
||||
if (strcmp(roleStr, "system") == 0 && (!system_str || system_str[0] == 0)) {
|
||||
char *cs = content_to_string(json_object_object_get(m, "content"));
|
||||
free(system_str);
|
||||
system_str = cs;
|
||||
@@ -160,17 +280,19 @@ char *build_gradio_payload(void *req_obj, const char *model_default) {
|
||||
json_object *m = json_object_array_get_idx(messages, i);
|
||||
const char *roleStr = get_str(m, "role");
|
||||
json_object *item = json_object_new_object();
|
||||
if (!item) continue;
|
||||
json_object_object_add(item, "role", json_object_new_string(roleStr));
|
||||
|
||||
json_object *content = json_object_object_get(m, "content");
|
||||
char *cs = content_to_string(content);
|
||||
const char *cstr = cs ? cs : "";
|
||||
if (strcmp(roleStr, "assistant") == 0) {
|
||||
if (cs[0] != 0)
|
||||
json_object_object_add(item, "content", json_object_new_string(cs));
|
||||
if (cstr[0] != 0)
|
||||
json_object_object_add(item, "content", json_object_new_string(cstr));
|
||||
else
|
||||
json_object_object_add(item, "content", json_object_new_null());
|
||||
} else {
|
||||
json_object_object_add(item, "content", json_object_new_string(cs));
|
||||
json_object_object_add(item, "content", json_object_new_string(cstr));
|
||||
}
|
||||
free(cs);
|
||||
|
||||
@@ -214,25 +336,25 @@ char *build_gradio_payload(void *req_obj, const char *model_default) {
|
||||
json_object *m = json_object_array_get_idx(messages, i);
|
||||
const char *roleStr = get_str(m, "role");
|
||||
char *lastContent = content_to_string(json_object_object_get(m, "content"));
|
||||
const char *lc = lastContent ? lastContent : "";
|
||||
if (strcmp(roleStr, "tool") == 0 || strcmp(roleStr, "function") == 0) {
|
||||
const char *toolName = get_str(m, "name");
|
||||
if (toolName[0] == 0) toolName = get_str(m, "tool_call_id");
|
||||
if (toolName[0] != 0) {
|
||||
size_t need = strlen("Tool result for : ") + strlen(toolName) +
|
||||
strlen(lastContent) + 1;
|
||||
strlen(lc) + 1;
|
||||
char *s = (char *)malloc(need);
|
||||
snprintf(s, need, "Tool result for %s: %s", toolName, lastContent);
|
||||
free(message_str);
|
||||
message_str = s;
|
||||
if (s) {
|
||||
snprintf(s, need, "Tool result for %s: %s", toolName, lc);
|
||||
message_str = s;
|
||||
}
|
||||
free(lastContent);
|
||||
} else {
|
||||
free(message_str);
|
||||
message_str = strdup(lastContent);
|
||||
message_str = lastContent;
|
||||
}
|
||||
} else {
|
||||
free(message_str);
|
||||
message_str = strdup(lastContent);
|
||||
message_str = lastContent;
|
||||
}
|
||||
free(lastContent);
|
||||
}
|
||||
|
||||
free(nonSys);
|
||||
@@ -250,20 +372,27 @@ char *build_gradio_payload(void *req_obj, const char *model_default) {
|
||||
bool topp_present = has_nonnull(req, "top_p");
|
||||
double topp = topp_present ? get_double(req, "top_p") : 0.0;
|
||||
|
||||
char *functions_json = NULL;
|
||||
const char *functions_json = "";
|
||||
json_object *tools = NULL;
|
||||
if (json_object_object_get_ex(req, "tools", &tools) &&
|
||||
json_object_get_type(tools) == json_type_array) {
|
||||
const char *s = json_object_to_json_string(tools);
|
||||
if (s) functions_json = strdup(s);
|
||||
if (s) functions_json = s;
|
||||
}
|
||||
if (!functions_json) functions_json = strdup("");
|
||||
|
||||
/* Assemble the Gradio data array. */
|
||||
json_object *root = json_object_new_object();
|
||||
json_object *data = json_object_new_array();
|
||||
json_object_array_add(data, json_object_new_string(message_str));
|
||||
json_object_array_add(data, json_object_new_string(system_str));
|
||||
if (!root || !data) {
|
||||
if (root) json_object_put(root);
|
||||
if (data) json_object_put(data);
|
||||
json_object_put(history_arr);
|
||||
free(system_str);
|
||||
free(message_str);
|
||||
return NULL;
|
||||
}
|
||||
json_object_array_add(data, json_object_new_string(message_str ? message_str : ""));
|
||||
json_object_array_add(data, json_object_new_string(system_str ? system_str : ""));
|
||||
json_object_array_add(data, history_arr);
|
||||
json_object_array_add(data, json_object_new_string("high"));
|
||||
if (temp_present)
|
||||
@@ -284,7 +413,6 @@ char *build_gradio_payload(void *req_obj, const char *model_default) {
|
||||
json_object_put(root);
|
||||
free(system_str);
|
||||
free(message_str);
|
||||
free(functions_json);
|
||||
return payload;
|
||||
}
|
||||
|
||||
@@ -336,6 +464,14 @@ int parse_gradio_stream(const char *data_json,
|
||||
*out_reasoning = (r && json_object_get_type(r) == json_type_string)
|
||||
? strdup(json_object_get_string(r))
|
||||
: strdup("");
|
||||
if (!*out_content || !*out_reasoning) {
|
||||
free(*out_content);
|
||||
free(*out_reasoning);
|
||||
*out_content = NULL;
|
||||
*out_reasoning = NULL;
|
||||
json_object_put(root);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (m >= 3) {
|
||||
json_object *tcobj = json_object_array_get_idx(inner, 2);
|
||||
@@ -343,38 +479,47 @@ int parse_gradio_stream(const char *data_json,
|
||||
int len = json_object_array_length(tcobj);
|
||||
if (len > 0) {
|
||||
tool_call_t *arr = (tool_call_t *)calloc((size_t)len, sizeof(tool_call_t));
|
||||
int cnt = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
json_object *e = json_object_array_get_idx(tcobj, i);
|
||||
if (json_object_get_type(e) != json_type_object) continue;
|
||||
json_object *fid = NULL, *ffn = NULL, *fname = NULL, *fargs = NULL;
|
||||
json_object_object_get_ex(e, "id", &fid);
|
||||
json_object_object_get_ex(e, "function", &ffn);
|
||||
if (ffn && json_object_get_type(ffn) == json_type_object) {
|
||||
json_object_object_get_ex(ffn, "name", &fname);
|
||||
json_object_object_get_ex(ffn, "arguments", &fargs);
|
||||
if (arr) {
|
||||
int cnt = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
json_object *e = json_object_array_get_idx(tcobj, i);
|
||||
if (json_object_get_type(e) != json_type_object) continue;
|
||||
json_object *fid = NULL, *ftype = NULL, *ffn = NULL, *fname = NULL, *fargs = NULL;
|
||||
json_object_object_get_ex(e, "id", &fid);
|
||||
json_object_object_get_ex(e, "type", &ftype);
|
||||
json_object_object_get_ex(e, "function", &ffn);
|
||||
if (ffn && json_object_get_type(ffn) == json_type_object) {
|
||||
json_object_object_get_ex(ffn, "name", &fname);
|
||||
json_object_object_get_ex(ffn, "arguments", &fargs);
|
||||
}
|
||||
arr[cnt].id = (fid && json_object_get_type(fid) == json_type_string)
|
||||
? strdup(json_object_get_string(fid))
|
||||
: strdup("");
|
||||
arr[cnt].type = (ftype && json_object_get_type(ftype) == json_type_string)
|
||||
? strdup(json_object_get_string(ftype))
|
||||
: strdup("");
|
||||
arr[cnt].name = (fname && json_object_get_type(fname) == json_type_string)
|
||||
? strdup(json_object_get_string(fname))
|
||||
: strdup("");
|
||||
arr[cnt].arguments =
|
||||
(fargs && json_object_get_type(fargs) == json_type_string)
|
||||
? strdup(json_object_get_string(fargs))
|
||||
: strdup("");
|
||||
if (!arr[cnt].id || !arr[cnt].type || !arr[cnt].name || !arr[cnt].arguments) {
|
||||
free(arr[cnt].id);
|
||||
free(arr[cnt].type);
|
||||
free(arr[cnt].name);
|
||||
free(arr[cnt].arguments);
|
||||
continue;
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
if (cnt > 0) {
|
||||
*out_tc = arr;
|
||||
*out_n_tc = cnt;
|
||||
} else {
|
||||
free(arr);
|
||||
}
|
||||
arr[cnt].id = (fid && json_object_get_type(fid) == json_type_string)
|
||||
? strdup(json_object_get_string(fid))
|
||||
: strdup("");
|
||||
arr[cnt].type = (json_object_object_get_ex(e, "type", &fid) &&
|
||||
json_object_get_type(fid) == json_type_string)
|
||||
? strdup(json_object_get_string(fid))
|
||||
: strdup("");
|
||||
arr[cnt].name = (fname && json_object_get_type(fname) == json_type_string)
|
||||
? strdup(json_object_get_string(fname))
|
||||
: strdup("");
|
||||
arr[cnt].arguments =
|
||||
(fargs && json_object_get_type(fargs) == json_type_string)
|
||||
? strdup(json_object_get_string(fargs))
|
||||
: strdup("");
|
||||
cnt++;
|
||||
}
|
||||
if (cnt > 0) {
|
||||
*out_tc = arr;
|
||||
*out_n_tc = cnt;
|
||||
} else {
|
||||
free(arr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -436,11 +581,15 @@ char *build_completion_response(const char *id, long created, const char *model,
|
||||
json_object_object_add(root, "choices", choices);
|
||||
|
||||
int completion_tokens = count_completion_tokens(content, reasoning, tc, n_tc);
|
||||
int reasoning_tokens = (reasoning && reasoning[0]) ? tok_count_str(reasoning) : 0;
|
||||
int total_tokens = prompt_tokens + completion_tokens;
|
||||
json_object *usage = json_object_new_object();
|
||||
json_object_object_add(usage, "prompt_tokens", json_object_new_int(prompt_tokens));
|
||||
json_object_object_add(usage, "completion_tokens", json_object_new_int(completion_tokens));
|
||||
json_object_object_add(usage, "total_tokens", json_object_new_int(total_tokens));
|
||||
json_object *details = json_object_new_object();
|
||||
json_object_object_add(details, "reasoning_tokens", json_object_new_int(reasoning_tokens));
|
||||
json_object_object_add(usage, "completion_tokens_details", details);
|
||||
json_object_object_add(root, "usage", usage);
|
||||
|
||||
const char *s = json_object_to_json_string(root);
|
||||
|
||||
Reference in New Issue
Block a user