This example demonstrates how to interact with uncloseai.com API endpoints using C and libcurl. It covers three core functionalities:
The implementation uses libcurl for HTTP requests. In Alpine Linux:
apk add gcc musl-dev curl-dev make
// Construct JSON request payload
const char *hermes_json = "{"
"\"model\":\"adamo1139/Hermes-3-Llama-3.1-8B-FP8-Dynamic\","
"\"messages\":[{\"role\":\"user\",\"content\":\"Give a C function to check if a number is prime\"}],"
"\"temperature\":0.5,"
"\"max_tokens\":150"
"}";
// Make POST request with libcurl
struct MemoryStruct chunk = {NULL, 0};
chunk.memory = malloc(1);
chunk.size = 0;
if(post_request("https://hermes.ai.unturf.com/v1/chat/completions",
hermes_json, &chunk) == 0) {
printf("Response received (%zu bytes)\n", chunk.size);
}
free(chunk.memory);
const char *qwen_json = "{"
"\"model\":\"hf.co/unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF:Q4_K_M\","
"\"messages\":[{\"role\":\"user\",\"content\":\"Write a C function to reverse a string in place\"}],"
"\"temperature\":0.5,"
"\"max_tokens\":200"
"}";
struct MemoryStruct chunk = {NULL, 0};
chunk.memory = malloc(1);
chunk.size = 0;
if(post_request("https://qwen.ai.unturf.com/v1/chat/completions",
qwen_json, &chunk) == 0) {
printf("Response received (%zu bytes)\n", chunk.size);
}
free(chunk.memory);
const char *tts_json = "{"
"\"model\":\"tts-1\","
"\"voice\":\"alloy\","
"\"input\":\"Hello from C with libcurl!\""
"}";
CURL *curl = curl_easy_init();
if(curl) {
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Content-Type: application/json");
headers = curl_slist_append(headers, "Authorization: Bearer YOLO");
struct MemoryStruct chunk = {NULL, 0};
chunk.memory = malloc(1);
chunk.size = 0;
curl_easy_setopt(curl, CURLOPT_URL, "https://speech.ai.unturf.com/v1/audio/speech");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, tts_json);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
CURLcode res = curl_easy_perform(curl);
if(res == CURLE_OK) {
FILE *fp = fopen("speech.mp3", "wb");
if(fp) {
fwrite(chunk.memory, 1, chunk.size, fp);
fclose(fp);
printf("Speech file created: speech.mp3\n");
}
}
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
free(chunk.memory);
}
struct MemoryStruct {
char *memory;
size_t size;
};
static size_t WriteMemoryCallback(void *contents, size_t size,
size_t nmemb, void *userp) {
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
char *ptr = realloc(mem->memory, mem->size + realsize + 1);
if(!ptr) {
printf("Not enough memory\n");
return 0;
}
mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
Key points:
WriteMemoryCallback is called by libcurl as data arrivesrealloc to grow the buffer dynamicallyint post_request(const char *url, const char *json_data,
struct MemoryStruct *chunk) {
CURL *curl;
CURLcode res;
struct curl_slist *headers = NULL;
curl = curl_easy_init();
if(!curl) return -1;
// Set Content-Type and Authorization headers
headers = curl_slist_append(headers, "Content-Type: application/json");
headers = curl_slist_append(headers, "Authorization: Bearer dummy-key");
// Configure curl options
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_data);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)chunk);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 30L);
res = curl_easy_perform(curl);
curl_slist_free_all(headers);
curl_easy_cleanup(curl);
return (res == CURLE_OK) ? 0 : -1;
}
Key points:
CURLOPT_URL - Target endpointCURLOPT_HTTPHEADER - Custom headers (Content-Type, Authorization)CURLOPT_POSTFIELDS - JSON request bodyCURLOPT_WRITEFUNCTION - Callback for response dataCURLOPT_TIMEOUT - 30-second timeoutint main(void) {
// Initialize libcurl globally (once per process)
curl_global_init(CURL_GLOBAL_ALL);
// ... make API calls ...
// Cleanup libcurl globally before exit
curl_global_cleanup();
return 0;
}
Key points:
curl_global_init() must be called before any curl operationscurl_global_cleanup() should be called before program exitdocker build -t ai-unturf-c languages/c/
docker run --rm ai-unturf-c
# Install dependencies (Alpine Linux)
apk add gcc musl-dev curl-dev make
# Compile
make
# Run
./examples
# Alpine Linux
apk add curl-dev
# Debian/Ubuntu
apt-get install libcurl4-openssl-dev
# macOS
brew install curl
ca-certificates is installed:
apk add ca-certificates
Ensure you're linking against libcurl:
gcc -o examples examples.c -lcurl
The -lcurl flag must come after the source file.
Always free allocated memory:
chunk.memory after each requestcurl_slist_free_all() on header listscurl_easy_cleanup() on curl handlescurl_global_cleanup() before program exitThis example demonstrates raw HTTP communication. For production use, add JSON parsing:
Example with cJSON:
#include <cjson/cJSON.h>
// After receiving response in chunk.memory:
cJSON *json = cJSON_Parse(chunk.memory);
if(json) {
cJSON *choices = cJSON_GetObjectItem(json, "choices");
cJSON *first_choice = cJSON_GetArrayItem(choices, 0);
cJSON *message = cJSON_GetObjectItem(first_choice, "message");
cJSON *content = cJSON_GetObjectItem(message, "content");
printf("AI Response: %s\n", content->valuestring);
cJSON_Delete(json);
}
CURLOPT_SSL_VERIFYPEER for production HTTPS