/* * LLM Proxy Client - C++ Version (Linux/WSL using libcurl) * Dependencies: sudo apt install g++ libcurl4-openssl-dev * Compile: g++ -std=c++11 -O2 -Wall -Wextra -pedantic client.cpp -lcurl -o llm_client_cpp * Usage: ./llm_client_cpp */ #include #include #include #include #include #include struct LLMModel { const char* name; const char* id; }; 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"} }; const std::size_t MODEL_COUNT = sizeof(MODELS) / sizeof(MODELS[0]); class CurlGlobal { public: CurlGlobal() { const CURLcode result = curl_global_init(CURL_GLOBAL_DEFAULT); if (result != CURLE_OK) { throw std::runtime_error(std::string("Failed to initialize libcurl: ") + curl_easy_strerror(result)); } } ~CurlGlobal() { curl_global_cleanup(); } CurlGlobal(const CurlGlobal&) = delete; CurlGlobal& operator=(const CurlGlobal&) = delete; }; class CurlHandle { public: CurlHandle() : handle_(curl_easy_init()) { if (!handle_) { throw std::runtime_error("Failed to create libcurl handle"); } } ~CurlHandle() { curl_easy_cleanup(handle_); } CurlHandle(const CurlHandle&) = delete; CurlHandle& operator=(const CurlHandle&) = delete; CURL* get() const { return handle_; } private: CURL* handle_; }; class CurlHeaders { public: ~CurlHeaders() { curl_slist_free_all(headers_); } void append(const std::string& header) { curl_slist* updated = curl_slist_append(headers_, header.c_str()); if (!updated) { throw std::runtime_error("Failed to allocate HTTP headers"); } headers_ = updated; } curl_slist* get() const { return headers_; } CurlHeaders(const CurlHeaders&) = delete; CurlHeaders& operator=(const CurlHeaders&) = delete; CurlHeaders() = default; private: curl_slist* headers_ = nullptr; }; std::size_t writeResponse(char* data, std::size_t size, std::size_t count, void* output) { const std::size_t bytes = size * count; static_cast(output)->append(data, bytes); return bytes; } void requireCurlOption(CURLcode result, const char* option) { if (result != CURLE_OK) { throw std::runtime_error(std::string("Failed to set ") + option + ": " + curl_easy_strerror(result)); } } std::string askLLM(const std::string& prompt, const LLMModel& model) { CurlHandle curl; CurlHeaders headers; std::string response; headers.append("Content-Type: text/plain; charset=utf-8"); headers.append(std::string("X-Model: ") + model.id); requireCurlOption(curl_easy_setopt(curl.get(), CURLOPT_URL, "https://ttl0110-llm-proxy.hf.space/ask"), "request URL"); requireCurlOption(curl_easy_setopt(curl.get(), CURLOPT_HTTPHEADER, headers.get()), "request headers"); requireCurlOption(curl_easy_setopt(curl.get(), CURLOPT_POST, 1L), "POST method"); requireCurlOption(curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDS, prompt.c_str()), "request body"); requireCurlOption(curl_easy_setopt(curl.get(), CURLOPT_POSTFIELDSIZE_LARGE, static_cast(prompt.size())), "request body size"); requireCurlOption(curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, writeResponse), "response callback"); requireCurlOption(curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &response), "response destination"); requireCurlOption(curl_easy_setopt(curl.get(), CURLOPT_CONNECTTIMEOUT, 30L), "connection timeout"); requireCurlOption(curl_easy_setopt(curl.get(), CURLOPT_TIMEOUT, 120L), "request timeout"); requireCurlOption(curl_easy_setopt(curl.get(), CURLOPT_USERAGENT, "LLM-Proxy-Cpp-Client/1.0"), "user agent"); const CURLcode result = curl_easy_perform(curl.get()); if (result != CURLE_OK) { throw std::runtime_error(std::string("Request failed: ") + curl_easy_strerror(result)); } long statusCode = 0; const CURLcode statusResult = curl_easy_getinfo(curl.get(), CURLINFO_RESPONSE_CODE, &statusCode); if (statusResult != CURLE_OK) { throw std::runtime_error(std::string("Failed to read HTTP status: ") + curl_easy_strerror(statusResult)); } if (statusCode < 200 || statusCode >= 300) { throw std::runtime_error("Server returned HTTP " + std::to_string(statusCode) + (response.empty() ? "" : ": " + response)); } return response; } std::size_t selectModel() { std::cout << "Chon Model LLM:\n"; for (std::size_t i = 0; i < MODEL_COUNT; ++i) { std::cout << i + 1 << ". " << MODELS[i].name << '\n'; } int choice = 0; while (choice < 1 || choice > static_cast(MODEL_COUNT)) { std::cout << "Nhap lua chon (1-" << MODEL_COUNT << "): "; if (!(std::cin >> choice)) { std::cin.clear(); } std::cin.ignore(std::numeric_limits::max(), '\n'); } return static_cast(choice - 1); } int main() { try { CurlGlobal curlGlobal; std::cout << "=== C++ LLM Assistant (HuggingFace Proxy) ===\n\n"; const LLMModel& selectedModel = MODELS[selectModel()]; std::cout << "Ban da chon: " << selectedModel.name << "\n\n"; std::cout << "Nhap prompt prefix (bo trong neu khong dung): "; std::string promptPrefix; std::getline(std::cin, promptPrefix); std::cout << "Huong dan: Nhap prompt cua ban. Nhap 'SUBMIT' o dong cuoi de gui.\n"; std::cout << "Nhap 'EXIT' o mot dong rieng de thoat.\n"; while (true) { std::cout << "\nBan [" << selectedModel.name << "]:\n"; std::ostringstream prompt; std::string line; bool exitRequested = false; while (std::getline(std::cin, line)) { if (line == "EXIT") { exitRequested = true; break; } if (line == "SUBMIT") { break; } if (prompt.tellp() > 0) { prompt << '\n'; } prompt << line; } if (exitRequested || !std::cin) { break; } const std::string promptText = prompt.str(); if (promptText.empty()) { std::cout << "Prompt trong, vui long nhap lai.\n"; continue; } const std::string fullPrompt = promptPrefix.empty() ? promptText : promptPrefix + "\n\n" + promptText; std::cout << "Thinking...\n"; try { std::cout << "\n[LLM]: " << askLLM(fullPrompt, selectedModel) << '\n'; } catch (const std::exception& error) { std::cout << "\nError: " << error.what() << '\n'; } std::cout << "-------------------------------------------\n"; } std::cout << "Tam biet!\n"; return 0; } catch (const std::exception& error) { std::cerr << "Fatal error: " << error.what() << '\n'; return 1; } }