index.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. /**
  2. * ChatGPT工具
  3. * @author zhaoxianlie
  4. */
  5. import AI from './fh.ai.js';
  6. new Vue({
  7. el: '#pageContainer',
  8. data: {
  9. prompt: '',
  10. demos: [
  11. 'FeHelper是什么?怎么安装?',
  12. '用Js写一个冒泡排序的Demo',
  13. 'Js里的Fetch API是怎么用的'
  14. ],
  15. initMessage: {
  16. id:'id-test123',
  17. sendTime:'2022/12/20 12:12:12',
  18. message: '你好,可以告诉我你是谁吗?我该怎么和你沟通?',
  19. respTime: '2022/12/20 12:12:13',
  20. respContent: '你好,我是FeHelper智能助理,由OpenAI提供技术支持;你可以在下面的输入框向我提问,我会尽可能回答你~~~'
  21. },
  22. respResult:{
  23. id: '',
  24. sendTime:'',
  25. message:'',
  26. respTime:'',
  27. respContent:''
  28. },
  29. history:[],
  30. tempId:'',
  31. hideDemo: false,
  32. undergoing: false
  33. },
  34. mounted: function () {
  35. this.$refs.prompt.focus();
  36. this.hideDemo = !!(new URL(location.href)).searchParams.get('hideDemo');
  37. },
  38. methods: {
  39. // 这个代码,主要用来判断大模型返回的内容是不是包含完整的代码块
  40. validateCodeBlocks(content) {
  41. let backticksCount = 0;
  42. let inCodeBlock = false;
  43. let codeBlockStartIndex = -1;
  44. for (let i = 0; i < content.length; i++) {
  45. // 检查当前位置是否是三个连续的反引号
  46. if (content.startsWith('```', i)) {
  47. backticksCount++;
  48. i += 2; // 跳过接下来的两个字符,因为它们也是反引号的一部分
  49. // 如果我们遇到了奇数个反引号序列,那么我们进入了代码块
  50. if (backticksCount % 2 !== 0) {
  51. inCodeBlock = true;
  52. codeBlockStartIndex = i - 2;
  53. } else { // 否则,我们离开了代码块
  54. inCodeBlock = false;
  55. if (codeBlockStartIndex === -1 || codeBlockStartIndex > i) {
  56. return false; // 这意味着有不匹配的反引号
  57. }
  58. codeBlockStartIndex = -1;
  59. }
  60. }
  61. }
  62. // 如果最终 backticksCount 是偶数,则所有代码块都正确关闭
  63. return backticksCount % 2 === 0 && !inCodeBlock;
  64. },
  65. sendMessage(prompt){
  66. if(this.undergoing) return;
  67. if(this.respResult.id){
  68. this.history.push(this.respResult);
  69. this.respResult.id = '';
  70. }
  71. this.undergoing = true;
  72. let sendTime = (new Date()).format('yyyy/MM/dd HH:mm:ss');
  73. this.$nextTick(() => {
  74. this.scrollToBottom();
  75. });
  76. this.tempId = '';
  77. let respContent = '';
  78. AI.askYiLarge(prompt,(respJson,done) => {
  79. if(done){
  80. this.undergoing = false;
  81. return;
  82. }
  83. let id = respJson.id;
  84. respContent = respJson.content || '';
  85. if(!this.validateCodeBlocks(respContent)) {
  86. respContent += '\n```';
  87. }
  88. respContent = marked(respContent);
  89. if(this.tempId !== id) {
  90. this.tempId = id;
  91. let dateTime = new Date(respJson.created * 1000);
  92. let respTime = dateTime.format('yyyy/MM/dd HH:mm:ss');
  93. this.respResult = { id,sendTime,message:prompt,respTime,respContent };
  94. }else{
  95. this.respResult.respContent = respContent;
  96. }
  97. this.$nextTick(() => {
  98. let elm = document.getElementById(id);
  99. elm.querySelectorAll('pre code').forEach((block) => {
  100. hljs.highlightBlock(block);
  101. });
  102. this.scrollToBottom();
  103. });
  104. });
  105. },
  106. scrollToBottom(){
  107. this.$refs.boxResult.scrollTop = this.$refs.boxResult.scrollHeight;
  108. },
  109. goChat(){
  110. this.sendMessage(this.prompt);
  111. this.$nextTick(() => this.prompt='');
  112. }
  113. }
  114. });