Download client_curl_pipe.c from ttl0110/llm-proxy: direct link, hf CLI and curl.
- Browser
- Download file 10.3 kB
-
https://huggingface.co/spaces/ttl0110/llm-proxy/resolve/main/client_curl_pipe.c
- Command line
-
hf download hf://spaces/ttl0110/llm-proxy/client_curl_pipe.c
-
curl -L -o client_curl_pipe.c https://huggingface.co/spaces/ttl0110/llm-proxy/resolve/main/client_curl_pipe.c
10.3 kB
| /* | |
| * 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. | |
| */ | |
| 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://huggingface.co/proxy/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); | |
| } | |
| } | |