# aardio 范例: DeepSeek OCR - AI 图像识别，HF 接口

```aardio
//DeepSeek OCR - AI 图像识别，HF 接口
import win.ui;
import win.ui.simpleWindow;
import fonts.fontAwesome;
import gdip.webp;//导入则 plus 控件可显示 WebP 图像
import inet.http; // 使 plus 控件支持远程图像 URL
/*DSG{{*/
var winform = win.form(text="DeepSeek OCR - AI 图像识别";right=1169;bottom=573;bgcolor=0xF5F5F5;border="none")
winform.add(
bkplus={cls="bkplus";left=0;top=516;right=1170;bottom=575;bgcolor=0xE8E8E8;db=1;dl=1;dr=1;z=1};
bkplus2={cls="bkplus";text="DeepSeek OCR 2";left=23;top=4;right=238;bottom=35;align="left";color=0xEEEEEE;z=19};
btnCopy={cls="plus";text="复制结果";left=1030;top=532;right=1140;bottom=562;align="left";color=0x3C3C3C;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=5};
btnOcr={cls="plus";text="识别文本";left=900;top=532;right=1010;bottom=562;align="left";bgcolor=0x3498DB;border={radius=4};color=0xFFFFFF;db=1;dr=1;font=LOGFONT(h=-13;weight=600);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=10}};iconText='\uF0F6';notify=1;textPadding={left=28};z=7};
btnOpen={cls="plus";text="打开图像文件";left=180;top=532;right=300;bottom=562;align="left";color=0x3C3C3C;db=1;dl=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=8}};iconText='\uF03E';notify=1;textPadding={left=25};z=4};
btnPaste={cls="plus";text="粘贴";left=100;top=532;right=170;bottom=562;align="left";color=0x3C3C3C;db=1;dl=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=8}};iconText='\uF0EA';notify=1;textPadding={left=25};z=6};
btnScreenClip={cls="plus";text="截屏";left=20;top=532;right=90;bottom=562;align="left";color=0x3C3C3C;db=1;dl=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=11};
comboTask={cls="combobox";left=365;top=537;right=560;bottom=563;db=1;dl=1;edge=1;items={'\uD83D\uDCCB Markdown','\uD83D\uDCDD Free OCR','\uD83D\uDCCD Locate','\uD83D\uDD0D Describe','\u270F\uFE0F Custom'};mode="dropdownlist";z=13};
edit={cls="edit";left=589;top=40;right=1168;bottom=515;autohscroll=false;aw=1;db=1;dr=1;dt=1;edge=1;multiline=1;vscroll=1;z=3};
editPrompt={cls="edit";left=580;top=537;right=880;bottom=563;db=1;dr=1;edge=1;hide=1;z=15};
lbTask={cls="static";text="任务：";left=310;top=532;right=360;bottom=562;align="right";center=1;db=1;dl=1;transparent=1;z=12};
picturebox={cls="plus";text="请复制图像到剪贴板 / 或拖放文件到此处";left=0;top=40;right=584;bottom=515;bgcolor=0xFFFFFF;border={color=0xFFE0E0E0;width=1};color=0x999999;db=1;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={font=LOGFONT(h=-60;name='FontAwesome')};iconText='\uF03E';notify=1;repeat="scale";textPadding={top=100};z=2};
resultPicture={cls="plus";left=589;top=40;right=1168;bottom=515;aw=1;bgcolor=0xFFFFFF;border={color=0xFFE0E0E0;width=1};db=1;dr=1;dt=1;hide=1;repeat="scale";z=16};
splitter={cls="splitter";left=583;top=40;right=588;bottom=515;bgcolor=0xFFFFFF;db=1;dt=1;frame=1;z=8};
tabLayout={cls="plus";text="布局检测";left=689;top=7;right=789;bottom=37;align="left";color=0xEEEEEE;dr=1;dt=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=11;top=1}};iconText='\uF03E';notify=1;textPadding={left=28;bottom=1};z=18};
tabResult={cls="plus";text="识别结果";left=589;top=7;right=689;bottom=37;align="left";color=0x3498DB;dr=1;dt=1;font=LOGFONT(h=-13;weight=600);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=11;top=1}};iconText='\uF0F6';notify=1;textPadding={left=28;bottom=1};z=17};
titleBar={cls="bkplus";left=0;top=0;right=1170;bottom=40;bgcolor=0x2C3E50;dl=1;dr=1;dt=1;z=14};
titleIcon={cls="bkplus";text='\uF1C5';left=15;top=8;right=45;bottom=34;color=0x3498DB;dl=1;dt=1;font=LOGFONT(h=-18;name='FontAwesome');z=9};
titleText={cls="bkplus";text="DeepSeek OCR - AI 图像识别";left=50;top=10;right=300;bottom=32;color=0xFFFFFF;dl=1;dt=1;font=LOGFONT(h=-15;weight=700);z=10}
)
/*}}*/

// 初始化下拉框选中项
winform.comboTask.selIndex = 1;  // 📋 Markdown

// 任务类型切换时显示/隐藏提示词输入框
winform.comboTask.onSelChange = function(){
    var taskType = owner.selText;
    // Locate 和 Custom 任务需要输入提示词
    winform.editPrompt.show(taskType == "📍 Locate" || taskType == "✏️ Custom");
}

import win.ui.tabs;
var tabs = win.ui.tabs(winform.tabResult,winform.tabLayout);
tabs.panel = null;

// 结果标签页切换
tabs.onSelChange = function(tabIndex,tabButton,formPage){
	showText = tabIndex == 1;
    winform.edit.show(showText);
    winform.resultPicture.show(!showText);
}
winform.editPrompt.setCueBannerText("请输入识别提示词",true);
winform.showResultPicture = function(){
	tabs.selIndex = 2;
}

// OCR 识别核心函数（线程内执行）
var doOcr = function(winform, dataUrl, taskType, customPrompt){
    import web.rest.gradioClient;
    
    // 创建 Gradio 客户端，使用新的 Space ID
    var gradio = web.rest.gradioClient("merterbak/DeepSeek-OCR-Demo", {
        // proxy = "socks=127.0.0.1:1081" // 可选指定代理
    });
    
    winform.edit.text = "正在上传图像...";
    
    // 图像数据格式
    var imageData = {
        url = dataUrl;
        orig_name = "image.png";
        meta = { _type = "gradio.FileData" };
    };
    
    winform.edit.text = "正在识别中，请稍候（需排队）...";
    
    // 调用新的 /run API 端点
    var result, err = gradio.xcall.run({
        data = [
            imageData,      // image: 图像数据
            null,           // file_path: 文件路径（用于 PDF，这里不使用）
            taskType,       // task: 任务类型
            customPrompt || "",  // custom_prompt: 提示词
            1               // page_num: 页码
        ]
    });
     
    if(result){
        // 返回值结构：[value_14, value_17, value_23, value_19, value_21]
        // value_14: Textbox（原始文本）
        // value_17: Markdown（格式化结果）
        // value_23: Textbox（另一个文本）
        // value_19: Image（结果图像）
        // value_21: Gallery（图片库）
        
        var ocrText = result[1] || result[2] || result[3];
        var layoutImage = result[4];
        var gallery = result[5];
        
        if(ocrText){
            // 去掉 Reference 与 Detection 标签(DeepSeek OCR,Qwen-VL 的 OCR 定位标签 Special Tokenized Format )
            ocrText = string.replace(ocrText, "\<\|<\a+>\|\>.+?\<\|/\1\|\>", "");
            winform.edit.text = string.crlf(ocrText,'\r\n');
            winform.btnCopy.disabled = false; 
            winform.showResultPicture();
        }
        else {
            winform.edit.text = "识别结果为空";
        }
        
        // 处理布局检测图像
        if(layoutImage){
            var webpUrl = layoutImage.url;
            if(webpUrl){
                winform.resultPicture.background = webpUrl;//WebP 图像
                winform.tabLayout.iconText = '\uF00C'; // 有结果时显示勾选图标
            }
        }
        elseif(gallery && #gallery > 0){
            // 尝试从 Gallery 获取第一张图
            var firstItem = gallery[1];
            if(firstItem){
                var img = firstItem.image;
                if(img){
                    var webpUrl = img.url;
                    if(webpUrl){
                        winform.resultPicture.background = webpUrl;
                        winform.tabLayout.iconText = '\uF00C';
                    }
                }
            }
        }
        else {
            winform.resultPicture.background = null;
            winform.resultPicture.text = "此任务无布局检测结果";
            winform.resultPicture.iconText = '\uF05E';
            winform.tabLayout.iconText = '\uF03E';
        }
    }
    else {
        winform.edit.text = "识别失败：" + (err || "未知错误");
    }
    
    winform.btnOcr.disabledText = null;
}

// 识别按钮点击事件
winform.btnOcr.oncommand = function(){
    if(!winform.picturebox.backgroundBitmap){
        return winform.msgbox("请先打开或拖放图像文件", "提示", "warn");
    }
    
    var taskType = winform.comboTask.selText;
    var customPrompt = winform.editPrompt.text;
    
    // 如果选择了 Locate 或 Custom 任务但没有输入提示词
    if((taskType == "📍 Locate" || taskType == "✏️ Custom") && !#string.trim(customPrompt)){
        return winform.msgbox("请输入提示词", "提示", "warn");
    }
    
    // 禁用按钮，显示加载动画
    winform.btnOcr.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'};
    winform.btnCopy.disabled = true;
    winform.edit.text = "正在连接服务器...";
    
    // 重置布局检测结果
    winform.resultPicture.background = null;
    winform.resultPicture.text = null;
    winform.resultPicture.iconText = null;
    tabs.selIndex = 1;
    
    // 将位图转换为 data URL 并在新线程中执行 OCR
    import inet.urlData;
    var dataUrl = inet.urlData.fromBitmap(winform.picturebox.backgroundBitmap);
    thread.invoke(doOcr, winform, dataUrl, taskType, customPrompt);
}

// 加载图像的通用函数
var loadImage = function(path){
    if(string.endsWith(path, ".webp", true)){
        import gdip.webp;
    }
    
    var bmp = gdip.bitmap(path);
    if(bmp){
        winform.picturebox.background = path;
        winform.picturebox.backgroundBitmap = bmp; // 保存位图对象
        winform.picturebox.text = null;
        winform.picturebox.iconText = null;
        winform.text = "DeepSeek OCR - " + io.splitpath(path).file;
    }
    else {
        winform.msgboxErr("无法加载图像文件", "错误");
    }
}

// 打开文件按钮
import fsys.dlg;
winform.btnOpen.oncommand = function(){
    var path = fsys.dlg.open(
        "图像文件|*.jpg;*.jpeg;*.jfif;*.bmp;*.gif;*.png;*.tif;*.tiff;*.webp||",
        , , winform
    );
    if(path){
        loadImage(path);
    }
}

// 拖放文件支持
winform.onDropFiles = function(files){
    var path = files[1];
    if(path){
        loadImage(path);
    }
}

// 粘贴按钮
import win.clip.bitmap;
winform.btnPaste.oncommand = function(){
    var bmp = win.clip.bitmap.read();
    if(bmp){
        winform.picturebox.background = bmp;
        winform.picturebox.backgroundBitmap = bmp; // 直接保存位图对象
        winform.picturebox.text = null;
        winform.picturebox.iconText = null;
        winform.text = "DeepSeek OCR - 剪贴板图像";
    }
}

// 剪贴板监视器 - 自动导入图像
import win.clip.viewer;
winform.clipViewer = win.clip.viewer(winform);
winform.clipViewer.onDrawClipboard = function(){
    if(winform.screenclip){
        win.showForeground(winform.hwnd);
        winform.screenclip = false;
    }
    winform.btnPaste.oncommand();
}

// 启动时自动粘贴剪贴板图像
winform.btnPaste.oncommand();

// 截屏按钮
winform.btnScreenClip.oncommand = function(){
    winform.show(6/*_SW_MINIMIZE*/);
    winform.screenclip = true;
    
    import win.clip.screen;
    win.clip.screen();
}

winform.onActivate = function(state, hwndOther, minimized){
    if(state){
        winform.screenclip = false;
    }
}

// 复制结果按钮
winform.btnCopy.oncommand = function(){
    var text = string.trim(winform.edit.text);
    if(#text){
        import win.clip;
        win.clip.write(text);
        
        // 显示复制成功提示
        winform.btnCopy.text = "已复制 ✓";
        winform.setTimeout(function(){
            winform.btnCopy.text = "复制结果";
        }, 1500);
    }
}

winform.edit.text = /*
任务 (Task) 选项：
---------------------------------------------
- 📋 Markdown: 识别排版 | 自动识别表格、标题，输出格式化文档（推荐）。
- 📝 Free OCR: 纯文本 | 提取所有文字，不保留排版格式。
- 📍 Locate: 视觉定位 | 输入物体名称（如"红色按钮"），返回坐标并画框。
- 🔍 Describe: 看图说话 | 分析统计图/流程图含义，而非单纯识字。
- ✏️ Custom: 自定义 | 输入自定义提示词，灵活控制识别行为。

使用说明：
---------------------------------------------
1. 通过截屏、粘贴或打开文件加载图像
2. 选择合适的任务类型
3. Locate 和 Custom 任务需要在右侧输入提示词
4. 点击「识别文本」开始识别
*/

// 右键菜单
winform.edit.enablePopMenu();

// 分割条
winform.splitter.split(winform.picturebox, [winform.edit,winform.resultPicture]);


// 设置选项卡交互样式
tabs.skin({
 
	color = {
		default = 0xFFEEEEEE;
		hover = 0xFF3498DB;
	};
	checked = {
		color = { default = 0xFFDB9834; hover = 0xFF3498DB; };
	}
})
//winform.tabLayout.iconText = '\uF00C'; // 有结果时显示勾选图标


// 按钮统一样式
var btnSkin = {
    color = {
        default = 0xFF3C3C3C;
        hover = 0xFF0078D4;
        active = 0xFF005A9E;
        disabled = 0xFFAAAAAA;
    };
    background = {
        hover = 0x1A0078D4;
        active = 0x330078D4;
    }
}

for i, ctrl in [
    winform.btnPaste,
    winform.btnOpen,
    winform.btnScreenClip,
    winform.btnCopy
] {
    ctrl.skin(btnSkin);
}

// 识别按钮特殊样式
winform.btnOcr.skin({
    background = {
        default = 0xFF3498DB;
        hover = 0xFF2980B9;
        active = 0xFF1F618D;
        disabled = 0xFFBDC3C7;
    };
    color = {
        default = 0xFFFFFFFF;
        disabled = 0xFF7F8C8D;
    }
});

// 复制按钮样式
winform.btnCopy.skin({
    color = {
        default = 0xFF27AE60;
        hover = 0xFF229954;
        active = 0xFF1E8449;
        disabled = 0xFFAAAAAA;
    };
    background = {
        hover = 0x1A27AE60;
        active = 0x3327AE60;
    }
});

// 无边框窗口样式
win.ui.simpleWindow(winform);

winform.show();
win.loopMessage();
```