diff --git a/bot_microservice/constants.py b/bot_microservice/constants.py index 02bc24c..4ce23e8 100644 --- a/bot_microservice/constants.py +++ b/bot_microservice/constants.py @@ -54,6 +54,7 @@ class ChatGptModelsEnum(StrEnum): gpt_3_5_turbo_stream_Cromicle = "gpt-3.5-turbo-stream-Cromicle" gpt_4_stream_Chatgpt4Online = "gpt-4-stream-Chatgpt4Online" gpt_3_5_turbo_stream_gptalk = "gpt-3.5-turbo-stream-gptalk" + llama2 = "llama2" gpt_3_5_turbo_stream_ChatgptDemo = "gpt-3.5-turbo-stream-ChatgptDemo" gpt_3_5_turbo_stream_gptforlove = "gpt-3.5-turbo-stream-gptforlove" diff --git a/chatgpt_microservice/include/free_gpt.h b/chatgpt_microservice/include/free_gpt.h index 5fb5e4b..a4c46b2 100644 --- a/chatgpt_microservice/include/free_gpt.h +++ b/chatgpt_microservice/include/free_gpt.h @@ -36,6 +36,7 @@ public: boost::asio::awaitable gptalk(std::shared_ptr, nlohmann::json); boost::asio::awaitable gptForLove(std::shared_ptr, nlohmann::json); boost::asio::awaitable chatGptDemo(std::shared_ptr, nlohmann::json); + boost::asio::awaitable llama2(std::shared_ptr, nlohmann::json); private: boost::asio::awaitable, std::string>> diff --git a/chatgpt_microservice/src/free_gpt.cpp b/chatgpt_microservice/src/free_gpt.cpp index d1b0172..e5a09a3 100644 --- a/chatgpt_microservice/src/free_gpt.cpp +++ b/chatgpt_microservice/src/free_gpt.cpp @@ -575,6 +575,90 @@ std::expected callZeus(const std::string& host, con return rsp; } +struct CurlHttpRequest { + CURL* curl; + std::string url; + std::string_view http_proxy; + size_t (*cb)(void* contents, size_t size, size_t nmemb, void* userp); + void* input; + std::unordered_map& headers; + std::string body; + std::multimap* response_header_ptr{nullptr}; + int32_t expect_response_code{200}; + bool ssl_verify{false}; +}; + +std::optional sendHttpRequest(const CurlHttpRequest& curl_http_request) { + auto& [curl, url, http_proxy, stream_action_cb, input, http_headers, body, response_header_ptr, response_code, + ssl_verify] = curl_http_request; + curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); + if (!http_proxy.empty()) + curl_easy_setopt(curl, CURLOPT_PROXY, http_proxy.data()); + if (!ssl_verify) { + curl_easy_setopt(curl, CURLOPT_CAINFO, nullptr); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); + } + curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 20L); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, 120L); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30L); + if (stream_action_cb != nullptr) + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, stream_action_cb); + if (input != nullptr) + curl_easy_setopt(curl, CURLOPT_WRITEDATA, input); + + std::string buffer; + auto header_callback = [](char* buffer, size_t size, size_t nitems, void* userdata) { + std::string str{(char*)buffer, size * nitems}; + static_cast(userdata)->append((char*)buffer, size * nitems); + return nitems * size; + }; + size_t (*fn_header_callback)(char* buffer, size_t size, size_t nitems, void* userdata) = header_callback; + if (response_header_ptr) { + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, fn_header_callback); + curl_easy_setopt(curl, CURLOPT_HEADERDATA, &buffer); + } + + struct curl_slist* headers = nullptr; + std::vector headers_list; + for (auto& [k, v] : http_headers) + headers_list.emplace_back(std::format("{}: {}", k, v)); + for (auto& header : headers_list) + headers = curl_slist_append(headers, header.c_str()); + if (headers != nullptr) + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + ScopeExit auto_exit{[=] { curl_slist_free_all(headers); }}; + + if (!body.empty()) + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str()); + + auto res = curl_easy_perform(curl); + if (res != CURLE_OK) { + auto error_info = std::format("curl_easy_perform() failed:{}", curl_easy_strerror(res)); + return error_info; + } + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); + if (response_code != 200) { + auto error_info = std::format("response_code :{}", response_code); + return error_info; + } + if (!buffer.empty() && response_header_ptr != nullptr) { + std::regex pattern(R"(([^:\r\n]+):([^\r\n]+))"); + std::smatch matches; + auto start = buffer.cbegin(); + auto end = buffer.cend(); + while (std::regex_search(start, end, matches, pattern)) { + std::string field_name = matches[1].str(); + std::string field_value = matches[2].str(); + (*response_header_ptr).insert(std::pair{field_name, field_value}); + start = matches[0].second; + } + } + return std::nullopt; +} + } // namespace FreeGpt::FreeGpt(Config& cfg) @@ -2558,15 +2642,20 @@ boost::asio::awaitable FreeGpt::chatGptDemo(std::shared_ptr ch, n auto prompt = json.at("meta").at("content").at("parts").at(0).at("content").get(); - CURLcode res; - int32_t response_code; - struct Input { std::shared_ptr ch; std::string recv; }; Input input; + std::unordered_map http_headers{ + {"authority", "chat.chatgptdemo.net"}, + {"origin", "https://chat.chatgptdemo.net"}, + {"referer", "https://chat.chatgptdemo.net/"}, + }; + std::multimap response_header; + + CURLcode res; CURL* curl = curl_easy_init(); if (!curl) { auto error_info = std::format("curl_easy_init() failed:{}", curl_easy_strerror(res)); @@ -2574,48 +2663,39 @@ boost::asio::awaitable FreeGpt::chatGptDemo(std::shared_ptr ch, n ch->try_send(err, error_info); co_return; } - curl_easy_setopt(curl, CURLOPT_URL, "https://chat.chatgptdemo.net/"); + ScopeExit auto_exit{[=] { curl_easy_cleanup(curl); }}; - if (!m_cfg.http_proxy.empty()) - curl_easy_setopt(curl, CURLOPT_PROXY, m_cfg.http_proxy.c_str()); - curlEasySetopt(curl); - - auto action_cb = [](void* contents, size_t size, size_t nmemb, void* userp) -> size_t { - auto input_ptr = static_cast(userp); - std::string data{(char*)contents, size * nmemb}; - auto& [ch, recv] = *input_ptr; - recv.append(data); - return size * nmemb; - }; - size_t (*action_fn)(void* contents, size_t size, size_t nmemb, void* userp) = action_cb; - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, action_fn); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &input); - - struct curl_slist* headers = nullptr; - headers = curl_slist_append(headers, "origin: https://chat.chatgptdemo.net"); - headers = curl_slist_append(headers, "referer: https://chat.chatgptdemo.net/"); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - - ScopeExit auto_exit{[=] { - curl_slist_free_all(headers); - curl_easy_cleanup(curl); - }}; - - res = curl_easy_perform(curl); - if (res != CURLE_OK) { + auto ret = sendHttpRequest(CurlHttpRequest{ + .curl = curl, + .url = "https://chat.chatgptdemo.net/", + .http_proxy = m_cfg.http_proxy, + .cb = [](void* contents, size_t size, size_t nmemb, void* userp) mutable -> size_t { + auto input_ptr = static_cast(userp); + std::string data{(char*)contents, size * nmemb}; + auto& [ch, recv] = *input_ptr; + recv.append(data); + return size * nmemb; + }, + .input = [&] -> void* { + input.recv.clear(); + return &input; + }(), + .headers = http_headers, + .body = std::string{}, + .response_header_ptr = &response_header, + .expect_response_code = 200, + .ssl_verify = false, + }); + if (ret) { co_await boost::asio::post(boost::asio::bind_executor(ch->get_executor(), boost::asio::use_awaitable)); - auto error_info = std::format("curl_easy_perform() failed:{}", curl_easy_strerror(res)); - ch->try_send(err, error_info); + ch->try_send(err, ret.value()); co_return; } - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); - if (response_code != 200) { - co_await boost::asio::post(boost::asio::bind_executor(ch->get_executor(), boost::asio::use_awaitable)); - ch->try_send(err, std::format("chatGptDemo http code:{}", response_code)); - co_return; - } - auto ret = findAll(R"(