使用Ai带你轻松开发一个自己的翻译软件

379 阅读7分钟

准备工作

在我们备战英语四级的时候,都想要有一个好用的翻译软件,可是那些翻译软件不是要会员就是一堆广告,今天我们来利用AI开发一个给自己用的翻译软件

首先在我们打开我们想创建项目的文件夹的终端,然后使用命令语句npm create vite@latest创建项目,然后使用编译器去打开这个项目,因为创建的这个项目需要一些依赖,所以我们使用命令语句npm i提前下载好,接下来使用命令语句npm run dev就可以一边开发一边运行项目了

26.png 由于一个项目可能会有许多代码块,而一般我们只会用App.vue展示出来,所以我们再创建一个文件translate.vue,然后将这个组件引入app.vue里面,然后使用标签的形式来使用。 今天的内容挺简单的就是做一个简洁的前端页面,后端放一个AI智能体就好了

前端页面

27.png

这个前端页面就很简单了,大体上就分为两个部分,一个是在页面的上方的横栏,一个用来翻译的主体,我们先来看看前端代码

<template>
    <div class="head">
      <div class="logo">AI翻译器</div>
      <div class="help">帮助中心</div>
    </div>
    <section class="main">
      <div class="box">
        <div class="title">
          <div class="lang">
            <span class="text">{{state.from}}</span>
            <i class="iconfont icon-xiajiantou"></i>
          </div>
  
          <i class="iconfont icon-shuangxiangzhuanhuanjiantou" @click="change"></i>
  
          <div class="lang">
            <span class="text">{{state.to}}</span>
            <i class="iconfont icon-xiajiantou"></i>
          </div>
        </div>
        <div class="content">
          <div class="input item">
            <textarea @keydown.enter="handle" v-model="state.inputText" placeholder="请输入要翻译的文本"></textarea>
          </div>
          <div class="output item">
            <textarea disabled placeholder="翻译结果将在这里显示">{{state.outputText}}</textarea>
          </div>
        </div>
      </div>
    </section>
  </template>
  
  <script setup>
  import { reactive } from "vue";
  const state = reactive({
    from: 'English',
    to: '中文',
    inputText: '',
    outputText: ''
  })
  
  </script>
  
  <style lang="css" scoped>
  .head{
    padding: 20px 80px;               /* 上下内边距20px左右80px */
    display: flex;                    /*  设置为弹性容器 */
    justify-content: space-between;      /* 容器内部的样式左右最大距离分开 */
    align-items: center;               /* 容器内部y轴居中 */
    background: #FFFFFF;              /*  背景颜色为白色 */
    border-bottom: 1px solid #e5e5e5;     /*  底部边框 */
  }
  .logo{        
    font-size: 24px;                      /*  字体大小24px */
  }
  .help{
    font-size: 16px;                      /*  字体大小16px */ 
    color: #999999;                      /*  颜色为灰色 */
  }
  .main{
    overflow: hidden;                   /*  溢出隐藏 */
  }
  .box {
    width: 896px;                          /*  宽度896px */
    height: 296px;                         /*  高度296px */
    background: #FFFFFF;
    box-shadow: 0px 10px 15px -3px rgba(0,0,0,0.1), 0px 4px 6px -4px rgba(0,0,0,0.1);       /*  阴影 */
    border-radius: 8px 8px 8px 8px;                         /*  圆角 */
    margin: 0 auto;                                          /*  水平居中 */
    margin-top: 32px;                                    /*  容器外边距顶部32px  */
    padding: 24px;                                          /*  内边距24px */
    box-sizing: border-box;                                     /*  ie盒子模型 */
  }
  .title{
    display: flex;                                              /*  弹性布局 */
    align-items: center;                                              /*  垂直居中 */

  }
  .lang{
    width: 86px;                                              /*  宽度86px */
    height: 40px;                                              /*  高度40px */
    background: #F3F4F6;                                    /*  背景颜色 */
    border-radius: 8px 8px 8px 8px;                           /*  圆角 */
    display: flex;                                              /*  弹性布局 */
    justify-content: center;                                  /*  水平居中 */ 
    align-items: center;                                       /*  垂直居中 */
    cursor: pointer;                                              /*  鼠标指针 */
  }
  .icon-shuangxiangzhuanhuanjiantou{
    margin: 0 16px;                                             /*  外边距左右16px */
    font-weight: 700;                                             /*  加粗 */
    cursor: pointer;                                              /*  鼠标指针 */
  }
  .content{
    margin-top: 16px;                                           /*  外边距顶部16px */
    display: flex;                                              /*  弹性布局 */
  }
  .content .item{
    flex: 1;              /*  宽度占1份 */
    height: 192px;          /*  高度192px */
  }
  .content .item:first-child{
    margin-right: 16px;              /*  外边距右16px */
  }
  .content .item textarea {
    width: 100%;                                                /*  宽度占满 */
    height: 100%;                                              /*  高度占满 */
    border-radius: 8px;    /* 圆角 */
    padding: 10px 6px;     /*  上下10px左右6px */
    box-sizing: border-box;   /*  ie盒子模型  */
    font-size: 18px;     /* 字体大小 */
  }
  </style>

先设置了一个head容器,再设置了一个main容器.head容器里面有login和help容器存放头部的两段文字内容。main需要用到一个大容器存放两个容器,一个容器用来放置两个文本容器和一个icon图标,两个文字容器也要分别放一个icon图标。我来教你们怎么引入icon图标,首先打开iconfont官网。

28.png

选择你想要的图标,然后加入购物车,是免费的,不用慌,然后在购物车里将它们添加至项目,我们使用font类方法添加,先点击生成代码,然后将css引入index.html文件当中

29.png

然后回到我们的.vue文件里面使用标签以这种格式 <i class="iconfont "></i>将它添加进去,iconfont后面的内容为你的标签的名字,购物车里会有,类似这样 <i class="iconfont icon-xiajiantou"></i>,然后就可以看到图标了。

然后由于我们要拿到翻译器输入的内容,可以使用v-model=""去赋值给js中的变量,从而拿到输入框里的内容,然后在标签里面使用,由于翻译器还要让它在点击回车键的时候会一个点击事件,所以我们要使用@keydown方法,但是这个只是键盘点击事件,点其它键也可以,所以我们要设置为点击回车键,使用@keydown.enter,这样就设置好了。拿到用户输入的内容后就可以传给js变量了,接下来我们来实现js部分的逻辑

  <script setup>
  import { reactive } from "vue";
  import axios from 'axios';
  
  const state = reactive({
    from: 'English',
    to: '中文',
    inputText: '',
    outputText: ''
  })
  
  const change = () => {
    [state.from, state.to] = [state.to, state.from]
  }
  
  const handle = () => {
    // console.log(state.inputText);
    // 将用户输入的内容传给后端
    axios.get(`http://localhost:3000?inputText=${state.inputText}`)
     .then(response => {
        state.outputText = response.data
      })
  }
  </script>
  

我们要给网页写一个接口,这里有一个封装好的库,我们来使用

首先在终端安装一下,npm i axios,然后import axios from 'axios'引入一下axios.get(),里面写你要发的网页地址,我这里是axios.get(http://localhost:3000`)`,然后我们要将用户输入的内容给后端,可以使用`axios.get(`http://localhost:3000?inputText=${state.inputText}`)`

这段代码的意思就是给这个网页发一个请求,并且携带了一个名为inputText的参数,如果后端给了我们响应的话就执行.then后面的内容,response.data就是从后端拿回来的内容,我们使用翻译框的变量去接收,这样翻译框就拿到后端返回的数据了

后端数据处理

我们创建一个一个server的文件夹,然后npm init -y进行初始化,这样就可以装第三方的依赖包,然后创建一个index.mjs包,Node.js支持CommonJS和ESM两种模块化规范,这个mjs是表示我们要使用ESM语法。我们使用npm i openai,安装一个名为openai的包,让我们可以使用里面的方法,再装一个名为dotenv的包。

然后我们要使用ai,先要去拿到一个key,,可以去github上找代理

31.png 点击左上角找到Marketplace

32.png 使用gpt模型,然后去右上角获得key

33.png

然后去生成key

34.png

选择下面这个 35.png

取个名字,然后一路划到底创建就好了 36.png 后面就会有一个生成的key,你可以复制保存下来。

然后回退到Get API key,找到这个url,有了这两个我们就可以去使用这个模型了

38.png

接下来回到我们创建的server文件夹下面,创建一个.env文件,这个文件的意思就是环境变量文件,然后把我们的url和key放进去

40.png

最后在index.mjs中实现后端功能就行了

import OpenAI from "openai";
import dotenv from "dotenv";
import http from "http";


dotenv.config();  // 让 node 运行时去读取.env 中的内容
const client = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
  baseURL: process.env.OPENAI_BASE_URL
})



// 链接 LLM
const getCompletion = async (prompt) => {
  // 用户说的话
  const messages = [{
    role: 'user',
    content: prompt,
  }]
  // chat 
  const response = await client.chat.completions.create({
    model: 'gpt-4o',
    messages: messages,
    temperature: 0.1
  })
  return response.choices[0].message.content
}

// 跟 ai 交互
const main = async (message) => {
  const user_message = message
  const prompt = `请帮我翻译以下的文字到英文,只需要给出英文单词,"${user_message[0]}"`
  const result = await getCompletion(prompt)
  return result
}


const server = http.createServer( async(req, res) => {
  // 允许跨域
 
  res.writeHead(200, {
    "access-control-allow-origin": '*'
  });
  //res.end('hello world')

  // 获取到前端的参数
  const query = new URL(req.url, `http://${req.headers.host}`).searchParams;
  const inputText = query.get('inputText')

  const message = [
    inputText
  ]
  const result = await main(message)

  res.end(result)
})

server.listen(3000, () => {
  console.log("Server is running on port 3000");
})

先要有一个后端给我们使用,所以我们创建了一个localhost:3000的网址,然后我们要拿到前端的数据,接着连接大模型,要引入openai的库,由于后端会自带保护措施,所以我们要设置允许跨域,接下来就是和ai进行交流了,最后得到ai返回的数据,我们进行返回,然后在后端对main()函数进行调用得到结果,最后返回给前端变量,然后然后在页面上展示就可以了

最后效果

5.gif

学会了就拿去备战英语考试吧

21.png