//chat 聊天界面 import web.form; import web.form.simpleMarkdown; import web.rest.aiChat.message; namespace web.form; class chat{ ctor( ... ){ this = ..web.form.simpleMarkdown(...) this.chatMessage = ..web.rest.aiChat.message(); }; findSystem = function(pattern){ var chatMessage = this.chatMessage; for(i=1;#chatMessage;1){ var msg = chatMessage[i] if(msg[["role"]]=="system"){ if(msg.content && ..string.find(msg.content,pattern) ){ return msg.content; } } } }; aardioSystem = function(prompt){ this.chatMessage.aardioSystem(prompt); }; system = function(content){ this.pushMessage({ role = "system"; content = content; }); }; prompt = function(content,imageUrl){ if(imageUrl){ var typeImage = type(imageUrl); if((typeImage=="string") && ..io.exist(imageUrl)){ imageUrl = ..string.loadBuffer(imageUrl); if(imageUrl) typeImage ="buffer"; } if(typeImage==="buffer"){ var b = imageUrl; if( b[1] == 0xFF && b[2] == 0xD8 ){ b="image/jpeg" } elseif( b[1] == 0x89 && b[2] == 0x50 && b[3] == 0x4e && b[4] == 0x47){ b="image/png" } elseif( b[1] == 0x47 && b[2] == 0x49 && b[3] == 0x46){ b="image/gif" } elseif( b[1] == 0x52 && b[2] == 0x49 && b[3] == 0x46 && b[4] == 0x46){ b="image/webp" } else{ error("错误的图像数据",2); } import crypt; imageUrl = ..string.format('data:%s;base64,%s',b,..crypt.encodeBin(imageUrl,,0x40000001/*_CRYPT_STRING_BASE64*/ ) ) } content = { { "type": "text", "text": content }, { "type": "image_url", "image_url": { "url": imageUrl } } } } if(content){ if(type.isString(content)){ content = ..string.replace(content, "^(<<```>?!.>+\N+)(```+)",'\\1\n\\2'); content = ..string.replace(content, "!\N[ \t]*(```+)[ \t]*(<?!\S>+<<```>?!.>*)$",'\\1\n\\2'); } } this.pushMessage( { role = "user"; content = content; } ); }; assistant = function(content){ this.pushMessage(content); }; url = function(urlData){ this.chatMessage.url(urlData); }; pushMessage = function(msg){ //加入聊天消息 if(msg){ if(type.isString(msg)){ this.writeDelta(msg); } elseif(msg.role=="user"){ var lastastAssistant = this.lastAssistantMessage(); if(lastastAssistant[["content"]]){ lastastAssistant[["content"]] = ..string.replace(lastastAssistant[["content"]] ,"\<(|)\>(.+?)\",""); } var txtContent; var content = msg.content; if(..table.isArrayLike(content)){ txtContent = ""; for(i=1;#content;1){ var item = content[i]; if(item.type=="text"){ txtContent = ..string.concat(txtContent,item.text) } elseif(item.type=="image_url"){ txtContent = ..string.concat(txtContent,..string.concat("![](",item.image_url[["url"]],")") ) } } } else { txtContent = content; } if(..string.find(txtContent,"<#+\s+>|||<`>|<===>|<\-\-\->")){ this.writeDelta('\n\n\n
\n'+txtContent + '\n
\n\nAI\n\n'); } else{ this.writeDelta('\n\n\n
'+txtContent + '
\n\nAI\n\n'); } this.showLoading("正在思考 "); } this.chatMessage.push(msg); } else{ this.writeDelta(null); this.chatMessage.push(null); } }; lastMarkdown = function(){ var chatMessage = this.chatMessage; var lastMsg = chatMessage[#chatMessage] if(lastMsg[["role"]]=="assistant"){ return lastMsg.content; } }; lastAssistantMessage = function(){ var chatMessage = this.chatMessage; var lastMsg = chatMessage[#chatMessage] if(lastMsg[["role"]]=="assistant"){ return lastMsg; } }; errorMessage = function(msg){ if(type(msg)=="table") msg = ..table.tostring(msg) this.showError(msg); }; clear = function(){ this.setMarkdown(""); this.chatMessage.clear(); }; started = function(){ return this.chatMessage.started(); }; } /*****intellisense() web.form.chat = 用于显示 Markdown 生成的 HTML 的 AI 助手专用 web 窗体。\n此对象继承自 web.form.simpleMarkdown 与 web.form 对象。 web.form.chat( = 创建用于显示 Markdown 生成的 HTML 的 AI 助手专用 web 窗体。 \n此对象继承自 web.form.simpleMarkdown 与 web.form 对象。 web.form.chat(.(winform,hostFlags,dlControl,userAgent,securityTrusted) = 创建 Web 窗体。\n\n参数 @winform 可指定窗体或 custom 控件作为网页宿主窗口。\n@winform 也可以指定 null 值或 win.form 构造参数表以创建新窗体。\n\n其他参数不必指定,这些参数的用法请参考 web.form 。 web.form.chat() = !webFormChat. end intellisense*****/ /*****intellisense(!webFormChat) enableKatex(true) = 允许解析数学公式,参数为 false 则禁用此功能(默认)。\n仅在 Win10 以上系统有效。 started() = 是否已经发起对话。\n发起对话指的是消息队列中包含非 system 角色的消息。 clear() = 清除会话记录 errorMessage(__/*错误信息*/) = 显示错误信息。\n参数可指定字符串、table 对象或 null 值,其他类型转换为字符串显示。\n参数指定 null 值忽略不执行任何操作。 assistant(__/*增量文本*/) = 显示并记录 AI 接口返回的增量文本。\n参数必须是文本或者表示输出完成的 null 值。 prompt(.(content) = 添加用户提示词。\ncontent 可以是字符串,也可以是对象数组。\n请参考调用模型与接口的文档了解支持的对象格式。 prompt(.(txtContent,imageUrl) = 添加并显示用户 @txtContent 参数指定的文本提示词。\n可选用 @imageUrl 指定图像网址,\n本地图像可调用 inet.urlData 转换为 Data URL(Base64) 格式。\n注意请参考接口文档了解调用模型是否支持图像识别。 prompt(.(txtContent,imageBufferOrPath) = 添加并显示用户 @txtContent 参数指定的文本提示词。\n可选用 @imageBufferOrPath 指定图像数据(必须是 buffer 对象),\n支持 JPG,PNG,GIF,WEBP 格式图像。\n\n注意请参考接口文档以了解调用模型是否支持图像识别。\n\n如果 @imageBufferOrPath 使用字符串指定文件路径则调用 string.loadBuffer 读取为 buffer。 system(__/*提示词*/) = 添加并显示系统提示词 url(__) = 获取参数 @1 指定网址的内容并转换为 Markdown 格式或者文本格式提示词。\n参数 @1 也可以指定包含 url 字段的对象,或这样的对象数组。\n参数为 包含 url 字段的对象时如果同时包含 text 字段,则直接自 text 字段获取网页文本。\n如果参数 @1 指定数组参数,则将所有数组成员作为参数获取目标内容。\n如果参数为空数组、空字符串、null 则返回 null。\n成功返回添加的提示词,失败返回 null,错误信息 。\n\n如果提前导入 web.turndown 库则支持自动转换 HTML 为 Markdown 格式文本。 aardioSystem( = 自动创建 aardio 编程助手系统提示词。\n除函数自带的基本的 aardio 助手提示词以外,EXE 目录下必须存在待添加的文档。 aardioSystem(.(prompt) = 增加 aardio 编程助手提示词(如果已添加则忽略)。\n如果指定参数 prompt 则追加到系统提示词(不检测之前是否已添加过) findSystem(__/*模式串*/) = 使用模式匹配语法查找消息队列中是否存在指定的系统提示词 chatMessage = 消息队列,用于发送到 chat/completions 聊天接口。\n!webRestChatMessage. lastMarkdown() = 获取最后一次 AI 回复的原始 Markdown 格式内容。 lastAssistantMessage() = AI 最后一次返回的消息,如果没有则返回 null。 getMarkdown() = 返回输出到页面的所有 Markdown 格式内容。 setMarkdown(__) = 输出 Markdown 格式内容到页面,覆盖控件存储的 Markdown。 write(__) = 清空页面内容,解析并显示参数 @1 指定的 Markdown 为网页。\n控件仅解析与显示 Markdown,不会存储此 Markdown,\n也不会改变 getMarkdown 函数的返回值。 writeDelta(__) = 向页面追加 Markdown 格式内容。\n解析、显示、并存储写入的 Markdown。\n\nAI 回复的消息应当调用 assistant 方法写入而不是调用 writeDelta 方法写入。\nwriteDelta 只会输出内容到页面,但不会添加到 chatMessage 属性保存的消息队列。 onWriteEnd = @.onWriteEnd = function(){ __/*发出问题以后,AI 回复完成或出现错误回调此事件*/ } beforerWriteEnd = @.beforerWriteEnd = function(markdown){ __/*在输出完整回复以前,可在此回调中修改返回输出的全部 Markdown。\n错误输出不会触发此函数。*/ } showLoading(.(title) = 显示加载动画,可选用 title 指定标题。 showThinking(.(reasoning) = 显示推理过程,reasoning 参数指定 AI 返回的推理响应文本。 doModal(.(ownerForm,showFlags) = 宿主窗口显示为模态对话框。\n可选用参数 @ownerForm 指定所有者窗口,\n参数 @showFlags 可选用 _SW_ 前缀常量指定显示选项。 show(.(true) = 显示窗口 show(.(false) = 隐藏窗口 close(.() = 立即关闭窗口 close(.(true) = 异步关闭窗口 renderPollinationsAsImg = 允许将 id 为 pollinations 的折叠块(details 标签)转换为图像链接 end intellisense*****/