注意注意,别把这个语句放在有隐私的笔记里面!!!
原有功能与实现教程:
思源笔记页面内实现 ai 聊天与 ai 读取笔记内容进行回复(自动)! - 链滴
让 ai 根据当前笔记内容进行回复
代码功能:
在创建日记的时候进行回复
在每天写完日记以后,让 ai 根据日记内容进行回复
//!js
// Function to get context from recently updated documents (Keep as is)
async function getDocumentContext() {
try {
let currentDocId = Query.root_id(protyle);
const sqlQuery = `
select * from blocks
where root_id = '${currentDocId}'
order by sort ASC
limit 9999
`;
let blocks = await Query.sql(sqlQuery);
if (blocks && blocks.length > 0) {
let contextEntries = blocks.map(block => {
const content = block.markdown || block.content || '[No Content]';
return `Document Path: ${block.hpath || 'N/A'}\nContent:\n---\n${content}\n---`;
});
return "以下是当前文档的内容,请参考:\n==========\n" + contextEntries.join('\n\n') + "\n==========\n";
} else {
return "当前文档没有内容可供参考。\n";
}
} catch (error) {
console.error("查询文档时出错:", error);
return "查询参考文档时出现错误。\n";
}
}
// Function to create the UI elements (Keep as is)
const ui = () => {
const textarea = document.createElement('textarea');
textarea.className = "fn__block b3-text-field";
textarea.rows = 3;
textarea.placeholder = "继续提问...";
const buttonContainer = document.createElement('div');
buttonContainer.style.display = 'flex';
buttonContainer.style.justifyContent = 'flex-end';
buttonContainer.style.gap = '8px';
buttonContainer.style.marginTop = '8px';
const removeLastButton = document.createElement('button');
removeLastButton.className = "b3-button";
removeLastButton.textContent = "我不会和别人说的🌹";
buttonContainer.appendChild(removeLastButton);
const sendButton = document.createElement('button');
sendButton.className = "b3-button";
sendButton.textContent = "是这样的😄";
buttonContainer.appendChild(sendButton);
return { textarea, buttonContainer, sendButton, removeLastButton };
}
// Main chat function (Modified to fix null querySelector error)
const chat = async () => {
let dv = Query.DataView(protyle, item, top);
const messages = dv.useState('messages', []);
const msgIds = dv.useState('msgIds', []);
// --- Initial Rendering Structure ---
dv.addmd(`#### 向我分享你的一天吧!`);
// 1. Render existing messages from state
const initialMsgIds = [];
messages().forEach(msg => {
try {
let el = dv.addmd(`**${msg.role === 'user' ? 'You' : 'GPT'}**: ${msg.content}`);
if (el && el.dataset && el.dataset.id) {
initialMsgIds.push(el.dataset.id);
}
} catch (e) {
console.error("Error rendering message:", e);
}
});
if (msgIds().length === 0 && initialMsgIds.length > 0) {
msgIds(initialMsgIds);
}
// 2. Add Separator
dv.addmd('---');
// 3. Create UI Elements but don't store unnecessary references
const { textarea, buttonContainer, sendButton, removeLastButton } = ui();
// Just add them directly without storing the references
dv.addele(textarea);
dv.addele(buttonContainer);
// --- Function to perform AI query (Modified with better error handling) ---
const performAIQuery = async (prompt, isInitialQuery = false) => {
try {
sendButton.disabled = true;
removeLastButton.disabled = true;
// Add placeholder with better error handling
let respondPlaceholder;
let gptMsgId = null;
try {
respondPlaceholder = dv.addmd(`**GPT**: 正在检索参考资料并思考... 🤔`);
if (respondPlaceholder && respondPlaceholder.dataset) {
gptMsgId = respondPlaceholder.dataset.id;
// Add placeholder ID to state only if it's valid
if (gptMsgId) {
msgIds([...msgIds(), gptMsgId]);
}
}
} catch (e) {
console.error("Error adding placeholder:", e);
// If we can't add a placeholder, we'll just add a new message later
}
// Safe function to replace or add content
const updateContent = (id, content) => {
try {
if (id) {
dv.replaceView(id, dv.md(`**GPT**: ${content}`));
} else {
// If no ID, add as new message
let newEl = dv.addmd(`**GPT**: ${content}`);
if (newEl && newEl.dataset && newEl.dataset.id) {
msgIds([...msgIds(), newEl.dataset.id]);
}
}
} catch (e) {
console.error("Error updating content:", e);
// Last resort fallback - just add a new message
try {
dv.addmd(`**GPT**: ${content}`);
} catch (e) {
console.error("Failed to add fallback message:", e);
}
}
};
const docReference = await getDocumentContext();
const prefixText = `${docReference}\n这是我的提问背景信息:`;
const suffixText = "\n请基于以上参考信息,回复我的问题。注意:多用表情,尽量简短且切中要点。";
const fullPrompt = `${prefixText}\n${prompt}\n${suffixText}`;
const response = await Query.gpt(fullPrompt, {
stream: true,
streamInterval: 3,
streamMsg: (content) => {
// Safely update with streaming content
updateContent(gptMsgId, content);
}
});
// Update state with final response
const gptMessage = { role: 'assistant', content: response };
const currentMessages = messages();
if (isInitialQuery) {
messages([gptMessage]);
} else {
messages([...currentMessages, gptMessage]);
}
// Final update with safe function
updateContent(gptMsgId, response);
} catch (error) {
console.error("GPT 调用或处理失败:", error);
const errorMessageContent = `抱歉,处理时遇到问题: ${error.message}`;
try {
if (gptMsgId) {
dv.replaceView(gptMsgId, dv.md(`**GPT**: ${errorMessageContent}`));
} else {
dv.addmd(`**GPT**: ${errorMessageContent}`);
}
const errorMessage = { role: 'assistant', content: errorMessageContent };
const currentMessages = messages();
if (isInitialQuery) {
messages([errorMessage]);
} else {
messages([...currentMessages, errorMessage]);
}
} catch (e) {
console.error("Error handling GPT failure:", e);
// Try one more time with a simple message
try {
dv.addmd(`**Error**: ${error.message}`);
} catch (finalError) {
console.error("Failed all error handling attempts:", finalError);
}
}
} finally {
// Re-enable buttons regardless of outcome
try {
sendButton.disabled = false;
removeLastButton.disabled = false;
// Safely repaint
dv.repaint();
} catch (e) {
console.error("Error in finally block:", e);
}
}
};
// --- Initial Query Logic ---
if (messages().length === 0) {
const predefinedPrompt = "今天真是美好的一天,请你基于参考内容,激励我度过美好的一天吧!请你用满满的正能量激励我,并且要加入很多的表情,让我的心情愉快!";
try {
await performAIQuery(predefinedPrompt, true);
} catch (e) {
console.error("Initial query failed:", e);
// Try to add a fallback message
dv.addmd("**System**: 初始查询失败,但你仍然可以开始对话。");
}
}
// --- Button Handlers ---
sendButton.onclick = async () => {
const userInput = textarea.value.trim();
if (!userInput) return;
// 1. Add user message to state and UI with better error handling
const userMessage = { role: 'user', content: userInput };
messages([...messages(), userMessage]);
let userEl;
let userMsgId = null;
try {
userEl = dv.addmd(`**You**: ${userInput}`);
if (userEl && userEl.dataset) {
userMsgId = userEl.dataset.id;
if (userMsgId) {
msgIds([...msgIds(), userMsgId]);
}
}
} catch (e) {
console.error("Error adding user message:", e);
}
textarea.value = '';
// 2. Perform AI query with error handling
try {
await performAIQuery(userInput, false);
} catch (e) {
console.error("Query failed:", e);
dv.addmd(`**System**: 查询失败,请重试。错误: ${e.message}`);
}
};
// Remove last button click handler (with better error handling)
removeLastButton.onclick = () => {
try {
const currentMessages = messages();
let currentMsgIds = [...msgIds()];
if (currentMessages.length < 2 || currentMsgIds.length < 2) return;
// Update messages state first (in case view operations fail)
messages(currentMessages.slice(0, -2));
// Then try to remove the views
try {
const lastGptId = currentMsgIds.pop();
const lastUserId = currentMsgIds.pop();
if (lastGptId) dv.removeView(lastGptId);
if (lastUserId) dv.removeView(lastUserId);
// Update msgIds state only after successful removal
msgIds(currentMsgIds);
} catch (e) {
console.error("Error removing views:", e);
}
// Always try to repaint
dv.repaint();
} catch (e) {
console.error("Error in removeLastButton handler:", e);
}
};
// --- Final Render ---
try {
dv.render();
} catch (e) {
console.error("Error rendering DataView:", e);
}
}
// Execute the chat function with error handling
try {
return chat();
} catch (e) {
console.error("Fatal error in chat function:", e);
return "Error initializing chat. Please check console for details.";
}
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于