flutter3.32+deepseek+dio+markdown搭建windows版流式输出AI模板

随着deepseek的火爆出圈,2025年开发了多个deepseek流式对话应用。最近又基于Flutter3.32+Dio+DeepSeek搭建了一款桌面客户端Ai程序。

flutter3-win-deepseek实现了流式打字对话、代码高亮、本地存储会话等功能。

使用技术

  • 编码工具:Vscode
  • 技术框架:flutter3.32.0+dart3.8.0
  • AI大模型:deepseek-v3
  • 流请求:dio^5.8.0+1
  • 窗口管理:window_manager^0.5.0
  • 托盘管理:system_tray^2.0.3
  • 路由/状态管理:get^4.7.2
  • 存储服务:get_storage^2.1.1
  • markdown解析:flutter_markdown^0.7.7
  • 高亮组件:flutter_highlight^0.7.0
  • 环境变量配置:flutter_dotenv^5.2.1

项目结构目录

整个项目使用最新Flutter3.32搭建框架,整合deepseek api实现流式输出功能。

flutter3配置.env

去deepseek网站申请一个apikey,替换掉.env文件里的Key即可体验ai聊天对话功能。

ts 复制代码
# 项目名称
APP_NAME = 'Flutter3-WinSeek'

# DeepSeek API配置
DEEPSEEK_API_KEY = apikey
DEEPSEEK_BASE_URL = https://api.deepseek.com

获取环境变量

ts 复制代码
// 获取.env环境变量baseUrl和apiKey
String baseURL = dotenv.get('DEEPSEEK_BASE_URL');
String apiKEY = dotenv.get('DEEPSEEK_API_KEY');

flutter3通用布局模板

整个项目分为可收缩侧边栏+顶部自定义导航条+聊天对话区三个模块。

ts 复制代码
return Scaffold(
  backgroundColor: Colors.grey[50],
  body: DragToResizeArea(
    child: Row(
      children: [
        // 侧边栏
        AnimatedSize(
          duration: const Duration(milliseconds: 300),
          curve: Curves.easeInOut,
          child: Container(
            width: collapsed ? 0 : 260,
            decoration: BoxDecoration(
              border: Border(right: BorderSide(color: Colors.grey.withAlpha(50)))
            ),
            child: Material(
              color: Color(0xFFF3F3F3),
              child: Sidebar(),
            ),
          ),
        ),
        // 主体容器
        Expanded(
          child: Column(
            children: [
              // 自定义导航栏
              SizedBox(
                height: 30.0,
                child: Row(
                  children: [
                    IconButton(
                      onPressed: () {
                        setState(() {
                          collapsed = !collapsed;
                        });
                      },
                      icon: Icon(collapsed ? Icons.format_indent_increase : Icons.format_indent_decrease, size: 16.0,),
                      tooltip: collapsed ? '展开' : '收缩',
                    ),
                    Expanded(
                      child: DragToMoveArea(
                        child: SizedBox(
                          height: double.infinity,
                        ),
                      ),
                    ),
                    // 右上角操作按钮
                    WinBtns(
                      leading: Row(
                        children: [
                          ...
                        ],
                      ),
                    ),
                  ],
                ),
              ),
              // 右侧主面板
              Expanded(
                child: Container(
                  child: widget.child,
                ),
              ),
            ],
          ),
        ),
      ],
    ),
  ),
);

flutter3对话编辑框

ts 复制代码
return Container(
  width: double.infinity,
  padding: EdgeInsets.symmetric(vertical: 10.0),
  child: Column(
    spacing: 6.0,
    children: [
      // 技能栏
      if (widget.skillbar)
      ScrollConfiguration(
        behavior: CustomScrollBehavior(),
        child: SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          padding: EdgeInsets.symmetric(horizontal: 15.0),
          child: Row(
            spacing: 4.0,
            children: [
              ...
            ]
          ),
        ),
      ),
      // 编辑框
      Container(
        margin: EdgeInsets.symmetric(horizontal: 15.0),
        padding: EdgeInsets.all(10.0),
        decoration: BoxDecoration(
          color: Colors.white,
          border: Border.all(color: Colors.grey.withAlpha(100), width: .5),
          borderRadius: BorderRadius.circular(15.0),
          boxShadow: [
            BoxShadow(
              color: Colors.black.withAlpha(20),
              offset: Offset(0.0, 3.0),
              blurRadius: 6.0,
              spreadRadius: 0.0,
            ),
          ]
        ),
        child: Column(
          spacing: 10.0,
          children: [
            // 输入框
            ConstrainedBox(
              constraints: BoxConstraints(minHeight: 48.0, maxHeight: 150.0),
              child: TextField(
                ...
              ),
            ),
            // 操作栏
            Row(
              spacing: 10.0,
              children: [
                SizedBox(
                  height: 30.0,
                  child: TextButton(
                    onPressed: () {
                      setState(() {
                        isDeep =! isDeep;
                      });
                    },
                    style: ButtonStyle(
                      backgroundColor: WidgetStateProperty.all(isDeep ? Color(0xFF4F6BFE).withAlpha(30) : Colors.grey[200]),
                      padding: WidgetStateProperty.all(EdgeInsets.symmetric(horizontal: 10.0)),
                    ),
                    child: Row(
                      spacing: 4.0,
                      children: [
                        Icon(Icons.stream, color: isDeep ? Color(0xFF4F6BFE) : Colors.black, size: 18.0,),
                        Text('深度思考(R1)', style: TextStyle(color: isDeep ? Color(0xFF4F6BFE) : Colors.black, fontSize: 13.0),),
                      ],
                    ),
                  ),
                ),
                SizedBox(
                  height: 30.0,
                  child: TextButton(
                    onPressed: () {
                      setState(() {
                        isNetwork =! isNetwork;
                      });
                    },
                    style: ButtonStyle(
                      backgroundColor: WidgetStateProperty.all(isNetwork ? Color(0xFF4F6BFE).withAlpha(30) : Colors.grey[200]),
                      padding: WidgetStateProperty.all(EdgeInsets.symmetric(horizontal: 10.0)),
                    ),
                    child: Row(
                      spacing: 4.0,
                      children: [
                        Icon(Icons.travel_explore, color: isNetwork ? Color(0xFF4F6BFE) : Colors.black, size: 18.0,),
                        Text('联网', style: TextStyle(color: isNetwork ? Color(0xFF4F6BFE) : Colors.black, fontSize: 13.0),),
                      ],
                    ),
                  ),
                ),
                Spacer(),
                SizedBox(
                  height: 30.0,
                  width: 30.0,
                  child: PopupMenuButton(
                    icon: Icon(Icons.add),
                    padding: EdgeInsets.zero,
                    tooltip: '',
                    offset: Offset(-35.0, 0),
                    constraints: BoxConstraints(maxWidth: 160),
                    color: Colors.white,
                    itemBuilder: (BuildContext context) {
                      return [
                        PopupMenuItem(value: 'camera', height: 40.0, child: Row(spacing: 5.0, children: [Icon(Icons.camera_alt_outlined), Text('拍照识文字')],)),
                        PopupMenuItem(value: 'image', height: 40.0, child: Row(spacing: 5.0, children: [Icon(Icons.image_outlined), Text('图片识文字')],)),
                        PopupMenuItem(value: 'file', height: 40.0, child: Row(spacing: 5.0, children: [Icon(Icons.file_present_outlined), Text('文件')],)),
                      ];
                    },
                    onSelected: (value) {
                      debugPrint(value);
                    },
                  ),
                ),
                SizedBox(
                  height: 30.0,
                  width: 30.0,
                  child: IconButton(
                    onPressed: disabled ? null : () => handleSubmit(),
                    icon: loading ?
                      SizedBox(height: 16.0, width: 16.0, child: CircularProgressIndicator(color: Colors.white, strokeWidth: 2.0,))
                      :
                      Icon(Icons.send, color: Colors.white, size: 18.0)
                    ,
                    style: ButtonStyle(
                      backgroundColor: WidgetStateProperty.all(disabled ? Color(0xFF4F6BFE).withAlpha(100) : Color(0xFF4F6BFE)),
                      padding: WidgetStateProperty.all(EdgeInsets.zero)
                    ),
                    disabledColor: Colors.red,
                  ),
                )
              ],
            ),
          ],
        ),
      ),
    ],
  )
);

flutter3接入deepseek流输出对话

在flutter3中通过dio调用deepseek api接口,实现流式输出对话。

ts 复制代码
final response = await dio.post(
  '$baseURL/v1/chat/completions',
  options: Options(
    // 响应超时
    receiveTimeout: const Duration(seconds: 60),
    headers: {
      "Content-Type": "application/json",
      "Authorization": "Bearer $apiKEY",
    },
    // 设置响应类型为流式响应
    responseType: ResponseType.stream,
  ),
  data: {
    // 多轮会话
    'messages': widget.multiConversation ? chatStore.historySession : [{'role': 'user', 'content': editorValue}],
    'model': 'deepseek-chat', // deepseek-chat对话模型 deepseek-reasoner推理模型
    'stream': true, // 流式输出
    'max_tokens': 8192, // 限制一次请求中模型生成 completion 的最大 token 数(默认使用 4096)
    'temperature': 0.4, // 严谨采样 越低越严谨(默认1)
  }
);

好了,以上就是flutter3 接入deepseek实战客户端ai流式对话的一些分享。感谢大家的阅读与支持~

flutter3+dio+deepseek跨平台ai流式对话模板

基于uniapp+vue3+deepseek+markdown搭建app版流式输出AI模板

vue3.5+deepseek+arco+markdown搭建web版流式输出AI模板

vue3仿Deepseek/ChatGPT流式聊天AI界面,对接deepseek/OpenAI API

Flutter3.x深度融合短视频+直播+聊天app实例

自研tauri2.0+vite6.x+vue3+rust+arco-design桌面版os管理系统Tauri2-ViteOS

自研tauri2.0+vite5+vue3+element-plus电脑版exe聊天系统Vue3-Tauri2Chat

uni-vue3-wechat:基于uni-app+vue3+pinia2多端仿微信App聊天

相关推荐
新智元4 分钟前
90 后王虹连夺两大「菲尔兹奖」风向标!韦神都来听她讲课,陶哲轩盛赞
人工智能·openai
Sailing1 小时前
5分钟搞定 DeepSeek API 配置:从配置到调用一步到位
前端·openai·ai编程
傅里叶4 小时前
Flutter项目使用 buf.build
flutter
恋猫de小郭5 小时前
iOS 26 开始强制 UIScene ,你的 Flutter 插件准备好迁移支持了吗?
android·前端·flutter
yuanlaile6 小时前
Flutter开发HarmonyOS鸿蒙App商业项目实战已出炉
flutter·华为·harmonyos
楚莫识6 小时前
Comet AI 浏览器免费开放了,还送 Perplexity Pro 会员!
openai·ai编程·cursor
机器之心6 小时前
刚刚,Thinking Machines Lab博客提出在策略蒸馏,Qwen被cue 38次
人工智能·openai
CodeCaptain7 小时前
可直接落地的「Flutter 桥接鸿蒙 WebSocket」端到端实施方案
websocket·flutter·harmonyos
stringwu7 小时前
Flutter 中的 MVVM 架构实现指南
前端·flutter