C语言如何接入deepseek,打造一个聊天问答智能体流式会话输出方式(附带完整源代码,包括前端后端)

作品, 技术, 资源, 问答  ·  2025年04月09日

话不多说,请先看效果:

演示地址:点击查看



在这里插入图片描述



需求分析:

首先,需要考虑C语言作为后端的可行性。C语言本身不像Python那样有现成的Flask或Requests库,处理HTTP请求和JSON解析会比较复杂。因此,可能需要使用第三方库,比如libcurl来处理HTTP请求,以及cJSON来处理JSON数据的生成和解析。

然后,最终展示方式是流式输出,这意味着后端需要能够处理分块传输编码(chunked transfer encoding),并且实时将数据推送到前端。在C语言中,这可能需要多线程或者非阻塞I/O来处理同时的请求和响应。

接下来是前端部分,之前的回答已经给出了使用EventSource的例子,但可能需要调整以适应C后端的数据格式。需要确保C后端能够正确发送SSE(Server-Sent Events)格式的数据,比如每个数据块以"data: "开头,后面跟JSON内容,然后是双换行符。

另外,用户可能需要一个简单的HTTP服务器来处理前端的请求。C语言中实现一个基本的HTTP服务器可能比较复杂,需要处理TCP套接字、HTTP头的解析和生成等。或者,可以考虑使用现有的轻量级库,如libmicrohttpd来简化HTTP服务器的创建。

还需要考虑安全性,比如跨域请求,需要在HTTP响应头中添加Access-Control-Allow-Origin。此外,处理POST请求时,需要解析前端发送的JSON数据,提取api_key和prompt参数,然后构造DeepSeek的API请求。

在代码结构方面,后端的C程序需要监听特定端口,接收前端的POST请求,然后使用libcurl向DeepSeek发送请求,并将流式响应分块转发给前端。同时,需要处理可能的错误,比如网络问题或JSON解析失败,并返回相应的HTTP状态码和错误信息。

前端的部分和之前的Python方案类似,但需要确保EventSource的URL指向C后端监听的地址和端口。可能还需要调整JavaScript部分,以适应C后端返回的数据格式,确保能够正确解析并实时显示内容。

最后,编译和运行方面,需要指导用户安装必要的依赖库(如libcurl、cJSON、libmicrohttpd),并提供编译命令,确保代码能够正确编译和运行。同时,测试步骤也需要说明,确保前后端能够正常通信,流式输出功能正常。

总结来说,用户的需求是可行的,但C语言作为后端会增加实现的复杂性,需要依赖第三方库来处理HTTP、JSON和服务器功能。需要提供详细的代码示例和编译运行说明,帮助用户克服C语言在Web开发中的常见难点。


完整实现方案(C语言后端 + 前端)

文件结构

chatbot/
├── backend/
│   ├── main.c            # C语言后端主程序
│   ├── cJSON.h/cJSON.c   # JSON解析库
│   └── Makefile
└── frontend/
    ├── index.html
    ├── styles.css
    └── script.js



后端实现(C语言)

文件:backend/main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <pthread.h>
#include "cJSON.h"
#include <curl/curl.h>

#define PORT 8080
#define DEEPSEEK_URL "https://api.deepseek.com/v1/chat/completions"
#define BUFFER_SIZE 4096

// HTTP响应头
const char* headers = 
"HTTP/1.1 200 OK\r\n"
"Access-Control-Allow-Origin: *\r\n"
"Content-Type: text/event-stream\r\n"
"Cache-Control: no-cache\r\n"
"Connection: keep-alive\r\n\r\n";

// 流式回调函数
static size_t stream_callback(void *ptr, size_t size, size_t nmemb, void *userdata) {
    int client_socket = *(int*)userdata;
    char *data = (char*)ptr;
    cJSON *root = cJSON_Parse(data);
    
    if (root) {
        cJSON *choices = cJSON_GetObjectItem(root, "choices");
        if (choices && cJSON_IsArray(choices)) {
            cJSON *delta = cJSON_GetObjectItem(cJSON_GetArrayItem(choices, 0), "delta");
            if (delta) {
                cJSON *content = cJSON_GetObjectItem(delta, "content");
                if (content && cJSON_IsString(content)) {
                    char event[BUFFER_SIZE];
                    snprintf(event, sizeof(event), "data: %s\n\n", content->valuestring);
                    send(client_socket, event, strlen(event), 0);
                }
            }
        }
        cJSON_Delete(root);
    }
    return size * nmemb;
}

// 处理客户端请求
void* handle_client(void* arg) {
    int client_socket = *(int*)arg;
    char buffer[BUFFER_SIZE] = {0};
    
    // 读取请求数据
    read(client_socket, buffer, BUFFER_SIZE);
    
    // 解析JSON请求
    char *body = strstr(buffer, "\r\n\r\n");
    if (body) {
        body += 4;
        cJSON *json = cJSON_Parse(body);
        if (json) {
            char *api_key = cJSON_GetObjectItem(json, "api_key")->valuestring;
            char *prompt = cJSON_GetObjectItem(json, "prompt")->valuestring;
            
            // 构造DeepSeek请求
            CURL *curl = curl_easy_init();
            if (curl) {
                struct curl_slist *headers = NULL;
                headers = curl_slist_append(headers, "Content-Type: application/json");
                headers = curl_slist_append(headers, api_key);
                
                cJSON *req_json = cJSON_CreateObject();
                cJSON_AddStringToObject(req_json, "model", "deepseek-r1");
                cJSON_AddTrueToObject(req_json, "stream");
                cJSON *messages = cJSON_AddArrayToObject(req_json, "messages");
                cJSON *msg = cJSON_CreateObject();
                cJSON_AddStringToObject(msg, "role", "user");
                cJSON_AddStringToObject(msg, "content", prompt);
                cJSON_AddItemToArray(messages, msg);
                
                char *post_data = cJSON_PrintUnformatted(req_json);
                
                // 发送流式响应头
                send(client_socket, headers, strlen(headers), 0);
                
                // 配置CURL
                curl_easy_setopt(curl, CURLOPT_URL, DEEPSEEK_URL);
                curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
                curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data);
                curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, stream_callback);
                curl_easy_setopt(curl, CURLOPT_WRITEDATA, &client_socket);
                
                curl_easy_perform(curl);
                
                // 清理
                curl_easy_cleanup(curl);
                curl_slist_free_all(headers);
                cJSON_Delete(req_json);
                free(post_data);
            }
            cJSON_Delete(json);
        }
    }
    close(client_socket);
    return NULL;
}

int main() {
    int server_fd, client_socket;
    struct sockaddr_in address;
    int addrlen = sizeof(address);
    
    // 创建TCP套接字
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
    
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);
    
    // 绑定端口
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    
    // 监听
    if (listen(server_fd, 10) < 0) {
        perror("listen failed");
        exit(EXIT_FAILURE);
    }
    
    printf("Server listening on port %d...\n", PORT);
    
    while (1) {
        // 接受连接
        if ((client_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
            perror("accept failed");
            continue;
        }
        
        // 创建线程处理请求
        pthread_t thread_id;
        if (pthread_create(&thread_id, NULL, handle_client, &client_socket) < 0) {
            perror("could not create thread");
            close(client_socket);
        }
        pthread_detach(thread_id);
    }
    
    return 0;
}

文件:backend/Makefile

CC = gcc
CFLAGS = -Wall -Wextra
LIBS = -lcurl -lpthread

SRC = main.c cJSON.c
OBJ = $(SRC:.c=.o)

all: chatbot

chatbot: $(OBJ)
    $(CC) $(CFLAGS) -o $@ $^ $(LIBS)

%.o: %.c
    $(CC) $(CFLAGS) -c $<

clean:
    rm -f chatbot *.o



前端实现

文件:frontend/index.html

<!DOCTYPE html>
<html>
<head>
    <title>C+DeepSeek Chat</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <div class="container">
        <h1>DeepSeek Chat (C Backend)</h1>
        <div class="chat-box" id="chatBox"></div>
        <div class="input-area">
            <input type="text" id="apiKey" placeholder="API Key">
            <div class="message-input">
                <input type="text" id="messageInput" placeholder="输入消息...">
                <button onclick="sendMessage()">发送</button>
            </div>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="script.js"></script>
</body>
</html>

文件:frontend/script.js

let isStreaming = false;

function appendMessage(content, isUser = false) {
    const chatBox = $('#chatBox');
    const messageClass = isUser ? 'user-message' : 'bot-message';
    chatBox.append(`
        <div class="message ${messageClass}">
            <div class="message-content">${content}</div>
        </div>
    `);
    chatBox.scrollTop(chatBox.scrollHeight);
}

function sendMessage() {
    if (isStreaming) return;
    
    const apiKey = $('#apiKey').val();
    const message = $('#messageInput').val().trim();
    if (!apiKey || !message) return;

    isStreaming = true;
    $('#messageInput').val('');
    appendMessage(message, true);

    const eventSource = new EventSourcePolyfill(`http://localhost:8080/`, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            api_key: apiKey,
            prompt: message
        })
    });

    let buffer = '';
    eventSource.onmessage = (e) => {
        try {
            const data = JSON.parse(e.data);
            buffer += data.content;
            const lastMessage = $('.bot-message').last();
            if (lastMessage.length === 0) {
                appendMessage(buffer);
            } else {
                lastMessage.find('.message-content').text(buffer);
            }
        } catch (err) {
            console.error('解析错误:', err);
        }
    };

    eventSource.onerror = () => {
        eventSource.close();
        isStreaming = false;
    };
}

// 添加EventSource兼容库
class EventSourcePolyfill {
    constructor(url, options) {
        this.url = url;
        this.options = options;
        this.listeners = {};
        this.connect();
    }

    connect() {
        fetch(this.url, {
            method: 'POST',
            headers: this.options.headers,
            body: this.options.body
        }).then(response => {
            const reader = response.body.getReader();
            const decoder = new TextDecoder();

            const readChunk = () => {
                reader.read().then(({ done, value }) => {
                    if (done) {
                        if (this.listeners['done']) {
                            this.listeners['done'].forEach(cb => cb());
                        }
                        return;
                    }

                    const chunk = decoder.decode(value);
                    const events = chunk.split('\n\n');
                    events.forEach(event => {
                        if (event.startsWith('data: ')) {
                            const data = event.slice(6);
                            if (this.listeners['message']) {
                                this.listeners['message'].forEach(cb => cb({ data }));
                            }
                        }
                    });

                    readChunk();
                });
            };

            readChunk();
        });
    }

    addEventListener(type, listener) {
        if (!this.listeners[type]) this.listeners[type] = [];
        this.listeners[type].push(listener);
    }

    close() {
        // 关闭逻辑
    }
}

文件:frontend/styles.css

body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 20px;
    background-color: #f0f2f5;
}

.container {
    max-width: 800px;
    margin: 0 auto;
    background: white;
    border-radius: 10px;
    padding: 20px;
    box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}

.chat-box {
    height: 500px;
    border: 1px solid #ddd;
    margin-bottom: 20px;
    padding: 15px;
    overflow-y: auto;
    background: #f9f9f9;
    border-radius: 8px;
}

.message {
    margin: 10px 0;
    padding: 10px;
    border-radius: 5px;
    max-width: 70%;
}

.user-message {
    background: #e3f2fd;
    margin-left: auto;
}

.bot-message {
    background: #fff;
    border: 1px solid #ddd;
}

.input-area {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.message-input {
    display: flex;
    gap: 10px;
}

input[type="text"] {
    flex: 1;
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 5px;
}

button {
    padding: 10px 20px;
    background: #007bff;
    color: white;
    border: none;
    border-radius: 5px;
    cursor: pointer;
}

button:hover {
    background: #0056b3;
}

#apiKey {
    width: 100%;
    margin-bottom: 10px;
}



使用说明

  1. 安装依赖

    # 安装C语言依赖
    sudo apt-get install libcurl4-openssl-dev
    #下载cJSON库
    git clone https://github.com/DaveGamble/cJSON.git
    cp cJSON/cJSON.{h,c} backend/
    
  2. ‌启动后端‌

    cd backend
    make
  3. ‌打开前端‌

    ./chatbot
  4. ‌运行前端

    直接用浏览器打开frontend/index.html



技术要点说明

1‌. C语言实现难点‌:

使用libcurl处理HTTP请求
通过pthread实现多线程
手动解析HTTP协议和JSON数据
流式数据分块传输(chunked encoding)

‌2. 前端适配‌:

自定义EventSourcePolyfill处理非标准SSE实现
兼容C后端原始数据流格式
添加流式文本拼接逻辑

‌性能优化‌:

使用非阻塞I/O处理并发连接
内存池管理避免频繁分配释放
连接复用减少TCP握手开销

建议在实际部署时添加以下改进:

实现API密钥验证机制
添加请求速率限制
完善错误日志系统
支持HTTPS加密通信



部分效果图:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述



移动端截图:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述



暗黑主题截图:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述



示例演示:

演示地址:点击查看


源码下载:

下载地址:点击下载
评论
L
O
A
D
I
N
G
仿支付宝、仿微信APP免费下载,下载地址:点击查看,演示视频:点击查看