使用Rust构建一个完整的DeepSeekWeb聊天应用

在现代软件开发中,Rust 正在成为构建高性能、可靠应用程序的首选语言之一。今天,我将分享如何使用Rust构建一个完整的 Web 聊天应用,它能够与 DeepSeek API 交互,提供类似 ChatGPT 的体验。

项目概览

我们的目标是创建一个功能完整的聊天应用,它包含:

  • 一个基于 Axum 的后端服务
  • 一个带有 Markdown 渲染功能的前端界面
  • 与 DeepSeek API 的集成
  • 良好的错误处理和用户体验

技术栈选择

对于这个项目,我们选择了以下技术栈:

  • Axum:一个模块化、快速、简洁的RustWeb 框架
  • Tokio:异步运行时,用于处理并发请求
  • Reqwest:用于发送 HTTP 请求到 DeepSeek API
  • Serde:用于 JSON 序列化和反序列化
  • Tower HTTP:提供静态文件服务等功能
  • Marked.js:前端 Markdown 渲染库

项目结构

plain 复制代码
deepseek_web/
├── Cargo.toml
├── src/
│   └── main.rs
└── static/
    └── index.html

实现细节

Cargo.toml配置

rust 复制代码
[package]
name = "deepseek_web"
version = "0.1.0"
edition = "2021"

[dependencies]
axum = "0.6"
tokio = { version = "1.0", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
reqwest = { version = "0.11", features = ["json"] }
tower-http = { version = "0.4", features = ["cors", "fs"] }

这几个dependencies是Rust生态中常用的库,主要用于构建网络服务和处理数据,各自的作用如下:

  1. axum
    基于 Tokio、Tower 构建的现代化 Web 框架,专注于简洁性和可扩展性。适合构建 REST API、HTTP 服务等,支持路由、中间件、请求/响应处理等核心 Web 功能,设计风格贴近Rust的异步编程模型。
  2. tokio
    Rust 最流行的异步运行时,提供异步 I/O、任务调度、计时器等核心能力。features = ["full"] 启用了所有功能(如多线程调度器、网络/文件系统异步操作等),是 axum 等异步框架的基础依赖。
  3. serde
    通用的数据序列化/反序列化库,支持 JSON、CSV、XML 等多种格式。features = ["derive"] 允许通过 #[derive(Serialize, Deserialize)] 自动生成序列化代码,简化数据转换逻辑。
  4. serde_json
    基于 serde 的 JSON 格式实现,提供 JSON 字符串与Rust数据结构之间的转换,常用于处理 HTTP 请求/响应中的 JSON 数据。
  5. reqwest
    异步 HTTP 客户端,支持发送 GET/POST 等请求,features = ["json"] 启用 JSON 自动序列化/反序列化功能,方便与 REST API 交互(例如服务端向其他接口发起请求)。
  6. tower-http
    基于 Tower 生态的 HTTP 中间件集合。cors 功能提供跨域资源共享(CORS)支持,fs 支持静态文件服务,常用于 axum 等框架中扩展 HTTP 处理能力。

这些库组合起来,通常用于构建一个完整的异步 Web 服务:axum 处理 HTTP 路由和逻辑,tokio 提供异步运行时,serde 系列处理数据序列化,reqwest 用于服务端发起 HTTP 请求,tower-http 补充中间件功能(如跨域、静态文件)。

1. 后端实现

后端使用 Axum 框架构建,主要包含以下组件:

rust 复制代码
// 主要依赖
use axum::{
    extract::State,
    http::StatusCode,
    response::Html,
    routing::{get, post},
    Json, Router,
};
use serde::{Deserialize, Serialize};
use std::sync::{Arc, Mutex};
use tower_http::services::ServeDir;
use std::net::SocketAddr;
use std::env;

我们定义了与 DeepSeek API 交互所需的数据结构:

rust 复制代码
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "lowercase")]
enum Role {
    System,
    User,
    Assistant,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
struct Message {
    role: Role,
    content: String,
}

#[derive(Serialize, Deserialize, Debug)]
struct ChatCompletionRequest {
    model: String,
    messages: Vec<Message>,
    stream: bool,
}

核心的聊天处理函数负责与 DeepSeek API 通信:

rust 复制代码
async fn chat_handler(
    State(state): State<AppState>,
    Json(request): Json<ChatRequest>,
) -> Result<Json<ChatResponse>, (StatusCode, Json<ErrorResponse>)> {
    // 获取API密钥
    let api_key = env::var("DEEPSEEK_API_KEY")
        .map_err(|_| (
            StatusCode::INTERNAL_SERVER_ERROR, 
            Json(ErrorResponse { 
                error: "服务器未正确配置: 未设置 DEEPSEEK_API_KEY 玱境变量".to_string()
            })
        ))?;

    // 添加用户消息到历史
    let user_message = Message {
        role: Role::User,
        content: request.message.clone(),
    };

    // ... 处理逻辑 ...

    // 发送请求到 DeepSeek API
    let response = state
        .client
        .post("https://api.deepseek.com/chat/completions")
        .header("Content-Type", "application/json")
        .header("Authorization", format!("Bearer {}", api_key))
        .json(&request_body)
        .send()
        .await
        .map_err(|e| (
            StatusCode::INTERNAL_SERVER_ERROR, 
            Json(ErrorResponse { 
                error: format!("网络请求失败: {}", e)
            })
        ))?;

    // ... 处理响应 ...
}

2. 错误处理

一个健壮的应用需要良好的错误处理机制。我们在程序启动时检查必要的环境变量:

rust 复制代码
#[tokio::main]
async fn main() {
    // 检查是否设置了 API 密钥
    if env::var("DEEPSEEK_API_KEY").is_err() {
        eprintln!("错误: 未设置 DEEPSEEK_API_KEY 环境变量");
        eprintln!("请设置环境变量,例如: export DEEPSEEK_API_KEY=your_api_key_here");
        std::process::exit(1);
    }
    
    // ... 其余初始化代码 ...
}

这种方法确保了在缺少必要配置时,应用能够提供清晰的错误信息而不是神秘的崩溃。

3. 前端实现

前端使用原生 HTML、CSS 和 JavaScript 构建,集成了 Marked.js 库来渲染 Markdown:

html 复制代码
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script>
// 配置 marked 库
marked.setOptions({
    breaks: true,
    gfm: true,
});

// 渲染 Markdown 内容
function addMessageToHistory(role, content) {
    // ... 其他代码 ...
    if (role === 'assistant') {
        // 为AI消息渲染Markdown
        const contentDiv = document.createElement('div');
        contentDiv.className = 'assistant-message-content';
        contentDiv.innerHTML = marked.parse(content);
        messageDiv.appendChild(contentDiv);
    }
    // ... 其他代码 ...
}
</script>

4. 用户体验优化

为了提供更好的用户体验,我们实现了以下功能:

  • 实时加载指示器
  • 响应式设计,适配移动设备
  • 快捷键支持(Ctrl+Enter 发送消息)
  • 自动滚动到最新消息
  • Markdown 渲染支持

部署和运行

要运行这个应用,首先需要设置 DeepSeek API 密钥。如上图所述,秘钥可以到https://platform.deepseek.com/api_keys申请:

bash 复制代码
export DEEPSEEK_API_KEY=your_actual_api_key_here

然后启动应用:

bash 复制代码
cargo run

应用将在 http://127.0.0.1:3000 上运行。

效果展示

可以看到,我们实现了一个类似大模型聊天的应用。DeepSeek返回的markdown格式内容也能够被正确渲染展示,效果还是不错的。

总结

通过这个项目,我们展示了如何使用Rust构建一个完整的 Web 应用。Axum 框架提供了简洁而强大的 API 来处理 HTTP 请求,Tokio 提供了高效的异步运行时,而 Reqwest 使得与外部 API 的交互变得简单。

这个应用不仅功能完整,还具有良好的错误处理机制和用户体验。它展示了Rust在构建现代 Web 应用方面的潜力,既保证了性能,又确保了安全性。如果你对Rust感兴趣,或者想构建自己的 AI 聊天应用,这个项目是一个很好的起点。你可以根据自己的需求进行扩展,比如添加用户认证、持久化聊天历史、支持更多 AI 模型等功能。

想了解更多关于Rust语言的知识及应用,可前往华为开放原子旋武开源社区(https://xuanwu.openatom.cn/),了解更多资讯~

相关推荐
Jaising6662 小时前
MySQL 与 Clickhouse 多数据源切换技术分析
数据库·后端·mybatis
白起那么早2 小时前
我又开发了一款idea插件-ContiNewGenerator
java·后端
Python私教2 小时前
fasttushare 需求分析
后端
iOS开发上架哦3 小时前
接口调试从入门到精通,Fiddler抓包工具、代理配置与HTTPS抓包实战技巧
后端
leonardee3 小时前
Golang笔记——Interface类型
java·后端
算法如诗3 小时前
**MATLAB R2025a** 环境下,基于 **双向时间卷积网络(BITCN)+ 双向长短期记忆网络(BiLSTM)** 的多特征分类预测完整实现
开发语言·网络·matlab
k09333 小时前
在组件外(.js文件)中使用pinia的方法2--在http.js中使用pinia
开发语言·javascript·http
武子康3 小时前
大数据-155 Apache Druid 存储与查询架构实战:Segment/Chunk/Roll-up/Bitmap 一文讲清
大数据·后端·nosql
张彦峰ZYF3 小时前
高并发优惠权益聚合接口的优雅实现(含超时控制 + 来源标识 + Fallback 降级)
java·后端·面试