modified: languages/awk/Dockerfile
modified: languages/c/curl/Dockerfile modified: languages/c/libsoup/Dockerfile modified: languages/c/nghttp2/Dockerfile modified: languages/c/nghttp2/uncloseai.c modified: languages/cpp/boost-beast/Dockerfile modified: languages/cpp/cpp-httplib/Dockerfile modified: languages/cpp/libcurl/Dockerfile modified: languages/csharp/openai/Dockerfile modified: languages/go/http/Dockerfile modified: languages/go/openai/Dockerfile modified: languages/lua/Dockerfile modified: languages/ruby/openai/Dockerfile modified: languages/vbnet/Dockerfile
This commit is contained in:
parent
fc4b021b7f
commit
45ccee4b71
14 changed files with 228 additions and 63 deletions
|
|
@ -1,5 +1,5 @@
|
|||
# GNU AWK 5.3.2 (checked 2025-10-13: gawk 5.3.2-r2 is latest in Alpine edge)
|
||||
FROM alpine:3.22
|
||||
FROM alpine:latest
|
||||
|
||||
RUN apk add --no-cache gawk curl ca-certificates
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Pin to specific Alpine version (checked 2025-10-12: alpine:3.21 is latest stable)
|
||||
FROM alpine:3.21
|
||||
FROM alpine:latest
|
||||
|
||||
# Install C compiler and libcurl development libraries
|
||||
RUN apk --no-cache add \
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Pin to specific Alpine version (checked 2025-10-14: alpine:3.20 is latest stable)
|
||||
FROM alpine:3.20
|
||||
FROM alpine:latest
|
||||
|
||||
# Install C compiler and libsoup development libraries
|
||||
RUN apk --no-cache add \
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Pin to specific Alpine version (checked 2025-10-14: alpine:3.20 is latest stable)
|
||||
FROM alpine:3.20
|
||||
FROM alpine:latest
|
||||
|
||||
# Install C compiler and nghttp2 development libraries
|
||||
RUN apk --no-cache add \
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* UncloseAI C Client using nghttp2 (HTTP/2)
|
||||
* OpenAI-compatible API client with HTTP/2 support
|
||||
* OpenAI-compatible API client with HTTP/2 and streaming support
|
||||
* Compatible with vLLM, Ollama, and OpenAI-compatible endpoints
|
||||
*/
|
||||
|
||||
|
|
@ -43,6 +43,9 @@ struct Connection {
|
|||
size_t response_size;
|
||||
size_t response_capacity;
|
||||
int done;
|
||||
int streaming;
|
||||
char stream_buffer[8192];
|
||||
size_t stream_buffer_pos;
|
||||
};
|
||||
|
||||
// Request data provider
|
||||
|
|
@ -151,23 +154,86 @@ ssize_t recv_callback(nghttp2_session *session, uint8_t *buf, size_t length,
|
|||
return rv;
|
||||
}
|
||||
|
||||
// Extract content from SSE data chunk
|
||||
void extract_sse_content(const char *data, char *content, size_t max_len) {
|
||||
const char *content_marker = "\"content\":\"";
|
||||
const char *start = strstr(data, content_marker);
|
||||
if (!start) return;
|
||||
|
||||
start += strlen(content_marker);
|
||||
const char *end = start;
|
||||
|
||||
// Find closing quote, handling escaped quotes
|
||||
while (*end && *end != '"') {
|
||||
if (*end == '\\' && *(end + 1)) {
|
||||
end += 2;
|
||||
} else {
|
||||
end++;
|
||||
}
|
||||
}
|
||||
|
||||
size_t len = end - start;
|
||||
if (len > max_len - 1) len = max_len - 1;
|
||||
strncpy(content, start, len);
|
||||
content[len] = '\0';
|
||||
}
|
||||
|
||||
// Data chunk received callback
|
||||
int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id, const uint8_t *data,
|
||||
size_t len, void *user_data) {
|
||||
struct Connection *conn = (struct Connection *)user_data;
|
||||
|
||||
// Resize buffer if needed
|
||||
if (conn->response_size + len > conn->response_capacity) {
|
||||
size_t new_capacity = (conn->response_capacity + len) * 2;
|
||||
char *new_data = realloc(conn->response_data, new_capacity);
|
||||
if (!new_data) return 0;
|
||||
conn->response_data = new_data;
|
||||
conn->response_capacity = new_capacity;
|
||||
}
|
||||
if (conn->streaming) {
|
||||
// Process streaming SSE data
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (conn->stream_buffer_pos >= sizeof(conn->stream_buffer) - 1) {
|
||||
conn->stream_buffer_pos = 0; // Reset if overflow
|
||||
}
|
||||
|
||||
memcpy(conn->response_data + conn->response_size, data, len);
|
||||
conn->response_size += len;
|
||||
conn->stream_buffer[conn->stream_buffer_pos++] = data[i];
|
||||
|
||||
// Check for line ending
|
||||
if (data[i] == '\n' && conn->stream_buffer_pos >= 2 &&
|
||||
conn->stream_buffer[conn->stream_buffer_pos - 2] == '\n') {
|
||||
conn->stream_buffer[conn->stream_buffer_pos] = '\0';
|
||||
|
||||
// Process SSE line
|
||||
if (strncmp(conn->stream_buffer, "data: ", 6) == 0) {
|
||||
const char *json_data = conn->stream_buffer + 6;
|
||||
|
||||
// Check for [DONE]
|
||||
if (strncmp(json_data, "[DONE]", 6) == 0) {
|
||||
conn->stream_buffer_pos = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// Extract and print content
|
||||
char content[1024];
|
||||
extract_sse_content(json_data, content, sizeof(content));
|
||||
|
||||
if (strlen(content) > 0) {
|
||||
printf("%s", content);
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
conn->stream_buffer_pos = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Non-streaming: accumulate response
|
||||
if (conn->response_size + len > conn->response_capacity) {
|
||||
size_t new_capacity = (conn->response_capacity + len) * 2;
|
||||
char *new_data = realloc(conn->response_data, new_capacity);
|
||||
if (!new_data) return 0;
|
||||
conn->response_data = new_data;
|
||||
conn->response_capacity = new_capacity;
|
||||
}
|
||||
|
||||
memcpy(conn->response_data + conn->response_size, data, len);
|
||||
conn->response_size += len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -201,38 +267,8 @@ ssize_t data_provider_read_callback(nghttp2_session *session, int32_t stream_id,
|
|||
return to_copy;
|
||||
}
|
||||
|
||||
// Make HTTP/2 request
|
||||
int http2_request(const char *host, int port, const char *path,
|
||||
const char *method, const char *body,
|
||||
char **response, size_t *response_size) {
|
||||
int sock = connect_to_server(host, port);
|
||||
if (sock < 0) return -1;
|
||||
|
||||
// Initialize connection
|
||||
struct Connection conn = {0};
|
||||
conn.sock = sock;
|
||||
conn.response_data = malloc(BUFFER_SIZE);
|
||||
conn.response_capacity = BUFFER_SIZE;
|
||||
conn.response_size = 0;
|
||||
conn.done = 0;
|
||||
|
||||
// Setup nghttp2 callbacks
|
||||
nghttp2_session_callbacks *callbacks;
|
||||
nghttp2_session_callbacks_new(&callbacks);
|
||||
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
|
||||
nghttp2_session_callbacks_set_recv_callback(callbacks, recv_callback);
|
||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(callbacks, on_data_chunk_recv_callback);
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback(callbacks, on_stream_close_callback);
|
||||
|
||||
// Create client session
|
||||
nghttp2_session_client_new(&conn.session, callbacks, &conn);
|
||||
nghttp2_session_callbacks_del(callbacks);
|
||||
|
||||
// Send HTTP/2 connection preface
|
||||
nghttp2_submit_settings(conn.session, NGHTTP2_FLAG_NONE, NULL, 0);
|
||||
|
||||
// Prepare headers
|
||||
nghttp2_nv hdrs[5];
|
||||
// Setup HTTP/2 headers
|
||||
void setup_http2_headers(nghttp2_nv *hdrs, const char *method, const char *path, const char *host) {
|
||||
hdrs[0].name = (uint8_t *)":method";
|
||||
hdrs[0].value = (uint8_t *)method;
|
||||
hdrs[0].namelen = strlen(":method");
|
||||
|
|
@ -262,6 +298,46 @@ int http2_request(const char *host, int port, const char *path,
|
|||
hdrs[4].namelen = strlen("content-type");
|
||||
hdrs[4].valuelen = strlen("application/json");
|
||||
hdrs[4].flags = NGHTTP2_NV_FLAG_NONE;
|
||||
}
|
||||
|
||||
// Setup nghttp2 session with callbacks
|
||||
void setup_nghttp2_session(struct Connection *conn, nghttp2_session_callbacks *callbacks) {
|
||||
nghttp2_session_callbacks_new(&callbacks);
|
||||
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
|
||||
nghttp2_session_callbacks_set_recv_callback(callbacks, recv_callback);
|
||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(callbacks, on_data_chunk_recv_callback);
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback(callbacks, on_stream_close_callback);
|
||||
|
||||
nghttp2_session_client_new(&conn->session, callbacks, conn);
|
||||
nghttp2_session_callbacks_del(callbacks);
|
||||
|
||||
nghttp2_submit_settings(conn->session, NGHTTP2_FLAG_NONE, NULL, 0);
|
||||
}
|
||||
|
||||
// Make HTTP/2 request
|
||||
int http2_request(const char *host, int port, const char *path,
|
||||
const char *method, const char *body,
|
||||
char **response, size_t *response_size) {
|
||||
int sock = connect_to_server(host, port);
|
||||
if (sock < 0) return -1;
|
||||
|
||||
// Initialize connection
|
||||
struct Connection conn = {0};
|
||||
conn.sock = sock;
|
||||
conn.response_data = malloc(BUFFER_SIZE);
|
||||
conn.response_capacity = BUFFER_SIZE;
|
||||
conn.response_size = 0;
|
||||
conn.done = 0;
|
||||
conn.streaming = 0;
|
||||
conn.stream_buffer_pos = 0;
|
||||
|
||||
// Setup nghttp2 session and callbacks
|
||||
nghttp2_session_callbacks *callbacks;
|
||||
setup_nghttp2_session(&conn, callbacks);
|
||||
|
||||
// Prepare headers
|
||||
nghttp2_nv hdrs[5];
|
||||
setup_http2_headers(hdrs, method, path, host);
|
||||
|
||||
// Submit request
|
||||
if (body && strlen(body) > 0) {
|
||||
|
|
@ -290,6 +366,55 @@ int http2_request(const char *host, int port, const char *path,
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Make streaming HTTP/2 request
|
||||
int http2_stream_request(const char *host, int port, const char *path,
|
||||
const char *method, const char *body) {
|
||||
int sock = connect_to_server(host, port);
|
||||
if (sock < 0) return -1;
|
||||
|
||||
// Initialize connection for streaming
|
||||
struct Connection conn = {0};
|
||||
conn.sock = sock;
|
||||
conn.response_data = malloc(BUFFER_SIZE);
|
||||
conn.response_capacity = BUFFER_SIZE;
|
||||
conn.response_size = 0;
|
||||
conn.done = 0;
|
||||
conn.streaming = 1; // Enable streaming mode
|
||||
conn.stream_buffer_pos = 0;
|
||||
|
||||
// Setup nghttp2 session and callbacks
|
||||
nghttp2_session_callbacks *callbacks;
|
||||
setup_nghttp2_session(&conn, callbacks);
|
||||
|
||||
// Prepare headers
|
||||
nghttp2_nv hdrs[5];
|
||||
setup_http2_headers(hdrs, method, path, host);
|
||||
|
||||
// Submit request
|
||||
if (body && strlen(body) > 0) {
|
||||
struct RequestData req_data = {body, strlen(body), 0};
|
||||
nghttp2_data_provider data_prd;
|
||||
data_prd.source.ptr = &req_data;
|
||||
data_prd.read_callback = data_provider_read_callback;
|
||||
nghttp2_submit_request(conn.session, NULL, hdrs, 5, &data_prd, NULL);
|
||||
} else {
|
||||
nghttp2_submit_request(conn.session, NULL, hdrs, 4, NULL, NULL);
|
||||
}
|
||||
|
||||
// Send and receive (streaming prints directly in callback)
|
||||
while (!conn.done) {
|
||||
if (nghttp2_session_send(conn.session) != 0) break;
|
||||
if (nghttp2_session_recv(conn.session) != 0) break;
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
free(conn.response_data);
|
||||
nghttp2_session_del(conn.session);
|
||||
close(sock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Simple JSON string extractor
|
||||
void extract_model_ids(const char *json, const char *endpoint) {
|
||||
const char *search = json;
|
||||
|
|
@ -393,17 +518,17 @@ int main(void) {
|
|||
}
|
||||
printf("\n");
|
||||
|
||||
// Non-streaming chat
|
||||
printf("=== Non-Streaming Chat ===\n");
|
||||
// Non-streaming chat (Hermes)
|
||||
printf("=== Non-Streaming Chat (Hermes) ===\n");
|
||||
printf("Model: %s\n", models[0].id);
|
||||
|
||||
char json[2048];
|
||||
snprintf(json, sizeof(json),
|
||||
"{\"model\":\"%s\","
|
||||
"\"messages\":[{\"role\":\"user\",\"content\":\"Explain quantum computing in one sentence\"}],"
|
||||
"\"messages\":[{\"role\":\"user\",\"content\":\"Give a Python Fizzbuzz solution in one line of code?\"}],"
|
||||
"\"stream\":false,"
|
||||
"\"max_tokens\":100,"
|
||||
"\"temperature\":0.7}",
|
||||
"\"max_tokens\":150,"
|
||||
"\"temperature\":0.5}",
|
||||
models[0].id);
|
||||
|
||||
char *response = NULL;
|
||||
|
|
@ -421,6 +546,46 @@ int main(void) {
|
|||
printf("Request failed\n\n");
|
||||
}
|
||||
|
||||
// Streaming chat (Hermes)
|
||||
printf("=== Streaming Chat (Hermes) ===\n");
|
||||
printf("Model: %s\n", models[0].id);
|
||||
printf("Response: ");
|
||||
|
||||
char stream_json_hermes[2048];
|
||||
snprintf(stream_json_hermes, sizeof(stream_json_hermes),
|
||||
"{\"model\":\"%s\","
|
||||
"\"messages\":[{\"role\":\"user\",\"content\":\"Give a Python Fizzbuzz solution in one line of code?\"}],"
|
||||
"\"stream\":true,"
|
||||
"\"max_tokens\":500,"
|
||||
"\"temperature\":0.7}",
|
||||
models[0].id);
|
||||
|
||||
if (http2_stream_request(models[0].host, models[0].port, path, "POST", stream_json_hermes) != 0) {
|
||||
printf("\nStreaming request failed");
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
// Streaming chat (Qwen Coder 3) - if second model available
|
||||
if (model_count >= 2) {
|
||||
printf("=== Streaming Chat (Qwen Coder 3) ===\n");
|
||||
printf("Model: %s\n", models[1].id);
|
||||
printf("Response: ");
|
||||
|
||||
char stream_json_qwen[2048];
|
||||
snprintf(stream_json_qwen, sizeof(stream_json_qwen),
|
||||
"{\"model\":\"%s\","
|
||||
"\"messages\":[{\"role\":\"user\",\"content\":\"Write a hello world program in C\"}],"
|
||||
"\"stream\":true,"
|
||||
"\"max_tokens\":500,"
|
||||
"\"temperature\":0.7}",
|
||||
models[1].id);
|
||||
|
||||
if (http2_stream_request(models[1].host, models[1].port, path, "POST", stream_json_qwen) != 0) {
|
||||
printf("\nStreaming request failed");
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
// TTS
|
||||
if (tts_count > 0) {
|
||||
printf("=== TTS Speech Generation ===\n");
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Pin to specific Alpine version (checked 2025-10-14: alpine:3.20 is latest stable)
|
||||
FROM alpine:3.20
|
||||
FROM alpine:latest
|
||||
|
||||
# Install C++ compiler and Boost libraries
|
||||
RUN apk --no-cache add \
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Pin to specific Alpine version (checked 2025-10-14: alpine:3.20 is latest stable)
|
||||
FROM alpine:3.20
|
||||
FROM alpine:latest
|
||||
|
||||
# Install C++ compiler and build tools
|
||||
RUN apk --no-cache add \
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Pin to specific Alpine version (checked 2025-10-12: alpine:3.21 is latest stable)
|
||||
FROM alpine:3.21
|
||||
FROM alpine:latest
|
||||
|
||||
# Install C++ compiler and libcurl development libraries
|
||||
RUN apk --no-cache add \
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Use official .NET SDK to build
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS builder
|
||||
FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
|
@ -12,7 +12,7 @@ COPY uncloseai.cs ./
|
|||
RUN dotnet build -c Release -o /app/build
|
||||
|
||||
# Run stage
|
||||
FROM mcr.microsoft.com/dotnet/runtime:8.0
|
||||
FROM mcr.microsoft.com/dotnet/runtime:9.0-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ COPY uncloseai.go .
|
|||
RUN go build -o uncloseai uncloseai.go
|
||||
|
||||
# Use minimal alpine image for runtime
|
||||
FROM alpine:3.21
|
||||
FROM alpine:latest
|
||||
|
||||
# Install ca-certificates for HTTPS
|
||||
RUN apk --no-cache add ca-certificates
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Multi-stage build for Go with official OpenAI SDK
|
||||
FROM golang:1.22-alpine AS builder
|
||||
FROM golang:1.23-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Alpine 3.22 with Lua 5.4 (checked 2025-10-13: alpine:3.22 with lua5.4 is latest stable)
|
||||
FROM alpine:3.22
|
||||
FROM alpine:latest
|
||||
|
||||
RUN apk add --no-cache lua5.4 lua5.4-dev luarocks5.4 ca-certificates openssl-dev gcc musl-dev
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# Use official Ruby image
|
||||
FROM ruby:3.3-slim
|
||||
FROM ruby:3.3-alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:9.0-alpine AS base
|
||||
WORKDIR /app
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
|
||||
FROM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build
|
||||
WORKDIR /src
|
||||
COPY ["UncloseAI.vbproj", "."]
|
||||
RUN dotnet restore "UncloseAI.vbproj"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue