# aardio 范例: 八字（AI 版）

```aardio
import time.lunar;
import time.ganzhi;
import fonts.fontAwesome;
import win.ui;
/*DSG{{*/
var winform = win.form(text="AI 八字命理";right=960;bottom=640;bgcolor=0xF5F0EB;border="none")
winform.add(
baziPanel={cls="plus";left=32;top=580;right=324;bottom=610;border={color=0xFFD4C4B0;radius=6;width=1};db=1;dl=1;z=21};
btnStart={cls="plus";text="开始推算命理";left=32;top=520;right=324;bottom=572;bgcolor=0x8B5A2B;border={radius=10};color=0xFFFFFF;db=1;dl=1;font=LOGFONT(h=-18;weight=600);iconStyle={align="left";font=LOGFONT(h=-20;name='FontAwesome');padding={left=60}};iconText='\uF005';notify=1;textPadding={left=90};z=20};
chatPanel={cls="custom";left=364;top=70;right=936;bottom=616;bgcolor=0xFAF9F8;db=1;dl=1;dr=1;dt=1;z=23};
comboSex={cls="combobox";left=221;top=297;right=275;bottom=321;dl=1;dt=1;edge=1;items={"男","女"};mode="dropdown";z=15};
editDate={cls="edit";left=32;top=115;right=324;bottom=145;bgcolor=0xFAFDFF;dl=1;dt=1;edge=1;z=7};
editLunarDate={cls="edit";left=32;top=217;right=324;bottom=247;bgcolor=0xFAFDFF;dl=1;dt=1;edge=1;z=11};
editName={cls="edit";left=32;top=293;right=190;bottom=323;bgcolor=0xFAFDFF;dl=1;dt=1;edge=1;z=14};
editQuestion={cls="edit";left=32;top=388;right=324;bottom=480;bgcolor=0xFAFDFF;db=1;dl=1;edge=1;multiline=1;z=18};
hintDate={cls="bkplus";text="格式：1990-01-15 08:30 或 19900115";left=32;top=154;right=324;bottom=172;align="left";color=0x999999;dl=1;dt=1;font=LOGFONT(h=-11);z=8};
hintQuestion={cls="bkplus";text="可写近日困惑、期望或任意想法";left=32;top=484;right=324;bottom=502;align="left";color=0x999999;db=1;dl=1;font=LOGFONT(h=-11);z=19};
iconDate={cls="bkplus";text='\uF073';left=32;top=82;right=52;bottom=104;color=0x8B5A2B;dl=1;dt=1;font=LOGFONT(h=-16;name='FontAwesome');z=5};
iconLunar={cls="bkplus";text='\uF186';left=32;top=187;right=52;bottom=209;color=0x8B5A2B;dl=1;dt=1;font=LOGFONT(h=-16;name='FontAwesome');z=9};
iconName={cls="bkplus";text='\uF007';left=32;top=259;right=52;bottom=281;color=0x8B5A2B;dl=1;dt=1;font=LOGFONT(h=-16;name='FontAwesome');z=12};
iconQuestion={cls="bkplus";text='\uF0E6';left=32;top=346;right=52;bottom=368;color=0x8B5A2B;db=1;dl=1;font=LOGFONT(h=-16;name='FontAwesome');z=16};
inputPanelBg={cls="bkplus";left=16;top=64;right=340;bottom=624;bgcolor=0xFAFDFF;border=1;db=1;dl=1;dt=1;z=1};
labelDate={cls="bkplus";text="出生日期（公历）";left=56;top=82;right=200;bottom=104;align="left";color=0x5A4030;dl=1;dt=1;font=LOGFONT(h=-14;weight=600);z=6};
labelLunar={cls="bkplus";text="农历日期（自动转换）";left=56;top=185;right=240;bottom=207;align="left";color=0x5A4030;dl=1;dt=1;font=LOGFONT(h=-14;weight=600);z=10};
labelName={cls="bkplus";text="姓名";left=56;top=259;right=120;bottom=281;align="left";color=0x5A4030;dl=1;dt=1;font=LOGFONT(h=-14;weight=600);z=13};
labelQuestion={cls="bkplus";text="心中所想（随缘一语）";left=56;top=346;right=280;bottom=368;align="left";color=0x5A4030;db=1;dl=1;font=LOGFONT(h=-14;weight=600);z=17};
resultPanelBg={cls="plus";left=358;top=64;right=946;bottom=625;bgcolor=0xFAF9F8;border={color=0xFFE0D5C8;radius=8;width=1};db=1;dl=1;dr=1;dt=1;z=22};
titleBar={cls="bkplus";left=0;top=0;right=962;bottom=48;bgcolor=0x2B4B6F;dl=1;dr=1;dt=1;z=2};
titleIcon={cls="bkplus";text='\uF0C8';left=16;top=10;right=46;bottom=40;color=0xE8C170;dl=1;dt=1;font=LOGFONT(h=-22;name='FontAwesome');z=3};
titleText={cls="bkplus";text="八字命理分析";left=50;top=6;right=220;bottom=42;align="left";color=0xFFFFFF;dl=1;dt=1;font=LOGFONT(h=-20;weight=600);z=4}
)
/*}}*/

// 美化开始按钮
winform.btnStart.skin({
	background={
		default=0xFF8B5A2B;
		hover=0xFFA0704A;
		active=0xFF6B4A1B;
		disabled=0xFFBBBBBB
	};
	color={
		default=0xFFFFFFFF;
		disabled=0xFF888888
	}
});
 
// 聊天界面
import web.form.chat;
var chatUi = web.form.chat(winform.chatPanel);

// 设置默认值
winform.comboSex.selIndex = 1;
winform.editName.text = "";
winform.editQuestion.text = "";
winform.editDate.setCueBannerText("1990-01-1 00:00",true);
winform.editLunarDate.setCueBannerText("1989-12-05 00:00",true);

// 更新八字显示
var updateBaziDisplay = function(dateStr){

	var gz = time.ganzhi(dateStr);
	if(!gz) {
		winform.baziPanel.text = "";
		return;
	}
	
	winform.baziPanel.text = "八字：" + gz.bazi + "  |  生肖：" + gz.zodiac;
	winform.baziPanel.color = 0x8B5A2B;
};

// 公历日期变化
winform.editDate.onChange = function(){
	if(!owner.modified) return;
	
	var tm = time(owner.text,"%Y-%m-%d %H:%M") || time(owner.text,"%Y-%m-%d %H");
	if(tm){
		var lunarDate = time.lunar(tm);
		winform.editLunarDate.text = lunarDate.format(`%Lyyyy-%Lmm-%Ldd %H:%M`);
		updateBaziDisplay(owner.text);
	}
};

// 农历日期变化
winform.editLunarDate.onChange = function(){
	if(!owner.modified) return;
	
	var tm = time.lunar.toSolar(owner.text);
	if(tm){
		winform.editDate.text = tm.format("%Y-%m-%d %H:%M");
		updateBaziDisplay(winform.editDate.text);
	}
};

// 初始化显示
updateBaziDisplay(winform.editDate.text);
var lunarDate = time.lunar(winform.editDate.text);
if(lunarDate){
	winform.editLunarDate.text = lunarDate.format(`%Lyyyy-%Lmm-%Ldd %H:%M`);
}

var tip = /*
八字，即出生年、月、日、时的天干地支，共八个字。  

> 命理八字以立春为一年起点，而民俗农历、生肖以正月初一为起点

- 年柱（年干+年支）： 代表根基、祖业、父母，对应幼年时期（约0-16岁）。
- 月柱（月干+月支）： 代表成长环境、兄弟姐妹，对应青年时期（约17-32岁）。
- 日柱（日干+日支）： 日干代表本我（核心性格），日支为夫妻宫（配偶），对应中年时期（约33-48岁）。
- 时柱（时干+时支）： 代表子女、晚年运势，对应49岁之后的晚年生活。 

整个命盘就是围绕日主，分析其他七个字与它的关系，这些关系用“十神”来命名。十神依据是根据天干（或地支所藏天干）的五行（金木水火土）生克和阴阳属性确定。

- 生我（长辈、保护）：正印（异性相生）、偏印（同性相生）
- 我生（才华、表达）：伤官（异性相生）、食神（同性相生）
- 克我（约束、事业）：正官（异性相克）、七杀（同性相克，也叫偏官）
- 我克（财富、掌控）：正财（异性相克）、偏财（同性相克）
- 同我（同辈、竞争）：劫财（异性相同）、比肩（同性相同）

> 阴阳不同为“正”（异性相吸，作用温和），阴阳相同为“偏”（同性相斥，作用激烈）

举例：假如你的日主是丁火（阴性火），那么：  
见甲木（阳木）为正印（生我者，木生火，阴阳不同），见己土（阴土）为食神（我生者，火生土，阴阳相同）
*/

// 开始推算按钮
winform.btnStart.oncommand = function(id,event){
	// 输入验证
	var dateStr = winform.editDate.text;
	var tm = time.date(dateStr);
	if(!tm){
		winform.editLunarDate.showWarningTip("请输入正确的出生日期");
		winform.editLunarDate.setFocus();
		return;
	}
	
	if(!#winform.editName.text){
		winform.editName.showWarningTip("请输入姓名");
		winform.editName.setFocus();
		return;
	}
	
	if(!#winform.editQuestion.text){
		winform.editQuestion.showWarningTip("请输入此时此刻心中所想");
		winform.editQuestion.setFocus();
		return;
	}
	
	var name = winform.editName.text;
	var sex = winform.comboSex.selText;
	var question = winform.editQuestion.text;
	
	// 系统提示词
	chatUi.system(`# 角色
你是来自中国的算命先生，一个传统八字命理大师，精通四柱八字、五行生克、十神论命。

# 任务
用户会发送他的出生日期、命理八字，以及用户此时此刻心中所想。
你需要根据中国传统八字命理学分析用户的命理，结合年龄、性别以及用户心中所想来推断其性格特点、人生运势。

# 要求
1. 分析要有理有据，引用八字命理知识
2. 语言要有古韵雅致，但通俗易懂
3. 给出正面积极的建议
4. 适当使用传统术语，但要解释含义

# 八字简介

` + tip);

	var lunarDate = time.lunar(dateStr);
	var dateInfo = tostring(lunarDate, "%Y/%m/%d %H:%M 农历%Ly年（%LY）%Lm月%Ld日 %LH时");
	
	var gz = time.ganzhi(dateStr);
	
	// 用户提示词
	var prompt = '## 我的信息\n\n';
	prompt += '- **出生日期**：' + dateInfo + '\n';
	prompt += '- **命理八字**：' + gz.bazi + '\n';
	prompt += '- **生肖**：' + gz.zodiac + '\n';
	if(#name > 0){
		prompt += '- **姓名**：' + name + '\n';
	}
	prompt += '- **性别**：' + sex + '\n';
	if(#question > 0){
		prompt += '- **此时此刻心中所想**：' + question + '\n';
	}
	prompt += '\n请大师帮我分析命理，指点迷津！';
	
	chatUi.chatMessage.prompt(prompt);
	
	// 禁用按钮并显示加载动画
	winform.btnStart.disabledText = ['\uF254','\uF251','\uF252','\uF253','\uF250']

	thread.invoke(
		function(winform, chatUi, dateStr, name, sex, question){
			
			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 = 2048
			);
			
			// 发送请求
			var resp, err = aiClient.messages(chatUi.chatMessage,
				function(deltaText, reasoning){
					if(reasoning) chatUi.showThinking(reasoning);
					chatUi.assistant(deltaText);
				}
			);
			
			if(err){
				chatUi.assistant("\n\n⚠️ " + err);
			}
			
			// 恢复按钮
			winform.btnStart.disabledText = null;
			
		}, winform, chatUi, dateStr, name, sex, question
	);
};

chatUi.write(tip)


// 标题栏按钮（无边框窗口）
import win.ui.simpleWindow;
win.ui.simpleWindow(winform);

winform.show(3/*_SW_MAXIMIZE*/);
win.loopMessage();
```