# aardio 范例: ChatGPT Images 2.0 文生图



```aardio
import win.ui.simpleWindow;
import fonts.fontAwesome;
import gdip.webp;
import win.ui;
/*DSG{{*/
var winform = win.form(text="ChatGPT Images 2.0 文生图";right=1150;bottom=700;bgcolor=0xF5F5F5;border="none")
winform.add(
btnCopy={cls="plus";text="复制图像 / 图像文件";left=921;top=631;right=1110;bottom=680;align="left";anchors={right=1;bottom=1};bgcolor=0x27AE60;border={radius=6};color=0xFFFFFF;disabled=1;font=LOGFONT(h=-14;weight=600);iconStyle={align="left";font=LOGFONT(h=-14;name='FontAwesome');padding={left=17;top=1}};iconText='\uF0EA';notify=1;textPadding={left=37};z=19};
btnGenerate={cls="plus";text="生成图像";left=742;top=631;right=902;bottom=680;align="left";anchors={right=1;bottom=1};bgcolor=0x3498DB;border={radius=6};color=0xFFFFFF;font=LOGFONT(h=-15;weight=600);iconStyle={align="left";font=LOGFONT(h=-16;name='FontAwesome');padding={left=17;top=1}};iconText='\uF1FC';notify=1;textPadding={left=37};z=18};
btnOpenKeyUrl={cls="plus";text="设置 API 接口";left=748;top=86;right=872;bottom=116;align="left";anchors={top=1;right=1};color=0x3498DB;iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome')};iconText='\uF08E';notify=1;textPadding={left=18};z=15};
comboBackground={cls="combobox";left=745;top=306;right=1105;bottom=331;anchors={right=1;bottom=1};edge=1;items={"auto","opaque","transparent"};mode="dropdownlist";z=14};
comboFormat={cls="combobox";left=745;top=245;right=1105;bottom=270;anchors={right=1;bottom=1};edge=1;items={"png","jpeg","webp"};mode="dropdownlist";z=12};
comboSize={cls="combobox";left=745;top=184;right=1105;bottom=209;anchors={top=1;right=1};edge=1;items={"auto","1024x1024","2048x2048","1536x1024","2048x1152","3840x2160","1024x1536","2160x3840"};mode="dropdownlist";z=10};
editPrompt={cls="edit";left=30;top=565;right=710;bottom=680;anchors={left=1;right=1;bottom=1};autohscroll=false;bgcolor=0xFFFFFF;edge=1;multiline=1;vscroll=1;z=8};
labelBackground={cls="bkplus";text="背景 (Background)：";left=745;top=282;right=930;bottom=302;align="left";anchors={right=1;bottom=1};color=0x666666;z=13};
labelFormat={cls="bkplus";text="输出格式 (Format)：";left=745;top=221;right=930;bottom=241;align="left";anchors={right=1;bottom=1};color=0x666666;z=11};
labelPrompt={cls="bkplus";text="提示词 (Prompt)：";left=30;top=540;right=200;bottom=560;align="left";anchors={left=1;bottom=1};color=0x999999;font=LOGFONT(h=-13;weight=600);z=7};
labelSettings={cls="bkplus";text="AI 图像生成设置";left=745;top=51;right=940;bottom=71;align="left";anchors={top=1;right=1};color=0x999999;font=LOGFONT(h=-13;weight=600);z=5};
labelSize={cls="bkplus";text="尺寸 (Size)：";left=745;top=160;right=930;bottom=180;align="left";anchors={top=1;right=1};color=0x666666;z=9};
labelTip={cls="plus";left=767;top=556;right=1069;bottom=607;anchors={right=1;bottom=1};border={color=0x008000;radius=16;width=1};hide=1;z=16};
picturebox={cls="plus";text="请在下方输入提示词生成图像";left=30;top=57;right=710;bottom=500;anchors={left=1;top=1;right=1;bottom=1};border={color=0xEEEEEE;radius=8;width=1};color=0x999999;font=LOGFONT(h=-16);iconStyle={font=LOGFONT(h=-60;name='FontAwesome')};iconText='\uF03E';notify=1;repeat="scale";textPadding={top=100};z=3};
progressBar={cls="plus";left=812;top=138;right=1023;bottom=349;anchors={top=1;right=1;bottom=1};bgcolor=0xECF0F1;border={radius=3};forecolor=0x3498DB;hide=1;z=17};
settingsGroup={cls="bkplus";left=730;top=57;right=1120;bottom=612;anchors={top=1;right=1;bottom=1};bgcolor=0xFFFFFF;border={color=0x000000};z=1};
titleBar={cls="bkplus";left=0;top=0;right=1150;bottom=46;anchors={left=1;top=1;right=1};bgcolor=0x2C3E50;z=2};
titleIcon={cls="bkplus";text='\uF03E';left=284;top=6;right=324;bottom=42;anchors={left=1;top=1};color=0x3498DB;font=LOGFONT(h=-20;name='FontAwesome');z=6};
titleText={cls="bkplus";text="通用文生图(web.rest.aiImage)";left=16;top=10;right=289;bottom=34;anchors={left=1;top=1};color=0xFFFFFF;font=LOGFONT(h=-16;weight=700);z=4}
)
/*}}*/

import fsys.table;
var configImage = fsys.table(io.appData("aardio/std/examples/AI/images/OpenAI2.table"),{
	edit = "text";
	comboSize = "1024x1024";
	comboFormat = "png";
	comboBackground = "auto";
	editPrompt = `A cinematic photo of a tiny astronaut riding a corgi on Mars, dramatic sunset, ultra detailed, 35mm lens.`;
	selItem = 1;
	itemData = [{
		key= '';
		model="gpt-image-2.5-flare";
		temperature=1; 
	}] 
});
var aiChatConfig = configImage.itemData[[configImage.selItem]] : {}  ;

winform.bindConfig( configImage,{
	edit = "text"; 
	combobox = "selText"; 
} );

winform.editPrompt.setPadding(5,5,5,5); 
winform.progressBar.setPieRange(0,100);
winform.progressBar.orphanWindow(true);
winform.lastImagePath = null;
winform.lastImageExt = "png";

winform.showTip = function(str){
    winform.labelTip.text = str;
    winform.labelTip.show(true);
    winform.setTimeout(
        function(){
            winform.labelTip.show(false);
        },5000
    );
}

winform.setBusy = function(busy){
    if(busy){
        winform.btnGenerate.disabledText = {'\uF254';'\uF251';'\uF252';'\uF253';'\uF250'};
        winform.btnCopy.disabled = true;
        winform.progressBar.show(true);
        winform.progressBar.startProgress();
    }
    else{
        winform.btnGenerate.disabledText = null;
        winform.progressBar.stopProgress();
        winform.progressBar.show(false);
    }
}

winform.btnGenerate.oncommand = function(){
    var prompt = string.trim(winform.editPrompt.text);
    if(!#prompt){
        return winform.msgbox("请输入提示词。","提示","warn");
    }

    if(!aiChatConfig[["url"]]){
        return winform.msgbox("请先配置 API 接口。",,"warn");
    }
    
    var size = winform.comboSize.selText || "1024x1024";
    var outputFormat = winform.comboFormat.selText || "png";
    var background = winform.comboBackground.selText || "auto";

    if(background == "transparent" && outputFormat == "jpeg"){
        outputFormat = "png";
        winform.comboFormat.selText = "png";
        winform.showTip("透明背景不适合 JPEG，已自动切换为 PNG。");
    }

    winform.picturebox.background = null;
    winform.picturebox.foreground = null;
    winform.picturebox.iconText = '\uF03E';
    winform.picturebox.text = "正在连接生成图像模型...";
    winform.text = "文生图 - 生成中";
    winform.btnCopy.text = "复制图像 / 图像文件";
    winform.btnCopy.iconText = '\uF0EA';
    winform.lastImagePath = null;
    winform.lastImageExt = outputFormat;
    winform.setBusy(true);

    thread.invoke(
        function(winform, aiChatConfig, prompt, size, outputFormat, background){
            winform.picturebox.text = "正在生成图像，请稍候...";
            
			import web.rest.aiImage;
            var ai = web.rest.aiImage(aiChatConfig); 

			var path,err = ai.generate(prompt,{
    			size = size;
                outputFormat = outputFormat;
                background = background;
			});
			
            if(path){   
                winform.picturebox.background = path;
                winform.picturebox.text = null;
                winform.picturebox.iconText = null;
                winform.btnCopy.disabled = false;
                winform.text = "文生图 - 生成成功";
                winform.lastImagePath = path;
                winform.lastImageExt = io.splitpath(path).ext;

                winform.showTip("已生成图像，双击图像可放大预览。");
            }
       
            else{
                winform.picturebox.text = "生成失败";
                winform.picturebox.iconText = '\uF057';
                winform.msgboxErr(err,"文生图 API 请求失败");
            }

            winform.setBusy(false);
        },winform,aiChatConfig,prompt,size,outputFormat,background
    );
}

winform.btnCopy.oncommand = function(){
    var imagePath = winform.lastImagePath;
    if(!imagePath || !io.exists(imagePath)){
        return winform.showTip("请先生成图像。");
    }

    if(winform.btnCopy.text == "打开图像文件"){
        raw.explore(imagePath);
        winform.showTip("已打开图像所在位置。");
        winform.btnCopy.text = "复制图像 / 图像文件";
        winform.btnCopy.iconText = '\uF0EA';
    }
    else{
        import win.clip.bitmap;
        win.clip.bitmap.writeHtml(imagePath);

        import win.clip.file;
        win.clip.file.write(imagePath,"copy",false);
        winform.btnCopy.text = "打开图像文件";
        winform.btnCopy.iconText = '\uF1C5';
        winform.showTip("已复制图像与图像文件。");
    }
}

winform.picturebox.onMouseDoubleClick = function(wParam,lParam){
    var imagePath = winform.lastImagePath;
    if(!imagePath || !io.exists(imagePath)){
        return winform.msgboxErr("请先生成图像。","错误");
    }

    var frmPreview = win.form(text="图像预览";right=757;bottom=466;bgcolor=0xFFFFFF;border="none")
    frmPreview.add(
    btnClose={cls="close";text="×";left=725;top=3;right=753;bottom=31;bgcolor=0xCC8B94;anchors={right=1;bottom=1};font=LOGFONT(h=-21);notify=1;z=2};
    picturebox={cls="plus";left=0;top=0;right=758;bottom=467;bgcolor=0xFFFFFF;anchors={left=1;top=1;right=1;bottom=1};foreRepeat="scale";notify=1;repeat="scale";z=1}
    )

    frmPreview.onActivateApp = function(activated){ if(!activated) frmPreview.close(); }
    frmPreview.onCancel = function(){ frmPreview.close(); }
    frmPreview.picturebox.onMouseDoubleClick = function(){ frmPreview.close(); }
    frmPreview.picturebox.foreground = imagePath;
    frmPreview.fullscreen();
    frmPreview.btnClose.oncommand = function(){ frmPreview.close(); }
    frmPreview.btnClose.show(true);
}

winform.btnOpenKeyUrl.oncommand = function(){
    import web.rest.aiChat.settingForm;
    
	table.assign(configImage,{
		protocols = ["auto","openai","openrouter","google","modelscope","fal"];
		title = "文生图 - 接口设置"; // 标题  
		hyperlink1Title = "获取 key"; // key 输入框显示嵌入链接
		allowKatex = false;
	});
	
	if(!configImage.itemData){
		configImage.itemData = []
	}
		
	var text = winform.editPrompt.text;
	//打开 AI 设置窗口，参数 2 指定配置文件
	var frmSetting = web.rest.aiChat.settingForm(mainForm,configImage);
	winform.editPrompt.text = text;//防止设置对话框载入配置文件时重置对话框
	
	if( frmSetting.doModal(mainForm) ){ 
 		
		aiChatConfig = configImage.itemData[configImage.selItem]; 
	}
}

winform.onDestroy = function(){
    if(winform.lastImagePath){
    	io.remove(winform.lastImagePath) //调用方有责任清理临时文件
    }
}

winform.btnGenerate.skin({
    background={
        default=0xFF3498DB;
        hover=0xFF2980B9;
        active=0xFF1F618D;
        disabled=0xFFBDC3C7;
    };
    color={
        default=0xFFFFFFFF;
        disabled=0xFF7F8C8D;
    }
});

winform.btnCopy.skin({
    background={
        default=0xFF27AE60;
        hover=0xFF229954;
        active=0xFF1E8449;
        disabled=0xFFBDC3C7;
    };
    color={
        default=0xFFFFFFFF;
        disabled=0xFF7F8C8D;
    }
});

winform.btnOpenKeyUrl.skin({
    color={
        default=0xFF3498DB;
        hover=0xFF2980B9;
        active=0xFF1F618D;
    }
});

win.ui.simpleWindow(winform);
winform.show();
win.loopMessage();
```

