前军教程网

中小站长与DIV+CSS网页布局开发技术人员的首选CSS学习平台

vue3+deepseek 实现简单的问答

概述

本文档描述了基于 DeepSeek API 实现的智能助手 Web 应用的技术实现细节。该应用提供文本聊天和语音输入功能,支持与 DeepSeek 大模型进行交互。

功能特性

  1. 文本聊天:用户可通过文本输入与 AI 进行交互
  2. 语音输入:支持按住说话进行语音输入
  3. 响应式设计:适配移动端和 Web 端
  4. 消息展示:区分用户消息和 AI 回复
  5. 加载状态:显示加载动画提升用户体验

技术栈

  • Vue 3 (Composition API)
  • Axios (HTTP 请求)
  • Web Speech API (语音识别)
  • Vant UI (部分组件)
  • DeepSeek API (AI 交互)

API 配置

javascript

复制

const apiKey = '自己的key';
const baseURL = 'https://api.deepseek.com';

核心组件

模板结构

html

复制

<template>
  <div class="chat-container">
    <!-- 标题 -->
    <div class="title">智能助手</div>
    
    <!-- 消息列表 -->
    <div class="inner">
      <!-- 消息项 -->
      <div v-for="(msg, index) in messages" :key="index" :class="['msgbox', msg.role == 'user' ? 'msgboxright' : 'msgboxleft']">
        <!-- 头像 -->
        <div class="headImg" v-if="msg.role != 'user'">
          <img src="机器人头像URL" />
        </div>
        
        <!-- 消息内容 -->
        <div :class="['message', msg.role]">
          {{ msg.content }}
        </div>
        
        <!-- 用户头像 -->
        <div class="headImg" v-if="msg.role == 'user'">
          <img src="用户头像URL" />
        </div>
      </div>
      
      <!-- 加载动画 -->
      <div v-if="isLoading" class="snippet" data-title=".dot-elastic">
        <div class="stage">
          <div class="dot-elastic"></div>
        </div>
      </div>
    </div>
    
    <!-- 底部输入区域 -->
    <div class="footer">
      <div class="talk">
        <!-- 语音/文本输入切换 -->
        <div v-if="flag" class="aa" @touchstart="startListening" @touchend="stopListening">
          {{ talkFlag ? '讲话中...' : '按住说话' }}
        </div>
        
        <!-- 文本输入框 -->
        <input placeholder="请输入您的问题" v-else v-model="userInput" @keyup.enter="sendToDeepSeek" />
        
        <!-- 发送按钮/切换按钮 -->
        <div v-if="userInput" @click.stop="sendToDeepSeek">
          <img v-if="!flag" src="发送图标URL" class="send" />
        </div>
        <div v-else @click.prevent.stop="changeFlag">
          <img :src="flag ? '键盘图标URL' : '语音图标URL'" class="jianpan" />
        </div>
      </div>
    </div>
  </div>
</template>

运行 HTML

脚本逻辑

javascript

复制

import { ref, onMounted } from 'vue';
import axios from 'axios';

// 响应式数据
const messages = ref([{ role: 'system', content: '您好,请问有什么可以帮助您的吗?' }]);
const flag = ref(true); // 语音/文本输入标志
const userInput = ref(''); // 用户输入
const isLoading = ref(false); // 加载状态
const recognition = ref(null); // 语音识别对象
const transcript = ref(''); // 语音识别文本
const talkFlag = ref(false); // 语音识别状态

// 初始化语音识别
const initSpeechRecognition = () => {
  if (window.webkitSpeechRecognition) {
    recognition.value = new window.webkitSpeechRecognition();
    recognition.value.continuous = true;
    recognition.value.interimResults = true;
    recognition.value.lang = 'zh-CN';
  } else {
    alert('你的浏览器不支持语音识别功能');
  }
};

// 开始语音识别
const startListening = (e) => {
  e.preventDefault();
  talkFlag.value = true;
  if (recognition.value) {
    recognition.value.start();
    recognition.value.onresult = (event) => {
      transcript.value = Array.from(event.results)
        .map(result => result[0])
        .map(result => result.transcript)
        .join('');
    };
  }
};

// 停止语音识别
const stopListening = (e) => {
  e.preventDefault();
  talkFlag.value = false;
  if (recognition.value) {
    if (transcript.value) {
      messages.value.push({ role: 'user', content: transcript.value });
      setTimeout(() => {
        scrollNext();
        handelMes();
      });
    }
    recognition.value.stop();
  }
};

// 发送消息到DeepSeek
const sendToDeepSeek = () => {
  messages.value.push({ role: 'user', content: userInput.value });
  userInput.value = '';
  setTimeout(() => {
    scrollNext();
    handelMes();
  });
};

// 处理AI回复
const handelMes = async () => {
  try {
    isLoading.value = true;
    const response = await axios.post(
      `${baseURL}/chat/completions`,
      {
        model: 'deepseek-chat',
        messages: [...messages.value],
        temperature: 0.7,
        stream: false
      },
      {
        headers: {
          Authorization: `Bearer ${apiKey}`,
          'Content-Type': 'application/json'
        }
      }
    );
    messages.value.push(response.data.choices[0].message);
    setTimeout(() => {
      scrollNext();
    });
  } catch (error) {
    console.error('API调用失败:', error.response?.data || error.message);
  } finally {
    isLoading.value = false;
  }
};

// 滚动到最新消息
const scrollNext = () => {
  let list = document.getElementsByClassName('msgbox');
  let tmp = list[list.length - 1];
  let bottom = tmp.getBoundingClientRect().top;
  window.scrollTo({
    top: bottom,
    left: 0,
    behavior: 'smooth'
  });
};

// 切换输入模式
const changeFlag = () => {
  userInput.value = '';
  transcript.value = '';
  talkFlag.value = false;
  flag.value = !flag.value;
};

onMounted(() => {
  initSpeechRecognition();
});

样式设计

css

复制

.chat-container {
  min-height: 100vh;
  overflow-y: auto;
  
  .title {
    color: #fff;
    font-size: 20px;
    line-height: 60px;
    padding: 0px 20px;
    font-weight: bold;
    background: rgb(0, 162, 255);
  }
  
  .inner {
    padding: 20px;
  }
  
  .msgbox {
    display: flex;
    font-size: 14px;
    margin-bottom: 30px;
    
    .headImg {
      width: 40px;
      height: 40px;
      border-radius: 50%;
      overflow: hidden;
      margin-right: 15px;
      
      img {
        width: 100%;
        height: 100%;
        object-fit: fill;
      }
    }
    
    .message {
      max-width: 80%;
      background: #fff;
      padding: 12px 16px;
      border-radius: 12px;
      box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
    }
  }
  
  .msgboxright {
    justify-content: end;
    
    .headImg {
      margin-left: 15px;
    }
  }
  
  .footer {
    display: flex;
    bottom: 0px;
    width: 100%;
    height: 80px;
    padding: 0px 20px;
    position: fixed;
    background: #fff;
    align-items: center;
    justify-content: center;
    
    .talk {
      width: 100%;
      border-radius: 30px;
      border: 1px solid #e9e7e7;
      height: 50px;
      display: flex;
      align-items: center;
      padding: 0px 15px;
      justify-content: space-between;
      
      .aa {
        font-size: 14px;
        font-weight: bold;
        line-height: 50px;
        text-align: center;
        width: 100%;
      }
      
      input {
        width: 70%;
        border: 0;
        padding: 0px 5px;
        font-size: 14px;
      }
      
      .send, .jianpan {
        width: 30px;
        height: 30px;
      }
    }
  }
}

/* 加载动画样式 */
.dot-elastic {
  position: relative;
  width: 5px;
  height: 5px;
  margin: auto;
  border-radius: 50%;
  background-color: rgb(0, 162, 255);
  color: rgb(0, 162, 255);
  animation: dotElastic 1s infinite linear;
}

/* 动画关键帧定义 */
@keyframes dotElasticBefore {
  0% { transform: scale(1, 1); }
  25% { transform: scale(1, 1.5); }
  50% { transform: scale(1, 0.67); }
  75% { transform: scale(1, 1); }
  100% { transform: scale(1, 1); }
}

@keyframes dotElastic {
  0% { transform: scale(1, 1); }
  25% { transform: scale(1, 1); }
  50% { transform: scale(1, 1.5); }
  75% { transform: scale(1, 1); }
  100% { transform: scale(1, 1); }
}

@keyframes dotElasticAfter {
  0% { transform: scale(1, 1); }
  25% { transform: scale(1, 1); }
  50% { transform: scale(1, 0.67); }
  75% { transform: scale(1, 1.5); }
  100% { transform: scale(1, 1); }
}

部署说明

  1. 在 DeepSeek 平台注册账号并获取 API Key
  2. 替换代码中的 apiKey 为您的实际 Key
  3. 构建并部署 Vue 应用

注意事项

  1. API Key 应妥善保管,避免泄露
  2. 语音识别功能需要浏览器支持 Web Speech API
  3. 生产环境应考虑添加 API 调用频率限制和错误处理
  4. 对于敏感信息,建议在后端处理 API 调用而非前端

示例效果

可通过以下链接查看实际效果:

https://h5-dev.ennejb.cn/h5_application/#/test

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言