<%*
// ========== 1. 全局配置 (集中管理) ==========
const CONFIG = {
apiKey: "", // 你的API Key
apiUrl: "",
model: "",
timeout: 10000, // 超时时间(毫秒)
prompts: {
encouragement: "请生成一句简短、独特且充满力量的每日鼓励语,对象是一位坚持自我成长的朋友。避免鸡汤,结合新奇的比喻。只输出一句话。",
questionFallback: "请提出一个能引发自我觉察的深刻问题(关于个人成长、价值观或未来规划)。要求:1. 只输出问题本身,不要任何解释或背景铺垫。2. 问题要简短有力,一针见血。3. 语气像一个老朋友的关切询问。",
system: "你是一个极简主义的苏格拉底式导师。你的回答必须极其简练,直击灵魂,拒绝任何废话。"
}
};
// ========== 2. 日期与文件准备 ==========
const today = tp.date.now("YYYY-MM-DD");
const weekday = tp.date.now("dddd");
const yesterday = tp.date.now("YYYY-MM-DD", -1);
const yesterdayFile = `Diary/${yesterday}.md`;
const tomorrow = tp.date.now("YYYY-MM-DD", 1);
// ========== 3. 核心工具函数 ==========
async function callAI(prompt, systemPrompt = CONFIG.prompts.system) {
if (!CONFIG.apiKey || CONFIG.apiKey.includes("YOUR_API_KEY")) return "请配置API Key";
try {
// 使用 Obsidian 原生 requestUrl 绕过 CORS
const requestPromise = requestUrl({
url: CONFIG.apiUrl,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${CONFIG.apiKey}`
},
body: JSON.stringify({
model: CONFIG.model,
messages: [
{ role: "system", content: systemPrompt },
{ role: "user", content: prompt }
],
temperature: 0.7,
max_tokens: 500
})
});
// 手动实现超时控制
const timeoutPromise = new Promise((_, reject) =>
setTimeout(() => reject(new Error("Timeout")), CONFIG.timeout)
);
const response = await Promise.race([requestPromise, timeoutPromise]);
// requestUrl 若状态码 >= 400 会自动 throw error,这里只需处理成功情况
const data = response.json;
return data.choices[0].message.content.trim();
} catch (error) {
console.error("AI Error:", error);
if (error.message === "Timeout") return "[AI响应超时]";
// 尝试解析更详细的错误
if (error.status === 401) return "[API Key无效]";
if (error.status === 404) return "[接口地址错误]";
return `[AI连接失败: ${error.message || error.status}]`;
}
}
function sanitizeQuestion(text) {
const s = String(text || "").replace(/[*_#>`]/g, "").replace(/(.*?)/g, "").trim();
const m = s.match(/(.{3,120}?[??])/);
if (m) return m[1].trim();
const lines = s.split("\n").map(l => l.trim()).filter(Boolean);
if (lines.length) return lines[0].replace(/^.*?:\s*/, "").replace(/^\"|\"$/g, "").trim();
return "今天,你最需要面对的是什么?";
}
// ========== 4. 并行执行任务 (Promise.all) ==========
// 4.1 任务迁移 (本地)
let migratedTasks = "";
try {
const prevFile = app.vault.getAbstractFileByPath(yesterdayFile);
if (prevFile) {
const content = await app.vault.read(prevFile);
const match = content.match(/## 📅 明日预览\s*\n([\s\S]*?)(?=\n## |\n---|$)/);
if (match) {
const tasks = match[1].split('\n')
.filter(l => l.trim().startsWith('- [ ]'))
.map(l => l.replace(/📅 \d{4}-\d{2}-\d{2}/, '').trim());
if (tasks.length > 0) migratedTasks = `\n` + tasks.join('\n') + `\n`;
}
}
} catch (e) { console.error("迁移失败", e); }
// 4.2 AI任务 (网络)
const pEncouragement = callAI(CONFIG.prompts.encouragement, "你是一位语言优美、充满创意的鼓舞者。");
let pQuestionBlock = (async () => {
try {
const prevFile = app.vault.getAbstractFileByPath(yesterdayFile);
if (prevFile) {
const content = await app.vault.read(prevFile);
const answerMatch = content.match(/## 🤔 .*AI.*[\s\S]*?我的回答:\s*\n([\s\S]*?)(?=\n## |\n---|$)/);
if (answerMatch && answerMatch[1].trim().length > 5) {
const lastAnswer = answerMatch[1].trim();
const res = await callAI(`昨天问题与回答:\n"${lastAnswer}"\n请基于此追问一个更深层的问题。要求:只输出问题本身,不要任何客套话或分析。`, "你是一个善于追问的导师。");
const q = sanitizeQuestion(res);
return `## 🤔 昨日AI问答与思考\n**AI反馈与追问**:${q}\n\n**我的回答**:\n`;
}
}
const newQ = await callAI(CONFIG.prompts.questionFallback);
const q = sanitizeQuestion(newQ);
return `## 🤔 AI启发式问题\n**今日提问**:${q}\n\n**我的回答**:\n`;
} catch (e) { return `## 🤔 AI启发式问题\n**今日提问**:(读取失败)\n\n**我的回答**:\n`; }
})();
// 等待AI结果
const [dailyEncouragement, aiQuestionBlock] = await Promise.all([pEncouragement, pQuestionBlock]);
// ========== 5. 输出内容 (Output) ==========
// 头部
tR += `> **${today} ${weekday}** | ${dailyEncouragement}\n\n`;
// TODO部分
tR += `## 📋 今日TODO \n`;
if (migratedTasks) tR += migratedTasks;
// 交互式提问 (核心任务)
const topTask = await tp.system.prompt("你今天最想完成的1件事是什么?") || "思考人生";
tR += `- [ ] **${topTask}**(核心任务)\n`;
-%>
- [ ] 背单词
- [ ]
## 💡 今日思考
1.
## 🙏 感激之事
1.
<%- aiQuestionBlock %>
## 📅 明日预览
- [ ]