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

news2024/11/24 15:03:13

实现了如下功能(使用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);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1943697.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OCC 扫掠

目录 一、概述 1、扫掠类型分类 2、扫掠方式分类 二、详细介绍 1. 直线扫掠(Linear Sweep) 2. 旋转扫掠(Revolution) 3. 一般路径扫掠(General Path Sweep) 三、总结 一、概述 OpenCASCADE (OCC) 中的扫掠(Sweeping)操作是一种常用的几何建模技术,用于通过沿着…

Java文件读取 jar包内文件读取

全文详见个人博客&#xff1a;https://www.coderli.com/jar-classloader/ Java文件读取 jar包内文件读取最近遇到一些Jar包内外配置文件读取的问题。索性自己测试总结一下&#xff0c;与大家分享。 主要是关于ClassLoader.getResource和Class.getResource方法路径区别的问题。…

python:切片

Python 中的切片&#xff08;slicing&#xff09;是一种强大的功能&#xff0c;它允许你获取序列&#xff08;如列表、元组、字符串等&#xff09;的一个子集。切片操作通过指定序列的起始索引、结束索引&#xff08;可选&#xff09;和步长&#xff08;可选&#xff09;来实现…

IOCTLance:一款针对x64 WDM驱动程序的漏洞检测工具

关于IOCTLance IOCTLance是一款针对x64 WDM驱动程序的漏洞检测工具&#xff0c;该工具来源于CODE BLUE 2023上展示的一个名为“使用符号执行和污点分析增强 WDM 驱动程序漏洞检测 ”的项目。该工具能够有效增强检测Windows驱动程序模型&#xff08;WDM&#xff09;驱动程序中各…

数模·插值和拟合算法

插值 将离散的点连成曲线或者线段的一种方法 题目中有"任意时刻任意的量"时使用插值&#xff0c;因为插值一定经过样本点 插值函数的概念 插值函数与样本离散的点一一重合 插值函数往往有多个区间&#xff0c;多个区间插值函数样态不完全一样&#xff0c;简单来说就…

动态住宅IP和静态住宅IP主要区别是什么?

在互联网连接的世界中&#xff0c;IP地址是我们识别和访问网络资源的关键。住宅IP地址&#xff0c;特别是动态住宅IP和静态住宅IP&#xff0c;是两种不同类型的IP分配方式&#xff0c;它们在使用和功能上存在显著差异。 1. IP地址的稳定性 动态住宅IP&#xff1a;这种IP地址是…

redis命令超详细

redis数据结构介绍 redis是一个key-value的数据库&#xff0c;key一般是String类型&#xff0c;但是value的类型有很多&#xff1a; 基本类型&#xff1a;String,Hash,List,Set,SortedSet(可排序的不能重复的集合) 特殊类型&#xff1a;GEO,BitMap,HyperLog等 文档官网&…

CSS3雷达扫描效果

CSS3雷达扫描效果https://www.bootstrapmb.com/item/14840 要创建一个CSS3的雷达扫描效果&#xff0c;我们可以使用CSS的动画&#xff08;keyframes&#xff09;和transform属性。以下是一个简单的示例&#xff0c;展示了如何创建一个类似雷达扫描的动画效果&#xff1a; HTM…

Python -numpy 基础-------1

NumPy&#xff08;Numerical Python&#xff09;是Python的一个开源数值计算扩展库。它支持大量的维度数组与矩阵运算&#xff0c;此外也针对数组运算提供大量的数学函数库。NumPy的数组&#xff08;ndarray&#xff09;对象是一个快速且灵活的多维数组对象&#xff0c;用于存储…

power bi-all 相关函数

power bi-all 相关函数 1. all 函数2. allselected 函数3. allexcept&#xff08;&#xff09;函数4. allnoblankrow() 函数 1. all 函数 作用&#xff1a; 清除筛选返回&#xff1a;清除筛选后的表格或列总结 当all参数为表时&#xff0c;忽略所有的筛选条件&#xff0c;无论…

github连接不上的解决方案(持续更新)

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于大模型算法的研究与应用。曾担任百度千帆大模型比赛、BPAA算法大赛评委,编写微软OpenAI考试认证指导手册。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。授权多项发明专利。对机器学…

鸿蒙仓颉语言【模块module】

module 模块 模块配置文件&#xff0c;这里指项目的modules.json 文件&#xff0c;用于描述代码项目的基础元属性。 {"name": "file name", //当前项目的名称"description": "项目描述", //项目描述"version": "1.0…

十、Docker版Redis集群搭建

目录 一、3主3从Redis集群配置 1、新建6个docker容器实例 2、进入容器redis-node-1并为6台机器构建集群关系 3、以6381为切入点&#xff0c;查看集群状态 二、主从容错切换迁移案例 1、数据读写存储 2、假如6381宕机了&#xff0c;他的从库6386会不会切换 三、主从扩容案…

(C语言) 文件读写基础

文章目录 &#x1f5c2;️前言&#x1f4c4;ref&#x1f4c4;访问标记&#x1f5c3;️文件访问标记 &#x1f5c2;️Code&#x1f4c4;demo&#x1f4c4;分点讲解&#x1f5c3;️打开/关闭&#x1f5c3;️写&#x1f5c3;️读 &#x1f5c2;️END&#x1f31f;关注我 &#x1f…

Linux-socket详解

前言 OSI七层模型和TCP/IP四层模型在这里就不说了。 套接字&#xff08;socket&#xff09;是一个抽象层&#xff0c;应用程序可以通过它发送或接收数据&#xff0c;可对其进行像对文件一样的打开、读写和关闭等操作。套接字允许应用程序将IO插入到网络中&#xff0c;并与网络…

Nest.js 实战 (四):利用 Pipe 管道实现数据验证和转换

什么是管道&#xff08;Pipe&#xff09;&#xff1f; 在 Nest.js 中&#xff0c;管道&#xff08;Pipelines&#xff09; 是一种强大的功能&#xff0c;用于预处理进入控制器方法的请求数据&#xff0c;如请求体、查询参数、路径参数等。管道允许开发者在数据到达控制器方法之…

使用GoAccess进行Web日志可视化

运行网站的挑战之一是了解您的 Web 服务器正在做什么。虽然各种监控应用程序可以在您的服务器以高负载或页面响应缓慢运行时提醒您&#xff0c;但要完全了解正在发生的事情&#xff0c;唯一的方法是查看 Web 日志。阅读日志数据页面并了解正在发生的事情可能需要花费大量时间。…

慎用 readFileSync 读取大文件, 教你一招如何优雅处理大文件读取

我们在编写 nodejs 服务的时候&#xff0c;有时候需要使用 fs.readFileSync api 去读取文件&#xff0c;但是使用 fs.readFileSync 会将文件读取在内存中&#xff0c;如果遇到了文件很大时&#xff0c;fs.readFileSync 会占据服务器大量的内存&#xff0c;即使读取的文件比较小…

代发考试战报:7月16号武汉参加HCIP-Transmission传输 H31-341考试通过

代发考试战报&#xff1a;7月16号武汉参加HCIP-Transmission传输 H31-341考试通过&#xff0c;&#xff0c;有2个题好像没见到过&#xff0c;其他都是题库里的原题&#xff0c;题库很准&#xff0c;这个题库也不是一直不变的&#xff0c;也没规律可循什么时候变题&#xff0c;哪…

【TAROT学习日记】韦特体系塔罗牌学习(6)——教皇 THE HIEROPHANT

韦特体系塔罗牌学习&#xff08;6&#xff09;——教皇 THE HIEROPHANT 目录 韦特体系塔罗牌学习&#xff08;6&#xff09;——教皇 THE HIEROPHANT牌面分析1. 基础信息2. 图片元素 正位牌意1. 关键词/句2.爱情婚姻3. 学业事业4. 人际财富5. 其他象征意 逆位牌意1. 关键词/句2…