diff --git a/.clangd b/.clangd
new file mode 100644
index 0000000..11d6e06
--- /dev/null
+++ b/.clangd
@@ -0,0 +1,12 @@
+Hover:
+    ShowAKA: Yes
+Diagnostics:
+    UnusedIncludes: None        # 禁用未使用头文件提示
+    Suppress: [
+        anon_type_definition,   # 禁用匿名的typedef提示
+        unused-variable,        # 禁用未使用变量提示
+        unused-function,        # 禁用未使用函数提示
+        unused-includes,        # 禁用未使用的头文件提示
+    ]
+    ClangTidy:
+        Remove: misc-unused-alias-decls
diff --git a/.vscode/settings.json b/.vscode/settings.json
index e0368a5..e7a44fd 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -26,8 +26,6 @@
     },
     "cmake.options.statusBarVisibility": "visible",
     "cmake.generator": "Ninja",
-    "C_Cpp.default.compileCommands": "${workspaceRoot}/build/compile_commands.json",
-    "C_Cpp.default.cppStandard": "c++17",
     "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
     "editor.inlayHints.enabled": "off",
     "editor.unicodeHighlight.allowedLocales": {
@@ -35,104 +33,17 @@
         "zh-hant": true,
         "zh-hans": true
     },
-    "files.associations": {
-        "ostream": "cpp",
-        "string": "cpp",
-        "any": "cpp",
-        "array": "cpp",
-        "atomic": "cpp",
-        "bit": "cpp",
-        "*.tcc": "cpp",
-        "cctype": "cpp",
-        "clocale": "cpp",
-        "cmath": "cpp",
-        "codecvt": "cpp",
-        "compare": "cpp",
-        "concepts": "cpp",
-        "cstdarg": "cpp",
-        "cstddef": "cpp",
-        "cstdint": "cpp",
-        "cstdio": "cpp",
-        "cstdlib": "cpp",
-        "cstring": "cpp",
-        "ctime": "cpp",
-        "cwchar": "cpp",
-        "cwctype": "cpp",
-        "deque": "cpp",
-        "forward_list": "cpp",
-        "map": "cpp",
-        "unordered_map": "cpp",
-        "vector": "cpp",
-        "exception": "cpp",
-        "algorithm": "cpp",
-        "functional": "cpp",
-        "iterator": "cpp",
-        "memory": "cpp",
-        "memory_resource": "cpp",
-        "numeric": "cpp",
-        "optional": "cpp",
-        "random": "cpp",
-        "ratio": "cpp",
-        "string_view": "cpp",
-        "system_error": "cpp",
-        "tuple": "cpp",
-        "type_traits": "cpp",
-        "utility": "cpp",
-        "initializer_list": "cpp",
-        "iomanip": "cpp",
-        "iosfwd": "cpp",
-        "iostream": "cpp",
-        "istream": "cpp",
-        "limits": "cpp",
-        "new": "cpp",
-        "numbers": "cpp",
-        "ranges": "cpp",
-        "span": "cpp",
-        "sstream": "cpp",
-        "stdexcept": "cpp",
-        "streambuf": "cpp",
-        "typeinfo": "cpp",
-        "valarray": "cpp",
-        "fstream": "cpp",
-        "chrono": "cpp",
-        "filesystem": "cpp",
-        "ios": "cpp",
-        "list": "cpp",
-        "locale": "cpp",
-        "xfacet": "cpp",
-        "xhash": "cpp",
-        "xiosbase": "cpp",
-        "xlocale": "cpp",
-        "xlocbuf": "cpp",
-        "xlocinfo": "cpp",
-        "xlocmes": "cpp",
-        "xlocmon": "cpp",
-        "xlocnum": "cpp",
-        "xloctime": "cpp",
-        "xmemory": "cpp",
-        "xmemory0": "cpp",
-        "xstddef": "cpp",
-        "xstring": "cpp",
-        "xtr1common": "cpp",
-        "xtree": "cpp",
-        "xutility": "cpp",
-        "condition_variable": "cpp",
-        "csignal": "cpp",
-        "future": "cpp",
-        "mutex": "cpp",
-        "shared_mutex": "cpp",
-        "thread": "cpp",
-        "variant": "cpp",
-        "*.ipp": "cpp",
-        "xthread": "cpp",
-        "bitset": "cpp",
-        "charconv": "cpp",
-        "coroutine": "cpp",
-        "format": "cpp",
-        "hash_map": "cpp",
-        "set": "cpp",
-        "source_location": "cpp",
-        "stop_token": "cpp",
-        "unordered_set": "cpp"
-    }
+    "C_Cpp.intelliSenseEngine": "disabled",
+    "clangd.arguments": [
+        "--header-insertion=never",
+        "--all-scopes-completion",
+        "--completion-style=detailed",
+        "--clang-tidy",
+        "-j=4",
+        "--pch-storage=memory",
+        "--compile-commands-dir=build",
+        "--background-index",
+        "--ranking-model=heuristics",
+        "--function-arg-placeholders=false"
+    ],
 }
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fb69c3c..558f821 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,10 +8,6 @@ if (MSVC)
     add_compile_options(/utf-8)
 endif()
 
-if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_SYSTEM_NAME MATCHES "Windows")
-    MESSAGE(STATUS "Add MinGW Param.")
-endif()
-
 add_definitions(-D_WIN32_WINNT=0x0601)
 
 set(CMAKE_DEBUG_POSTFIX "d")
@@ -22,9 +18,7 @@ set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib/${CMAKE_BUILD_TYPE})
 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin/${CMAKE_BUILD_TYPE}/) 
 
 include_directories(3rd)
-find_package(CURL REQUIRED)
-
-add_executable(openai-api main.cxx zapi.h zapi.cxx jsondata.h jsondata.cxx handle.h handle.cxx server.h server.cxx)
-target_link_libraries(openai-api PRIVATE CURL::libcurl)
-
-add_executable(openai-api-test client_test.cxx)
\ No newline at end of file
+include_directories(.)
+add_subdirectory(cexport)
+add_subdirectory(server)
+add_subdirectory(test)
diff --git a/cexport/CMakeLists.txt b/cexport/CMakeLists.txt
new file mode 100644
index 0000000..5726617
--- /dev/null
+++ b/cexport/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.16)
+
+project(copenai LANGUAGES CXX)
+
+add_library(copenai SHARED
+    cdllexport.h
+    cdllexport.cpp
+    ../openaiclient.h
+    ../openaiclient.cpp
+)
diff --git a/cexport/cdllexport.cpp b/cexport/cdllexport.cpp
new file mode 100644
index 0000000..aac7e62
--- /dev/null
+++ b/cexport/cdllexport.cpp
@@ -0,0 +1,60 @@
+#include "cdllexport.h"
+
+#include <asio.hpp>
+#include <cstdlib>
+#include <memory>
+#include <string>
+
+#include "../openaiclient.h"
+
+class CApiDllExport
+{
+public:
+    CApiDllExport();
+
+public:
+    static void init_exchange(ExchangeData* ex);
+
+public:
+    static std::shared_ptr<OpenAIClient> client;
+    static std::string server_ip;
+    static unsigned int port;
+    asio::io_context io_context;
+};
+
+std::shared_ptr<OpenAIClient> CApiDllExport::client = nullptr;
+
+CApiDllExport::CApiDllExport()
+{
+}
+
+void CApiDllExport::init_exchange(ExchangeData* ex)
+{
+    if (ex == nullptr) {
+        return;
+    }
+    ex->content = nullptr;
+    ex->ck = 0;
+    ex->pk = 0;
+    ex->len = 0;
+}
+
+void init_api(const char* ip, unsigned int port)
+{
+
+}
+
+ExchangeData* ask_openai(const char* content)
+{
+    ExchangeData* ret = (ExchangeData*)malloc(sizeof(ExchangeData));
+    if (ret == nullptr) {
+        return ret;
+    }
+    CApiDllExport::init_exchange(ret);
+
+    return ret;
+}
+
+void free_exchange_data(ExchangeData* data)
+{
+}
diff --git a/cexport/cdllexport.h b/cexport/cdllexport.h
new file mode 100644
index 0000000..cc95ff5
--- /dev/null
+++ b/cexport/cdllexport.h
@@ -0,0 +1,25 @@
+#ifndef CDLLEXPORT_H
+#define CDLLEXPORT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct ExchangeData {
+    char* content;
+    unsigned int len;
+    unsigned int pk;
+    unsigned int ck;
+} ExchangeData;
+
+void init_api(const char* ip, unsigned int port);
+
+ExchangeData* ask_openai(const char* content);
+
+void free_exchange_data(ExchangeData* data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif   // CDLLEXPORT_H
diff --git a/client_test.cxx b/client_test.cxx
deleted file mode 100644
index 3e3927d..0000000
--- a/client_test.cxx
+++ /dev/null
@@ -1,113 +0,0 @@
-#include "communicate.hpp"
-
-#include <array>
-#include <asio.hpp>
-#include <iostream>
-#include <string>
-#include <thread>
-
-constexpr size_t g_BuffSize = 1024 * 10;
-class Client
-{
-public:
-    Client(asio::io_context& io_context) : io_context_(io_context), socket_(io_context)
-    {
-        ip_ = "127.0.0.1";
-        port_ = "9999";
-    }
-
-public:
-    bool connect()
-    {
-        try {
-            asio::ip::tcp::resolver resolver(io_context_);
-            asio::ip::tcp::resolver::results_type endpoints = resolver.resolve(ip_, port_);
-            asio::connect(socket_, endpoints);
-            std::cout << "Connected to server " << ip_ << ":" << port_ << std::endl;
-            return true;
-        } catch (const std::exception& ex) {
-            std::cerr << "Exception: " << ex.what() << "\n";
-            return false;
-        }
-    }
-
-    FrameData* post_deepseek(const std::string& text)
-    {
-        FrameData send;
-        send.type = FrameType::TYPE_REQUEST;
-        send.data = new char[text.size()];
-        send.len = text.size();
-        memcpy(send.data, text.c_str(), text.size());
-
-        char* send_data{};
-        int len{};
-
-        std::shared_ptr<int> deleter(new int(1), [send_data](int* p) {
-            delete p;
-            delete[] send_data;
-        });
-
-        if (!com_pack(&send, &send_data, len)) {
-            std::cerr << "com_pack error" << std::endl;
-            return nullptr;
-        }
-
-        auto send_size = socket_.write_some(asio::buffer(send_data, len));
-        if (send_size != len) {
-            std::cerr << "send_size != text.size()" << std::endl;
-            return nullptr;
-        }
-        size_t read_size = socket_.read_some(asio::buffer(tmp_buf_));
-        FrameData* ret = nullptr;
-        while (read_size > 0) {
-            buffer_.push(tmp_buf_.data(), read_size);
-            auto* frame = com_parse(buffer_);
-            if (frame) {
-                ret = frame;
-                return ret;
-            }
-            read_size = socket_.read_some(asio::buffer(tmp_buf_));
-        }
-        return ret;
-    }
-
-private:
-    std::string ip_{};
-    std::string port_{};
-    asio::ip::tcp::socket socket_;
-    asio::io_context& io_context_;
-    CMutBuffer buffer_{};
-    std::array<char, g_BuffSize> tmp_buf_{};
-};
-
-int main()
-{
-#ifdef _WIN32
-    system("chcp 65001");
-#endif
-
-    asio::io_context io_context;
-    Client client(io_context);
-
-    if (!client.connect()) {
-        return -1;
-    }
-
-    std::thread t([&io_context]() { io_context.run(); });
-
-    std::string text = "将【天文历】翻译为英文,直接给出结果。";
-    // std::string text = "This is a test.";
-    FrameData* frame = client.post_deepseek(text);
-    if (frame) {
-        std::cout << "type: " << frame->type << std::endl;
-        std::cout << "data: " << frame->data << std::endl;
-        std::cout << "len: " << frame->len << std::endl;
-        std::cout << "protk: " << frame->protk << std::endl;
-        std::cout << "coptk: " << frame->coptk << std::endl;
-    }
-
-    delete frame;
-    t.join();
-
-    return 0;
-}
\ No newline at end of file
diff --git a/communicate.hpp b/communicate.hpp
index e316f9a..18f763e 100644
--- a/communicate.hpp
+++ b/communicate.hpp
@@ -10,6 +10,8 @@
 #undef min
 #endif
 
+constexpr size_t g_BuffSize = 1024 * 10;
+
 enum FrameType : int16_t {
     TYPE_REQUEST = 0,
     TYPE_RESPONSE_SUCCESS,
@@ -103,10 +105,10 @@ private:
 inline FrameData* com_parse(CMutBuffer& buffer)
 {
     FrameData* r = nullptr;
-    constexpr char header[] = {0xFF, 0xFE};
-    constexpr char tail[] = {0xFF, 0xFF};
+    constexpr unsigned char header[] = {0xFF, 0xFE};
+    constexpr unsigned char tail[] = {0xFF, 0xFF};
 
-    int find = buffer.index_of(header, sizeof(header));
+    int find = buffer.index_of((const char*)header, sizeof(header));
     if (find < 0) {
         return r;
     }
@@ -163,8 +165,8 @@ inline bool com_pack(FrameData* data, char** out_buf, int& len)
         data->len = 0;
     }
 
-    constexpr char header[] = {0xFF, 0xFE};
-    constexpr char tail[] = {0xFF, 0xFF};
+    constexpr unsigned char header[] = {0xFF, 0xFE};
+    constexpr unsigned char tail[] = {0xFF, 0xFF};
 
     len = sizeof(header) + sizeof(data->type) + sizeof(data->len) + sizeof(data->protk) + sizeof(data->coptk) + data->len +
           sizeof(tail);
@@ -186,4 +188,4 @@ inline bool com_pack(FrameData* data, char** out_buf, int& len)
     return true;
 };
 
-#endif   // COMMUNICATE_HPP
\ No newline at end of file
+#endif   // COMMUNICATE_HPP
diff --git a/openaiclient.cpp b/openaiclient.cpp
new file mode 100644
index 0000000..e606358
--- /dev/null
+++ b/openaiclient.cpp
@@ -0,0 +1,68 @@
+#include "openaiclient.h"
+
+#include <iostream>
+
+OpenAIClient::OpenAIClient(asio::io_context& io_context) : io_context_(io_context), socket_(io_context)
+{
+}
+
+bool OpenAIClient::connect(const std::string& ip, unsigned int port)
+{
+    ip_ = ip;
+    port_ = std::to_string(port);
+    try {
+        asio::ip::tcp::resolver resolver(io_context_);
+        asio::ip::tcp::resolver::results_type endpoints = resolver.resolve(ip_, port_);
+        asio::connect(socket_, endpoints);
+        std::cout << "Connected to server " << ip_ << ":" << port_ << std::endl;
+        return true;
+    } catch (const std::exception& ex) {
+        std::cerr << "Exception: " << ex.what() << "\n";
+        return false;
+    }
+}
+
+FrameData* OpenAIClient::ask_openai(const std::string& text)
+{
+    FrameData send;
+    send.type = FrameType::TYPE_REQUEST;
+    send.data = new char[text.size()];
+    send.len = text.size();
+    memcpy(send.data, text.c_str(), text.size());
+
+    char* send_data{};
+    int len{};
+
+    std::shared_ptr<int> deleter(new int(1), [send_data](int* p) {
+        delete p;
+        delete[] send_data;
+    });
+
+    if (!com_pack(&send, &send_data, len)) {
+        std::cerr << "com_pack error" << std::endl;
+        return nullptr;
+    }
+
+    auto send_size = socket_.write_some(asio::buffer(send_data, len));
+    if (send_size != len) {
+        std::cerr << "send_size != text.size()" << std::endl;
+        return nullptr;
+    }
+    size_t read_size = socket_.read_some(asio::buffer(tmp_buf_));
+    FrameData* ret = nullptr;
+    while (read_size > 0) {
+        buffer_.push(tmp_buf_.data(), read_size);
+        auto* frame = com_parse(buffer_);
+        if (frame) {
+            ret = frame;
+            return ret;
+        }
+        read_size = socket_.read_some(asio::buffer(tmp_buf_));
+    }
+    return ret;
+}
+
+void OpenAIClient::disconnect()
+{
+
+}
diff --git a/openaiclient.h b/openaiclient.h
new file mode 100644
index 0000000..121390e
--- /dev/null
+++ b/openaiclient.h
@@ -0,0 +1,26 @@
+#ifndef OPENAICLIENT_H
+#define OPENAICLIENT_H
+
+#include <asio.hpp>
+#include <communicate.hpp>
+
+class OpenAIClient
+{
+public:
+    OpenAIClient(asio::io_context& io_context);
+
+public:
+    bool connect(const std::string& ip, unsigned int port);
+    FrameData* ask_openai(const std::string& text);
+    void disconnect();
+
+private:
+    std::string ip_{};
+    std::string port_{};
+    asio::ip::tcp::socket socket_;
+    asio::io_context& io_context_;
+    CMutBuffer buffer_{};
+    std::array<char, g_BuffSize> tmp_buf_{};
+};
+
+#endif   // OPENAICLIENT_H
diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt
new file mode 100644
index 0000000..98d605a
--- /dev/null
+++ b/server/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 3.16)
+
+project(openai-server LANGUAGES CXX)
+set(CMAKE_CXX_STANDARD 17)
+
+find_package(CURL REQUIRED)
+
+set(SERVER_SOURCES
+    zapi.h
+    zapi.cxx
+    jsondata.h
+    jsondata.cxx
+    server.h
+    server.cxx
+    config.h
+    config.cxx
+    main.cxx
+)
+
+add_executable(openai-server ${SERVER_SOURCES})
+target_link_libraries(openai-server PRIVATE CURL::libcurl)
diff --git a/handle.cxx b/server/config.cxx
similarity index 90%
rename from handle.cxx
rename to server/config.cxx
index a9c8e81..bffa9bd 100644
--- a/handle.cxx
+++ b/server/config.cxx
@@ -1,12 +1,9 @@
-#include "handle.h"
-#include <SimpleIni.h>
-#include <cctype>
-#include <iomanip>
-#include <iostream>
-#include <random>
-#include <sstream>
+#include "config.h"
 
-bool CConfig::parse_config(ConfigInfo& config, const std::string& config_path)
+#include <SimpleIni.h>
+#include <iostream>
+
+bool ConfigSet::parse_config(Configuration& config, const std::string& config_path)
 {
     CSimpleIniA ini_handle{};
     SI_Error ret = ini_handle.LoadFile(config_path.c_str());
diff --git a/handle.h b/server/config.h
similarity index 54%
rename from handle.h
rename to server/config.h
index 074422c..40a2785 100644
--- a/handle.h
+++ b/server/config.h
@@ -2,7 +2,7 @@
 
 #include <string>
 
-struct ConfigInfo {
+struct Configuration {
     std::string api_env_key;
     std::string base_url;
     std::string user_name;
@@ -11,11 +11,11 @@ struct ConfigInfo {
     long max_tokens{};
 };
 
-class CConfig
+class ConfigSet
 {
 public:
-    CConfig() = default;
-    ~CConfig() = default;
+    ConfigSet() = default;
+    ~ConfigSet() = default;
 public:
-    static bool parse_config(ConfigInfo& config, const std::string& config_path = "");
-};
\ No newline at end of file
+    static bool parse_config(Configuration& config, const std::string& config_path = "");
+};
diff --git a/jsondata.cxx b/server/jsondata.cxx
similarity index 63%
rename from jsondata.cxx
rename to server/jsondata.cxx
index a8c6d39..a180de4 100644
--- a/jsondata.cxx
+++ b/server/jsondata.cxx
@@ -1,5 +1,6 @@
 #include "jsondata.h"
 #include <iostream>
+#include <fstream>
 
 CJsonOper::CJsonOper(const std::string& user_name, const std::string& model, const std::string& assistant_name)
     : user_(user_name), model_(model), assistant_(assistant_name)
@@ -30,35 +31,6 @@ std::vector<std::string> CJsonOper::split(const std::string& input, const std::s
     return result;
 }
 
-std::string CJsonOper::multi_format_reuqest(const std::string& content, size_t per_sec_size)
-{
-    std::string model = model_;
-    std::string role = user_;
-    nlohmann::json json_data;
-    json_data["model"] = model;
-
-    std::vector<nlohmann::json> messages;
-    size_t s = 0;
-    while (s < content.size()) {
-        size_t i = 0;
-        size_t t = 0;
-        while (i < per_sec_size && s + i < content.size()) {
-            t = get_u8_len(content[s + i]);
-            if (t == 0) {
-                std::cerr << "invalid codec!!!" << std::endl;
-                exit(1);
-            }
-            i += t;
-        }
-        std::string part = content.substr(s, i);
-        messages.push_back({{"role", role}, {"content", "\n附加数据:\n" + part}});
-        s += i;
-    }
-
-    json_data["messages"] = messages;
-    return json_data.dump();
-}
-
 Message CJsonOper::parse(const std::string& data)
 {
     Message re;
@@ -147,39 +119,3 @@ std::string CJsonOper::trim(const std::string& input)
     return input.substr(start, end - start + 1);
 }
 
-std::string CJsonOper::get_all_dir_content(const std::string& dir, const std::string& types)
-{
-    auto vec = split(types, ",");
-    std::vector<std::string> t;
-    for (const auto& item : vec) {
-        auto c = trim(item);
-        if (c.empty()) {
-            continue;
-        }
-        t.push_back("." + item);
-        std::cout << "use type:" << item << std::endl;
-    }
-    std::vector<std::string> task;
-    for (const auto& entry : fs::directory_iterator(dir)) {
-        if (!fs::is_regular_file(entry)) {
-            continue;
-        }
-        auto exten = entry.path().filename().extension().string();
-        if (std::find(t.begin(), t.end(), exten) != t.end()) {
-            std::cout << "Parse:" << entry.path().string() << std::endl;
-            task.push_back(entry.path().string());
-        }
-    }
-    // 提取内容
-    std::string content;
-    for (const auto& item : task) {
-        std::string one;
-        if (read_txt(item, one)) {
-            content.append("\n\n" + one);
-        } else {
-            std::cerr << "Can't read file: " << item << std::endl;
-            exit(1);
-        }
-    }
-    return content;
-}
diff --git a/jsondata.h b/server/jsondata.h
similarity index 80%
rename from jsondata.h
rename to server/jsondata.h
index 091198a..54771ab 100644
--- a/jsondata.h
+++ b/server/jsondata.h
@@ -1,10 +1,7 @@
 #ifndef JSON_DATA
 #define JSON_DATA
 
-#include <filesystem>
-#include <fstream>
 #include <nlohmann/json.hpp>
-#include <optional>
 #include <string>
 #include <vector>
 
@@ -27,13 +24,11 @@ public:
 
 public:
     std::string format_request(const std::string& content);
-    std::string multi_format_reuqest(const std::string& content, size_t per_sec_size);
     Message parse(const std::string& data);
     static bool save_md(const std::string& data, const std::string& id);
     static bool read_txt(const std::string& path, std::string& out);
     static std::vector<std::string> split(const std::string& input, const std::string& delimiter);
     static size_t get_u8_len(unsigned char ch);
-    static std::string get_all_dir_content(const std::string& dir, const std::string& types);
     static std::string trim(const std::string& input);
 
 private:
@@ -42,4 +37,4 @@ private:
     std::string assistant_{};
 };
 
-#endif
\ No newline at end of file
+#endif
diff --git a/main.cxx b/server/main.cxx
similarity index 96%
rename from main.cxx
rename to server/main.cxx
index 1290292..79f82c3 100644
--- a/main.cxx
+++ b/server/main.cxx
@@ -1,5 +1,5 @@
 
-#include "handle.h"
+#include "config.h"
 #include "jsondata.h"
 #include "server.h"
 #include "zapi.h"
@@ -42,8 +42,8 @@ int main(int argc, char* argv[])
 
     int port = std::stoi(argv[1]);
 
-    ConfigInfo config;
-    if (!CConfig::parse_config(config, "openai.ini")) {
+    Configuration config;
+    if (!ConfigSet::parse_config(config, "openai.ini")) {
         std::cerr << "parse config failed." << std::endl;
         return -1;
     }
diff --git a/server.cxx b/server/server.cxx
similarity index 93%
rename from server.cxx
rename to server/server.cxx
index b9b06f5..0fbe76e 100644
--- a/server.cxx
+++ b/server/server.cxx
@@ -1,7 +1,8 @@
 #include "server.h"
-#include "util.hpp"
+
 #include <iostream>
 
+
 Server::Server(asio::io_context& io_context, short port) : io_context_(io_context), acceptor_(io_context)
 {
     port_ = port;
@@ -16,11 +17,7 @@ Server::~Server()
 
 void Server::print_exception(const std::exception& e)
 {
-#ifdef _WIN32
-    std::cerr << ansi_to_u8(e.what()) << '\n';
-#else
     std::cerr << e.what() << '\n';
-#endif
 }
 
 void Server::start()
@@ -61,8 +58,9 @@ void Server::do_accept()
             std::string client_key = endpoint.address().to_string() + ":" + std::to_string(endpoint.port());
             std::unique_lock<std::mutex> lock(cli_mutex_);
             client_map_[client_key] = std::make_shared<ClientCache>();
-            clients_.insert(std::make_pair(socket->remote_endpoint().address().to_string(),
-                                           std::thread([this, socket, client_key]() { th_client(socket, client_key); })));
+            clients_.insert(
+                std::make_pair(socket->remote_endpoint().address().to_string(),
+                               std::thread([this, socket, client_key]() { th_client(socket, client_key); })));
         }
 
         do_accept();
@@ -163,4 +161,4 @@ bool Server::send_frame(const std::shared_ptr<asio::ip::tcp::socket>& socket, Fr
 
     delete[] send_data;
     return send_len == len;
-}
\ No newline at end of file
+}
diff --git a/server.h b/server/server.h
similarity index 95%
rename from server.h
rename to server/server.h
index 0fddffa..b5a89d3 100644
--- a/server.h
+++ b/server/server.h
@@ -1,15 +1,14 @@
 #ifndef SERVER_H
 #define SERVER_H
 
-#include "communicate.hpp"
-#include "handle.h"
-#include "jsondata.h"
-#include "zapi.h"
 #include <asio.hpp>
 #include <mutex>
 #include <unordered_map>
 
-constexpr size_t g_BuffSize = 1024 * 10;
+#include "communicate.hpp"
+#include "jsondata.h"
+#include "zapi.h"
+
 struct ClientCache {
     std::array<char, g_BuffSize> tmp_buf_{};
     CMutBuffer buffer_{};
@@ -28,6 +27,7 @@ public:
 public:
     void set_worker(std::shared_ptr<COpenAI> worker, std::shared_ptr<CJsonOper> json);
     void set_token(long tokens);
+
 private:
     void do_accept();
     void th_client(const std::shared_ptr<asio::ip::tcp::socket>& socket, const std::string& client_key);
@@ -52,4 +52,4 @@ private:
     long use_tokens_{};
 };
 
-#endif
\ No newline at end of file
+#endif
diff --git a/zapi.cxx b/server/zapi.cxx
similarity index 100%
rename from zapi.cxx
rename to server/zapi.cxx
diff --git a/zapi.h b/server/zapi.h
similarity index 100%
rename from zapi.h
rename to server/zapi.h
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 0000000..48fccf5
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.16)
+
+project(openai-test LANGUAGES CXX)
+set(CMAKE_CXX_STANDARD 17)
+
+add_executable(openai-test client_test.cxx ../openaiclient.cpp)
diff --git a/test/client_test.cxx b/test/client_test.cxx
new file mode 100644
index 0000000..0f14920
--- /dev/null
+++ b/test/client_test.cxx
@@ -0,0 +1,39 @@
+#include <asio.hpp>
+#include <iostream>
+#include <string>
+#include <thread>
+
+#include "../openaiclient.h"
+#include "communicate.hpp"
+
+int main()
+{
+#ifdef _WIN32
+    system("chcp 65001");
+#endif
+
+    asio::io_context io_context;
+    OpenAIClient client(io_context);
+
+    if (!client.connect("127.0.0.1", 9999)) {
+        return -1;
+    }
+
+    std::thread t([&io_context]() { io_context.run(); });
+
+    std::string text = "将【天文历】翻译为英文,直接给出结果。";
+    // std::string text = "This is a test.";
+    FrameData* frame = client.ask_openai(text);
+    if (frame) {
+        std::cout << "type: " << frame->type << std::endl;
+        std::cout << "data: " << frame->data << std::endl;
+        std::cout << "len: " << frame->len << std::endl;
+        std::cout << "protk: " << frame->protk << std::endl;
+        std::cout << "coptk: " << frame->coptk << std::endl;
+    }
+
+    delete frame;
+    t.join();
+
+    return 0;
+}
diff --git a/util.hpp b/util.hpp
deleted file mode 100644
index c6b2fcb..0000000
--- a/util.hpp
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef UTIL_HPP
-#define UTIL_HPP
-
-#ifdef _WIN32
-#include <windows.h>
-#endif
-
-#include <string>
-
-#ifdef _WIN32
-std::string ansi_to_u8(const std::string& str)
-{
-    int wideCharLen = MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, nullptr, 0);
-    if (wideCharLen <= 0) {
-        return "";
-    }
-    std::wstring wideStr(wideCharLen, L'\0');
-    MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, &wideStr[0], wideCharLen);
-
-    int utf8Len = WideCharToMultiByte(CP_UTF8, 0, wideStr.c_str(), -1, nullptr, 0, nullptr, nullptr);
-    if (utf8Len <= 0) {
-        return "";
-    }
-    std::string utf8Str(utf8Len, '\0');
-    WideCharToMultiByte(CP_UTF8, 0, wideStr.c_str(), -1, &utf8Str[0], utf8Len, nullptr, nullptr);
-
-    utf8Str.resize(utf8Len - 1);
-    return utf8Str;
-}
-#endif
-#endif   // UTIL_HPP
\ No newline at end of file