1.ChatServer:

       1.基本功能介绍:

      现在我们底层的代码已经实现好了 那么现在我们需要进行网页交互 那么我们需要实现一个前端页面,还需要实现一个聊天服务器。

也就是现在我们要实现一个接口用于与前端页面进行交互,然后ChatSever发请求去给chatSDK然后再去云端服务器响应去返回消息,实现一个交互的功能。

           2.接口的介绍

             RESTful API

由于整个和⼤模型交互都是基于HTTP协议,聊天助⼿将来也是浏览器借助HTTP协议和服务器交互, 因此本项⽬接⼝采⽤RESTful API⻛格进⾏设计,它是基于HTTP协议的应⽤接⼝设计规划,提供了⼀ 种通过标准化操作和资源访问模式进⾏客⼾端和服务器通信的⽅式。

REST是 Representational State Transfer 的缩写,翻译过来就是表现层状态转移。

资源(Resource)RESTful API 中的每⼀个对象、实体或数据都被抽象为⼀个资源。例如,⽤⼾、⽂章 等都可以

作为资源。每个资源都通过⼀个唯⼀的 URI (统⼀资源标识符)标识。

URI(统⼀资源标识)

URI是⽤于标识资源的地址。 RESTful API 中,通常使⽤ URL (统⼀资源定位符)作为

URI 。例如:

/users/123 表⽰ id 为 123 的⽤⼾资源

/posts/456 表⽰ id 为 456 的⽂章资源

HTTP动作(HTTP Methods)

RESTful API 依赖于 HTTP 协议的常⻅⽅法来对资源进⾏操作,每个 HTTP ⽅法对应不同的

操作:

GET :获取资源

POST :创建新的资源

PUT :更新资源

DELETE :删除资源

⽆状态

每个请求都是独⽴的,服务器不会保存客⼾端任何会话状态。客⼾端发来的每⼀个请求,都必须包

含服务器处理该请求所需的所有信息。

表现层状态转移(Representational State Transfer)

资源的表现形式可以是 JSON 、 XML 、 HTML 等格式,通常 RESTful API 使⽤ JSON 作

为数据交换格式,因为它轻量且易于解析。

请求URL: POST /api/user/id

3.接口的设计:

4.ChatServer的初始化:

  我们在实现ChatServer时 我们要严格按照这个接口的设计来写他的格式。

我们设计的这个要和SDK级别是一致的

          1.头文件:

这里我们能调用他的文件是因为我们上面已经执行安装成一个静态库了 直接include就直接包过来

这样就可以使用了

有了chatsdk后我们还要进行初始化 这里我们就要传一些模型的配置参数。

我们需要的基本的结构体和变量已经定义完成了

 2.源文件:

这里我们要初始化模型 我们可以参考testLLM里的初始化方法:

这里复制过来即可

这里面模型的配置信息就不能写死了 测试的时候可以写死 现在要通过chat'sdk的配置参数来调用

ChatServer的初始化就好了 初始化模型 和初始化服务器。

  5.ChatServer 服务器的启动:

头文件的更改

   

给一个成员变量用来标记服务器是否正在运行。

这里我们用库中的函数来提供一个线程 单独开一个线程  监听一下 但是这里我们需要服务器的ip地址和端口号 但是这里的配置信息只有在构造函数里面可见  所以这里我们还需要添加一个成员函数用来获取配置信息。这样就能获得用户传过来的配置信息了。

启动服务器这里就完成了

6..ChatServer 服务器的停止:

这里改变为用原子变量存储 来保证线程安全。

7.服务器接口的实现 :

我们一共要处理这七个接口。

   1.创建会话的接口:

      

要根据这个接口来实现,通过解析请求体 拿到请求参数

如果响应失败就没有这个数据信息就直接返回success的值和message的值即可。

这样实现的话中间那段错误信息的解析就重复实现了 所以我们再单独实现一个函数 用来专门实现这个错误信息的。

这样使用我们刚才所封装好的方法即可:

 //处理创建会话请求
    void ChatServer::handleCreateSessionRequest(const httplib::Request& request, httplib::Response& response){
        //通过反序列化拿到请求体的Json格式
        Json::Value requestJson;
        Json::Reader reader;
        //序列化body成功的话 结果保存在requestJson中
        if(!reader.parse(request.body,requestJson)){
            //构建错误响应的Json字符串
            std::string errorJsonStr = buildErrorResponse("parse request body failed,JSON format error");
            response.status = 400;//客户端请求语法错误 400表示请求体格式错误
            response.set_content(errorJsonStr,"application/json");//设置响应内容为Json格式
            return;
        }
        //获取请求参数
        std::string modelName = requestJson.get("model","deepseek-chat").asString();
        //创建会话
        std::string sessionID = _chatSDK->createSession(modelName);
        if(sessionID.empty()){  
            //构建错误响应的Json字符串
            std::string errorJsonStr = buildErrorResponse("create session failed");
            response.status = 500;//服务器内部错误 500表示服务器内部错误
            response.set_content(errorJsonStr,"application/json");//设置响应内容为Json格式
            return;
        }
        //构建响应体
        Json::Value dataJson;//存储得到的响应数据
        dataJson["session_id"] = sessionID;
        dataJson["model"] = modelName;
        
        Json::Value responseJson;
        responseJson["success"] = true;
        responseJson["message"]="create session success";
        responseJson["data"] = dataJson;
        //对成功信息进行序列化 序列化成字节流
        Json::StreamWriterBuilder writerBuilder;
        std::string responseJsonStr = Json::writeString(writerBuilder,responseJson);
        response.status = 200;//成功 200表示请求成功
        response.set_content(responseJsonStr,"application/json");//设置响应
        return;
         
        
    }//end handleCreateSessionRequest

这就是整个创建会话接口的实现。

2.获取会话列表的请求接口:

获取会话列表的请求接口就实现完成了

3.获取模型列表请求的接口:

 

这个接口是在用户新建对话时选择可用模型的时候弹出来的窗口

4.处理删除会话请求的接口:

这里我们要更改一下上面实现的构建响应请求的函数 如果只能构造错误请求就有点鸡肋,所以这里实现成响应请求,如果成功就返回一个true

5.获取历史消息的请求接口:

6.发送消息--全量返回 的接口实现:

这个基本上用不到因为基本默认都是流式返回

7.发送消息--流式返回 的接口实现:

这里我们调用这个响应方法用到的参数 这个通常用于流式响应

总体的实现:

8.设置路由规则:

  我们要将网页上的操作与服务器接口的操作实现一一对应,调用正确的函数。

这个调用的路径就跟这个是一致的后面就不多赘述

这就是全部接口的路由设置 但是什么时候去调用还没有搞定

我们要在服务器监听之前去调用这些函数 所以我们绑定路由规则时要放在服务器监听之前。

所以我们在启动服务器时而且在监听服务器之前完成调用。

还有一件事就是我们前端代码的生成路径

9.整个代码全览:

#include "ChatServer.h"
#include <ai_chat_sdk/common.h>
#include <ai_chat_sdk/util/myLog.h>
#include <jsoncpp/json/reader.h>
#include <jsoncpp/json/value.h>
#include <jsoncpp/json/forwards.h>
#include <jsoncpp/json/writer.h>



namespace ai_chat_server{

    ChatServer::ChatServer(const ServerConfig& config){
    //配置支持的模型参数:云端模型:deepseek-chat gpt-4o-mini gemini-2.0-flash  ollamma本地接入的模型:deepseek-r1:1.5b
    //deepseek-chat
    auto deepseekModelConfig = std::make_shared<ai_chat_sdk::APIConfig>();//创建DeepSeekProvider对象 用shared_ptr管理内存
    deepseekModelConfig->_modelName = "deepseek-chat";
    deepseekModelConfig->_apikey = config.deepseekAPIKey;
    deepseekModelConfig->_temperature = config.temperature;//温度参数  控制生成文本的随机性
    deepseekModelConfig->_max_tokens = config.maxTokens;//最大生成token数

    //gpt-4o-mini
    auto chatGPTModelConfig = std::make_shared<ai_chat_sdk::APIConfig>();//创建GPTProvider对象 用shared_ptr管理内存
    chatGPTModelConfig->_modelName = "gpt-4o-mini";
    chatGPTModelConfig->_apikey = config.chatGPTAPIKey;
    chatGPTModelConfig->_temperature = config.temperature;//温度参数  控制生成文本的随机性
    chatGPTModelConfig->_max_tokens = config.maxTokens;//最大生成token数

    //gemini-2.0-flash
    auto geminiModelConfig = std::make_shared<ai_chat_sdk::APIConfig>();//创建GeminiProvider对象 用shared_ptr管理内存
    geminiModelConfig->_modelName = "gemini-2.0-flash";
    geminiModelConfig->_apikey = config.geminiAPIKey;
    geminiModelConfig->_temperature = config.temperature;//温度参数  控制生成文本的随机性
    geminiModelConfig->_max_tokens = config.maxTokens;//最大生成token数

    //ollama本地接入的模型:deepseek-r1:1.5b
    auto ollamaModelConfig = std::make_shared<ai_chat_sdk::OllamaConfig>();//创建OllamaProvider对象 用shared_ptr管理内存
    ollamaModelConfig->_modelName = config.ollamaModelName;
    ollamaModelConfig->_modelDesc = config.ollamaModelDesc;
    ollamaModelConfig->_endpoint = config.ollamaEndpoint;
    ollamaModelConfig->_temperature = config.temperature;//温度参数  控制生成文本的随机性
    ollamaModelConfig->_max_tokens = config.maxTokens;//最大生成token数

    std::vector<std::shared_ptr<ai_chat_sdk::Config>> modelConfigs = {deepseekModelConfig,chatGPTModelConfig,geminiModelConfig,ollamaModelConfig};

    if(!_chatSDK->initModels(modelConfigs)){
        ERR("chatSDK initModels failed");
        return;
    }

    //初始化HTTP服务器
    _chatServer = std::unique_ptr<httplib::Server>(new httplib::Server());
    if(!_chatServer){
        ERR("chatServer init failed");
        return;
    }
    
  }//end ChatServer::ChatServer
  //启动服务器
  bool ChatServer::start(){
    if(_isRunning.load())//如果服务器正在运行 则返回false 表示服务器已启动
    {
        ERR("server is running");
        return false;
    }

    //设置路由规则
    setHTTPRoutes();

    //设置静态资源的路径
    //前端页面相关的文件都放在www目录下  服务器启动时会自动将www目录下的文件挂载到服务器的根路径下
    //注意 将来前端页面的名称会命名为index.html
    //当用户在浏览器中输入:http://ip:port/index.html  会返回www目录下的index.html文件  http://ip:port/ 也能返回www目录下的index.html文件 ip:port 为服务器的IP地址和端口号
    //在httblib中 默认情况下 如果请求只有ip和端口号  则httplib会默认使用index.html文件
    _chatServer->set_mount_point("/","./www");//设置静态资源的路径  /www 表示静态资源的路径


    //这里要让服务器在单独的线程中运行 不卡主程序的执行
    std::thread serverThread([this](){
        _chatServer->listen(_config.host,_config.port);
        INFO("server start success on {}:{}",_config.host,_config.port);//打印服务器启动成功信息 包含IP地址和端口号
    });
    serverThread.detach();//分离线程 让线程在后台运行 不阻塞主程序的执行
    _isRunning.store(true);//设置服务器为正在运行状态
    INFO("chatServer start success");//打印服务器启动成功信息
    return true;
  }
  //停止服务器
  void ChatServer::stop(){
    if(!_isRunning.load()){
        ERR("server is not running");
        return;
    }
    if(_chatServer){//如果HTTP服务器存在 则停止HTTP服务器
        _chatServer->stop();//停止HTTP服务器
    }
    _isRunning.store(false);//设置服务器为未运行状态
    INFO("chatServer stop success");//打印服务器停止成功信息
  }
  //判断服务器是否正在运行
  bool ChatServer::isRunning(){
    return _isRunning.load();//返回服务器是否正在运行
  }
    //构造响应的Json字符串
    std::string buildResponse(const std::string& message,bool success){
        Json::Value responseJson;
        responseJson["success"] = success;
        responseJson["message"] = message;
        //对响应信息进行序列化
        Json::StreamWriterBuilder writerBuilder;
        std::string responseJsonStr = Json::writeString(writerBuilder,responseJson);
        return responseJsonStr;
    }
    //处理创建会话请求
    void ChatServer::handleCreateSessionRequest(const httplib::Request& request, httplib::Response& response){
        //通过反序列化拿到请求体的Json格式
        Json::Value requestJson;
        Json::Reader reader;
        //序列化body成功的话 结果保存在requestJson中
        if(!reader.parse(request.body,requestJson)){
            //构建错误响应的Json字符串
            std::string errorJsonStr = buildResponse("parse request body failed,JSON format error");
            response.status = 400;//客户端请求语法错误 400表示请求体格式错误
            response.set_content(errorJsonStr,"application/json");//设置响应内容为Json格式
            return;
        }
        //获取请求参数
        std::string modelName = requestJson.get("model","deepseek-chat").asString();
        //创建会话
        std::string sessionID = _chatSDK->createSession(modelName);
        if(sessionID.empty()){  
            //构建错误响应的Json字符串
            std::string errorJsonStr = buildResponse("create session failed");
            response.status = 500;//服务器内部错误 500表示服务器内部错误
            response.set_content(errorJsonStr,"application/json");//设置响应内容为Json格式
            return;
        }
        //构建响应体
        Json::Value dataJson;//存储得到的响应数据
        dataJson["session_id"] = sessionID;
        dataJson["model"] = modelName;
        
        Json::Value responseJson;
        responseJson["success"] = true;
        responseJson["message"]="create session success";
        responseJson["data"] = dataJson;
        //对成功信息进行序列化 序列化成字节流
        Json::StreamWriterBuilder writerBuilder;
        std::string responseJsonStr = Json::writeString(writerBuilder,responseJson);
        response.status = 200;//成功 200表示请求成功
        response.set_content(responseJsonStr,"application/json");//设置响应
        return;
         
        
    }//end handleCreateSessionRequest
    //处理获取会话列表的请求
    void ChatServer::handleGetSessionListsRequest(const httplib::Request& request, httplib::Response& response){
        //获取会话列表
        std::vector<std::string> sessionIDs = _chatSDK->getSessionLists();//获取所有会话ID

        //构建Session信息
        Json::Value dataArray(Json::arrayValue);//创建Json数组 用于存储会话信息
        for(const auto& sessionID : sessionIDs){
            //通过会话ID 获取会话信息
            auto session = _chatSDK->getSession(sessionID);
            if(session){//如果会话存在 则添加到数组中
                Json::Value sessionJson;
                sessionJson["id"] =session->_sessionid;
                sessionJson["model"] = session->_modelName;
                sessionJson["created_at"] = static_cast<int64_t>(session->_createdAt);
                sessionJson["updated_at"] = static_cast<int64_t>(session->_updatedAt);
                sessionJson["message_count"] = session->_messages.size();
                //如果不空去获取第一条消息
                if(!session->_messages.empty()){
                    sessionJson["first_user_message"] = session->_messages.front()._content;
                }

                dataArray.append(sessionJson);
            }
        }
        //构建响应体
        Json::Value responseJson;
        responseJson["success"] = true;
        responseJson["message"]="get session lists success";
        responseJson["data"] = dataArray;
        //对成功信息进行序列化 序列化成字节流
        Json::StreamWriterBuilder writerBuilder;
        std::string responseJsonStr = Json::writeString(writerBuilder,responseJson);
        response.status = 200;//成功 200表示请求成功
        response.set_content(responseJsonStr,"application/json");//设置响应
        return;
        
    }//end handleGetSessionListsRequest
    //处理获取模型列表的请求
    void ChatServer::handleGetModelListsRequest(const httplib::Request& request, httplib::Response& response){
        //获取模型列表
        auto modelLists = _chatSDK->getAvailableModels();//获取所有可用模型名称

        //构建响应体
        Json::Value dataArray(Json::arrayValue);//创建Json数组 用于存储模型信息
        for(const auto& modelInfo : modelLists){//遍历模型列表
           Json::Value modelJson;
           modelJson["name"] = modelInfo._modelName;//模型名称
           modelJson["des"] = modelInfo._modelDesc;//模型描述
           dataArray.append(modelJson);
        }
        //构建响应体
        Json::Value responseJson;
        responseJson["success"] = true;
        responseJson["message"]="get model lists success";
        responseJson["data"] = dataArray;
        //序列化模型列表
        Json::StreamWriterBuilder writerBuilder;
        std::string responseJsonStr = Json::writeString(writerBuilder,responseJson);
        response.status = 200;//成功 200表示请求成功
        response.set_content(responseJsonStr,"application/json");//设置响应
        return;

    }//end handleGetModelListsRequest
    //处理删除会话请求
    void ChatServer::handleDeleteSessionRequest(const httplib::Request& request, httplib::Response& response){
        //获取会话ID 这里是一个路径参数
        std::string sessionID = request.matches[1];//获取路径参数 session_id
        //删除会话
        bool ret = _chatSDK->deleteSession(sessionID);
        if(ret){//如果删除成功 则返回删除成功信息
            std::string errorJsonStr = buildResponse("delete session success",true);//调用构建删除成功响应函数
            response.status = 200;//200表示请求成功
            response.set_content(errorJsonStr,"application/json");//设置响应
            return;
        }else{
            //如果删除失败 则返回删除失败信息
            std::string errorJsonStr = buildResponse("delete session failed,session not found");//调用构建删除失败响应函数
            response.status = 404;//404表示资源不存在
            response.set_content(errorJsonStr,"application/json");//设置响应
            return;
        }
        
        
    }//end handleDeleteSessionRequest
    //处理获取历史消息的请求
    void ChatServer::handleGetHistoryMessagesRequest(const httplib::Request& request, httplib::Response& response){
        //获取会话id 这里是一个路径参数
        std::string sessionID = request.matches[1];//获取路径参数 session_id

        //获取会话信息
        auto session = _chatSDK->getSession(sessionID);
        if(!session){//如果会话不存在 则返回会不存在信息
            std::string errorJsonStr = buildResponse("session not found");//调用构建会话不存在响应函数
            response.status = 404;//404表示资源不存在
            response.set_content(errorJsonStr,"application/json");//设置响应
            return;
        }
        //会话存在 构建历史消息列表
        Json::Value dataArray(Json::arrayValue);//创建Json数组 用于存储消息信息
        for(const auto& message : session->_messages){//遍历消息列表
           Json::Value messageJson;
           messageJson["id"] = message._messageid;//消息ID
           messageJson["role"] = message._role;//用户角色
           messageJson["content"] = message._content;//消息内容
           messageJson["timestamp"] = static_cast<int64_t>(message._timestamp);//消息时间戳
           dataArray.append(messageJson);
        }
        //构建响应体
        Json::Value responseJson;
        responseJson["success"] = true;
        responseJson["message"]="get history messages success";
        responseJson["data"] = dataArray;
        //对成功信息进行序列化 序列化成字节流
        Json::StreamWriterBuilder writerBuilder;
        std::string responseJsonStr = Json::writeString(writerBuilder,responseJson);
        response.status = 200;//成功 200表示请求成功
        response.set_content(responseJsonStr,"application/json");//设置响应
        return;

    }//end handleGetHistoryMessagesRequest
    //处理发送消息的请求  --全量返回
    void ChatServer::handleSendMessageRequest(const httplib::Request& request, httplib::Response& response){
        //获取请求参数
        Json::Value requestJson;
        Json::Reader reader;
        if(!reader.parse(request.body,requestJson)){
            std::string errorJsonStr = buildResponse("parse request body failed,json format error");//调用构建无效请求体响应函数
            response.status = 400;//400表示请求体无效
            response.set_content(errorJsonStr,"application/json");//设置响应
            return;
        }

        //解析请求参数
        std::string sessionID = requestJson["session_id"].asString();//获取会话ID 从Json中提取 session_id 字段
        std::string message = requestJson["message"].asString();//获取消息内容

        if(sessionID.empty() || message.empty()){
            std::string errorJsonStr = buildResponse("session_id or message is empty");//调用构建无效请求体响应函数
            response.status = 400;//400表示请求体无效
            response.set_content(errorJsonStr,"application/json");//设置响应
            return;
        }

        //发送消息
        std::string assistantMessage = _chatSDK->sendMessage(sessionID,message);//调用发送消息函数
        //如果发送失败 则返回发送失败信息
        if(assistantMessage.empty()){
            std::string errorJsonStr = buildResponse("Failed to send AI response message");//调用构建无效请求体响应函数
            response.status = 500;//500表示服务器内部错误
            response.set_content(errorJsonStr,"application/json");//设置响应
            return;
        }
        //构造响应参数
        Json::Value dataJson;
        dataJson["session_id"] = sessionID;
        dataJson["response"] = assistantMessage;

        //构建响应体
        Json::Value responseJson;
        responseJson["success"] = true;
        responseJson["message"]="send message success";
        responseJson["data"] = dataJson;
        //对成功信息进行序列化 序列化成字节流
        Json::StreamWriterBuilder writerBuilder;
        std::string responseJsonStr = Json::writeString(writerBuilder,responseJson);
        response.status = 200;//成功 200表示请求成功
        response.set_content(responseJsonStr,"application/json");//设置响应
        return;

    }//end handleSendMessageRequest
    //处理发送消息的请求  --流式返回
    void ChatServer::handleSendMessageStreamRequest(const httplib::Request& request, httplib::Response& response){
        //获取请求参数
        Json::Value requestJson;
        Json::Reader reader;
        if(!reader.parse(request.body,requestJson)){
            std::string errorJsonStr = buildResponse("parse request body failed,json format error");//调用构建无效请求体响应函数
            response.status = 400;//400表示请求体无效
            response.set_content(errorJsonStr,"application/json");//设置响应
            return;
        }
        //解析请求参数
        std::string sessionID = requestJson["session_id"].asString();//获取会话ID 从Json中提取 session_id 字段
        std::string message = requestJson["message"].asString();//获取消息内容

        if(sessionID.empty() || message.empty()){
            std::string errorJsonStr = buildResponse("session_id or message is empty");//调用构建无效请求体响应函数
            response.status = 400;//400表示请求体无效
            response.set_content(errorJsonStr,"application/json");//设置响应
            return;
        }
        //准备流式响应需要的字段
        response.status = 200;//成功 200表示请求成功
        response.set_header("Cache-Control","no-cache");//不使用缓存 立即返回
        response.set_header("Connection","keep-alive");//保持连接 不断推送数据
        //set_chunked_content_provider 让服务器知道,响应内不是一次性发送的,而是分多次发送给客户端 一般用在实时生成响应内容的情况
        response.set_chunked_content_provider("application/json",[this,sessionID,message](size_t offset, httplib::DataSink& dataSink)->bool{   
            //定义回调函数 用于处理每个分块数据 给sendMessageStream函数调用
            auto writeChunk =[&](const std::string& chunk,bool last){ //捕获列表放引用可以捕获上下文中的变量
                //将chunk转换为SSE的格式  即添加data: 前缀
                //chunk中可能还要特殊字符 比如笑脸 还有两个连续的换行符 等 所以这里还要进行转义 Json::valueToQuotedString(chunk.c_str())
                std::string sseData = "data: " + Json::valueToQuotedString(chunk.c_str()) + "\n\n"; //添加data: 前缀 并换行
               //需要将模型返回的结果 chunk 返回给客户端
                dataSink.write(sseData.c_str(),sseData.size()); //将SSE格式的字符串写入数据接收器 立即发送到客户端

                if(last){ //如果是最后一个分块 添加结束标记 通知客户端数据发送完成
                    std::string doneData = "data: [DONE]\n\n"; //添加data: done 前缀 并换行
                    dataSink.write(doneData.c_str(),doneData.size()); //将结束标记写入数据接收器 立即发送到客户端
                    dataSink.done(); //通知数据接收器 发送完成
                }
           }; //end writeChunk

            //先给客户端发送空的数据块防止客户端认为数据为空而关闭连接
            writeChunk("",true);
            //调用发送消息函数 并将回调函数作为参数传递
            _chatSDK->sendMessageStream(sessionID,message,writeChunk);
            return true; //表明后续还有数据要发送
        });//end set_chunked_content_provider
    }//end handleSendMessageStreamRequest


    //设置路由规则  --将请求分发给不同的处理函数
    void ChatServer::setHTTPRoutes(){
    //处理创建会话请求
    _chatServer->Post("/api/session",[this](const httplib::Request& request, httplib::Response& response){
        handleCreateSessionRequest(request,response);
    });

    //处理获取会话列表的请求
    _chatServer->Get("/api/sessions",[this](const httplib::Request& request, httplib::Response& response){
        handleGetSessionListsRequest(request,response);
    });
    //处理获取模型列表的请求
    _chatServer->Get("/api/models",[this](const httplib::Request& request, httplib::Response& response){
        handleGetModelListsRequest(request,response);
    });
    //处理删除会话请求
    _chatServer->Delete("/api/session/${session_id}",[this](const httplib::Request& request, httplib::Response& response){
        handleDeleteSessionRequest(request,response);
    });
    
    //处理获取历史消息的请求
    _chatServer->Get("/api/session/${session_id}/history",[this](const httplib::Request& request, httplib::Response& response){
        handleGetHistoryMessagesRequest(request,response);
    });
    //处理发送消息的请求  --全量返回
    _chatServer->Post("/api/message",[this](const httplib::Request& request, httplib::Response& response){
        handleSendMessageRequest(request,response);
    });
    
    //处理发送消息的请求  --流式返回
    
    _chatServer->Post("/api/message/async",[this](const httplib::Request& request, httplib::Response& response){
        handleSendMessageStreamRequest(request,response);
    });

    }//end setHTTPRoutes

} //end namespace ai_chat_server

2.main方法的生成:

1.生成:

目前我们的服务器还运行不了 因为缺少了main方法

这里main方法我们需要提供ServerConfig的信息。

复杂的整体实现我们实现好了 接下来这些简单的代码我们交给trae来给我们生成。

这是trae生成的主函数的代码:

trae生成的CMake文件:

2.测试编译是否通过:

先cd到ChatServer目录下来  然后构建一个build目录来测试 编译结果放到build目录下

cmake ..让他去上一层目录去寻找编译的文件

产生的问题是我忘记实现析构函数了,所以这里报错

加上析构函数就可以了

编译完成后在build目录下生成了一个AIChatServer的文件

3.测试服务器是否生成成功:

问题解释是这个flag version被定义了多次 那么就是mian函数出了问题

我们这里把注释掉重新编译再运行一下看看是否可行

这里系统崩溃了并且没有任何的打印。

那么我们这里就要检查main函数里的实现方法了。

在main函数里面--help可以使用但是-h无法使用 这是因为我们没有定义-h的参数

那么在这里识别不出来 -h被gflags解析了但是没有定义-h的参数所以gflag无法识别进行报错

我们把这里的解析参数放到前面

这样gflags就去调用库里的-h去识别参数

这样就可以正确识别出来了

但是解决完这个程序还是报错了 而且很奇怪的是没有打印报错信息

经过和ai的长时间拉扯终于找到了问题所在

是main函数生成的有问题

3.接口测试:

   1.获取可用模型的接口测试:

这个没有请求参数所以不用写请求参数

这里要事先导入环境变量要不然初始化不了模型

因为这里我chatgpt和gemini没有额度了所以我没导入apikey

这样我们的接口就没问题了

2.创建会话的接口测试:

这里我分别用deepseek和deeepseek-1.5b创建了两个会话

这里终端也创建成功了。

3.获取会话列表的接口测试:

这样我们终端也运行成功了

4.删除会话的接口测试:

这个id就是我们刚才获取到会话列表里面的id

这里有语法请求错误他才会报错,这里正是我传递参数错误了,而不是我程序有错误。

5.发送消息--全量返回的接口测试:

这里我跟他打招呼

这里既插入了用户发送的消息,也插入了模型的消息

6.获取会话的历史消息:

这里我写的格式有问题不能加上$这个字符  这样就获取到了历史消息

在终端我们可以看到生成了一个chatDB.db的数据库存储有两张表 

可以看到存储的内容

7.发送消息--流式返回的接口测试

这里传回来的消息有误,只有done那么说明我们代码出现了问题。

这里不能传true传了这个代表对话就结束了,所以我们这里要穿false。

这里发送空消息的目的就是减少用户的等待,而这里如果传true直接进入if语句返回done了

所以要改成false

更改之后这里还是有问题。并不是流式返回的

是因为我之前写的是applyjson格式返回的这里不是这里要以流式来返回

我这里还有一个问题就流式响应结束不了就是这个false的原因应该传flase不应该传true

这里ollama的测试也成功了。

那么到这里所有的接口测试也就完成了,那么说明我们后端的代码已经完全没有问题了。

接下来就要来完成前端页面的内容了。

启动服务器之前记得把三个模型的apikey的环境变量给配置一下,这里环境变量可以直接配置到环境变量中,这里就是配置到环境变量中但是不是永久配置的,服务器一关闭就得重新配置,这里我就不永久配置了。

4.前端的实现以及测试:

这样由ai生成的整个前端页面也就实现完成了,在这里还可以调教一下大模型,让他生成更美观的前端界面。这里我就不演示了。

5.上传到远端仓库:

这就是我们创建的远端仓库,现在我们要把写好的代码打包上传到仓库中。

6.项目总结:

这里从0用C++实现了接入deepseek,chatgpt,Gemini的云端大模型接入还通过ollama接入了本地大模型,用到了trae,apifox等工具,熟悉了第三方库如spdlog日志库,gflags,gtest,jsoncpp,httplib等的第三方库的使用。

1.掌握大模型接入的思路:

       1.到官方申请apikey

        2.查看官方文档中提供访问模型的API接口,了解接口的功能,以及熟悉接口的请求参数格式,以及响应的格式

        3.使用第三方工具进行接口的快速验证如apifox,crul

2.掌握单例模式和策略模式的使用

3.掌握流式响应处理,SSE数据格式,如何通过httplib库实现流式响应

4.掌握ollama工具的使用,如何下载模型,如何运行模型,等终端命令

5.掌握sqlit数据库的使用

6.掌握什么是SDK,如何封装SDK,SDK的安装,以及CMake的编写

7.熟练掌握让大模型帮我们解决问题和生成代码,学会使用提示词

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐