AI学习记录 -使用react开发一个网页,对接chatgpt接口,附带一些英语的学习prompt
创始人
2024-12-17 08:36:57
0

实现了如下功能(使用react实现,原创)

实现功能:
1、对接gpt35模型问答,并实现了流式传输(在java端)
2、在实际使用中,我们的问答历史会经常分享给他人,所以下图的 copy all 按钮,可以copy成一个json然后通过社交软件发送给别人,别人就可以轻松应用你的问答历史。
3、选择文件,在我们预想当中,我们可能会经常遇到向文档提问(当时还不知道embedding的知识哈哈哈),通过拆分文档,一段段跟gpt提问,当前段落是否和用户内容相关,相关就回答段落问题(段落拆分通过java实现)
在这里插入图片描述
4、我们需要经常保存我们的聊天记录,特别是在调试我们的prompt的时候,所以加了一个缓存功能,可以随时提取缓存记录来提问。
在这里插入图片描述
5、利用这个分享的时候,设计了很多便利我去学习英语的prompt,避免老是手打提示词

role.js
export default {     "专业的英语翻译家": (text = "示例") => {         return "现在你充当我专业的翻译家。当我输入中文,你就翻译成英文。当我输入英文,你就翻译成中文。请翻译:" + text     },     "文章截断翻译": (text = "示例") => {         return "因为我是中国的软件开发工程师,我要面试美国的软件开发岗位,所以我要学习英语,我要你充当我的翻译家," +             "所以我给一些中文的软件知识给你帮我翻译,但是你不能直译,因为中文说出来的知识,英语的表达有不一样,所" +             "以请你理解我的中文知识,按照自己的理解用英语表达出来,所以我给你一段文字,首先你要将文章拆分成一句一句,理解每" +             "一句的意思,然后用英语将你理解的意思输出。输出格式为一句中文,输出一个回车符,下一行输出你的英文理解。并且每一句末尾都" +             "给生僻词单独翻译。文章内容为:“" + text + "”"     },     "给出5个英语句子对应的词汇": (text = "示例") => {         return "我给你一个英文单词,请你用这个英文单词造出5个英文句子,句子要求是计算机互联网相关知识" +             "(包括但不限于前端专业细节知识,react专业细节知识,vue专业细节知识,js专业细节知识,管理系统的功能专业细节知识," +             "http网络相关专业细节知识),并附带中文翻译。最后还要给出他的衍生词汇," +             "给出他的发音以及词汇类型。单词为:" + text     },     "给你一个中文词汇,你给我说出英语一般用什么句式去表达": (text = "示例") => {         return "我给你一个中文词汇,你给我说出英语一般用什么句式去表达。" +             "例如:中文意思:确保一些东西是有效的,英语一般表达为:ensure that somethings is valid。" +             "这个(ensure that ... is valid)就是英语的常规表达句式。" +             "例如:允许轻松自定义表单验证,,英语一般表达为:ensure that somethings is valid。" +             "这个(allows for ... 。" +             "中文词汇为:" + text     },     "面试中怎么表达这个中文意思": (text = "示例") => {         return "在美国的it开发工程师英语面试当中,怎么表达:" + text + ", 请用三种或者三种以上不同的句式表达"     },     "在英语中有多少英文表达这个中文意思": (text = "示例") => {         return "在英语中有多少英文表达这个中文意思,请列举出来,中文为:" + text     },     "假设你是一个从小就在美国长大的人": (text = "示例") => {         return "假设你是一个从小就在美国长大的人,你已经30岁,在互联网公司工作8年,请你使用简洁的口语帮我将中文翻译成英文,重点是简洁,简洁,你自己听得懂就好。中文为:" + text     } } 
index.js
 import React, { useState, useCallback, useRef } from 'react'; import './index.css'; import { useEffect } from 'react'; import axios from 'axios'; import { PrismLight as SyntaxHighlighter } from "react-syntax-highlighter"; import { vscDarkPlus, coyWithoutShadows, darcula } from 'react-syntax-highlighter/dist/esm/styles/prism'; // 设置高亮的语言 import { jsx, javascript } from "react-syntax-highlighter/dist/esm/languages/prism"; import ReactMarkdown from 'react-markdown'; import ClipboardJS from 'clipboard'; import { Drawer, Input, message, Select } from 'antd'; import roles from "./roles";  const { Search } = Input; const { TextArea } = Input; const { Option } = Select;  function clearLocalStorage() {   localStorage.setItem("LOCALDATA", "[]"); }  // 封装localStorage的get方法 function getLocalStorage() {   let arrStr = localStorage.getItem("LOCALDATA");   if (arrStr) {     let arr = JSON.parse(arrStr);     return arr;   } else {     return [];   } }  const them = {   dark: vscDarkPlus,   light: coyWithoutShadows }; const ENDTEXT = "__END__";  let comments = []; let streaming = false  export default function App1() {   const [question, setQuestion] = useState("");   const [roleType, setRoleType] = useState("");   const [frontPrompts, setFrontPrompts] = useState("");    const list_container_id = useRef(null);   const currentTexts = useRef("");   const [count, setCount] = useState(0);   const [messageApi, contextHolder] = message.useMessage();   const [open, setOpen] = useState(false);   const [openMoreFunction, setOpenMoreFunction] = useState(false);    const [jsonData, setJsonData] = useState("{}");   const key = 'copy';   const postStreamList = async (callback) => {     let requestList = [];     comments.map((item) => {       if (item.type === "chatgpt-url") {         if (item.contents[0]) {           requestList.push({ "role": "user", "content": item.contents[0].hiddenQuestion });           requestList.push({ "role": "assistant", "content": item.contents[0].hiddenContent });         }       } else {         requestList.push({ "role": "user", "content": item.name });         if (item.contents[0] && item.contents[0].text) {           requestList.push({ "role": "assistant", "content": item.contents[0].text });         }       }     })      const requestOptions = {       method: 'POST',       headers: {         'Content-Type': 'application/json',         "Authorization": "Bearer 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"       },       body: JSON.stringify({         "model": "gpt-3.5-turbo",         "messages": requestList       })     };     let count = 0;     const streamResponse = await fetch('/chat', requestOptions);     // const streamResponse = await fetch('/search/api/dev/stream', requestOptions);     const reader = streamResponse.body.getReader();     let errText = "";     const read = () => {       return reader.read().then(({ done, value }) => {         count++;         if (done) {           console.log("victor react reviced: end");           callback(ENDTEXT);           return;         }          const textDecoder = new TextDecoder();         // console.log("返回的数据:", textDecoder.decode(value));         let text = "";         const strArr = (errText + textDecoder.decode(value)).split("data: ");         console.log("解析字符", textDecoder.decode(value))         if (strArr) {           for (let i = 0; i < strArr.length; i++) {             let json = {};             if (strArr[i] && strArr[i] !== "[DONE]") {               try {                 json = JSON.parse(strArr[i]);                 if (json.choices.length && json.choices[0].delta.content) {                   text = text + json.choices[0].delta.content;                 }                 errText = "";               } catch (e) {                 console.log("出错", strArr[i])                 errText = strArr[i];               }              }           }           callback(text);         }         return read();       });     }      read();   }    const postStreamListAudio = async (erjinzhi) => {     const requestOptions = {       method: 'POST',       headers: {         'Content-Type': 'application/json'       },       body: JSON.stringify({         "model": "gpt-3.5-turbo",         "messages": [{ "role": "assistant", "content": erjinzhi }]       })     };     let count = 0;     const streamResponse = await fetch('/chat', requestOptions);     // const streamResponse = await fetch('/search/api/dev/stream', requestOptions);     const reader = streamResponse.body.getReader();     let errText = "";     const read = () => {       return reader.read().then(({ done, value }) => {         count++;         if (done) {           console.log("victor react reviced: end");           return;         }          const textDecoder = new TextDecoder();         // console.log("返回的数据:", textDecoder.decode(value));         let text = "";         const strArr = (errText + textDecoder.decode(value)).split("data: ");         console.log("解析字符", textDecoder.decode(value))         if (strArr) {           for (let i = 0; i < strArr.length; i++) {             let json = {};             if (strArr[i] && strArr[i] !== "[DONE]") {               try {                 json = JSON.parse(strArr[i]);                 if (json.choices.length && json.choices[0].delta.content) {                   text = text + json.choices[0].delta.content;                 }                 errText = "";               } catch (e) {                 console.log("出错", strArr[i])                 errText = strArr[i];               }              }           }           console.log(text);         }         return read();       });     }     read();   }    const addLocalStorage = (dataArr) => {     var now = new Date();     var year = now.getFullYear(); //获取完整的年份(4位,1970-????)     var month = now.getMonth() + 1; //获取当前月份(0-11,0代表1月)     var date = now.getDate(); //获取当前日(1-31)     var hour = now.getHours(); //获取当前小时数(0-23)     var minute = now.getMinutes(); //获取当前分钟数(0-59)     var second = now.getSeconds(); //获取当前秒数(0-59)     var timestamp = year + "-" + (month < 10 ? "0" + month : month) + "-" + (date < 10 ? "0" + date : date) + " " + (hour < 10 ? "0" + hour : hour) + ":" + (minute < 10 ? "0" + minute : minute) + ":" + (second < 10 ? "0" + second : second);     try {       let arrStr = localStorage.getItem("LOCALDATA");       if (arrStr) {         let arr = JSON.parse(arrStr);         arr.push({           time: timestamp,           dataArr: dataArr         });         localStorage.setItem("LOCALDATA", JSON.stringify(arr));       } else {         let arr = [];         arr.push({           time: timestamp,           dataArr: dataArr         });         localStorage.setItem("LOCALDATA", JSON.stringify(arr));       }       messageApi.open({         key,         type: 'success',         content: '缓存成功',         duration: 1       });     } catch (err) {       console.error('localStorage set error: ', err);     }   }    const addComment = async (e) => {     if (question.trim() === '') {       alert('请输入问题');       return;     }     setQuestion('');     let index = comments.length;     comments.push({       id: Math.random(),       role: 'user',       type: "chatgpt",       name: question,       contents: []     });     setCount(count + 1);     setTimeout(async () => {       let responseList = await getList();       if (responseList[0].type === "chatgpt-url") {         comments[index].type = "chatgpt-url";       }       comments[index].contents = responseList;       setQuestion('');       setCount(0);     }, 0);   }    const getList = (question) => {     let requestList = [];     comments.map((item) => {       if (item.type === "chatgpt-url") {         if (item.contents[0]) {           requestList.push({ "role": "user", "content": item.contents[0].hiddenQuestion });           requestList.push({ "role": "assistant", "content": item.contents[0].hiddenContent });         }       } else {         requestList.push({ "role": "user", "content": item.name });         if (item.contents[0]) {           requestList.push({ "role": "assistant", "content": item.contents[0].text });         }       }     })     return new Promise((resolve) => {       axios.post('/search/send', {         frequency_penalty: 0,         max_tokens: 2048,         model: "text-davinci-003",         presence_penalty: 0,         message: requestList,         temperature: 0.5,         top_p: 1       }).then((response) => {          if (Array.isArray(response.data.choices)) {           // console.log('请求成功', response);           let arr = response.data.choices.map((item) => {             if (item.message.type === "chatgpt-url") {               return {                 type: item.message.type,                 index: item.index,                 text: "我已经对这个链接学习完成,你可以向我提问关于这个链接的内容",                 hiddenQuestion: item.message.question,                 hiddenContent: item.message.content               }             } else {               return {                 type: item.type,                 index: item.index,                 text: item.message.content               }             }           })           resolve(arr);         } else {           alert('程序错误');         }         // 请求成功       }).catch((error) => {         // 请求失败,         console.log(error);       });     })   }    const scrollBottom = () => {     if (!list_container_id.current) {       return;     }     setTimeout(() => {       list_container_id.current.scrollTop = list_container_id.current.scrollHeight     }, 0);   }    const updateScroll = useCallback(() => {     scrollBottom()   })    const addStreamComment = async ({     question1 = "",     isCreate = false,     isContinue = false   }) => {     if (question.trim() === '' && !question1 && isContinue === false) {       alert('请输入问题');       return;     }     streaming = true;     setQuestion('');     let index = 0;     // 修改不需要新数据, 创建就需要push新item     if (isCreate || comments.length === 0) {       console.log("走创建")       index = comments.length;       let questionText = question1 || question;       if (roles[roleType]) {         questionText = roles[roleType](question1 || question)       }       comments.push({         id: Math.random(),         role: 'user',         type: "chatgpt",         name: questionText,         edit: false,         contents: [{ index: Math.random(), text: "", edit: false }]       });     } else if (isContinue === true) {       console.log("走继续")       index = comments.length - 1;       comments[index] = {         ...comments[index],         id: Math.random(),         role: 'user',         type: "chatgpt",         edit: false       };     } else {       console.log("走编辑")       index = comments.length - 1;       comments[index] = {         id: Math.random(),         role: 'user',         type: "chatgpt",         name: question1 || question,         edit: false,         contents: [{ index: Math.random(), text: "", edit: false }]       };     }     setCount(count + 1);     let str = comments[index].contents[0].text;     const callback = (text) => {       if (text === ENDTEXT) {         streaming = false;         setCount(1);         return;       }       str = str + text;       comments[index].contents[0].text = str;       setQuestion('');       setCount((count) => count + 1);     }     postStreamList(callback);   }    const copy = (index) => {     const clipboard = new ClipboardJS("#copyBtn" + index);     clipboard.on('success', () => {       messageApi.open({         key,         type: 'success',         content: '复制成功',         duration: 1       });     });   }   useEffect(() => {     const clipboard = new ClipboardJS("#copyBtnAll");     clipboard.on('success', () => {       messageApi.open({         key,         type: 'success',         content: '复制成功',         duration: 1       });     });     comments.map((item, index) => {       const clipboard = new ClipboardJS("#copyBtn" + index);       clipboard.on('success', () => {         messageApi.open({           key,           type: 'success',           content: '复制成功',           duration: 2         });       });     })   })   console.log("comments", comments)   const renderList = () => {     return comments.length === 0 ?       (
{ flex: 1 }}>
暂无问题,快去提问吧~
) : (
(el) => { list_container_id.current = el; }} style={{ flex: 1 }} className="list_container" >
    { color: 'white' }}> {comments.map((item, index) => (
  • item.id} style={{ color: 'white' }}> { item.name ? (
    { marginLeft: 8 }}>
    提问:
    "copyBtn" + index} data-clipboard-text={item.name} onClick={(e) => copy(index)}>copy
    {comments.length === index + 1 ? (
    () => { if (item.edit === false) { item.edit = true; setCount(count + 1); } else { addStreamComment({ question1: item.name, isCreate: false, isContinue: false }); } }}>{!item.edit ? "edit" : "submit"}
    ) : null}
    () => { comments.splice(index, 1); setCount(count + 1); }}>delete
    { !item.edit ?

    {item.name}

    : (