AI学习记录 -使用react开发一个网页,对接chatgpt接口,附带一些英语的学习prompt

avatar
作者
筋斗云
阅读量: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 ?       (<div style={{ flex: 1 }}>         <div className='no-comment'>暂无问题,快去提问吧~</div>       </div>)       : (         <div           ref={(el) => {             list_container_id.current = el;           }}           style={{ flex: 1 }}           className="list_container"         >           <ul style={{ color: 'white' }}>             {comments.map((item, index) => (               <li key={item.id} style={{ color: 'white' }}>                 {                   item.name ? (                     <div className='quiz'>                       <div className='response' style={{ marginLeft: 8 }}>                         <div className='action_btn'>                           <div>提问:</div>                           <div className="copy_button" id={"copyBtn" + index} data-clipboard-text={item.name} onClick={(e) => copy(index)}>copy</div>                           {comments.length === index + 1 ? (                             <div                               className="copy_button"                               onClick={() => {                                 if (item.edit === false) {                                   item.edit = true;                                   setCount(count + 1);                                 } else {                                   addStreamComment({                                     question1: item.name,                                     isCreate: false,                                     isContinue: false                                   });                                 }                               }}>{!item.edit ? "edit" : "submit"}</div>                           ) : null}                           <div                             className="copy_button"                             onClick={() => {                               comments.splice(index, 1);                               setCount(count + 1);                             }}>delete</div>                          </div>                         {                           !item.edit ? <p>{item.name}</p> : (                             <div className="">                               <TextArea                                 rows={4}                                 defaultValue={item.name}                                 onChange={(e) => {                                   item.name = e.target.value;                                 }}                               />                             </div>                           )                         }                       </div>                     </div>                   ) : null                 }                 {                   item.contents.length ? (                     <>                       <div                         className='answer'>                         <div style={{ marginLeft: 8, marginBottom: 10 }} >                           <div className='action_btn'>                             <div>回答:</div>                             <div className="copy_button" id={"copyBtn" + index} data-clipboard-text={item.contents[0].text} onClick={(e) => copy(index)}>copy</div>                           </div>                           <pre style={{ width: "100%" }}><OmsSyntaxHighlight textContent={item.contents[0].text} language={"javascript"} darkMode /></pre></div>                       </div>                       <div>{currentTexts.current}</div>                     </>                   ) : <div>                     <div style={{ display: 'flex', justifyContent: 'center', backgroundColor: 'black' }}><div className='heike'  >chatgpt</div></div>                     <div className='answer2'>思考中...</div>                   </div>                 }               </li>             ))             }           </ul >         </div >       )   }   const handleForm = (e) => {     setQuestion(e.target.value)   }    const handleSelectChange = (value) => {     setFrontPrompts(value);     setRoleType(value);   };    useEffect(() => {     scrollBottom()   })    const overWriteData = (jsonData) => {     let jsonData1 = JSON.parse(jsonData);     // console.log("jsonData1", jsonData1)     comments = [];     jsonData1.map((item, index) => {       if (index % 2 === 0) {         comments.push({           id: Math.random(),           role: 'user',           type: "chatgpt",           name: item.content,           edit: false,           contents: [{             index: Math.random(),             edit: false,             text: jsonData1[index + 1].content           }]         })         // console.log(comments)         setCount(count + 1)       }     })   }    const handleLocalDataChange = (value) => {     overWriteData(value);   };    useEffect(() => {     const mp3File = document.getElementById('mp3-file');      mp3File.addEventListener('change', () => {       const file = mp3File.files[0];       const reader = new FileReader();        reader.addEventListener('loadend', () => {         const byteArray = new Uint8Array(reader.result);         // 将byteArray上传至服务器         console.log(byteArray)         postStreamListAudio(byteArray);       });        reader.readAsArrayBuffer(file);     });   }, [])    const renderHeader = () => {     return (       <div className='header_button'>         <div           className="copy_all_button"           style={{ color: "white" }}           onClick={() => {             let tmp = [];             comments.map((item) => {               tmp.push({                 role: 'user',                 content: item.name,               })               tmp.push({                 role: 'assistant',                 content: item.contents[0].text               })             })             setJsonData(JSON.stringify(tmp));             setOpen(true);           }}>           copy all         </div>         <input type="file" id="mp3-file"></input>         <div           className="copy_all_button"           onClick={() => {             setOpenMoreFunction(true);           }}           style={{ color: "white" }}         >           更多功能         </div>       </div>     )   }    const renderDrawerCopyBtnAll = () => {     return (       <Drawer         title={           <div style={{ display: 'flex' }}>             <div               className='copy_button'               id={"copyBtnAll"}               data-clipboard-text={jsonData}               onClick={(e) => {                 const clipboard = new ClipboardJS("#copyBtnAll");                 clipboard.on('success', () => {                   messageApi.open({                     key,                     type: 'success',                     content: '复制成功',                     duration: 2                   });                 });               }}>copy</div>             <div className='copy_button' onClick={() => {               try {                 overWriteData(jsonData);                 setOpen(false);               } catch (e) {                 messageApi.open({                   key,                   type: 'error',                   content: 'json格式出错',                   duration: 2                 });               }             }}>               执行json             </div>             <div className='copy_button' onClick={() => {               try {                 addLocalStorage(jsonData);               } catch (e) {                 messageApi.open({                   key,                   type: 'error',                   content: 'json格式出错',                   duration: 2                 });               }             }}>               缓存             </div>           </div>         }         placement={"bottom"}         open={open}         size='small'         onClose={() => {           setOpen(false)         }}       >         <TextArea           rows={4}           value={jsonData}           onChange={(e) => {             setJsonData(e.target.value);           }}         />       </Drawer>     )   }    const renderDrawerMoreFunction = () => {     return (       <Drawer         title={"更多功能"}         placement={"bottom"}         open={openMoreFunction}         size='small'         onClose={() => {           setOpenMoreFunction(false)         }}       >         <div>           {             !streaming ? (               <button                 className="copy_all_button"                 onClick={() => {                   comments = [];                   setCount(0);                 }}>clear</button>             ) : null           }           {             <button               className="copy_all_button"               onClick={() => {                 clearLocalStorage();                 setCount(10);               }}>clearStorage</button>           }           <div>             <span>角色:</span>             <Select               style={{ width: '100%' }}               defaultValue="origin"               onChange={handleSelectChange}               options={[                 { value: 'origin', label: 'origin' },                 ...Object.keys(roles).map((role) => ({ value: role, label: role }))               ]}             />           </div>           <div>             <span>缓存:</span>             <Select               style={{ width: '100%' }}               onChange={handleLocalDataChange}             >               {                 getLocalStorage().length ? getLocalStorage().map((item) => {                   return <Option value={item.dataArr} key={Math.random()}>{item.time}</Option>                 }) : <Option value={"0"} key="无"></Option>               }             </Select>           </div>         </div>       </Drawer>     )   }    const renderFrontPrompts = () => {     if (frontPrompts && roles[frontPrompts]) {       return <div className='frontPrompts'>前置指令:{roles[frontPrompts]()}</div>;     } else {       return null;     }   }    const renderQuestion = () => {     return (       <div className='input_style'>         <TextArea           className='input_quertion'           type="text"           placeholder="请输入问题"           value={question}           name="question"           onChange={handleForm}           autoSize={{ minRows: 1, maxRows: 5 }}         />         <div style={{ width: '1vw' }}></div>         <button onClick={() => {           addStreamComment({             isContinue: true,             isCreate: false,             question1: ""           });         }} className="confirm_button" >继续</button>         <div style={{ width: '1vw' }}></div>         <button onClick={() => {           const pattern = /(http|https):\/\/([\w.]+\/?)\S*/;           addStreamComment({ isCreate: true, isContinue: false, question1: "" });         }} className="confirm_button" >提问</button>       </div>     )   }    return (     <div className='app_container'>       {renderHeader()}       {renderFrontPrompts()}       {renderList()}       {contextHolder}       {renderQuestion()}       {renderDrawerCopyBtnAll()}       {renderDrawerMoreFunction()}     </div>   )  }  const OmsSyntaxHighlight = (props) => {   const { textContent, darkMode, language = 'txt' } = props;   const [value, setValue] = useState(textContent);   if (typeof darkMode === 'undefined') {     them.light = darcula;   }   if (typeof darkMode === 'boolean') {     them.light = coyWithoutShadows;   }   useEffect(() => {     SyntaxHighlighter.registerLanguage("jsx", jsx);     SyntaxHighlighter.registerLanguage("javascript", javascript);     SyntaxHighlighter.registerLanguage("js", javascript);   }, []);   return (     <ReactMarkdown source={value} escapeHtml={false} language={language}>{textContent}</ReactMarkdown>   ); };  
css文件
body, html {   margin: 0; }  ul, li, p {   padding: 0;   margin: 0;   list-style: none }  h3 {   margin-bottom: 0; }  .input_quertion {   width: 50vw;   height: 50px;   border-radius: 10px;   border: 1px solid black; }  pre {   white-space: pre-wrap;   white-space: -moz-pre-wrap;   white-space: -pre-wrap;   white-space: -o-pre-wrap;   word-wrap: break-word; }  .copy_button {   line-height: 35px;   margin-right: 4px;   border: 1px solid royalblue; }  .copy_all_button {   line-height: 44px;   margin-right: 4px;   border: 1px solid royalblue; }  .content {   width: 280px;   margin: 5px;   border: 1px solid black; }  .quickButton {   width: 70px;   border-radius: 10px;   background-color: #03b96b;   border: 0;   height: 30px;   color: white;   position: absolute;   right: 10px; }  .no-comment {   text-align: center;   padding: 20px;   color: white;   background-color: rgb(53, 54, 65); }   .frontPrompts {   text-align: left;   padding: 8px 46px;   color: white;   font-size: 12px;   background-color: rgb(53, 54, 65);   border-bottom: 1px solid black; }  .app_container {   width: 100%;   height: 100%;   display: flex;   flex-direction: column;   background-color: rgb(53, 54, 65); }  .confirm_button {   width: 26vw;   border-radius: 10px;   background-color: #03b96b;   border: 0;   height: 50px;   color: white;   box-shadow: 7px 6px 28px 1px rgba(0, 0, 0, 0.24);   cursor: pointer;   outline: none;   transition: 0.2s all; }  .list_container {   overflow: auto;   flex: 1; }  .qiu {   width: 15%;   height: 15%; }  .chatGPTImg {   position: fixed;   top: 0;   right: 0;   bottom: 0;   left: 0;   margin: auto;   width: 300px;   height: 300px;   z-index: 999; }  .response {   overflow-wrap: break-word;   word-break: normal;   white-space: normal;   flex: 1; }  .header_button {   width: 100%;   height: 67px;   display: flex;   align-items: center;   bottom: 0;   padding: 10px 40px 10px;   border-bottom: 1px solid;   background: linear-gradient(to bottom, rgba(0, 0, 0, 0.7) 0%, rgba(0, 0, 0, 0) 100%);   box-shadow: 0px -5px 10px rgba(0, 0, 0, 0.3); }   .input_style {   width: 100%;   display: flex;   bottom: 0;   padding: 1%;   align-items: end; }  .action_btn {   display: flex;   align-items: flex-start;   color: white; }  .quiz {   display: flex;   align-items: flex-start;   padding: 10px 40px 10px;   color: white;   line-height: 41px;   background-color: rgb(53, 54, 65); }  .quiz_avatar {   width: 40px;   height: 40px; }  .answer {   display: flex;   background-color: #3b3d53;   color: white;   height: auto;   line-height: 35px;   padding: 20px 40px;   overflow: auto;   white-space: normal;   word-break: break-all; }  .answer2 {   text-align: center;   padding-top: 40px; }  .confirm_button:active {   transform: scale(0.98);   background-color: blue;   box-shadow: 3px 2px 22px 1px rgba(0, 0, 0, 0.24); } 

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!