aardio 文档
aardio 范例: 专用增强版 Kimi 网页助手 - 点代码块复制按钮自动纠错
//Kimi 网页版 - 自动注入 Prompt 与代码纠错
import win.ui;
/*DSG{{*/
var winform = win.form(text="aardio 专用增强版 Kimi 网页助手 - 点代码块复制按钮自动纠错";right=966;bottom=622)
winform.add()
/*}}*/
import web.view;
//创建 WebView2 浏览器控件
var wb = web.view(winform,{
language = "zh-CN,zh;q=0.9";
userDataDir = _STUDIO_INVOKED ? io.appData("/aardio/webview2/user-data/ide/example/kimi")
})
import ide;
wb.external = {
onCopy = function(text,aardioTag){
import string.aardio;
if( true ){
winform.setTimeout( function(){
import ide.aifix;
var newCode,markdownFormat;
if(string.indexOf(text,"```aardio")){
newCode = ide.aifix.markdown(text,true);
markdownFormat = true;
}
else{
var latinLike = lambda(str) !..string.find(str,":") || (..string.len(str) > #str/1.5);
if(!latinLike(text)) return;
if(!string.find(text,"%\{\}")) return;
newCode = ide.aifix(text,true);
}
if((newCode!=text) && newCode){
if(!markdownFormat){
var f2,err2 = loadcode(newCode);
if(f2) {
import win.clip;
win.clip.write(newCode);
var f1,err1 = loadcode(text);
if(err1){
newCode = '编译你的代码遇到语法错误:\n\n```txt\n'+err1+'\n```\n\n'
+ '由 aardio 自动修正后的代码如下(编译通过无错误):\n\n```aardio\n'+newCode+'\n```\n\n';
wb.invoke("window.inputPrompt2",newCode)
}
}
}
else{
import win.clip;
win.clip.write(newCode);
}
}
else{
if(!markdownFormat){
var f1,err1 = loadcode(text);
if(err1){
var newValue = '编译代码遇到语法错误:\n\n```txt\n'+err1+'\n```\n\n';
wb.invoke("window.inputPrompt2",newValue)
}
}
}
});
}
};
getSystemPrompt = function(){
var prompt = ..string.removeBom(string.load("~\doc\guide\ide\system-prompt.md"));
prompt = string.replace(prompt,"\#\#\s*aardio\s*作者联系方式.*$",'');
var libs = ..string.removeBom(..string.load("~/lib/libs.txt"))
if(libs){
prompt = prompt + '\r\n\r\n---\r\n\r\naardio 全部可用库(内置库、标准库、扩展库)如下:' + libs + '\r\n\r\n以上库都可以用 import 语句导入,例如 `import JSON`。win.ui.ctrl 命名空间内的 custom,static,button,edit,richedit,plus,combobox,listbox,tab,progress,datetimepick,hotkey,listview,vlistview,treeview,checklist,trackbar,scrollbar,spin,calendar,thread,splitter,atlax,syslink,ipaddress,bk,bkplus,close,picturebox 等控件可按需自动导入(不需要再 import)\n\n';
}
return prompt + '## 任务\n\n';
};
busyHandler = function(){
/*
XPath 默认不识别 svg 特殊的 XML 命名空间,用 svg 作为标签名找不到节点。
要改用 local-name() 函数来绕过 XML 命名空间限制。
例如 `//*[local-name()='svg' and @name='Refresh']]`
*/
wb.waitEle(`//div[contains(@class, 'segment-429-tip') and contains(., '高峰期算力不足')]/following-sibling::div[contains(@class, 'segment-assistant-actions')]//div[contains(@class, 'icon-button') and .//*[local-name()='svg' and @name='Refresh']]`
,`this.click();setTimeout(aardio.busyHandler,1000)`);
}
}
//定义字符串 initScript,赋值为需要执行的 JavaScript
var initScript = /****
(function() {
// ---- 剪贴板处理部分 ----
const originalWriteText = navigator.clipboard.writeText;
navigator.clipboard.writeText = async function(text) {
if( ! await aardio.onCopy(text) ){
return originalWriteText.apply(this, arguments);
}
};
const originalSetData = DataTransfer.prototype.setData;
DataTransfer.prototype.setData = function(format, data) {
if (format === 'text/plain') {
aardio.onCopy(data);
}
return originalSetData.apply(this, arguments);
};
document.addEventListener('copy', async (event) => {
const selection = window.getSelection().toString();
if(selection) aardio.onCopy(selection);
});
localStorage.setItem('selectModel', `{"scenario":9,"thinking":true}`);
localStorage.setItem('selectSearch', `true`);
// ---- 网络请求拦截注入 Prompt 部分 ----
let cachedPrompt = "";
// 初始化时从 aardio 后台拉取 prompt
aardio.getSystemPrompt().then(p => { cachedPrompt = p });
const originalFetch = window.fetch;
window.fetch = async function(...args) {
let [resource, config] = args;
let url = (resource instanceof Request) ? resource.url : String(resource);
// Kimi 发送消息的接口
if (url.includes('/apiv2/kimi.gateway.chat.v1.ChatService/Chat')) {
try {
// 判断是否是新建对话:Kimi 首页路径为 '/',已经在对话中路径为 '/chat/xxx'
// 我们只在首页(新建对话时)注入庞大的 prompt,避免在对话过程中重复注入消耗 Token
if (window.location.pathname === '/' && cachedPrompt) {
let bodyBuffer = null;
if (resource instanceof Request) {
const newReq = resource.clone();
bodyBuffer = await newReq.arrayBuffer();
} else if (config && config.body) {
bodyBuffer = config.body; // fetch(url, {body: Uint8Array})
}
if (bodyBuffer) {
let bytes = new Uint8Array(bodyBuffer);
// 验证是否是 Connect RPC 的 5 字节协议头(第一位为 0)
if (bytes.length > 5 && bytes[0] === 0) {
// 1. 剥离前 5 个字节,解析后面的 JSON
let jsonBytes = bytes.slice(5);
let jsonString = new TextDecoder('utf-8').decode(jsonBytes);
let data = JSON.parse(jsonString);
// 2. Kimi 的新版 JSON 结构: data.message.blocks[0].text.content
if (data.message && data.message.blocks && data.message.blocks.length > 0) {
let textNode = data.message.blocks[0].text;
if (textNode && textNode.content) {
// 【核心注入点】拼接提示词和用户输入
textNode.content = cachedPrompt + textNode.content;
// 3. 重新编码为 UTF-8 字节
let newJsonBytes = new TextEncoder().encode(JSON.stringify(data));
let newLen = newJsonBytes.length;
// 4. 重建 Connect RPC 的 5 字节头部 (大端序长度)
let newPayload = new Uint8Array(5 + newLen);
newPayload[0] = 0; // 压缩标志:0
newPayload[1] = (newLen >> 24) & 0xFF;
newPayload[2] = (newLen >> 16) & 0xFF;
newPayload[3] = (newLen >> 8) & 0xFF;
newPayload[4] = newLen & 0xFF;
// 5. 拼接头部和新 JSON 数据
newPayload.set(newJsonBytes, 5);
// 6. 替换原始请求的数据
if (resource instanceof Request) {
resource = new Request(resource, { body: newPayload });
// 清除旧的 resource 配置,防止冲突
config = undefined;
} else {
config.body = newPayload;
}
}
}
}
}
}
} catch (e) {
console.error("拦截 Kimi 请求修改 Prompt 失败:", e);
}
}
return originalFetch.apply(this, [resource, config]);
};
})();
****/
wb.preloadScript(initScript)
wb.go("https://www.kimi.com/");
wb.external.busyHandler();
winform.show();
win.loopMessage();
Markdown 格式