手把手教大家开发一个基于DeepSeek的对话AI

AI 时代程序员必备技能

Codex、Claude Code、Cursor、Hermes Agent、OpenClaw等工程化实战专栏 ,讲透 AI 如何接管脏活累活

前言

最近的DeepSeek可谓是非常火,到处都在讨论DeepSeek,而且各种应用都开始接入DeepSeek,那我今天我也来凑凑热闹,查看DeepSeek官网可以看到有开放平台,调用方式也比较简单,那么话不多说,我们就基于DeepSeek开发一款属于自己的对话式AI应用。

对于技术栈的选择,由于是一个对话式AI应用,而且功能也是比较简单的,所以暂时不考虑接入后端,就一个前端页面能对话就可以满足需求了。所以采用Vite+Vue3来做这么一个小应用。

环境准备

首先安装node。这个就不多说了,官网下载node然后安装即可。安装后输入 node -v来查看是否安装成功。

//查看node版本。
node -v

在这里插入图片描述
出现版本号就表示安装成功了,接着通过脚手架初始化一个vue3的项目。
先设置一下镜像源

npm config set registry https://registry.npmmirror.com

然后安装 yarn这个包管理工具。也可以用npm或者pnpm,方式不唯一,能创建好一个vue3的项目即可。

npm install -g yarn

创建项目

接着开始创建一个vue3的项目,demo1是项目名称,后面按照自己的项目命名。

yarn create @vitejs/app demo1

在这里插入图片描述
上下键可以用来选择项目,我这里选择Vue,然后按下回车。
在这里插入图片描述
接着选择语言,我这里选择JavaScript,按下回车。
在这里插入图片描述
这样就说明项目新建好了, 按照提示,进入到项目目录下,然后安装依赖包,接着运行。

cd demo1
yarn
yarn dev

在这里插入图片描述
能出现这个页面就说明项目新建好了。
接下来安装一下axiosvue-routeraxios用来发送请求,vue-router用来控制页面跳转。

yarn add axios
yarn add vue-router

接下来对一些重点文件做一下说明,对前端开发人员来说都是常规操作。
在src目录下新建router文件夹,然后新建index.js文件,代码如下。

// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';
import DeepSeekIndex from '../views/DeepSeek.vue'; // 确保路径正确

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/deepseek',
    name: 'DeepSeekIndex',
    component: DeepSeekIndex // 确保组件正确
  }
];

const router = createRouter({
  history: createWebHistory(import.meta.env.VUE_APP_BASE_URL), // 修改这里
  routes
});

export default router;

在src下新建views文件夹,views文件夹下新建Home.vueDeepSeek.vue两个文件,Home.vue内容如下。

<template>
  <div class="home-container">
    <h1>欢迎来到 LMDeepSeek</h1>
    <p>这是一个与DeepSeek对话的应用程序。点击“开始对话”按钮,开始您的对话之旅。</p>
    <button @click="startConversation">开始对话</button> <!-- 添加开始对话按钮 -->
  </div>
</template>

<script>
export default {
  name: 'Home',
  methods: {
    startConversation() {
      this.$router.push('/deepseek'); // 跳转到/deepseek页面
    }
  }
}
</script>

<style scoped>
.home-container {
  max-width: 600px;
  margin: 0 auto;
  padding: 20px;
  text-align: center;
}

h1 {
  font-size: 2em;
  margin-bottom: 20px;
}

p {
  font-size: 1em;
  color: #555;
}

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

button:hover {
  background-color: #0056b3;
}
</style>

DeepSeek.vue内容如下。

<template>
  <div class="deepseek-container">
    <h1>DeepSeek 对话页面</h1>
    <div class="chat-box">
      <!-- 这里可以添加对话框组件 -->
      <p>欢迎使用 LMDeepSeek!请开始您的对话。</p>
    </div>
    <div class="input-area">
      <input v-model="userInput" @keyup.enter="sendMessage" placeholder="输入您的消息..." />
      <button @click="sendMessage">发送</button>
    </div>
  </div>
</template>

<script>
export default {
  name: 'DeepSeekIndex',
  data() {
    return {
      userInput: ''
    };
  },
  methods: {
    sendMessage() {
      // 这里可以添加发送消息到DeepSeek的逻辑
      console.log('用户输入:', this.userInput);
      this.userInput = ''; // 清空输入框
    }
  }
}
</script>

<style scoped>
.deepseek-container {
  max-width: 100%;
  margin: 0 auto;
  padding: 20px;
  border: 1px solid #ccc;
  border-radius: 8px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
  height: 80vh; /* 铺满整个窗口 */
  display: flex;
  flex-direction: column;
}

.chat-box {
  flex: 1; /* 铺满剩余空间 */
  overflow-y: scroll;
  border-bottom: 1px solid #ccc;
  padding: 10px;
  margin-bottom: 10px;
}

.input-area {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
}

.input-area input {
  flex: 1;
  padding: 10px;
  margin-right: 10px;
  border: 1px solid #ccc;
  border-radius: 4px;
}

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

.input-area button:hover {
  background-color: #0056b3;
}
</style>

好了,我们的工作已经完成了一大半了,接着运行起来看一下。
在这里插入图片描述
首先看到的是首页内容,接着我们点击开始对话。
在这里插入图片描述
会打开一个对话页面,不过目前还没有接入Deepseek。

接入DeepSeek

首先进入到DeepSeek的官网,注册一下,然后创建一个API Key,请注意,这个key只有在第一次创建的时候可以看到,之后就看不到了,注意保存。
在这里插入图片描述然后需要实名认证和充值,没有充值的话,调用接口会提示402 (Payment Required)错误,这就是接口没有充钱,如何只是测试用,稍微充个几块钱就行。

然后参考官网的接口文档。
在这里插入图片描述
安装openai

yarn add openai

接下来就是DeepSeek.vue的代码。

 <template>
  <div class="deepseek-container">
    <h1>DeepSeek 对话页面</h1>
    <div class="chat-box">
      <!-- 这里可以添加对话框组件 -->
      <div v-if="messages.length === 0" class="welcome-message">
        欢迎使用 LMDeepSeek!请开始您的对话。
      </div>
      <div
        v-for="(message, index) in messages"
        :key="index"
        :class="['message', message.role]"
      >
        <img
          :src="getAvatar(message.role)"
          :alt="`${message.role} avatar`"
          class="avatar"
        />
        <div v-if="message.role === 'system' && message.content ==''" class="loading"></div>
        <div v-else class="content">{{ message.content }}</div>
      </div>
    </div>
    <div class="input-area">
      <input
        v-model="userInput"
        @keyup.enter="sendMessage"
        placeholder="输入您的消息..."
      />
      <button @click="sendMessage">发送</button>
    </div>
  </div>
</template>

<script>
import OpenAI from "openai";
export default {
  name: "DeepSeekIndex",
  data() {
    return {
      userInput: "",
      messages: [
        // {
        //   role: "system",
        //   content: "",
        // },
        // {
        //   role: "user",
        //   content: "Hello! How can I assist you today?",
        // },
      ],
    };
  },
  methods: {
    async sendMessage() {
      this.messages.push(
        {
          role: "user",
          content: this.userInput,
        },
        {
          role: "system",
          content: "",
        }
      );
      const userInput = this.userInput;
      this.userInput = "";
      const openai = new OpenAI({
        baseURL: "https://api.deepseek.com",
        apiKey: "your key",
        dangerouslyAllowBrowser: true,
      });
      const completion = await openai.chat.completions.create({
        messages: [{ role: "user", content: userInput }],
        model: "deepseek-chat",
        stream: true,
      });
      let last = this.messages.length - 1;
      let content = "";
      for await (const chunk of completion) {
        content += chunk.choices[0].delta?.content || "";
        this.messages[last].content = content;
      }
    },
    getAvatar(role) {
      return role === "user"
        ? "/src/assets/user-avatar.png"
        : "/src/assets/deepseek-avatar.png";
    },
  },
};
</script>

<style scoped>
.deepseek-container {
  max-width: 100%;
  margin: 0 auto;
  padding: 20px;
  border: 1px solid #ccc;
  border-radius: 8px;
  box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
  height: 80vh; /* 铺满整个窗口 */
  display: flex;
  flex-direction: column;
}

.chat-box {
  flex: 1; /* 铺满剩余空间 */
  overflow-y: scroll;
  border-bottom: 1px solid #ccc;
  padding: 10px;
  margin-bottom: 10px;
  display: flex;
  flex-direction: column;
}
.message {
  display: flex;
  align-items: flex-start;
  margin-bottom: 10px;
}

.message.user {
  justify-content: flex-end;
  flex-direction: row-reverse; /* 用户消息反向排列 */
}

.message.system {
  justify-content: flex-start;
}

.avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  margin-right: 10px;
}

.message.user .avatar {
  margin-left: 10px;
  margin-right: 0;
}

.content {
  max-width: 70%;
  padding: 10px;
  border-radius: 8px;
  background-color: #007bff;
  color:#ffffff
}

.message.user .content {
  background-color: #007bff;
  color: white;
  margin-right: 10px; /* 用户消息内容与边界的距离 */
}
.message.system .content {
  margin-left: 10px; /* AI助手消息内容与边界的距离 */
  text-align: left;
}
/* 确保用户消息整体靠右对齐 */
.message.user {
  align-self: flex-end;
}
/* 确保系统消息整体靠左对齐 */
.message.system {
  align-self: flex-start;
}
.input-area {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
}

.input-area input {
  flex: 1;
  padding: 10px;
  margin-right: 10px;
  border: 1px solid #ccc;
  border-radius: 4px;
}

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

.input-area button:hover {
  background-color: #0056b3;
}
.welcome-message {
  text-align: center;
  color: #aaa;
}
.loading {
    display: inline-block;
    font-size: 20px; /* 根据需要调整大小 */
    position: relative;
}

.loading::after {
    content: '...';
    position: absolute;
    right: -1em;
    top: 0;
    animation: loadingDots 1.5s steps(5, end) infinite;
}

@keyframes loadingDots {
    0%, 20% {
        content: '...';
    }
    40% {
        content: '..';
    }
    60% {
        content: '.';
    }
    80%, 100% {
        content: '';
    }
}
</style>

官网默认的示例没有启用流式输出,所以等待时间会比较久,采用流式输出,可以减少等待时间,并且消息是一点点加载出来的,接下来看看效果。

在这里插入图片描述
想要获取全部源码的,请关注下方的微信公众号,然后回复ds,就可以获取全部源码啦。

Study hard and make progress every day.

AI 时代程序员必备技能

Codex、Claude Code、Cursor、Hermes Agent、OpenClaw等工程化实战专栏 ,讲透 AI 如何接管脏活累活

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李公子lm

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值