出于对技术的专研想还原ChatGPT里面的一些交互,中间遇到遇到一些小问题做下总结
一、还原里面的富文本展示
chatgpt返回结果是这样的
"冒泡排序是一种简单直观的排序算法,它重复地比较相邻的两个元素,如果顺序错误就交换它们的位置,直到没有任何一对数字需要比较为止。以下是 JavaScript 实现冒泡排序的代码:\n\n```\nfunction bubbleSort(arr) {\n var len = arr.length;\n for (var i = 0; i < len - 1; i++) {\n for (var j = 0; j < len - 1 - i; j++) {\n if (arr[j] > arr[j + 1]) {\n // 交换相邻两个元素\n var temp = arr[j];\n arr[j] = arr[j + 1];\n arr[j + 1] = temp;\n }\n }\n }\n return arr;\n}\n\n// 测试代码\nvar arr = [5, 2, 4, 6, 1, 3];\nconsole.log(bubbleSort(arr)); // [1, 2, 3, 4, 5, 6]\n```\n\n上述代码中,外层循环执行 len - 1 次,内层循环执行 len - 1 - i 次。如果 arr[j] 大于 arr[j + 1],则交换它们的位置。最后返回排好序的数组 arr。"
最终实现效果
这里不仅还原了文本格式的展示,而且也还原了代码高亮。
可以看出chatgpt返回的是markdawn文本格式,要对markdawn文本格式做下处理,采用的是很强大的marked.js工具,感情兴趣的同学可以到官网看看:https://marked.js.org/
// Create reference instance
import { marked } from 'marked';// Set options
// `highlight` example uses https://highlightjs.org
marked.setOptions({renderer: new marked.Renderer(),highlight: function(code, lang) {const hljs = require('highlight.js');const language = hljs.getLanguage(lang) ? lang : 'plaintext';return hljs.highlight(code, { language }).value;},langPrefix: 'hljs language-', // highlight.js css expects a top-level 'hljs' class.pedantic: false,gfm: true,breaks: false,sanitize: false,smartypants: false,xhtml: false
});// Compile
console.log(marked.parse(markdownString));
这是给出的官方示例,开箱即用。
项目里面引入marked.min.js
和highlight.min.js
文件
项目初始化时引入上面配置,marked.parse()
方法会把markdawn格式转化为html格式。
二、消息发送框还原文本格式
消息发送框一共有两种实现方案: div模拟
和textarea
div模拟textarea
效果如图
这里保留了原问题的换行符等格式,一开始实现简单的消息发送,采用的是input
框,当然input
框肯定保留不了文本格式,看了一下chatgpt网站,发现他们使用的是textarea
文本框,textarea文本框可以保留文本格式,我就采用dom的一个属性 contenteditable
去模拟了一个textarea,
<div class="ask-input" ref="ask-input3" @input="setAsk3" @keydown.enter.prevent="askSubmit3" contenteditable="true" placeholder="请输入内容..." @paste="paste"></div>
去掉粘贴文本格式
paste(event) {let e = event || window.event// 阻止默认粘贴e.preventDefault();let text = (e.originalEvent || e).clipboardData.getData('text/plain');document.execCommand("insertText", false, text);}
设置placeholder
.ask-input:empty:before{content: attr(placeholder);color:#bbb;
}
文本折行
.input-container .ask-input-box .ask-input * {word-break: break-all;white-space: pre-wrap !important;
}
去掉滚动条
.ask-input::-webkit-scrollbar {display: none
};
编辑的时候做了一个简单切换,这样也就能保留原来文本格式
textarea实现高度自适应
textareaHeight1: 22
<textarearef="textarea1"v-model="askInput1"@input="autoResize1"placeholder="请输入内容..."@keydown="eventListen1":style="{ height: `${textareaHeight1}px` }"
></textarea>
autoResize1() {this.textareaHeight1 = 22; // 自适应减小this.$nextTick(() => {this.textareaHeight1 = this.$refs.textarea1.scrollHeight;});
},
.input-container .ask-input-box textarea {width: 100%;max-height: 200px !important;color: var(--vscode-foreground);font-size: 14px;/* 去掉默认字体样式 */font-family: inherit; font-weight: inherit;border: 1px solid #ccc;border-radius: 4px;resize: none;padding: 0;border: none;outline: none;
}
实现起来也很简单!
其他的就不多讲了,感兴趣的小伙伴可以自己动手实现。