本人纯外行,非常感兴趣业余时间玩一玩,欢迎各位大佬提各种建议及想法。

当前功能:

实现API调用并进行多轮对话及思考链输出,并在本地存储对话内容。

聊天框:展示对话过程及思考链。

输入框:输入想发送的内容

button1:发送输入框内容,并触发对话将返回内容呈现到聊天框

button2:清空对话内容并重启对话

下一步实现功能:

对于不同用户,不同需求进行对话,本地对话历史调用。

(仅展示最新版本,一步一步过来的苦就不多说了。全程靠deepseek输出代码实现软件功能,包括以下绝大部分内容,不要骂我)

DeepSeek API聊天助手实现教程

本文将详细介绍一个使用C# WinForms和DeepSeek API构建的聊天助手应用程序的实现原理和功能。这个程序实现了与AI的实时对话、思考过程可视化以及对话历史记录等功能。

功能概述

该应用程序主要实现以下功能:

  • 用户输入消息并发送

  • 实时显示AI的思考过程和最终回复

  • 保存完整对话历史到CSV文件

  • 清除对话历史

  • 支持回车键发送消息

核心代码解析

1. 初始化与类成员

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private List<dynamic> conversationHistory = new List<dynamic>();
  • conversationHistory:动态列表,用于存储完整的对话历史(用户消息和AI回复)

  • 构造函数初始化窗体组件

2. 发送消息与API交互

private async void button1_Click(object sender, EventArgs e)
{
    string userMessage = textBox2.Text;
    textBox1.AppendText($"用户: {userMessage}{Environment.NewLine}{Environment.NewLine}");

    conversationHistory.Add(new
    {
        role = "user",
        content = userMessage
    });

功能

  1. 获取用户输入的消息

  2. 在聊天框中显示用户消息

  3. 将用户消息添加到对话历史

var baseurl = "https://api.deepseek.com";
var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer your-api-key");
var requestDate = new
{
    model = "deepseek-reasoner",
    messages = conversationHistory.ToArray(),
    max_tokens = 1000,
    return_reasoning = true,
    stream = true
};

(这里要说一下,"Bearer your-api-key"为deepseek上自己创建的API,需要自己申请。。。。。前面没搞懂代码的时候搜了半天)

功能

  1. 设置DeepSeek API端点

  2. 创建HTTP客户端并添加授权头

  3. 构建请求参数:

    • 指定AI模型

    • 包含完整对话历史

    • 限制最大token数

    • 要求返回思考过程

    • 启用流式响应

textBox1.AppendText($"DeepSeek 正在思考...{Environment.NewLine}");
int thinkingHeaderEnd = textBox1.TextLength;
string reasoningSeparator = $"----------";
textBox1.AppendText(reasoningSeparator + Environment.NewLine);
int reasoningStartPos = textBox1.TextLength;
int lastReasoningPos = reasoningStartPos;

功能

  1. 在聊天框中显示"正在思考"提示

  2. 记录当前文本位置,用于后续插入思考过程

  3. 添加分隔线区分不同内容区域

var response = await client.PostAsync($"{baseurl}/v1/chat/completions", content);
var stream = await response.Content.ReadAsStreamAsync();
var reader = new StreamReader(stream);
bool isReasoningComplete = false;
string currentAnswer = "";

while (!reader.EndOfStream)
{
    var line = await reader.ReadLineAsync();
    // 处理流式响应...
}

功能

  1. 发送API请求并获取流式响应

  2. 逐行处理API返回的数据

  3. 使用标志位区分思考过程和最终回复

this.Invoke((Action)(() =>
{
    // 处理思考链
    if (!string.IsNullOrEmpty(deltaReasoning))
    {
        textBox1.Select(lastReasoningPos, 0);
        textBox1.SelectedText = deltaReasoning;
        lastReasoningPos += deltaReasoning.Length;
    }
    
    // 切换到答案输出
    if (!isReasoningComplete && string.IsNullOrEmpty(deltaReasoning))
    {
        isReasoningComplete = true;
        textBox1.AppendText($"{Environment.NewLine}----------------------{Environment.NewLine}");
        textBox1.AppendText("Deepseek:" + Environment.NewLine);
    }
    
    // 处理答案
    if (!string.IsNullOrEmpty(deltaContent))
    {
        currentAnswer += deltaContent;
        textBox1.AppendText(deltaContent);
        textBox1.ScrollToCaret();
    }
}));

功能

  1. 思考过程处理:将AI的思考内容实时插入到指定位置

  2. 内容切换:当思考过程结束时添加分隔线并显示回复标题

  3. 答案处理:流式显示AI的最终回复

  4. 自动滚动到最新内容

private void SaveConversationToCsv()
{
    string documentsPath = @"E:\deepseekcc1\deepseek0610";
    string fileName = $"DeepSeek_Conversation_{DateTime.Now:yyyyMMdd}.csv";
    string filePath = Path.Combine(documentsPath, fileName);

    var csvContent = new StringBuilder();

    if (!File.Exists(filePath))
    {
        csvContent.AppendLine("Timestamp,Role,Content");
    }

    foreach (var message in conversationHistory)
    {
        string role = message.role;
        string content = message.content.Replace("\"", "\"\"");
        string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        csvContent.AppendLine($"\"{timestamp}\",\"{role}\",\"{content}\"");
    }

    File.AppendAllText(filePath, csvContent.ToString(), Encoding.UTF8);
}

(存储路径为第一条)

功能

  1. 按日期生成CSV文件名

  2. 首次创建文件时添加标题行

  3. 转义特殊字符(如双引号)

  4. 添加时间戳、角色和内容三列

  5. 追加保存到文件

// 回车键发送
private void textBox2_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Enter)
    {
        e.SuppressKeyPress = true;
        button1.PerformClick();
    }
}

// 清除历史
private void button2_Click(object sender, EventArgs e)
{
    conversationHistory.Clear();
    textBox1.Text = "对话历史已清除" + Environment.NewLine + Environment.NewLine;
}

功能

  1. 支持回车键发送消息(阻止默认提示音)

  2. 一键清除对话历史和聊天框内容

(哈哈哈deepseek给自己写的亮点)

技术亮点

  1. 流式响应处理:实时显示AI的思考过程和回复,提升用户体验

  2. 动态文本插入:精确定位插入点实现不同内容区域的区分显示

  3. 对话历史管理:完整记录并保存所有交互内容

  4. 异常处理:完善的错误处理机制确保程序稳定性

  5. 线程安全:使用Invoke确保跨线程UI操作安全

使用场景

这个聊天助手适用于:

  • 教育学习:解答学习问题,展示解题思路

  • 编程辅助:提供代码建议和解释

  • 内容创作:帮助生成和优化文本内容

  • 研究分析:展示思考过程增强可信度

  • 个人助手:日常问答和信息查询

(附上代码)

private async void button1_Click(object sender, EventArgs e)
{

    string userMessage = textBox2.Text;
    textBox1.AppendText($"用户: {userMessage}{Environment.NewLine}{Environment.NewLine}");

    conversationHistory.Add(new
    {
        role = "user",
        content = userMessage
    });

    var baseurl = "https://api.deepseek.com";
    var client = new HttpClient();
    client.DefaultRequestHeaders.Add("Authorization", "Bearer sk-ab----你创建的API--------");
    var requestDate = new
    {
        model = "deepseek-reasoner",
        //maxTokens:100,
        messages = conversationHistory.ToArray(),
        max_tokens = 1000, // 设置最大token数
        return_reasoning = true,
        stream = true
    };

    var jsonContent = JsonConvert.SerializeObject(requestDate);
    var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");
    //初始化UI显示
    textBox1.AppendText($"DeepSeek 正在思考...{Environment.NewLine}");
    int thinkingHeaderEnd = textBox1.TextLength;
    //添加明确的分隔标记(使用唯一标识符)
    string reasoningSeparator = $"----------";
    textBox1.AppendText(reasoningSeparator + Environment.NewLine);
    int reasoningStartPos = textBox1.TextLength; // 精确记录思考链开始位置
    int lastReasoningPos = reasoningStartPos;

    try
    {
        var response = await client.PostAsync($"{baseurl}/v1/chat/completions", content);
        var stream = await response.Content.ReadAsStreamAsync();
        var reader = new StreamReader(stream);
        bool isReasoningComplete = false; // 标记思考过程是否完成;
        //string currentReasoning = "";      // 当前累积的思考内容
        string currentAnswer = "";

        StringBuilder reasoningBuilder = new StringBuilder();
        StringBuilder answerBuilder = new StringBuilder();

        while (!reader.EndOfStream)
        {
            var line = await reader.ReadLineAsync();
            if (string.IsNullOrWhiteSpace(line) || !line.StartsWith("data:"))
                continue;

            var eventData = line.Substring("data:".Length).Trim();
            if (eventData == "[DONE]") // Fix: Ensure the loop breaks only when "[DONE]" is encountered
                break;

            dynamic chunk = JsonConvert.DeserializeObject(eventData);
            string deltaReasoning = chunk.choices[0]?.delta?.reasoning_content;
            string deltaContent = chunk.choices[0]?.delta?.content;

            this.Invoke((Action)(() =>
            {
                //处理思考链(追加模式)
                if (!string.IsNullOrEmpty(deltaReasoning))
                {
                    textBox1.Select(lastReasoningPos, 0);
                    textBox1.SelectedText = deltaReasoning;
                    lastReasoningPos += deltaReasoning.Length;
                }
                //切换到答案输出
                if (!isReasoningComplete && string.IsNullOrEmpty(deltaReasoning))
                {
                    isReasoningComplete = true;
                    textBox1.AppendText($"{Environment.NewLine}----------------------{Environment.NewLine}");
                    textBox1.AppendText("Deepseek:" + Environment.NewLine);
                }
                //处理答案(追加模式)
                if (!string.IsNullOrEmpty(deltaContent))
                {
                    currentAnswer += deltaContent;
                    textBox1.AppendText(deltaContent);
                    textBox1.ScrollToCaret();
                }
            }));
        }

        conversationHistory.Add(new
        {
            role = "assistant",
            content = currentAnswer
        });
    }
    catch (Exception ex)
    {
        this.Invoke((Action)(() =>
        {
            textBox1.AppendText($"{Environment.NewLine}错误: {ex.Message}{Environment.NewLine}");
        }));
    }
    finally
    {
        this.Invoke((Action)(() =>
        {
            textBox2.Text = "";
            textBox1.AppendText($"{Environment.NewLine}----------------------{Environment.NewLine}");
            SaveConversationToCsv();
        }));
    }
}

有什么创意都可以提喔,嘻嘻。deepseek应该都能实现的。

下面两周有空的话应该会更新一版能够调用不同本地的历史记录。

后面还想扩展成能够导入图片、PPT和Word并进行分析的。

本人是做机器视觉的,后期发展会偏向图像识别、AOI检测相关,到时候可能就嵌入到其他二次开发的视觉系统上。(就是不知道能不能行)

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐