# aardio 范例: 免费 OCR API（ocr.space）

```aardio
//免费 OCR API（ocr.space）
//相关范例 - 简单 OCR: https://www.aardio.com/zh-cn/doc/example/Automation/ComputerVision/soImage.ocr.example.html

import win.ui;
import win.dlg.message;
import fonts.fontAwesome;
/*DSG{{*/
var winform = win.form(text="OCR 识别 - 自动导入剪贴板图像";right=1169;bottom=573)
winform.add(
bkplus={cls="bkplus";left=-17;top=516;right=1170;bottom=575;bgcolor=0xD2D2D2;db=1;dl=1;dr=1;z=1};
btnOcr={cls="plus";text="识别文本";left=843;top=533;right=940;bottom=563;align="left";color=0x3C3C3C;db=1;dr=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=8}};iconText='\uF0F6';notify=1;textPadding={left=25};z=6};
btnOpen={cls="plus";text="打开图像文件";left=366;top=532;right=499;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=233;top=532;right=352;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=5};
btnScreenClip={cls="plus";text="截屏";left=149;top=532;right=219;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=10};
comboLanguage={cls="combobox";left=686;top=537;right=824;bottom=563;db=1;dr=1;edge=1;items={};mode="dropdown";vscroll=1;z=8};
edit={cls="richedit";left=589;top=0;right=1168;bottom=515;autohscroll=false;aw=1;db=1;dr=1;dt=1;edge=1;link=1;multiline=1;vscroll=1;z=3};
lbLanguage={cls="static";text="语言：";left=612;top=532;right=675;bottom=562;align="right";center=1;db=1;dr=1;transparent=1;z=9};
lnkOptimize={cls="plus";text="AI 优化";left=961;top=533;right=1048;bottom=563;align="left";color=0x3498DB;db=1;disabled=1;dr=1;font=LOGFONT(h=-14);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome')};iconText='\uF0D0 ';notify=1;textPadding={left=18};z=11};
lnkTranslate={cls="plus";text="AI 翻译";left=1063;top=533;right=1150;bottom=563;align="left";color=0x3498DB;db=1;disabled=1;dr=1;font=LOGFONT(h=-14);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome')};iconText='\uF0DB';notify=1;textPadding={left=18};z=12};
picturebox={cls="plus";text="请复制图像到剪贴板 / 或拖放文件到此处";left=0;top=0;right=584;bottom=515;aw=1;bgcolor=0xFFFFFF;color=0x999999;db=1;dl=1;dt=1;edge=1;font=LOGFONT(h=-16);iconStyle={font=LOGFONT(h=-60;name='FontAwesome')};iconText='\uF03E';repeat="scale";textPadding={top=100};z=2};
splitter={cls="splitter";left=583;top=0;right=588;bottom=515;bgcolor=0xFFFFFF;db=1;dt=1;frame=1;z=7}
)
/*}}*/

var ocr = function(winform,dataUrl){
	
	import web.rest.jsonLiteClient;
	var http = web.rest.jsonLiteClient();  

	// 此 API key 仅临时有效，稍后删除。
	var keyIndex = time().addDays(0).dayofyear%2 + 1;
	http.setHeaders( apikey = (["K83647549188957","K86141664788957"])[keyIndex] );
	/*
	自己申请一个永久免费 API key 非常简单 。
	
	1. 打开 https://mail.tm/zh/ 复制临时邮箱地址
	2. 打开 https://ocr.space/ocrapi/freekey 注册并输入上面的邮箱地址
	3. 回到 mail.tm 点刷新，点击确认邮件中的 “Yes, subscribe me to the free OCR API list.”
	4. 再次刷新并查收新邮件收到的  OCR API key 
	*/
	
	// 接口文档: https://ocr.space/OCRAPI
	var ocrApi = http.api("https://api.ocr.space/");
	
    var langId = string.match(winform.comboLanguage.selText,"\s+(\w+)$");
	
    var result,err = ocrApi.parse.image({
        base64Image = dataUrl;
        language = langId; 
        OCREngine = 2;    // 引擎 2 对中文和特殊字符支持更好
        isTable = true;   // 表格或收据,这里只能指定为 true 否则报参数错。
    })
    
	if(result){
		// 检查 OCR 退出状态码 (1 为成功,2 为部分成功)
        if( result.OCRExitCode == 1 || result.OCRExitCode == 2 ){
            var parsedResults = result.ParsedResults;
            if(#parsedResults){ 
                var text  = table.map(parsedResults,lambda(v,k) v.ParsedText ) 
                winform.edit.text = string.join(text,'\n\n'); 
                winform.lnkTranslate.disabled = false;
                winform.lnkOptimize.disabled = false;
            } 
        }
        else {
             winform.edit.print(result.ErrorMessage || result.ErrorDetails || "OCR 失败");
        }
	} 
	else{
		if(err==`"The API key is invalid"`){
			winform.edit.text = "请到 https://ocr.space/ocrapi/freekey 输入邮箱并领取免费 key"
		}
		else  winform.edit.text = err||"未知错误"
	}
	
	winform.btnOcr.disabledText = null;	
	winform.picturebox.disabledText = null;	
}

winform.btnOcr.oncommand = function(id,event){
	if(winform.picturebox.backgroundBitmap){ 
		winform.edit.text = "识别中 ..."
		winform.btnOcr.disabledText = ['\uF254','\uF251','\uF252','\uF253','\uF250',text='识别中 ...']
		
		import inet.urlData;
		thread.invoke(ocr,winform,inet.urlData.fromBitmap(winform.picturebox.backgroundBitmap));
	}
	else {
		winform.msgErr("请先复制图像到剪贴板 / 或打开图像文件")
	} 
}

import fsys.dlg;
winform.btnOpen.oncommand = function(id,event){
	var path = fsys.dlg.open("图像文件|*.jpg;*.jpeg;*.jfif;*.bmp;*.gif;*.png;*.tif;*.tiff;*.webp||",,,winform)
	if(path){
		if(string.endsWith(path,".webp",true)){
			import gdip.webp;
		}
		winform.picturebox.background = path; 
		winform.picturebox.backgroundBitmap = gdip.bitmap(path);
		winform.picturebox.text = null;
        winform.picturebox.iconText = null;
	}
}

winform.lnkTranslate.oncommand = function(id,event){
	var text = string.trim(winform.edit.text);
	if(#text){
		import web.edgeTextToSpeech.translate; 
		var transForm = web.edgeTextToSpeech.translate(,text) 
		transForm.text = "OCRAPI 中英翻译 - 此页面支持英文划词速查";
		transForm.doModal();
	} 
	else {
		winform.msgErr("识别结果为空")
	} 
}

winform.onDropFiles = function(files){
	var path = files[1]
	if(path){
		if(string.endsWith(path,".webp",true)){
			import gdip.webp;
		}
		
		winform.picturebox.backgroundBitmap = gdip.bitmap(path);
		if(winform.picturebox.backgroundBitmap){
			winform.picturebox.background = path; 
		} 
	}
}

import win.clip.bitmap;
winform.btnPaste.oncommand = function(id,event){
	var bmp = win.clip.bitmap.read()
	if(bmp){ 
		winform.picturebox.backgroundBitmap = bmp;
		winform.picturebox.background = bmp;
		winform.picturebox.text = null;
        winform.picturebox.iconText = null;
	}
}

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(id,event){
	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.edit.enablePopMenu()

winform.splitter.split(winform.picturebox,winform.edit);

// 定义一个统一的按钮皮肤样式
var btnSkin = {
    color = {
        default = 0xFF3C3C3C; // 默认深灰色文本
        hover = 0xFF0078D4;   // 鼠标悬停变蓝色
        active = 0xFF005A9E;  // 鼠标按下变深蓝色
        disabled = 0xFFAAAAAA; // 禁用状态灰色
    };
    background = {
        hover = 0x1A0078D4;   // 悬停时淡淡的背景色
        active = 0x330078D4;  // 按下时稍深的背景色
    }
}

// 批量为所有按钮应用样式
for i,ctrl in [
    winform.btnPaste,
    winform.btnOcr,
    winform.lnkTranslate,
    winform.btnOpen,
    winform.btnScreenClip
] {
    ctrl.skin(btnSkin);
}

winform.lnkOptimize.skin({
    color = {
        default = 0xFF3498DB;
        hover = 0xFF2980B9;
        active = 0xFF1F618D;
         disabled=0xFFAAAAAA;
    }
})

winform.lnkTranslate.skin({
    color = {
        default = 0xFF3498DB;
        hover = 0xFF2980B9;
        active = 0xFF1F618D;
         disabled=0xFFAAAAAA;
    }
})

/*
支持的全部语言
Arabic=ara
Bulgarian=bul
Chinese(Simplified)=chs
Chinese(Traditional)=cht
Croatian = hrv
Czech = cze
Danish = dan
Dutch = dut
English = eng
Finnish = fin
French = fre
German = ger
Greek = gre
Hungarian = hun
Korean = kor
Italian = ita
Japanese = jpn
Polish = pol
Portuguese = por
Russian = rus
Slovenian = slv
Spanish = spa
Swedish = swe
Thai = tha
Turkish = tur
Ukrainian = ukr
Vietnamese = vnm

全部添加到下拉框，格式例如
winform.comboLanguage.items = ["自动检测","简体中文 chs","繁体中文 cht","英文 enu"]

所有语言有空格分开标题与 ID，以便在程序中自动提取后面的语言 ID
*/
winform.comboLanguage.items = {
    "自动检测 auto";
    "简体中文 chs";
    "繁体中文 cht";
    "阿拉伯语 ara";
    "保加利亚语 bul";
    "克罗地亚语 hrv";
    "捷克语 cze";
    "丹麦语 dan";
    "荷兰语 dut";
    "英语 eng";
    "芬兰语 fin";
    "法语 fre";
    "德语 ger";
    "希腊语 gre";
    "匈牙利语 hun";
    "韩语 kor";
    "意大利语 ita";
    "日语 jpn";
    "波兰语 pol";
    "葡萄牙语 por";
    "俄语 rus";
    "斯洛文尼亚语 slv";
    "西班牙语 spa";
    "瑞典语 swe";
    "泰语 tha";
    "土耳其语 tur";
    "乌克兰语 ukr";
    "越南语 vnm"
}

winform.lnkOptimize.oncommand = function(id,event){
	var text = string.trim(winform.edit.text);
	if(!#text){
		return winform.msgboxErr("识别结果为空")
	}
	
	winform.btnOcr.disabled = true;
	winform.lnkTranslate.disabled = true; 
	winform.lnkOptimize.disabledText = ['\uF254','\uF251','\uF252','\uF253','\uF250']
			
	thread.invoke( 
		function(winform,text){
			
			import web.rest.aiChat;
			var aiClient = web.rest.aiChat(
				key =   '\0\1\96';
				url = "https://ai.aardio.com/api/v1/";//接口地址
				model = "prompt";
				temperature = 0.5;//温度
				maxTokens = 1024 //最大回复长度
			)
			
			//2. 第二步：创建消息队列，必须在这里保存对话，不然 AI 的回复没有上下文。
			//---------------------------------------------------------------------
			var msg = web.rest.aiChat.message();
			
			//可调用 msg.system() 函数添加系统提示词。
			msg.system(`# 角色
你是一位 OCR 图文识别结果修复工程师。

# 任务

用户输入的文本是使用 OCR 图文识别工具的识别结果。
你的任务是在尊重图文原意的基础上对识别结果进行评估与修复，纠正识别错误。

你应当根据文本相关的文化与背景知识对识别结果的格式进行整理。
如果识别结果中出现与前后文本完全不相关的多余字符应当去除（较大可能可以判定为 OCR 工具将非字符图形误判为文字）。

输出格式为纯文本，不使用 Markdown 标记（除非识别结果本身包含 Markdown 标记）。

# 要求  
无需解释你的思考过程，直接输入回复。
`)

			
			//添加用户提示词
			msg.prompt( "请修复 OCR 识别结果: " + text );
			 
			winform.edit.text = "";
			
			var resp,err = aiClient.messages(msg,
				function(deltaText,reasoning){
					 if(deltaText) winform.edit.appendText(deltaText); 
					 
				}
			);
			
			winform.btnOcr.disabled = false;
			winform.lnkTranslate.disabled = false; 
			winform.lnkOptimize.disabledText = null;
		},winform,text
	)	
}

winform.comboLanguage.selIndex = 1;

winform.show()
win.loopMessage();
```