# aardio 范例: 专用增强版 Kimi 网页助手 - 点代码块复制按钮自动纠错

``````aardio
//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();
``````