aardio 文档
aardio 范例: AI 编码助手
import win.ui;
import fonts.fontAwesome;
/*DSG{{*/
var winform = win.form(text="aardio - AI 编码助手";right=759;bottom=607)
winform.add(
btnClear={cls="plus";text="清除";left=589;top=572;right=655;bottom=602;align="left";color=3947580;db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=8}};iconText='\uF014';notify=1;textPadding={left=25};z=6};
btnCopy={cls="plus";text="复制";left=203;top=573;right=267;bottom=603;align="left";color=3947580;db=1;disabled=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=8}};iconText='\uF0C5';notify=1;textPadding={left=25};z=11};
btnSend={cls="plus";text="问 AI";left=660;top=572;right=732;bottom=602;align="left";color=3947580;db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=8}};iconText='\uF0AA';notify=1;textPadding={left=25};z=5};
btnSetting={cls="plus";text="设置";left=512;top=572;right=579;bottom=602;align="left";color=3947580;db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=8}};iconText='\uF013';notify=1;textPadding={left=25};z=7};
btnSnap={cls="plus";text="分享";left=138;top=573;right=202;bottom=603;align="left";color=3947580;db=1;disabled=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=8}};iconText='\uF030';notify=1;textPadding={left=25};z=13};
chkFix={cls="plus";text="更正";left=276;top=572;right=336;bottom=603;align="left";db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-14;name='FontAwesome')};iconText='\uF0C8 ';notify=1;textPadding={left=24};z=12};
editMaxTokens={cls="edit";left=427;top=577;right=470;bottom=600;align="right";db=1;dr=1;edge=1;z=9};
editPrompt={cls="richedit";left=11;top=452;right=754;bottom=567;db=1;dl=1;dr=1;edge=1;hscroll=1;multiline=1;vscroll=1;z=2};
promptTool={cls="syslink";text="增强检索";left=20;top=577;right=87;bottom=600;center=1;db=1;dl=1;notify=1;z=4};
spinMaxTokens={cls="spin";left=471;top=578;right=491;bottom=600;db=1;dr=1;z=8};
splitter={cls="splitter";left=8;top=453;right=751;bottom=458;db=1;dl=1;dr=1;frame=1;horz=1;z=3};
static={cls="static";text="回复长度:";left=352;top=575;right=418;bottom=598;align="right";center=1;db=1;dr=1;transparent=1;z=10};
wndBrowser={cls="custom";text="自定义控件";left=8;top=5;right=751;bottom=447;ah=1;db=1;dl=1;dr=1;dt=1;z=1}
)
/*}}*/
import fsys.table;
var config = fsys.table(io.appData("aardio/ide/aiChat/~"))
//创建显示聊天消虑的 Web 浏览器窗口
import web.form.chat;
var wb = web.form.chat(winform.wndBrowser);
wb.enableKatex(config.katex);
//清除上下文
var resetMessages = function(){
wb.clear();
//输入系统提示词
wb.aardioSystem( config.systemPrompt );
wb.aiSystemPropmptSupperHotkeys = null;
wb.aiSystemPropmptStringPatterns = null;
wb.aiSystemPropmptWebView = null;
wb.aiSystemPropmptPython = null;
wb.aiSystemPropmptWinform = null;
wb.aiSystemPropmptNet = null;
wb.aiSystemPropmptPlus = null;
wb.aiSystemPropmptFile = null;
import ide;
var projPath = ide.getProjectPath();
if(!#projPath) return;
import fsys.file;
var file = fsys.file(projPath,"r");
if(!file) return;
if(file.size() < 20000){
file.close();
return;
}
var xml = file.readAll();
var project = '\r\n\r\n'+"
## aardio 源文件与工程文件
aardio 代码文件的后缀名为 `.aardio`,可包含 UTF-8 编码的源代码,也可以包含编译后的二进制代码。
aardio 工程文件的后缀名为 `.aproj`,其内容是 XML 格式的工程配置,也使用 UTF-8 编码 。
"
project = project + '\r\n\r\n用户当前在 aardio 开发环境中打开的工程文件路径是: "'+projPath+'"\r\n'
project = project + '\r\n\r\n用户当前打开的工程文件内容如下:'
project = project + '\r\n\r\n```xml\r\n' + xml + '\r\n```\r\n\r\n'
var desc = /*****
工程文件各 XML 节点的作用与含义:
- project 元素指定工程配置,并作为工程根目录包含其他 folder 或 file 元素。
project 元素的属性 ui 指定图形界面。
* 如果 ui 为 "win" 则为图形界面发布后运行默认不显示控制台。
* 如果 ui 为"console" 则为控制台程序发布后运行时默认显示控制台窗口。
project 元素的属性 dstrip 指定是否移除调试符号。
* `dstrip="true"` 则发布后移除调试信息,生成的文件更小但错误信息会缺少调试信息(例如文件名行号)。
- folder 元素为工程中的虚拟目录
如果 folder 的属性 embed 为 "true" 则该目录发布后嵌入 EXE 资源文件,aardio 中很多函数和库都自动支持这种嵌入资源而不需要额外修改代码。例如对于 `string.load("/res/test.txt")`,无论参数指定的文件是不是 EXE 资源文件函数的返回值都是一样的,这是 aardio 的一个主要特性。
如果 folder 元素的属性 local 为 "true" 则表示这是一个本地目录(通常也是 Web 前端工程的发布目录),发布为 EXE 时将添加该目录下的所有文件。这种目录在工程中不显示子级文件或目录,右键菜单的『同步本地目录』也是无效的。
如果 folder 元素的属性 ignored 为 "true" 是指这个目录在发布时被忽略(ignored)。这种目录通常用来指向包含 Web 前端工程源码的目录,工程本身其实并不需要这些多余的目录,生成 EXE 时也会忽略这种目录。
- file 元素则表示添加到工程中的文件
在工程根目录下只能有一个应用程序启动文件, 文件路径必须是 `main.aardio` 或以 `.main.aardio` 结束。除了启动文件,工程根目录只能包含 folder 元素。
*****/
project = project + desc + '\r\n\r\n';
var codePath = ide.getActiveDocPath();
if(#codePath && ..string.endWith(codePath,".aardio",true) ){
project = project + '\r\n\r\n用户当前正在编辑的文件为: "'+codePath+'"\r\n'
}
wb.system(project);
}
resetMessages();
winform.btnClear.oncommand = function(id,event){
resetMessages();//清除聊天上下文
}
winform.splitter.origTop = winform.splitter.top;
//响应按键事件,输入用户提示词
winform.btnSend.oncommand = function(id,event){
var prompt = winform.editPrompt.text;
if(!#prompt){
wb.errorMessage("请先输入问题。")
winform.editPrompt.setFocus();
return;
}
//按钮显示等待动画
winform.btnSend.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'}
winform.btnClear.disabled = true;
winform.btnSnap.disabled = true;
winform.chkFix.disabled = true;
wb.limit = config.msgLimit;
var assistantMsg = wb.lastAssistantMessage();
if(assistantMsg && winform.chkFix.checked){
//Few-shot Learning
assistantMsg.content = ide.aifix.markdown(assistantMsg.content,true);
}
var knowledge = ""
prompt = string.replace(prompt,"(https?\://<www\.>?aardio\.com/zh\-cn/doc/\S+)\.<html>|<md>",
function(url){
url = url + ".md";
wb.showLoading("正在读取:"+url)
var md = inet.http.get(url);
if(md){
md = '\r\n\r\n用户输入的参考网址:' + url
+ '\r\n\r\n下面是自该网址获取的 Markdown 格式文档或范例:'
+ '\r\n\r\n' + md +'\r\n\r\n------------------------\r\n\r\n'
knowledge = knowledge + md;
}
});
if(#knowledge){
wb.system(knowledge)
}
if( !wb.aiSystemPropmptSupperHotkeys && ..string.find(prompt,"<超级热键>|<@@imtip@>|<key\.hotkey>|<@@superHotkey@>")){
if(!wb.findSystem("超级热键使用指南")){
wb.system(..string.load("~/doc/library-guide/std/key/hotkey.md"))
wb.aiSystemPropmptSupperHotkeys = true;
}
}
elseif( !wb.aiSystemPropmptWebView && ..string.find(prompt,"!\w<web.view>|<@@webview@>|<@@webview2@>|<@@react@>!\W")){
if(!wb.findSystem("web.view 快速入门指南")){
wb.system(..string.load("~/doc/library-guide/std/web/view/_.md"))
wb.aiSystemPropmptWebView = true;
}
}
elseif( !wb.aiSystemPropmptPython && ..string.find(prompt,"!\w<@@python@>|<py3>|<py2>!\W")){
if(!wb.findSystem("aardio 调用 Python 入门指南")){
var pyDoc = ..string.load("~/doc/library-guide/ext/python/_.md");
pyDoc = ..string.concat( pyDoc,'\r\n\r\n---\r\n\r\n',..string.load("~/doc/library-guide/ext/python/conversion.md"));
wb.system(..string.load(pyDoc))
wb.aiSystemPropmptPython = true;
}
}
elseif( !wb.aiSystemPropmptNet && ..string.find(prompt,"![\w\.]<\.<@@net@>>|<dotNet>|<System\.>|<[cC]#>![^#\.\a]")){
if(!wb.findSystem("aardio 调用 .NET 入门指南")){
var pyDoc = ..string.load("~/doc/library-guide/std/dotNet/_.md");
pyDoc = ..string.concat( pyDoc,'\r\n\r\n---\r\n\r\n',..string.load("~/doc/library-guide/std/dotNet/type-conversion.md"));
wb.system(..string.load(pyDoc))
wb.aiSystemPropmptNet = true;
}
}
elseif( !wb.aiSystemPropmptStringPatterns && ..string.find(prompt,"<模式匹配>|<string\.find>|<string\.match>|<string\.gmatch>|<string\.replace>|<string\.replaceUnmatched>")){
if(!wb.findSystem("模式匹配与正则表达式的区别")){
wb.system(..string.load("~/doc/library-guide/builtin/string/patterns.md"))
wb.aiSystemPropmptStringPatterns = true;
}
}
elseif( !wb.aiSystemPropmptPlus && ..string.find(prompt,"![\w\.]<plus\s*控件>")){
if(!wb.findSystem("plus 控件使用指南")){
wb.system(..string.load("~/doc/library-guide/std/win/ui/ctrl/plus.md"))
wb.aiSystemPropmptPlus = true;
}
}
elseif( !wb.aiSystemPropmptWinform && ..string.find(prompt,"<win\.ui>|<winform>|<win\.form>|<按钮>|<窗口>|<文本框>|<编辑框>")){
if(!wb.findSystem("如何创建窗口并添加控件")){
wb.system(..string.load("~/doc/library-guide/std/win/ui/create-winform.md"))
wb.aiSystemPropmptWinform = true;
}
}
elseif( !wb.aiSystemPropmptFile && ..string.find(prompt,"<io\.file>|<读文件>|<写文件>")){
if(!wb.findSystem("io 库文件操作")){
wb.system(..string.load("~/doc/ibrary-guide/builtin/io/file.md"))
wb.aiSystemPropmptFile = true;
}
}
//输入 AI 提示词
wb.prompt( prompt );
winform.editPrompt.text = "";
config.maxTokens = winform.spinMaxTokens.pos;
winform.splitter.splitAt(winform.splitter.origTop);
//创建多线程向服务端发送请求
thread.invoke(
function(wb,config){
for(k,v in config){
if(v=="")config[k] = null;
}
/*
下面的 key 24 小时后失效,
DeepSeek 的 key 充 10 元估计能用上一年,所以请自己申请一个好吗?!
*/
import string.escape2;
var testKey = string.escape2('\0\48\67\91\29\5\83\2\3\4\5\0\83\8\4\85\5\4\0\83\83\9\5\9\4\1\85\3\86\6\82\5\4\83\86\2\0');
config = table.mix(config,{
key = testKey;
url = "https://api.deepseek.com/v1";
model = "deepseek-chat";
temperature = 0.1;
});
if(config.maxTokens>1024 && (config.key === testKey ) ){
wb.errorMessage(`回复长度超过 1024 时,必须更改为您自己的 API 密钥 。<a href="https://platform.deepseek.com">点这里获取密钥</a>, <a href="javascript:void(0)" onclick="javascript:external.updateApiKey()">点这里设置新密钥</a>。`);
return;
}
//导入调用 HTTP 接口的 REST 客户端
import web.rest.aiChat;
var client = web.rest.aiChat(config);
var ok,err = client.messages(wb.chatMessage,function(deltaText){
wb.assistant(deltaText);
} );
if(err){
//获取错误对象(解析 JSON 格式的错误信息)
var errObject = client.lastResponseError()
if(errObject[["error"]][["type"]] == "authentication_error" ){
wb.errorMessage(`API 密钥错误!<a href="https://platform.deepseek.com">点这里获取密钥</a>, <a href="javascript:void(0)" onclick="javascript:external.updateApiKey()">点这里设置新密钥</a>`)
}
else {
wb.errorMessage(err)
}
}
},wb,config//将参数传入线程
)
winform.btnCopy.disabled = false;
}
//在 AI 回复结束后回调此函数
wb.onWriteEnd = function(){
winform.btnSend.disabledText = null;//关闭等待动画
winform.btnClear.disabled = false;
winform.btnCopy.disabled = false;
winform.btnSnap.disabled = false;
winform.chkFix.disabled = false;
winform.editPrompt.setFocus();
}
//在 AI 回复结束以前回调此函数,自动修正 aardio 代码块中的常见幻觉错误
import ide.aifix;
wb.beforerWriteEnd = function(markdown){
if(winform.chkFix.checked) return ide.aifix.markdown(markdown,true);
return markdown;
}
//导出 aardio 函数到网页 JavaScript 中。
wb.external = {
updateApiKey = function(){
winform.btnSetting.oncommand();
}
}
import key;
import win.clip;
winform.btnCopy.oncommand = function(id,event){
var md = wb.lastMarkdown();
if(!#md) return winform.msgboxErr("消息为空。");
if(key.getState("CTRL")){
var found;
for indent,_,code in string.gmatch(md,"!\N([ \t]*)(```+)<aardio>(.+?)!\N\s*\2![^`\S]") {
if(#indent){
text = string.replace(text,"\n+"+indent,'\n');
}
if(winform.chkFix.checked) code = ide.aifix(code,true);
win.clip.write( code );
found = true;
}
if(!found){
return winform.msgboxErr("没有找到代码块。");
}
}
else{
if(winform.chkFix.checked) md = ide.aifix.markdown(md,true);
win.clip.write( md )
}
winform.btnCopy.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250';text=''}
thread.delay(800);
winform.btnCopy.disabledText = null;
}
//设置接口地址与 API 令牌的窗口
winform.btnSetting.oncommand = function(id,event){
var frmSetting = win.form(text="aardio - 设置 AI 聊天助手";right=685;bottom=589;border="dialog frame";exmode="none";max=false;min=false;mode="popup")
frmSetting.add(
btnAdd={cls="plus";left=18;top=473;right=52;bottom=503;align="left";color=3947580;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=8}};iconText='\uF067';notify=1;textPadding={left=25};z=11};
btnEdit={cls="plus";left=93;top=473;right=127;bottom=503;align="left";color=3947580;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=8}};iconText='\uF044';notify=1;textPadding={left=25};z=13};
btnRemove={cls="plus";left=56;top=473;right=90;bottom=503;align="left";color=3947580;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=8}};iconText='\uF1F8';notify=1;textPadding={left=25};z=12};
btnSave={cls="button";text="更新配置";left=489;top=531;right=659;bottom=576;z=5};
chkKatex={cls="checkbox";text="解析数学公式";left=55;top=526;right=159;bottom=546;z=16};
editApiKey={cls="edit";left=284;top=104;right=662;bottom=131;edge=1;password=1;z=2};
editApiUrl={cls="combobox";left=284;top=31;right=662;bottom=57;edge=1;items={};mode="dropdown";z=19};
editModel={cls="edit";left=284;top=68;right=662;bottom=95;edge=1;z=6};
editProxy={cls="edit";left=283;top=180;right=661;bottom=207;edge=1;z=20};
editSystemPrompt={cls="edit";left=283;top=220;right=664;bottom=484;edge=1;hscroll=1;multiline=1;vscroll=1;z=22};
groupbox={cls="groupbox";text="选择当前配置:";left=9;top=6;right=675;bottom=513;edge=1;z=1};
lbMsgLimit={cls="static";left=423;top=546;right=451;bottom=566;transparent=1;z=17};
lbTemperature={cls="static";left=633;top=140;right=659;bottom=160;transparent=1;z=18};
lstConfig={cls="listbox";left=18;top=34;right=187;bottom=464;edge=1;hscroll=1;items={};vscroll=1;z=10};
static={cls="static";text="模型 ID:";left=196;top=72;right=279;bottom=93;align="right";transparent=1;z=3};
static2={cls="static";text="API key:";left=196;top=107;right=279;bottom=128;align="right";transparent=1;z=4};
static3={cls="static";text="不会联网读取系统提示词内的超链接,建议直接添加文档内容";left=282;top=489;right=649;bottom=508;color=5921370;transparent=1;z=24};
static4={cls="static";text="接口地址:";left=196;top=38;right=279;bottom=59;align="right";transparent=1;z=7};
static5={cls="static";text="temperature:";left=196;top=141;right=279;bottom=162;align="right";transparent=1;z=9};
static6={cls="static";text="上下文轮数:";left=33;top=560;right=128;bottom=592;align="right";transparent=1;z=15};
static7={cls="static";text="代理服务器:";left=196;top=184;right=279;bottom=205;align="right";transparent=1;z=21};
static8={cls="static";text="系统提示词:";left=196;top=219;right=279;bottom=240;align="right";transparent=1;z=23};
tbMsgLimit={cls="trackbar";left=132;top=552;right=415;bottom=582;max=100;min=0;z=14};
tbTemperature={cls="trackbar";left=283;top=137;right=633;bottom=167;max=100;min=0;z=8}
)
frmSetting.editModel.setCueBannerText("模型名前加 @ 使用 Anthropic 接口,否则使用 OpenAI 接口")
frmSetting.editProxy.setCueBannerText("socks=127.0.0.1:1081");
frmSetting.editSystemPrompt.limit = -1;
frmSetting.editApiUrl.items = {
"https://api.deepseek.com/v1",
"https://api.anthropic.com/v1",
"https://generativelanguage.googleapis.com/v1beta",
"https://dashscope.aliyuncs.com/compatible-mode/v1",
"https://ark.cn-beijing.volces.com/api/v3/bots",
"https://api.x.ai/v1",
"https://api.openai.com/v1"
}
frmSetting.editApiUrl.onListChange = function(){
var url = frmSetting.editApiUrl.selText;
if(url=="https://api.deepseek.com/v1"){
frmSetting.editModel.text = "deepseek-chat"
}
elseif(url=="https://api.anthropic.com/v1"){
frmSetting.editModel.text = "@claude-3-5-sonnet-latest"
}
elseif(url=="https://generativelanguage.googleapis.com/v1beta"){
frmSetting.editModel.text = "gemini-exp-1206"
}
elseif(url=="https://api.x.ai/v1"){
frmSetting.editModel.text = "grok-2-1212"
}
elseif(url=="https://api.openai.com/v1"){
frmSetting.editModel.text = "chatgpt-4o-latest"
}
elseif(url=="https://dashscope.aliyuncs.com/compatible-mode/v1"){
frmSetting.editModel.text = "qwen-coder-plus-latest"
}
elseif(url=="https://ark.cn-beijing.volces.com/api/v3/bots"){
frmSetting.editModel.text = "bot-"
}
}
frmSetting.tbMsgLimit.setRange(3,100);
frmSetting.tbTemperature.setRange(0,10);
frmSetting.tbTemperature.oncommand = function(id,event,pos){
var pos = frmSetting.tbTemperature.pos;
frmSetting.tbTemperature.tooltip = pos / 10;
frmSetting.lbTemperature.text = pos / 10;
}
frmSetting.tbMsgLimit.oncommand = function(id,event,pos){
frmSetting.lbMsgLimit.text = frmSetting.tbMsgLimit.pos;;
}
import win.ui.listEdit;
var listEdit = win.ui.listEdit(frmSetting.lstConfig);
listEdit.editBox.setCueBannerText("请输入配置名",true);
if(!#config.itemNames) {
config.itemNames = {"默认"}
config.itemData = {{
url = config.url || "https://api.deepseek.com/v1";
key = config.key;
model = #config.model ? config.model : "deepseek-chat";
temperature = config.temperature;
}};
}
frmSetting.lstConfig.onSelChange = function(){
var selIndex = frmSetting.lstConfig.selIndex;
if(config.selItem && config.selItem != selIndex){
//保存上一个配置
var configItem = {
url = frmSetting.editApiUrl.text;
key = frmSetting.editApiKey.text;
model = frmSetting.editModel.text;
temperature = frmSetting.tbTemperature.pos / 10;
msgLimit = frmSetting.tbMsgLimit.pos;
proxy = string.trim(frmSetting.editProxy.text);
systemPrompt = frmSetting.editSystemPrompt.text;
}
config.itemData[config.selItem] = configItem;
}
//加载下一个配置
var selIndex = frmSetting.lstConfig.selIndex;
var configItem = config.itemData[selIndex] || {};
frmSetting.editApiUrl.text = configItem.url;
frmSetting.editApiKey.text = configItem.key;
frmSetting.editProxy.text = configItem.proxy;
frmSetting.editSystemPrompt.text = configItem.systemPrompt;
if(configItem.temperature===null) configItem.temperature = 0.1;
frmSetting.tbTemperature.pos = configItem.temperature * 10;
frmSetting.tbTemperature.tooltip = configItem.temperature;
frmSetting.lbTemperature.text = configItem.temperature;
frmSetting.tbMsgLimit.pos = configItem.msgLimit || 15;
frmSetting.lbMsgLimit.text = configItem.msgLimit || 15;
frmSetting.editModel.text = configItem.model;
config.proxy = null;
table.assign(config,configItem);
config.itemData[selIndex] = configItem;
config.itemNames = frmSetting.lstConfig.items;
config.itemData = table.slice(config.itemData,1,#config.itemNames);
config.selItem = selIndex;
config.save();
}
frmSetting.lstConfig.items = config.itemNames;
frmSetting.lstConfig.selIndex = config.selItem || 1;
frmSetting.lstConfig.onSelChange();
frmSetting.chkKatex.checked = config.katex;
//保存并更新配置
import inet.url;
frmSetting.btnSave.oncommand = function(id,event){
var configItem = {
url = frmSetting.editApiUrl.text;
key = frmSetting.editApiKey.text;
model = frmSetting.editModel.text;
temperature = frmSetting.tbTemperature.pos / 10;
msgLimit = frmSetting.tbMsgLimit.pos;
proxy = string.trim(frmSetting.editProxy.text);
systemPrompt = frmSetting.editSystemPrompt.text;
}
if(!#configItem.proxy){
configItem.proxy = null;
}
var tUrl = inet.url.split(configItem.url);
if(tUrl[["host"]]=="api.anthropic.com"){
if(configItem.model[1]!='@'#){
configItem.model = '@' + configItem.model;
}
}
elseif(tUrl[["host"]]=="generativelanguage.googleapis.com"){
configItem.url = "https://generativelanguage.googleapis.com/v1beta"
}
var selIndex = frmSetting.lstConfig.selIndex;
config.selItem = selIndex;
config.itemData[selIndex] = configItem;
config.proxy = null;
table.assign(config,configItem);
config.katex = frmSetting.chkKatex.checked;
wb.enableKatex(config.katex);
config.save();
frmSetting.endModal();
if(!wb.started()){
resetMessages();
}
else {
var md = wb.getMarkdown();
if(winform.chkFix.checked){
md = ide.aifix.markdown(md,true)
}
wb.write(md);
}
thread.delay(100)
winform.editPrompt.setFocus();
}
frmSetting.btnEdit.oncommand = function(id,event){
listEdit.beginEdit();
}
frmSetting.btnAdd.oncommand = function(id,event){
listEdit.beginEdit(0);
}
frmSetting.btnRemove.oncommand = function(id,event){
if(frmSetting.lstConfig.count==1){
return frmSetting.msgboxErr("只有一个配置方案时不允许删除!");
}
var selIndex = frmSetting.lstConfig.selIndex;
..table.remove(config.itemData,selIndex);
..table.remove(config.itemNames,selIndex);
frmSetting.lstConfig.delete(selIndex)
selIndex = selIndex<=frmSetting.lstConfig.count ? selIndex : selIndex -1;
config.selItem = null;
frmSetting.lstConfig.selIndex = selIndex;
frmSetting.lstConfig.onSelChange()
}
listEdit.onEditChanged = function(newText,selIndex){
config.itemNames = frmSetting.lstConfig.items;
frmSetting.lstConfig.selIndex = selIndex;
frmSetting.lstConfig.onSelChange();
config.save();
}
frmSetting.btnAdd.skin({
color={
active=0xFF00FF00;
default=0xFF3C3C3C;
disabled=0xFF6D6D6D;
hover=0xFFFF0000
}
})
frmSetting.btnRemove.skin({
color={
active=0xFF00FF00;
default=0xFF3C3C3C;
disabled=0xFF6D6D6D;
hover=0xFFFF0000
}
})
frmSetting.btnEdit.skin({
color={
active=0xFF00FF00;
default=0xFF3C3C3C;
disabled=0xFF6D6D6D;
hover=0xFFFF0000
}
})
if(wb.documentMode<11){
frmSetting.chkKatex.checked = false;
frmSetting.chkKatex.disabled = true;
}
frmSetting.doModal(winform);
}
winform.chkFix.checked = true;
winform.chkFix.oncommand = function(id,event){
var md = wb.getMarkdown();
if(owner.checked){
md = ide.aifix.markdown(md,true)
}
wb.write(md);
}
var tip = /*
- 在代码编辑器中按 `F1` 键可调用`编码助手`帮您续写或补全代码。
* 建议在输入光标前用`行注释`说明需求,再按 `F1` 键。
* 如果按 F1 前已选中代码则会打开文档或 AI 搜索,AI 不会替换选区代码。
* 默认密钥仅提供有限功能,建议<a href="https://platform.deepseek.com">点这里获取新密钥</a>, <a href="javascript:void(0)" onclick="javascript:external.updateApiKey()">点这里设置新密钥</a>以取消限制。
- 聊天界面支持联网自动读取 aardio 文档。
- 按住 `Ctrl`键点下面的 `复制` 按钮可复制 AI 最后一次输出的代码块。
- 按住 `Ctrl`键点下面的 `分享` 可截长屏到剪贴板。
- 请注意查看下面提示词输入框的右键菜单。
- [VIP 专属技术支持服务](https://aardio.com/vip),限时 5 折!
*/
wb.write(tip)
//默认设置输入框焦点
winform.editPrompt.setFocus();
winform.splitter.ltMin = 200;
winform.splitter.rbMin = 150;
var scrollbarHeight = ::User32.GetSystemMetrics(3/*_SM_CYHSCROLL*/)
winform.editPrompt.onOk = function(ctrl,alt,shift){
if(ctrl){
winform.btnSend.oncommand();
return true;
}
var pt = ::POINT()
::User32.GetCaretPos(pt)
var lineCount = winform.editPrompt.lineCount;
var lineHeight = math.ceil(pt.x / lineCount + winform.dpiScale(5));
if(pt.y+(lineHeight+scrollbarHeight)*3>winform.editPrompt.height){
winform.wndBrowser.setRedraw(false)
winform.splitter.splitMove(-lineHeight)
winform.wndBrowser.setRedraw(true)
}
}
//打开 AI 搜索
winform.promptTool.link = "https://www.aardio.com/zh-cn/doc/?q=/zh-cn/ai/prompt/"
winform.promptTool.onHyperlinkClick = function(nmSysLink,url,id,index){
var q = winform.editPrompt.text;
if(#q){
import inet.url;
raw.execute("https://www.aardio.com/zh-cn/ai/prompt/?q="+inet.url.encode(q));
}
else {
raw.execute(url);
}
}
//拆分界面
winform.splitter.split(winform.wndBrowser,winform.editPrompt);
winform.editPrompt.enablePopMenu(function(){
return {
{ '问 AI(发送)\tCtrl+Enter'; function(id){
winform.btnSend.oncommand();
}; 0};
{ /*分隔线*/ };
{ (wb.aiSystemPropmptStringPatterns?"已自动":"")+"插入 模式匹配语法文档"; function(id){
winform.editPrompt.selText = " [aardio 模式匹配语法](https://www.aardio.com/zh-cn/doc/library-guide/builtin/string/patterns.md) "
}; wb.aiSystemPropmptStringPatterns?1/*_MF_GRAYED*/: 0};
{ (wb.aiSystemPropmptWebView?"已自动":"")+"插入 web.view 指南(网页相关)"; function(id){
winform.editPrompt.selText = " [web.view 使用指南](https://www.aardio.com/zh-cn/doc/library-guide/std/web/view/_.md) "
}; wb.aiSystemPropmptWebView?1/*_MF_GRAYED*/: 0};
{ "插入 web.rest 指南(HTTP 相关)"; function(id){
winform.editPrompt.selText = " [web.rest 使用指南](https://www.aardio.com/zh-cn/doc/library-guide/std/web/rest/client.md) "
}; 0};
{ "插入 多线程入门"; function(id){
winform.editPrompt.selText = " [多线程开发入门](https://www.aardio.com/zh-cn/doc/guide/language/thread.md) "
}; 0};
{ "插入 高级选项卡指南(多窗口)"; function(id){
winform.editPrompt.selText = " [高级选项卡指南](https://www.aardio.com/zh-cn/doc/library-guide/std/win/ui/tabs/_.md) "
}; 0};
{ (wb.aiSystemPropmptPlus?"已自动":"")+"插入 plus 控件指南(界面美化)"; function(id){
winform.editPrompt.selText = " [plus 控件使用指南](https://www.aardio.com/zh-cn/doc/library-guide/std/win/ui/ctrl/plus.md) "
}; wb.aiSystemPropmptPlus?1/*_MF_GRAYED*/: 0};
{ "插入 自定义控件指南"; function(id){
winform.editPrompt.selText = " [自定义控件使用指南](https://www.aardio.com/zh-cn/doc/library-guide/std/win/ui/ctrl/custom.md) "
}; 0};
{ (wb.aiSystemPropmptPython?"已自动":"")+"插入 调用 Python 文档"; function(id){
winform.editPrompt.selText = " [aardio 调用 Python 入门指南](https://www.aardio.com/zh-cn/doc/library-guide/ext/python/_.md) "
}; wb.aiSystemPropmptPython?1/*_MF_GRAYED*/: 0};
{ (wb.aiSystemPropmptNet?"已自动":"")+"插入 调用 NET 文档"; function(id){
winform.editPrompt.selText = " [aardio 调用 .NET 入门指南](https://www.aardio.com/zh-cn/doc/library-guide/std/dotNet/_.md) "
}; wb.aiSystemPropmptNet?1/*_MF_GRAYED*/: 0};
{ (wb.aiSystemPropmptSupperHotkeys?"已自动":"")+"插入 超级热键文档"; function(id){
winform.editPrompt.selText = " [超级热键使用指南](https://www.aardio.com/zh-cn/doc/library-guide/std/key/hotkey.md) "
}; wb.aiSystemPropmptSupperHotkeys?1/*_MF_GRAYED*/: 0};
{ "插入原生接口文档(调用 DLL)"; function(id){
winform.editPrompt.selText = " [原生类型](https://www.aardio.com/zh-cn/doc/library-guide/builtin/raw/datatype.md) [结构体](https://www.aardio.com/zh-cn/doc/library-guide/builtin/raw/struct.md) [声明原生 API](https://www.aardio.com/zh-cn/doc/library-guide/builtin/raw/api.md) [原生回调函数](https://www.aardio.com/zh-cn/doc/library-guide/builtin/raw/callback.md) "
}; 0};
{ "检索相关 aardio 文档"; function(id){
var q = winform.editPrompt.selText;
if(#q){
import inet.url;
raw.execute("https://www.aardio.com/zh-cn/ai/prompt/?q="+inet.url.encode(q));
}
}; !owner.canCopy() ? 1/*_MF_GRAYED*/ : 0};
{ "AI 搜索"; function(id){
var q = winform.editPrompt.selText;
if(#q){
import inet.url;
var url = inet.url.appendExtraInfo("http://api.aardio.com/search",{
q = '```aardio \n' + q + '\n```';
})
raw.execute(url);
}
}; !owner.canCopy() ? 1/*_MF_GRAYED*/ : 0};
}
})
global.onError = function( err,over ){
if(!over){
import debug;
var stack = debug.traceback(,"调用栈",3);
err = string.concat(err,stack);
}
if( _STUDIO_INVOKED ) {
import win;
win.msgboxErr(err);
}
}
winform.spinMaxTokens.buddy = winform.editMaxTokens;
winform.spinMaxTokens.setRange(1,1024*8);
winform.spinMaxTokens.pos = config.maxTokens || 1024;
winform.spinMaxTokens.inc = 1024;
winform.beforeDestroy = function(){
config.maxTokens = winform.spinMaxTokens.pos;
}
winform.btnSnap.oncommand = function(id,event){
import fsys.dlg;
import web.form.snap;
if(key.getState("CTRL")){
winform.btnSnap.disabled = true;
web.form.snap(wb,function(bmp){
var hbmp = bmp.copyHandle();
win.clip.writeBitmap(hbmp,true);
return true;
} );
}
else{
var path = fsys.dlg.save("*.jpg|*.jpg","AI 聊天助手 - 保存对话截图",,winform);
if(!path) return;
winform.btnSnap.disabled = true;
web.form.snap(wb,path);
winform.editPrompt.setFocus();
}
wb.doScript(`document.documentElement.scrollTop = document.documentElement.scrollHeight + 50;`);
thread.delay(1000);
winform.btnSnap.disabled = false;
}
//按钮外观样式
winform.btnClear.skin({
color={
active=0xFF00FF00;
default=0xFF3C3C3C;
disabled=0xFF999999;
hover=0xFFFF0000
}
})
//按钮外观样式
winform.btnSend.skin({
color={
active=0xFF00FF00;
default=0xFF3C3C3C;
disabled=0xFF999999;
hover=0xFFFF0000
}
})
//按钮外观样式
winform.btnSetting.skin({
color={
active=0xFF00FF00;
default=0xFF3C3C3C;
disabled=0xFF999999;
hover=0xFFFF0000
}
})
winform.btnCopy.skin({
color={
active=0xFF00FF00;
default=0xFF3C3C3C;
disabled=0xFF999999;
hover=0xFFFF0000
}
})
winform.btnSnap.skin({
color={
active=0xFF00FF00;
default=0xFF3C3C3C;
disabled=0xFF999999;
hover=0xFFFF0000
}
})
winform.chkFix.skin({
color={
active=0xFF00FF00;
default=0xFF000000;
disabled=0xFF999999;
hover=0xFFFF0000
};
checked={
iconText='\uF14A';
color={
active=0xFF00FF00;
default=0xFF000000;
disabled=0xFF999999;
hover=0xFFFF0000
};
}
})
winform.show();
win.loopMessage();
Markdown 格式