diff --git a/chatgpt_microservice/README.md b/chatgpt_microservice/README.md index a1373e0..cfa21c1 100644 --- a/chatgpt_microservice/README.md +++ b/chatgpt_microservice/README.md @@ -64,15 +64,15 @@ docker pull fantasypeak/freegpt:latest Run the application using Docker: ``` -docker run -p 8858:8858 -it --name freegpt fantasypeak/freegpt:latest +docker run --rm -p 8858:8858 -it --name freegpt fantasypeak/freegpt:latest // OR -docker run --net=host -it --name freegpt fantasypeak/freegpt:latest +docker run --rm --net=host -it --name freegpt fantasypeak/freegpt:latest // use http_proxy -docker run -p 8858:8858 -it --name freegpt -e HTTP_PROXY=http://127.0.0.1:8080 -e CHAT_PATH=/chat fantasypeak/freegpt:latest +docker run --rm -p 8858:8858 -it --name freegpt -e HTTP_PROXY=http://127.0.0.1:8080 -e CHAT_PATH=/chat fantasypeak/freegpt:latest // set active providers -docker run -p 8858:8858 -it --name freegpt -e CHAT_PATH=/chat -e PROVIDERS="[\"gpt-4-ChatgptAi\",\"gpt-3.5-turbo-stream-DeepAi\"]" fantasypeak/freegpt:latest +docker run --rm -p 8858:8858 -it --name freegpt -e CHAT_PATH=/chat -e PROVIDERS="[\"gpt-4-ChatgptAi\",\"gpt-3.5-turbo-stream-DeepAi\"]" fantasypeak/freegpt:latest // enable ip white list function -docker run -p 8858:8858 -it --name freegpt -e IP_WHITE_LIST="[\"127.0.0.1\",\"192.168.1.1\"]" fantasypeak/freegpt:latest +docker run --rm -p 8858:8858 -it --name freegpt -e IP_WHITE_LIST="[\"127.0.0.1\",\"192.168.1.1\"]" fantasypeak/freegpt:latest ``` ### Start the Zeus Service @@ -88,7 +88,7 @@ docker run --rm --net=host -it --name freegpt fantasypeak/freegpt:latest ### Call OpenAi Api ``` // It supports calling OpenAI's API, but need set API_KEY -docker run -p 8858:8858 -it --name freegpt -e CHAT_PATH=/chat -e API_KEY=a40f22f2-c1a2-4b1d-a47f-55ae1a7ddbed fantasypeak/freegpt:latest +docker run --rm -p 8858:8858 -it --name freegpt -e CHAT_PATH=/chat -e API_KEY=a40f22f2-c1a2-4b1d-a47f-55ae1a7ddbed fantasypeak/freegpt:latest ``` ### WebUI diff --git a/chatgpt_microservice/deprecated/free_gpt.cpp b/chatgpt_microservice/deprecated/free_gpt.cpp index 1598c93..4832766 100644 --- a/chatgpt_microservice/deprecated/free_gpt.cpp +++ b/chatgpt_microservice/deprecated/free_gpt.cpp @@ -1072,3 +1072,62 @@ boost::asio::awaitable FreeGpt::aivvm(std::shared_ptr ch, nlohman }); co_return; } + +std::string generateHexStr(int length) { + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution<> dis(0, 15); + + std::stringstream ss; + ss << std::hex; + + for (int i = 0; i < length; i++) + ss << std::nouppercase << std::setw(1) << std::setfill('0') << dis(gen); + return ss.str(); +} + +std::string encrypt(const std::string& raw_data) { + auto random_key_str = generateHexStr(16); + auto random_iv_str = generateHexStr(16); + char key_buffer[17]{}; + memcpy(key_buffer, random_key_str.c_str(), random_key_str.size()); + std::vector key = plusaes::key_from_string(&key_buffer); // 16-char = 128-bit + unsigned char iv[16]{}; + memcpy(iv, random_iv_str.data(), 16); + const unsigned long encrypted_size = plusaes::get_padded_encrypted_size(raw_data.size()); + std::vector encrypted(encrypted_size); + plusaes::encrypt_cbc((unsigned char*)raw_data.data(), raw_data.size(), &key[0], key.size(), &iv, &encrypted[0], + encrypted.size(), true); + std::stringstream ss; + std::transform(encrypted.begin(), encrypted.end(), std::ostream_iterator(ss), + [](unsigned char c) -> std::string { return std::format("{:02x}", int(c)); }); + return ss.str() + random_key_str + random_iv_str; +} + +#include +#include +#include +#include +#include +std::expected decompress(auto& res) { + try { + boost::iostreams::array_source src{res.body().data(), res.body().size()}; + boost::iostreams::filtering_istream is; + if (res["Content-Encoding"] == "deflate") { + SPDLOG_INFO("decompressing: {}", res["Content-Encoding"]); + is.push(boost::iostreams::zlib_decompressor{-MAX_WBITS}); // deflate + } else if (res["Content-Encoding"] == "gzip") { + SPDLOG_INFO("decompressing: {}", res["Content-Encoding"]); + is.push(boost::iostreams::gzip_decompressor{}); // gzip + } else if (res["Content-Encoding"] == "") { + SPDLOG_INFO("uncompressed: {}", res["Content-Encoding"]); + } + is.push(src); + std::stringstream strstream; + boost::iostreams::copy(is, strstream); + return strstream.str(); + } catch (const std::exception& e) { + return std::unexpected(e.what()); + } +} + diff --git a/chatgpt_microservice/src/free_gpt.cpp b/chatgpt_microservice/src/free_gpt.cpp index e5f7578..b4bdfb5 100644 --- a/chatgpt_microservice/src/free_gpt.cpp +++ b/chatgpt_microservice/src/free_gpt.cpp @@ -11,15 +11,8 @@ #include #include #include -#include -#include #include #include -#include -#include -#include -#include -#include #include #include "free_gpt.h" @@ -65,37 +58,6 @@ std::string md5(const std::string& str, bool reverse = true) { return md5_str; } -std::string generateHexStr(int length) { - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution<> dis(0, 15); - - std::stringstream ss; - ss << std::hex; - - for (int i = 0; i < length; i++) - ss << std::nouppercase << std::setw(1) << std::setfill('0') << dis(gen); - return ss.str(); -} - -std::string encrypt(const std::string& raw_data) { - auto random_key_str = generateHexStr(16); - auto random_iv_str = generateHexStr(16); - char key_buffer[17]{}; - memcpy(key_buffer, random_key_str.c_str(), random_key_str.size()); - std::vector key = plusaes::key_from_string(&key_buffer); // 16-char = 128-bit - unsigned char iv[16]{}; - memcpy(iv, random_iv_str.data(), 16); - const unsigned long encrypted_size = plusaes::get_padded_encrypted_size(raw_data.size()); - std::vector encrypted(encrypted_size); - plusaes::encrypt_cbc((unsigned char*)raw_data.data(), raw_data.size(), &key[0], key.size(), &iv, &encrypted[0], - encrypted.size(), true); - std::stringstream ss; - std::transform(encrypted.begin(), encrypted.end(), std::ostream_iterator(ss), - [](unsigned char c) -> std::string { return std::format("{:02x}", int(c)); }); - return ss.str() + random_key_str + random_iv_str; -} - auto splitString(const std::string& input, const std::string& delimiter) { std::vector fields; std::string::size_type start = 0; @@ -123,119 +85,32 @@ std::vector findAll(const std::string& pattern, const std::string& return matches; } -std::string charToHex(char c) { - std::string result; - char first, second; - - first = (c & 0xF0) / 16; - first += first > 9 ? 'A' - 10 : '0'; - second = c & 0x0F; - second += second > 9 ? 'A' - 10 : '0'; - - result.append(1, first); - result.append(1, second); - - return result; -} - -std::string urlEncode(const std::string& src) { - std::string result; - std::string::const_iterator iter; - - for (iter = src.begin(); iter != src.end(); ++iter) { - switch (*iter) { - case ' ': - result.append(1, '+'); - break; - // alnum - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': - case 'G': - case 'H': - case 'I': - case 'J': - case 'K': - case 'L': - case 'M': - case 'N': - case 'O': - case 'P': - case 'Q': - case 'R': - case 'S': - case 'T': - case 'U': - case 'V': - case 'W': - case 'X': - case 'Y': - case 'Z': - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - case 'g': - case 'h': - case 'i': - case 'j': - case 'k': - case 'l': - case 'm': - case 'n': - case 'o': - case 'p': - case 'q': - case 'r': - case 's': - case 't': - case 'u': - case 'v': - case 'w': - case 'x': - case 'y': - case 'z': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - // mark - case '-': - case '_': - case '.': - case '!': - case '~': - case '*': - case '\'': - case '(': - case ')': - case '&': - case '=': - case '/': - case '\\': - case '?': - result.append(1, *iter); - break; - // escape - default: - result.append(1, '%'); - result.append(charToHex(*iter)); - break; +std::string paramsToQueryStr(const std::multimap& params) { + auto encode_query_param = [](const std::string& value) { + std::ostringstream escaped; + escaped.fill('0'); + escaped << std::hex; + for (auto c : value) { + if (std::isalnum(static_cast(c)) || c == '-' || c == '_' || c == '.' || c == '!' || c == '~' || + c == '*' || c == '\'' || c == '(' || c == ')') { + escaped << c; + } else { + escaped << std::uppercase; + escaped << '%' << std::setw(2) << static_cast(static_cast(c)); + escaped << std::nouppercase; + } } + return escaped.str(); + }; + std::string query; + for (auto it = params.begin(); it != params.end(); ++it) { + if (it != params.begin()) + query += "&"; + query += it->first; + query += "="; + query += encode_query_param(it->second); } - - return result; + return query; } enum class Status : uint8_t { @@ -352,28 +227,6 @@ boost::asio::awaitable sendRequestRecvChunk( co_return ret; } -std::expected decompress(auto& res) { - try { - boost::iostreams::array_source src{res.body().data(), res.body().size()}; - boost::iostreams::filtering_istream is; - if (res["Content-Encoding"] == "deflate") { - SPDLOG_INFO("decompressing: {}", res["Content-Encoding"]); - is.push(boost::iostreams::zlib_decompressor{-MAX_WBITS}); // deflate - } else if (res["Content-Encoding"] == "gzip") { - SPDLOG_INFO("decompressing: {}", res["Content-Encoding"]); - is.push(boost::iostreams::gzip_decompressor{}); // gzip - } else if (res["Content-Encoding"] == "") { - SPDLOG_INFO("uncompressed: {}", res["Content-Encoding"]); - } - is.push(src); - std::stringstream strstream; - boost::iostreams::copy(is, strstream); - return strstream.str(); - } catch (const std::exception& e) { - return std::unexpected(e.what()); - } -} - boost::asio::awaitable< std::expected, boost::asio::ssl::context, boost::beast::ssl_stream>, @@ -433,154 +286,12 @@ uint64_t getTimestamp(std::chrono::time_point now = s return timestamp; } -struct HttpResponse { - int32_t http_response_code; - std::vector> http_header; - std::string body; -}; - -// export CURL_IMPERSONATE=chrome110 -std::optional getCookie(CURL* curl, const std::string& url, const std::string& proxy) { - bool auto_clean = curl ? false : true; - - if (!curl) { - curl = curl_easy_init(); - if (!curl) { - SPDLOG_ERROR("curl_easy_init() failed"); - return std::nullopt; - } - } - - HttpResponse http_response; - - curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - if (!proxy.empty()) - curl_easy_setopt(curl, CURLOPT_PROXY, proxy.c_str()); - - auto write_callback = [](void* contents, size_t size, size_t nmemb, void* userp) -> size_t { - static_cast(userp)->append((char*)contents, size * nmemb); - return size * nmemb; - }; - size_t (*fn_write_callback)(void* contents, size_t size, size_t nmemb, void* userp) = write_callback; - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fn_write_callback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &http_response.body); - - auto header_callback = [](char* buffer, size_t size, size_t nitems, void* userdata) { - 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; - curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, fn_header_callback); - - std::string buffer; - curl_easy_setopt(curl, CURLOPT_HEADERDATA, &buffer); - curlEasySetopt(curl); - - ScopeExit auto_exit{[=] { - if (auto_clean) - curl_easy_cleanup(curl); - }}; - - CURLcode res = curl_easy_perform(curl); - if (res != CURLE_OK) { - SPDLOG_ERROR("curl_easy_perform() failed: [{}]", curl_easy_strerror(res)); - return std::nullopt; - } - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_response.http_response_code); - - auto header_data = splitString(buffer, "\n"); - - std::unordered_multimap headers; - for (auto& str : header_data) { - // if (str.ends_with("Connection established\n\n")) - // continue; - if (str.size() == 1 && !headers.empty()) { - http_response.http_header.emplace_back(std::move(headers)); - headers.clear(); - continue; - } - if (!str.contains(": ")) { - auto value = splitString(str, " "); - if (value.size() >= 2) - headers.emplace("http_response_code", value[1]); - } else { - auto value = splitString(str, ": "); - if (value.size() >= 2) - headers.emplace(value[0], value[1]); - } - } - if (!headers.empty()) { - http_response.http_header.emplace_back(std::move(headers)); - } - for (auto& value : http_response.http_header) { - SPDLOG_INFO("========================================="); - for (auto& [k, v] : value) - SPDLOG_INFO("{}: {}", k, v); - } - return http_response; -} - -std::expected callZeus(const std::string& host, const std::string& request_body) { - CURLcode res; - CURL* curl = curl_easy_init(); - if (!curl) { - auto error_info = std::format("callZeus curl_easy_init() failed:{}", curl_easy_strerror(res)); - return std::unexpected(error_info); - } - curl_easy_setopt(curl, CURLOPT_URL, host.data()); - - struct Input { - std::string recv; - }; - Input input; - 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& [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_TIMEOUT, 120L); - curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, action_fn); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, &input); - curl_easy_setopt(curl, CURLOPT_POSTFIELDS, request_body.c_str()); - - struct curl_slist* headers = nullptr; - headers = curl_slist_append(headers, "Content-Type: application/json"); - 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 error_info = std::format("callZeus curl_easy_perform() failed:{}", curl_easy_strerror(res)); - return std::unexpected(error_info); - } - int32_t response_code; - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); - if (response_code != 200) { - return std::unexpected(std::format("callZeus http code:{}", response_code)); - } - nlohmann::json rsp = nlohmann::json::parse(input.recv, nullptr, false); - if (rsp.is_discarded()) { - SPDLOG_ERROR("json parse error"); - return std::unexpected("parse callZeus error"); - } - return rsp; -} - struct CurlHttpRequest { - CURL* curl; + CURL* curl{nullptr}; std::string url; std::string_view http_proxy; - size_t (*cb)(void* contents, size_t size, size_t nmemb, void* userp); - void* input; + size_t (*cb)(void* contents, size_t size, size_t nmemb, void* userp){nullptr}; + void* input{nullptr}; std::unordered_map& headers; std::string body; std::multimap* response_header_ptr{nullptr}; @@ -659,6 +370,49 @@ std::optional sendHttpRequest(const CurlHttpRequest& curl_http_requ return std::nullopt; } +std::expected callZeus(const std::string& host, const std::string& request_body) { + CURLcode res; + CURL* curl = curl_easy_init(); + if (!curl) { + auto error_info = std::format("callZeus curl_easy_init() failed:{}", curl_easy_strerror(res)); + return std::unexpected(error_info); + } + ScopeExit auto_exit{[=] { curl_easy_cleanup(curl); }}; + std::string http_proxy; + std::string recv; + + auto ret = sendHttpRequest(CurlHttpRequest{ + .curl = curl, + .url = host, + .http_proxy = http_proxy, + .cb = [](void* contents, size_t size, size_t nmemb, void* userp) mutable -> size_t { + auto recv_ptr = static_cast(userp); + std::string data{(char*)contents, size * nmemb}; + recv_ptr->append(data); + return size * nmemb; + }, + .input = &recv, + .headers = [&] -> auto& { + static std::unordered_map headers{ + {"Content-Type", "application/json"}, + }; + return headers; + }(), + .body = request_body, + .response_header_ptr = nullptr, + .expect_response_code = 200, + .ssl_verify = false, + }); + if (ret) + return std::unexpected(ret.value()); + nlohmann::json rsp = nlohmann::json::parse(recv, nullptr, false); + if (rsp.is_discarded()) { + SPDLOG_ERROR("json parse error"); + return std::unexpected("parse callZeus error"); + } + return rsp; +} + } // namespace FreeGpt::FreeGpt(Config& cfg) @@ -970,16 +724,17 @@ create_client: request.set(boost::beast::http::field::user_agent, user_agent); request.set("Content-Type", "application/x-www-form-urlencoded"); - std::stringstream ss; - ss << "message=" << urlEncode(std::format("user: {}\nassistant: ", prompt)) << "&"; - ss << "_wpnonce=" << nonce << "&"; - ss << "post_id=" << post_id << "&"; - ss << "url=" << urlEncode("https://chatgpt.ai") << "&"; - ss << "action=wpaicg_chat_shortcode_message&"; - ss << "bot_id=" << bot_id; - - SPDLOG_INFO("request: {}", ss.str()); - request.body() = ss.str(); + std::multimap params{ + {"message", std::format("user: {}\nassistant: ", prompt)}, + {"_wpnonce", nonce}, + {"post_id", post_id}, + {"url", "https://chatgpt.ai"}, + {"action", "wpaicg_chat_shortcode_message"}, + {"bot_id", bot_id}, + }; + auto str = paramsToQueryStr(params); + SPDLOG_INFO("request: {}", str); + request.body() = str; request.prepare_payload(); auto [ec, count] = co_await boost::beast::http::async_write(stream_, request, use_nothrow_awaitable); @@ -1001,7 +756,7 @@ create_client: co_await ch->async_send(err, response.reason(), use_nothrow_awaitable); co_return; } - ss.clear(); + std::stringstream ss; ss << response.base(); SPDLOG_INFO("{}", ss.str()); SPDLOG_INFO("response.body(): {}", response.body()); @@ -1310,81 +1065,108 @@ boost::asio::awaitable FreeGpt::huggingChat(std::shared_ptr ch, n } boost::asio::awaitable FreeGpt::you(std::shared_ptr ch, nlohmann::json json) { - boost::asio::post(*m_thread_pool_ptr, [=, this] { - boost::system::error_code err{}; - ScopeExit _exit{[=] { boost::asio::post(ch->get_executor(), [=] { ch->close(); }); }}; + co_await boost::asio::post(boost::asio::bind_executor(*m_thread_pool_ptr, boost::asio::use_awaitable)); + boost::system::error_code err{}; + ScopeExit _exit{[=] { boost::asio::post(ch->get_executor(), [=] { ch->close(); }); }}; - auto prompt = json.at("meta").at("content").at("parts").at(0).at("content").get(); - - static std::mutex mtx; - static std::queue, std::string>> cookie_queue; - std::tuple, std::string> cookie_cache; - std::queue, std::string>> tmp_queue; - std::unique_lock lk(mtx); - while (!cookie_queue.empty()) { - auto& [time_point, code] = cookie_queue.front(); - if (std::chrono::system_clock::now() - time_point < std::chrono::minutes(15)) - tmp_queue.push(std::move(cookie_queue.front())); - cookie_queue.pop(); - } - cookie_queue = std::move(tmp_queue); - SPDLOG_INFO("cookie_queue size: {}", cookie_queue.size()); - if (cookie_queue.empty()) { - lk.unlock(); - auto cookie_opt = getCookie(nullptr, "https://you.com", m_cfg.http_proxy); - if (!cookie_opt) { - boost::asio::post(ch->get_executor(), [=] { ch->try_send(err, "get cookie error!!!"); }); - return; - } - auto& [http_response_code, http_header, body] = cookie_opt.value(); - if (!cookie_opt) { - boost::asio::post(ch->get_executor(), [=] { ch->try_send(err, "http header is empty!!!"); }); - return; - } - SPDLOG_INFO("http_response_code: {}", http_response_code); - std::string cookie; - - auto range = http_header.back().equal_range("set-cookie"); - for (auto it = range.first; it != range.second; ++it) { - if (it->second.contains("__cf_bm=")) { - auto fields = splitString(it->second, " "); - if (fields.size() < 1) { - boost::asio::post(ch->get_executor(), [=] { ch->try_send(err, "can't get cookie"); }); - return; - } - cookie = std::move(fields[0]); - break; - } - } - - if (cookie.empty()) { - boost::asio::post(ch->get_executor(), [=] { ch->try_send(err, "cookie is empty"); }); - return; - } - cookie_cache = std::make_tuple(std::chrono::system_clock::now(), std::move(cookie)); - } else { - cookie_cache = std::move(cookie_queue.front()); - cookie_queue.pop(); - lk.unlock(); - } - SPDLOG_INFO("cookie: {}", std::get<1>(cookie_cache)); + auto prompt = json.at("meta").at("content").at("parts").at(0).at("content").get(); + static std::mutex mtx; + static std::queue, std::string>> cookie_queue; + std::tuple, std::string> cookie_cache; + std::queue, std::string>> tmp_queue; + std::unique_lock lk(mtx); + while (!cookie_queue.empty()) { + auto& [time_point, code] = cookie_queue.front(); + if (std::chrono::system_clock::now() - time_point < std::chrono::minutes(15)) + tmp_queue.push(std::move(cookie_queue.front())); + cookie_queue.pop(); + } + cookie_queue = std::move(tmp_queue); + SPDLOG_INFO("cookie_queue size: {}", cookie_queue.size()); + if (cookie_queue.empty()) { + lk.unlock(); CURL* curl = curl_easy_init(); if (!curl) { - auto error_info = std::format("curl_easy_init() failed"); - boost::asio::post(ch->get_executor(), [=] { ch->try_send(err, error_info); }); - return; + co_await boost::asio::post(boost::asio::bind_executor(ch->get_executor(), boost::asio::use_awaitable)); + ch->try_send(err, std::format("curl_easy_init() failed")); + co_return; } - auto url = std::format( - "https://you.com/api/" - "streamingSearch?q={}&page=1&count=10&safeSearch=Off&onShoppingPage=False&mkt=&responseFilter=" - "WebPages%" - "2CTranslations%2CTimeZone%2CComputation%2CRelatedSearches&domain=youchat&queryTraceId={}", - urlEncode(prompt), createUuidString()); - curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); - if (!m_cfg.http_proxy.empty()) - curl_easy_setopt(curl, CURLOPT_PROXY, m_cfg.http_proxy.c_str()); - auto cb = [](void* contents, size_t size, size_t nmemb, void* userp) -> size_t { + ScopeExit auto_exit{[=] { curl_easy_cleanup(curl); }}; + std::multimap response_header; + std::unordered_map headers; + auto ret = sendHttpRequest(CurlHttpRequest{ + .curl = curl, + .url = "https://you.com", + .http_proxy = m_cfg.http_proxy, + .cb = [](void* contents, size_t size, size_t nmemb, void* userp) mutable -> size_t { + return size * nmemb; + }, + .headers = headers, + .response_header_ptr = &response_header, + }); + if (ret) { + co_await boost::asio::post(boost::asio::bind_executor(ch->get_executor(), boost::asio::use_awaitable)); + ch->try_send(err, ret.value()); + co_return; + } + std::string cookie; + auto range = response_header.equal_range("set-cookie"); + for (auto it = range.first; it != range.second; ++it) { + if (!(it->second.contains("__cf_bm="))) + continue; + auto view = it->second | std::views::drop_while(isspace) | std::views::reverse | + std::views::drop_while(isspace) | std::views::reverse; + auto fields = splitString(std::string{view.begin(), view.end()}, " "); + if (fields.size() < 1) { + co_await boost::asio::post(boost::asio::bind_executor(ch->get_executor(), boost::asio::use_awaitable)); + ch->try_send(err, "can't get cookie"); + co_return; + } + cookie = std::move(fields[0]); + break; + } + if (cookie.empty()) { + co_await boost::asio::post(boost::asio::bind_executor(ch->get_executor(), boost::asio::use_awaitable)); + ch->try_send(err, "cookie is empty"); + co_return; + } + cookie_cache = std::make_tuple(std::chrono::system_clock::now(), std::move(cookie)); + } else { + cookie_cache = std::move(cookie_queue.front()); + cookie_queue.pop(); + lk.unlock(); + } + SPDLOG_INFO("cookie: {}", std::get<1>(cookie_cache)); + + CURL* curl = curl_easy_init(); + if (!curl) { + co_await boost::asio::post(boost::asio::bind_executor(ch->get_executor(), boost::asio::use_awaitable)); + ch->try_send(err, std::format("curl_easy_init() failed")); + co_return; + } + ScopeExit auto_exit{[=] { curl_easy_cleanup(curl); }}; + auto cookie_str = + std::format("uuid_guest={}; safesearch_guest=Off; {}", createUuidString(), std::get<1>(cookie_cache)); + curl_easy_setopt(curl, CURLOPT_COOKIE, std::get<1>(cookie_cache).c_str()); + auto ret = sendHttpRequest(CurlHttpRequest{ + .curl = curl, + .url = [&] -> auto { + std::multimap params{ + {"q", prompt}, + {"page", "1"}, + {"count", "10"}, + {"safeSearch", "Off"}, + {"onShoppingPage", "False"}, + {"mkt", ""}, + {"responseFilter", "WebPages,Translations,TimeZone,Computation,RelatedSearches"}, + {"domain", "youchat"}, + {"queryTraceId", createUuidString()}, + }; + return std::format("https://you.com/api/streamingSearch?{}", paramsToQueryStr(params)); + }(), + .http_proxy = m_cfg.http_proxy, + .cb = [](void* contents, size_t size, size_t nmemb, void* userp) -> size_t { boost::system::error_code err{}; auto ch_ptr = static_cast(userp); std::string data{(char*)contents, size * nmemb}; @@ -1404,41 +1186,25 @@ boost::asio::awaitable FreeGpt::you(std::shared_ptr ch, nlohmann: boost::asio::post(ch_ptr->get_executor(), [=] { ch_ptr->try_send(err, str); }); } return size * nmemb; - }; - size_t (*fn)(void* contents, size_t size, size_t nmemb, void* userp) = cb; - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fn); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, ch.get()); - auto cookie_str = - std::format("uuid_guest={}; safesearch_guest=Off; {}", createUuidString(), std::get<1>(cookie_cache)); - curl_easy_setopt(curl, CURLOPT_COOKIE, std::get<1>(cookie_cache).c_str()); - curlEasySetopt(curl); - struct curl_slist* headers = nullptr; - headers = curl_slist_append(headers, "referer: https://you.com/search?q=gpt4&tbm=youchat"); - headers = curl_slist_append(headers, "Accept: text/event-stream"); - ScopeExit auto_exit{[=] { - curl_slist_free_all(headers); - curl_easy_cleanup(curl); - }}; - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - CURLcode res = curl_easy_perform(curl); - - if (res != CURLE_OK) { - auto error_info = std::format("curl_easy_perform() failed:{}", curl_easy_strerror(res)); - boost::asio::post(ch->get_executor(), [=] { ch->try_send(err, error_info); }); - return; - } - int32_t response_code; - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code); - if (response_code != 200) { - boost::asio::post(ch->get_executor(), - [=] { ch->try_send(err, std::format("you http code:{}", response_code)); }); - } - { - std::lock_guard lk(mtx); - cookie_queue.push(std::move(cookie_cache)); - } - return; + }, + .input = ch.get(), + .headers = []() -> auto& { + static std::unordered_map headers{ + {"referer", "https://you.com/search?q=gpt4&tbm=youchat"}, + {"Accept", "text/event-stream"}, + }; + return headers; + }(), }); + if (ret) { + co_await boost::asio::post(boost::asio::bind_executor(ch->get_executor(), boost::asio::use_awaitable)); + ch->try_send(err, ret.value()); + co_return; + } + { + std::lock_guard lk(mtx); + cookie_queue.push(std::move(cookie_cache)); + } co_return; } @@ -1739,8 +1505,13 @@ boost::asio::awaitable FreeGpt::gptGo(std::shared_ptr ch, nlohman ch->try_send(err, error_info); co_return; } - auto get_token_url = - std::format("https://gptgo.ai/action_get_token.php?q={}&hlgpt=default&hl=en", urlEncode(prompt)); + + std::multimap params{ + {"q", prompt}, + {"hlgpt", "default"}, + {"hl", "en"}, + }; + auto get_token_url = std::format("https://gptgo.ai/action_get_token.php?{}", paramsToQueryStr(params)); curl_easy_setopt(curl, CURLOPT_URL, get_token_url.c_str()); if (!m_cfg.http_proxy.empty()) curl_easy_setopt(curl, CURLOPT_PROXY, m_cfg.http_proxy.c_str()); @@ -1971,7 +1742,7 @@ boost::asio::awaitable FreeGpt::chatForAi(std::shared_ptr ch, nlo ch->try_send(err, error_info); co_return; } - curl_easy_setopt(curl, CURLOPT_URL, "https://chatforai.com/api/handle/provider-openai"); + curl_easy_setopt(curl, CURLOPT_URL, "https://chatforai.store/api/handle/provider-openai"); if (!m_cfg.http_proxy.empty()) curl_easy_setopt(curl, CURLOPT_PROXY, m_cfg.http_proxy.c_str()); @@ -2581,7 +2352,7 @@ boost::asio::awaitable FreeGpt::gptForLove(std::shared_ptr ch, nl constexpr std::string_view request_str{R"({ "prompt": "hello", "options": {}, - "systemMessage": "You are ChatGPT, the version is GPT3.5, a large language model trained by OpenAI. Follow the user's instructions carefully. Respond using markdown.", + "systemMessage": "You are ChatGPT, the version is GPT3.5, a large language model trained by OpenAI. Follow the user's instructions carefully.", "temperature": 0.8, "top_p": 1, "secret": "U2FsdGVkX18vdtlMj0nP1LoUzEqJTP0is+Q2+bQJNMk=", diff --git a/chatgpt_microservice/tools/zeus.py b/chatgpt_microservice/tools/zeus.py index 36e259e..5fbd28b 100644 --- a/chatgpt_microservice/tools/zeus.py +++ b/chatgpt_microservice/tools/zeus.py @@ -38,9 +38,9 @@ def deepai_refresh(): @app.route("/gptforlove", methods=["POST"]) def get_gptforlove_secret(): dir = os.path.dirname(__file__) - dir += "/npm/node_modules/crypto-js" + include = dir + "/npm/node_modules/crypto-js/crypto-js" source = """ -CryptoJS = require('{dir}/crypto-js') +CryptoJS = require({include}) var k = '14487141bvirvvG' , e = Math.floor(new Date().getTime() / 1e3); var t = CryptoJS.enc.Utf8.parse(e) @@ -50,7 +50,7 @@ var t = CryptoJS.enc.Utf8.parse(e) }); return o.toString() """ - source = source.replace("{dir}", dir) + source = source.replace("{include}", json.dumps(include)) dict = {"secret": execjs.compile(source).call("")} return json.dumps(dict)