/* * LLM Proxy Client - C Version (Windows using curl.exe and anonymous pipes) * Compile: gcc -std=c11 -O2 -Wall -Wextra -o llm_client_curl_pipe.exe client_curl_pipe.c * Usage: llm_client_curl_pipe.exe * Requires curl.exe, included with current Windows 10 and Windows 11. * Prompt and response stay in memory; this client does not create temporary files. */ #include #include #include #include #define MAX_PROMPT_SIZE 4096 #define MAX_RESPONSE_SIZE 65536 typedef struct { const char *name; const char *id; } LLMModel; static const LLMModel MODELS[] = { {"Laguna S 2.1 (Free)", "poolside/laguna-s-2.1:free"}, {"Gemini 3.6 Flash (Paid)", "google/gemini-3.6-flash"}, {"Claude Opus 5 (Paid)", "anthropic/claude-opus-5"}, {"Claude Fable 5 (Paid)", "anthropic/claude-fable-5"}, {"GPT-5.6 Sol (Paid)", "openai/gpt-5.6-sol"}, {"GPT-5.6 Luna (Paid)", "openai/gpt-5.6-luna"}, {"Nemotron 3 Ultra (Free)", "nvidia/nemotron-3-ultra-550b-a55b:free"} }; static const int MODEL_COUNT = sizeof(MODELS) / sizeof(MODELS[0]); static char *copy_string(const char *text) { size_t size = strlen(text) + 1; char *copy = (char *)malloc(size); if (copy != NULL) { memcpy(copy, text, size); } return copy; } static char *error_message(const char *message, DWORD code) { char buffer[256]; snprintf(buffer, sizeof(buffer), "Error: %s (code: %lu)", message, (unsigned long)code); return copy_string(buffer); } static void close_handle(HANDLE *handle) { if (*handle != NULL && *handle != INVALID_HANDLE_VALUE) { CloseHandle(*handle); *handle = NULL; } } static int write_all(HANDLE pipe, const char *data, size_t size) { size_t total_written = 0; while (total_written < size) { DWORD chunk_size = (DWORD)(size - total_written); DWORD written = 0; if (!WriteFile(pipe, data + total_written, chunk_size, &written, NULL)) { return 0; } if (written == 0) { return 0; } total_written += written; } return 1; } static char *read_all(HANDLE pipe) { char *response = (char *)malloc(MAX_RESPONSE_SIZE); char buffer[4096]; if (response == NULL) { return copy_string("Error: Memory allocation failed"); } size_t total_size = 0; while (1) { DWORD bytes_read = 0; if (!ReadFile(pipe, buffer, sizeof(buffer), &bytes_read, NULL)) { DWORD error = GetLastError(); if (error == ERROR_BROKEN_PIPE) { break; } free(response); return error_message("Failed to read curl output", error); } if (bytes_read == 0) { break; } size_t remaining = MAX_RESPONSE_SIZE - 1 - total_size; size_t bytes_to_copy = bytes_read < remaining ? bytes_read : remaining; if (bytes_to_copy > 0) { memcpy(response + total_size, buffer, bytes_to_copy); total_size += bytes_to_copy; } } response[total_size] = '\0'; return response; } char *ask_llm(const char *prompt, const LLMModel *model) { SECURITY_ATTRIBUTES security_attributes; STARTUPINFOA startup_info; PROCESS_INFORMATION process_info; HANDLE stdin_read = NULL; HANDLE stdin_write = NULL; HANDLE stdout_read = NULL; HANDLE stdout_write = NULL; DWORD exit_code = 0; char curl_path[MAX_PATH]; char command[1024]; char *response = NULL; ZeroMemory(&security_attributes, sizeof(security_attributes)); ZeroMemory(&process_info, sizeof(process_info)); security_attributes.nLength = sizeof(security_attributes); security_attributes.bInheritHandle = TRUE; UINT system_path_length = GetSystemDirectoryA(curl_path, sizeof(curl_path)); if (system_path_length == 0 || system_path_length >= sizeof(curl_path) - 9) { return error_message("Failed to locate the Windows system directory", GetLastError()); } strcat(curl_path, "\\curl.exe"); if (!CreatePipe(&stdin_read, &stdin_write, &security_attributes, 0)) { return error_message("Failed to create curl stdin pipe", GetLastError()); } if (!SetHandleInformation(stdin_write, HANDLE_FLAG_INHERIT, 0)) { response = error_message("Failed to configure curl stdin pipe", GetLastError()); goto cleanup; } if (!CreatePipe(&stdout_read, &stdout_write, &security_attributes, 0)) { response = error_message("Failed to create curl output pipe", GetLastError()); goto cleanup; } if (!SetHandleInformation(stdout_read, HANDLE_FLAG_INHERIT, 0)) { response = error_message("Failed to configure curl output pipe", GetLastError()); goto cleanup; } int command_length = snprintf( command, sizeof(command), "curl.exe --silent --show-error --fail-with-body --connect-timeout 30 " "--max-time 120 --request POST --header \"Content-Type: text/plain; charset=utf-8\" " "--header \"X-Model: %s\" --data-binary @- " "https://ttl0110-llm-proxy.hf.space/ask", model->id); if (command_length < 0 || command_length >= (int)sizeof(command)) { response = copy_string("Error: curl command is too long"); goto cleanup; } ZeroMemory(&startup_info, sizeof(startup_info)); ZeroMemory(&process_info, sizeof(process_info)); startup_info.cb = sizeof(startup_info); startup_info.dwFlags = STARTF_USESTDHANDLES; startup_info.hStdInput = stdin_read; startup_info.hStdOutput = stdout_write; startup_info.hStdError = stdout_write; if (!CreateProcessA( curl_path, command, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &startup_info, &process_info)) { response = error_message("Failed to start curl.exe", GetLastError()); goto cleanup; } close_handle(&stdin_read); close_handle(&stdout_write); if (!write_all(stdin_write, prompt, strlen(prompt))) { response = error_message("Failed to write prompt to curl.exe", GetLastError()); } close_handle(&stdin_write); char *curl_output = read_all(stdout_read); if (response == NULL) { response = curl_output; } else { free(curl_output); } close_handle(&stdout_read); WaitForSingleObject(process_info.hProcess, INFINITE); if (!GetExitCodeProcess(process_info.hProcess, &exit_code) && response == NULL) { response = error_message("Failed to read curl exit code", GetLastError()); } close_handle(&process_info.hThread); close_handle(&process_info.hProcess); if (exit_code != 0 && response != NULL && response[0] == '\0') { free(response); response = error_message("curl.exe request failed", exit_code); } cleanup: close_handle(&stdin_read); close_handle(&stdin_write); close_handle(&stdout_read); close_handle(&stdout_write); close_handle(&process_info.hThread); close_handle(&process_info.hProcess); return response != NULL ? response : copy_string("Error: Unknown request failure"); } void clear_input_buffer(void) { int c; while ((c = getchar()) != '\n' && c != EOF); } int main(void) { char prompt[MAX_PROMPT_SIZE]; char prompt_prefix[MAX_PROMPT_SIZE] = {0}; int choice = 0; SetConsoleOutputCP(CP_UTF8); SetConsoleCP(CP_UTF8); printf("=== C LLM Assistant (curl.exe pipes) ===\n\n"); printf("Chon Model LLM:\n"); for (int i = 0; i < MODEL_COUNT; i++) { printf("%d. %s\n", i + 1, MODELS[i].name); } while (choice < 1 || choice > MODEL_COUNT) { printf("Nhap lua chon (1-%d): ", MODEL_COUNT); if (scanf("%d", &choice) != 1) { clear_input_buffer(); choice = 0; } } clear_input_buffer(); const LLMModel *selected_model = &MODELS[choice - 1]; printf("Ban da chon: %s\n\n", selected_model->name); printf("Nhap prompt prefix (bo trong neu khong dung): "); if (fgets(prompt_prefix, sizeof(prompt_prefix), stdin) != NULL) { prompt_prefix[strcspn(prompt_prefix, "\r\n")] = '\0'; } printf("Huong dan: Nhap prompt cua ban. Nhap dong trong de gui.\n"); printf("Nhap 'EXIT' de thoat.\n"); while (1) { char full_prompt[MAX_PROMPT_SIZE] = {0}; size_t total_len = 0; printf("\nBan [%s]:\n", selected_model->name); while (1) { if (fgets(prompt, sizeof(prompt), stdin) == NULL) { printf("Tam biet!\n"); return 0; } if (_strnicmp(prompt, "EXIT", 4) == 0 && (prompt[4] == '\n' || prompt[4] == '\r' || prompt[4] == '\0')) { printf("Tam biet!\n"); return 0; } if (prompt[0] == '\n' || (prompt[0] == '\r' && prompt[1] == '\n')) { break; } size_t line_len = strlen(prompt); if (total_len + line_len < MAX_PROMPT_SIZE - 1) { strcat(full_prompt, prompt); total_len += line_len; } } if (total_len == 0) { printf("Prompt trong, vui long nhap lai.\n"); continue; } while (total_len > 0 && (full_prompt[total_len - 1] == '\n' || full_prompt[total_len - 1] == '\r')) { full_prompt[--total_len] = '\0'; } char request_prompt[MAX_PROMPT_SIZE] = {0}; if (prompt_prefix[0] != '\0') { int written = snprintf(request_prompt, sizeof(request_prompt), "%s\n\n%s", prompt_prefix, full_prompt); if (written < 0 || written >= (int)sizeof(request_prompt)) { printf("Prompt va prefix qua dai, vui long nhap lai.\n"); continue; } } else { strcpy(request_prompt, full_prompt); } printf("Thinking...\n"); char *response = ask_llm(request_prompt, selected_model); printf("\n[LLM]: %s\n", response); printf("-------------------------------------------\n"); free(response); } }