Optimize startup, HTTP/SSE streaming, and fix macOS libedit bindings
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
* and non-streaming response parsing. */
|
||||
#include "bantam.hpp"
|
||||
#include <cerrno>
|
||||
#include <charconv>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
@@ -118,6 +119,19 @@ static void dump_str(std::string &out, std::string_view s) {
|
||||
const unsigned char *p = (const unsigned char *)s.data();
|
||||
size_t avail = s.size();
|
||||
while (avail > 0) {
|
||||
/* Fast path: scan contiguous unescaped printable ASCII. */
|
||||
size_t run = 0;
|
||||
while (run < avail) {
|
||||
unsigned char b = p[run];
|
||||
if (b >= 0x20 && b < 0x80 && b != '"' && b != '\\') run++;
|
||||
else break;
|
||||
}
|
||||
if (run > 0) {
|
||||
out.append((const char *)p, run);
|
||||
p += run;
|
||||
avail -= run;
|
||||
if (avail == 0) break;
|
||||
}
|
||||
unsigned char c = p[0];
|
||||
if (c < 0x80) {
|
||||
p++;
|
||||
@@ -130,10 +144,12 @@ static void dump_str(std::string &out, std::string_view s) {
|
||||
case '\n': out += "\\n"; break;
|
||||
case '\r': out += "\\r"; break;
|
||||
case '\t': out += "\\t"; break;
|
||||
default:
|
||||
if (c < 0x20) str_appendf(out, "\\u%04x", (unsigned)c);
|
||||
else out += (char)c;
|
||||
default: {
|
||||
char ubuf[7];
|
||||
std::snprintf(ubuf, sizeof ubuf, "\\u%04x", (unsigned)c);
|
||||
out.append(ubuf, 6);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
size_t pl = 0;
|
||||
@@ -160,12 +176,22 @@ static void dump_rec(std::string &out, const Json &j, int indent, int depth) {
|
||||
case JType::Bool:
|
||||
out += (j.bval ? "true" : "false");
|
||||
break;
|
||||
case JType::Int:
|
||||
str_appendf(out, "%lld", (long long)j.ival);
|
||||
case JType::Int: {
|
||||
char ibuf[32];
|
||||
auto [ptr, ec] = std::to_chars(ibuf, ibuf + sizeof ibuf, j.ival);
|
||||
if (ec == std::errc()) out.append(ibuf, (size_t)(ptr - ibuf));
|
||||
else str_appendf(out, "%lld", (long long)j.ival);
|
||||
break;
|
||||
}
|
||||
case JType::Float:
|
||||
if (!std::isfinite(j.dval)) out += "null";
|
||||
else str_appendf(out, "%.15g", j.dval);
|
||||
if (!std::isfinite(j.dval)) {
|
||||
out += "null";
|
||||
} else {
|
||||
char fbuf[32];
|
||||
int n = std::snprintf(fbuf, sizeof fbuf, "%.15g", j.dval);
|
||||
if (n > 0 && (size_t)n < sizeof fbuf) out.append(fbuf, (size_t)n);
|
||||
else str_appendf(out, "%.15g", j.dval);
|
||||
}
|
||||
break;
|
||||
case JType::Str:
|
||||
dump_str(out, j.sval);
|
||||
@@ -217,6 +243,7 @@ static void dump_rec(std::string &out, const Json &j, int indent, int depth) {
|
||||
|
||||
std::string Json::dump(int indent) const {
|
||||
std::string out;
|
||||
out.reserve(256);
|
||||
dump_rec(out, *this, indent, 0);
|
||||
return out;
|
||||
}
|
||||
@@ -278,16 +305,25 @@ struct JParser {
|
||||
if (pos >= src.size() || src[pos] != '"') return false;
|
||||
pos++;
|
||||
out.clear();
|
||||
while (pos < src.size()) {
|
||||
unsigned char c = (unsigned char)src[pos++];
|
||||
const char *base = src.data();
|
||||
size_t n = src.size();
|
||||
while (pos < n) {
|
||||
/* Fast path: scan contiguous unescaped bytes >= 0x20. */
|
||||
size_t run_start = pos;
|
||||
while (pos < n) {
|
||||
unsigned char b = (unsigned char)base[pos];
|
||||
if (b == '"' || b == '\\' || b < 0x20) break;
|
||||
pos++;
|
||||
}
|
||||
if (pos > run_start) {
|
||||
out.append(base + run_start, pos - run_start);
|
||||
}
|
||||
if (pos >= n) return false;
|
||||
unsigned char c = (unsigned char)base[pos++];
|
||||
if (c == '"') return true;
|
||||
if (c < 0x20) return false;
|
||||
if (c != '\\') {
|
||||
out += (char)c;
|
||||
continue;
|
||||
}
|
||||
if (pos >= src.size()) return false;
|
||||
char esc = src[pos++];
|
||||
if (pos >= n) return false;
|
||||
char esc = base[pos++];
|
||||
switch (esc) {
|
||||
case '"': out += '"'; break;
|
||||
case '\\': out += '\\'; break;
|
||||
@@ -301,7 +337,7 @@ struct JParser {
|
||||
uint32_t cp = 0;
|
||||
if (!parse_hex4(cp)) return false;
|
||||
if (cp >= 0xD800 && cp <= 0xDBFF) {
|
||||
if (pos + 6 <= src.size() && src[pos] == '\\' && src[pos + 1] == 'u') {
|
||||
if (pos + 6 <= n && base[pos] == '\\' && base[pos + 1] == 'u') {
|
||||
size_t saved = pos;
|
||||
pos += 2;
|
||||
uint32_t low = 0;
|
||||
@@ -353,20 +389,32 @@ struct JParser {
|
||||
if (pos >= src.size() || src[pos] < '0' || src[pos] > '9') return false;
|
||||
while (pos < src.size() && src[pos] >= '0' && src[pos] <= '9') pos++;
|
||||
}
|
||||
std::string num_str(src.substr(start, pos - start));
|
||||
const char *first = src.data() + start;
|
||||
const char *last = src.data() + pos;
|
||||
if (!is_float) {
|
||||
errno = 0;
|
||||
char *end = nullptr;
|
||||
long long iv = std::strtoll(num_str.c_str(), &end, 10);
|
||||
if (errno == 0 && end == num_str.c_str() + num_str.size()) {
|
||||
out = Json((int64_t)iv);
|
||||
int64_t iv = 0;
|
||||
auto [ptr, ec] = std::from_chars(first, last, iv);
|
||||
if (ec == std::errc() && ptr == last) {
|
||||
out = Json(iv);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
char stack_num[64];
|
||||
std::string heap_num;
|
||||
const char *cstr = nullptr;
|
||||
size_t nlen = pos - start;
|
||||
if (nlen < sizeof stack_num) {
|
||||
std::memcpy(stack_num, first, nlen);
|
||||
stack_num[nlen] = '\0';
|
||||
cstr = stack_num;
|
||||
} else {
|
||||
heap_num.assign(first, nlen);
|
||||
cstr = heap_num.c_str();
|
||||
}
|
||||
errno = 0;
|
||||
char *end = nullptr;
|
||||
double dv = std::strtod(num_str.c_str(), &end);
|
||||
if (end != num_str.c_str() + num_str.size() || !std::isfinite(dv)) return false;
|
||||
double dv = std::strtod(cstr, &end);
|
||||
if (end != cstr + nlen || !std::isfinite(dv)) return false;
|
||||
out = Json(dv);
|
||||
return true;
|
||||
}
|
||||
@@ -554,6 +602,7 @@ std::string build_request_json(const Cfg &cfg, const Messages &msgs,
|
||||
root["model"] = cfg.model;
|
||||
root["temperature"] = cfg.temperature;
|
||||
Json arr = Json::array();
|
||||
arr.aval.reserve(msgs.items.size());
|
||||
for (auto &m : msgs.items) {
|
||||
Json mo;
|
||||
serialize_message_json(mo, m);
|
||||
@@ -562,10 +611,12 @@ std::string build_request_json(const Cfg &cfg, const Messages &msgs,
|
||||
root["messages"] = std::move(arr);
|
||||
root["stream"] = stream;
|
||||
if (use_tools) {
|
||||
Json tools;
|
||||
if (Json::parse(TOOLS_JSON, tools)) {
|
||||
root["tools"] = std::move(tools);
|
||||
}
|
||||
static const Json kTools = []() {
|
||||
Json t;
|
||||
Json::parse(TOOLS_JSON, t);
|
||||
return t;
|
||||
}();
|
||||
root["tools"] = kTools;
|
||||
}
|
||||
if (stream) {
|
||||
Json so = Json::object();
|
||||
|
||||
Reference in New Issue
Block a user