1 line
56 KiB
JSON
1 line
56 KiB
JSON
{"repo": "aprilming/maiknote", "files": {"src/stores/assistantsStore.ts": {"89114e543bd4a1da0786820b37bc5bb96c226e42": {"t": 1785746031.7333798, "n": 7277, "h": "c25efa96aa9e5cae", "c": "import { defineStore } from 'pinia'\nimport { ref } from 'vue'\nimport { invoke } from '@tauri-apps/api/core'\nimport { useFileSystem } from '@/composables/useFileSystem'\n\n// Assistant interface\nexport interface Assistant {\n id: string\n name: string\n prompt: string\n searchEnabled: boolean\n createdAt: number // timestamp in milliseconds\n}\n\nexport interface AiConfig {\n url: string\n key: string\n model: string\n}\n\n// Default template assistants - using string literals to avoid Pinia initialization issues\nexport const defaultAssistants: Assistant[] = [\n {\n id: 'template-1',\n name: '优化内容',\n prompt: '你是一个笔记优化助手,严格按照以下规则优化笔记内容,直接输出结果,不附加任何说明。\\n' +\n '输出格式\\n' +\n '返回纯字符串,不使用 ``` 代码块包裹\\n' +\n '内容处理规则\\n' +\n '删除信息来源(如\"来源:\"\"转自:\"等)\\n' +\n '删除所有 tag 标签(如 #标签)\\n' +\n '标题处理:全文仅保留一个 H2 标题;若无标题则在顶部生成一个;若已有标题则不新增\\n' +\n '链接处理:保留核心内容中的 URL;若为裸链接可转为 Markdown 格式;禁止修改链接本身;无链接时禁止生成链接\\n' +\n '禁止输出\"注:\"\"备注:\"\"注意:\"等注释性内容\\n' +\n '禁止输出\"已优化\"\"优化笔记\"\"以下是\"等无关话语',\n createdAt: 0,\n searchEnabled: true,\n },\n {\n id: 'template-2',\n name: '提取任务',\n prompt: '从以下文本中提取待办事项,按如下格式输出:\\n' +\n '第一部分:笔记摘要\\n' +\n '用 h1–h3 标题概括笔记主题,标题 10 字以内\\n' +\n '标题下方正文仅保留日期、时间及关键信息,无则省略\\n' +\n '可适当添加表情 🎯\\n' +\n '第二部分:任务列表\\n' +\n '每条任务以 - [ ] 开头,保留时间、日期等关键信息\\n' +\n '不使用有序或无序列表,只用 - [ ] 格式\\n' +\n '特殊情况\\n' +\n '若无法提取到任务,则对笔记进行格式优化后输出\\n' +\n '不要输出任何引导语(如\"以下是……\")',\n createdAt: 0,\n searchEnabled: true,\n },\n {\n id: 'template-3',\n name: '优化提示词',\n prompt: '你是一个提示词优化专家,用户会给你一段提示词,你需要对其进行优化并直接输出结果。\\n' +\n '优化原则\\n' +\n '保留用户的原始意图,不改变核心需求\\n' +\n '补全缺失的约束条件(格式、边界情况、禁止行为等)\\n' +\n '消除歧义表达,改为明确、可执行的指令\\n' +\n '合并重复或冲突的规则\\n' +\n '结构清晰,分块呈现\\n' +\n '输出格式\\n' +\n '直接输出优化后的提示词,不加任何说明\\n' +\n '不使用 ``` 包裹\\n' +\n '不输出\"以下是优化后的提示词\"等引导语\\n' +\n '特殊情况\\n' +\n '若用户的提示词过于简单,主动补全合理的默认规则\\n' +\n '若存在矛盾规则,以最后出现的为准并合并',\n createdAt: 0,\n searchEnabled: true,\n },\n]\n\nexport const defaultAiConfig: AiConfig = {\n url: 'https://api.deepseek.com/chat/completions',\n key: '',\n model: 'deepseek-v4-flash',\n}\n\nexport const useAssistantsStore = defineStore('assistants', () => {\n // State\n const assistants = ref<Assistant[]>([])\n const isLoaded = ref(false)\n const aiUrl = ref(defaultAiConfig.url)\n const aiKey = ref(defaultAiConfig.key)\n const aiModel = ref(defaultAiConfig.model)\n const aiConfigExists = ref(false)\n const baiduSearchKey = ref('')\n\n // File system operations\n const { getICloudPath } = useFileSystem()\n\n /**\n * Generate a unique ID using crypto.randomUUID()\n */\n function generateId(): string {\n return crypto.randomUUID()\n }\n\n /**\n * Load assistants from iCloud file\n */\n async function loadAssistants(): Promise<void> {\n try {\n const path = await getICloudPath()\n const content = await invoke<string>('read_assistants', { basePath: path })\n\n if (content) {\n const parsed = JSON.parse(content)\n assistants.value = (parsed.assistants || []).map((a: Record<string, unknown>) => ({\n ...a,\n searchEnabled: a.searchEnabled === true,\n })) as Assistant[]\n\n // Load AI config from iCloud\n if (parsed.aiConfig) {\n aiUrl.value = parsed.aiConfig.url || defaultAiConfig.url\n aiKey.value = parsed.aiConfig.key || defaultAiConfig.key\n aiModel.value = parsed.aiConfig.model || defaultAiConfig.model\n aiConfigExists.value = true\n }\n\n // Load Baidu search key from iCloud\n if (parsed.baiduSearchKey) {\n baiduSearchKey.value = parsed.baiduSearchKey\n }\n }\n\n isLoaded.value = true\n } catch (e) {\n // If file doesn't exist or read fails, use default assistants\n console.error('Failed to load assistants, using defaults:', e)\n assistants.value = [...defaultAssistants]\n isLoaded.value = true\n }\n }\n\n /**\n * Save assistants and AI config to iCloud file\n */\n async function saveAssistants(): Promise<void> {\n try {\n const path = await getICloudPath()\n const content = JSON.stringify({\n version: 1,\n assistants: assistants.value,\n aiConfig: { url: aiUrl.value, key: aiKey.value, model: aiModel.value },\n baiduSearchKey: baiduSearchKey.value,\n }, null, 2)\n await invoke('write_assistants', { basePath: path, content })\n } catch (e) {\n console.error('Failed to save assistants:', e)\n }\n }\n\n /**\n * Add a new assistant\n */\n async function addAssistant(name: string, prompt: string, searchEnabled = false): Promise<Assistant> {\n const newAssistant: Assistant = {\n id: generateId(),\n name,\n prompt,\n searchEnabled,\n createdAt: Date.now(),\n }\n\n assistants.value.push(newAssistant)\n await saveAssistants()\n return newAssistant\n }\n\n /**\n * Update an existing assistant\n */\n async function updateAssistant(id: string, updates: Partial<Pick<Assistant, 'name' | 'prompt' | 'searchEnabled'>>): Promise<boolean> {\n const index = assistants.value.findIndex(a => a.id === id)\n if (index === -1) {\n return false\n }\n\n assistants.value[index] = {\n ...assistants.value[index],\n ...updates,\n }\n\n await saveAssistants()\n return true\n }\n\n /**\n * Delete an assistant\n */\n async function deleteAssistant(id: string): Promise<boolean> {\n const index = assistants.value.findIndex(a => a.id === id)\n if (index === -1) {\n return false\n }\n\n assistants.value.splice(index, 1)\n await saveAssistants()\n return true\n }\n\n /**\n * Get assistant by ID\n */\n function getAssistantById(id: string): Assistant | undefined {\n return assistants.value.find(a => a.id === id)\n }\n\n /**\n * Check if an assistant with the same prompt already exists\n * @param prompt The prompt to check\n * @param excludeId Optional ID to exclude from check (for updates)\n */\n function hasPrompt(prompt: string, excludeId?: string): boolean {\n return assistants.value.some(a => a.prompt === prompt && a.id !== excludeId)\n }\n\n /**\n * Check if an assistant with the same prompt already exists (excluding template assistants)\n * @param prompt The prompt to check\n * @param excludeId Optional ID to exclude from check (for updates)\n */\n function hasUserPrompt(prompt: string, excludeId?: string): boolean {\n return assistants.value.some(\n a => a.prompt === prompt && a.id !== excludeId && !a.id.startsWith('template-')\n )\n }\n\n /**\n * Update AI config (url, key, model) and persist to iCloud\n */\n async function updateAiConfig(url: string, key: string, model: string): Promise<void> {\n aiUrl.value = url\n aiKey.value = key\n aiModel.value = model\n await saveAssistants()\n }\n\n async function updateBaiduSearchKey(key: string): Promise<void> {\n baiduSearchKey.value = key\n await saveAssistants()\n }\n\n return {\n assistants,\n isLoaded,\n aiConfigExists,\n aiUrl,\n aiKey,\n aiModel,\n baiduSearchKey,\n loadAssistants,\n saveAssistants,\n addAssistant,\n updateAssistant,\n deleteAssistant,\n getAssistantById,\n hasPrompt,\n hasUserPrompt,\n updateAiConfig,\n updateBaiduSearchKey,\n }\n})\n"}, "e4e0def3f082380c62335f83eec641534dc827b8": {"t": 1785759032.3592613, "n": 7277, "h": "c25efa96aa9e5cae", "c": "import { defineStore } from 'pinia'\nimport { ref } from 'vue'\nimport { invoke } from '@tauri-apps/api/core'\nimport { useFileSystem } from '@/composables/useFileSystem'\n\n// Assistant interface\nexport interface Assistant {\n id: string\n name: string\n prompt: string\n searchEnabled: boolean\n createdAt: number // timestamp in milliseconds\n}\n\nexport interface AiConfig {\n url: string\n key: string\n model: string\n}\n\n// Default template assistants - using string literals to avoid Pinia initialization issues\nexport const defaultAssistants: Assistant[] = [\n {\n id: 'template-1',\n name: '优化内容',\n prompt: '你是一个笔记优化助手,严格按照以下规则优化笔记内容,直接输出结果,不附加任何说明。\\n' +\n '输出格式\\n' +\n '返回纯字符串,不使用 ``` 代码块包裹\\n' +\n '内容处理规则\\n' +\n '删除信息来源(如\"来源:\"\"转自:\"等)\\n' +\n '删除所有 tag 标签(如 #标签)\\n' +\n '标题处理:全文仅保留一个 H2 标题;若无标题则在顶部生成一个;若已有标题则不新增\\n' +\n '链接处理:保留核心内容中的 URL;若为裸链接可转为 Markdown 格式;禁止修改链接本身;无链接时禁止生成链接\\n' +\n '禁止输出\"注:\"\"备注:\"\"注意:\"等注释性内容\\n' +\n '禁止输出\"已优化\"\"优化笔记\"\"以下是\"等无关话语',\n createdAt: 0,\n searchEnabled: true,\n },\n {\n id: 'template-2',\n name: '提取任务',\n prompt: '从以下文本中提取待办事项,按如下格式输出:\\n' +\n '第一部分:笔记摘要\\n' +\n '用 h1–h3 标题概括笔记主题,标题 10 字以内\\n' +\n '标题下方正文仅保留日期、时间及关键信息,无则省略\\n' +\n '可适当添加表情 🎯\\n' +\n '第二部分:任务列表\\n' +\n '每条任务以 - [ ] 开头,保留时间、日期等关键信息\\n' +\n '不使用有序或无序列表,只用 - [ ] 格式\\n' +\n '特殊情况\\n' +\n '若无法提取到任务,则对笔记进行格式优化后输出\\n' +\n '不要输出任何引导语(如\"以下是……\")',\n createdAt: 0,\n searchEnabled: true,\n },\n {\n id: 'template-3',\n name: '优化提示词',\n prompt: '你是一个提示词优化专家,用户会给你一段提示词,你需要对其进行优化并直接输出结果。\\n' +\n '优化原则\\n' +\n '保留用户的原始意图,不改变核心需求\\n' +\n '补全缺失的约束条件(格式、边界情况、禁止行为等)\\n' +\n '消除歧义表达,改为明确、可执行的指令\\n' +\n '合并重复或冲突的规则\\n' +\n '结构清晰,分块呈现\\n' +\n '输出格式\\n' +\n '直接输出优化后的提示词,不加任何说明\\n' +\n '不使用 ``` 包裹\\n' +\n '不输出\"以下是优化后的提示词\"等引导语\\n' +\n '特殊情况\\n' +\n '若用户的提示词过于简单,主动补全合理的默认规则\\n' +\n '若存在矛盾规则,以最后出现的为准并合并',\n createdAt: 0,\n searchEnabled: true,\n },\n]\n\nexport const defaultAiConfig: AiConfig = {\n url: 'https://api.deepseek.com/chat/completions',\n key: '',\n model: 'deepseek-v4-flash',\n}\n\nexport const useAssistantsStore = defineStore('assistants', () => {\n // State\n const assistants = ref<Assistant[]>([])\n const isLoaded = ref(false)\n const aiUrl = ref(defaultAiConfig.url)\n const aiKey = ref(defaultAiConfig.key)\n const aiModel = ref(defaultAiConfig.model)\n const aiConfigExists = ref(false)\n const baiduSearchKey = ref('')\n\n // File system operations\n const { getICloudPath } = useFileSystem()\n\n /**\n * Generate a unique ID using crypto.randomUUID()\n */\n function generateId(): string {\n return crypto.randomUUID()\n }\n\n /**\n * Load assistants from iCloud file\n */\n async function loadAssistants(): Promise<void> {\n try {\n const path = await getICloudPath()\n const content = await invoke<string>('read_assistants', { basePath: path })\n\n if (content) {\n const parsed = JSON.parse(content)\n assistants.value = (parsed.assistants || []).map((a: Record<string, unknown>) => ({\n ...a,\n searchEnabled: a.searchEnabled === true,\n })) as Assistant[]\n\n // Load AI config from iCloud\n if (parsed.aiConfig) {\n aiUrl.value = parsed.aiConfig.url || defaultAiConfig.url\n aiKey.value = parsed.aiConfig.key || defaultAiConfig.key\n aiModel.value = parsed.aiConfig.model || defaultAiConfig.model\n aiConfigExists.value = true\n }\n\n // Load Baidu search key from iCloud\n if (parsed.baiduSearchKey) {\n baiduSearchKey.value = parsed.baiduSearchKey\n }\n }\n\n isLoaded.value = true\n } catch (e) {\n // If file doesn't exist or read fails, use default assistants\n console.error('Failed to load assistants, using defaults:', e)\n assistants.value = [...defaultAssistants]\n isLoaded.value = true\n }\n }\n\n /**\n * Save assistants and AI config to iCloud file\n */\n async function saveAssistants(): Promise<void> {\n try {\n const path = await getICloudPath()\n const content = JSON.stringify({\n version: 1,\n assistants: assistants.value,\n aiConfig: { url: aiUrl.value, key: aiKey.value, model: aiModel.value },\n baiduSearchKey: baiduSearchKey.value,\n }, null, 2)\n await invoke('write_assistants', { basePath: path, content })\n } catch (e) {\n console.error('Failed to save assistants:', e)\n }\n }\n\n /**\n * Add a new assistant\n */\n async function addAssistant(name: string, prompt: string, searchEnabled = false): Promise<Assistant> {\n const newAssistant: Assistant = {\n id: generateId(),\n name,\n prompt,\n searchEnabled,\n createdAt: Date.now(),\n }\n\n assistants.value.push(newAssistant)\n await saveAssistants()\n return newAssistant\n }\n\n /**\n * Update an existing assistant\n */\n async function updateAssistant(id: string, updates: Partial<Pick<Assistant, 'name' | 'prompt' | 'searchEnabled'>>): Promise<boolean> {\n const index = assistants.value.findIndex(a => a.id === id)\n if (index === -1) {\n return false\n }\n\n assistants.value[index] = {\n ...assistants.value[index],\n ...updates,\n }\n\n await saveAssistants()\n return true\n }\n\n /**\n * Delete an assistant\n */\n async function deleteAssistant(id: string): Promise<boolean> {\n const index = assistants.value.findIndex(a => a.id === id)\n if (index === -1) {\n return false\n }\n\n assistants.value.splice(index, 1)\n await saveAssistants()\n return true\n }\n\n /**\n * Get assistant by ID\n */\n function getAssistantById(id: string): Assistant | undefined {\n return assistants.value.find(a => a.id === id)\n }\n\n /**\n * Check if an assistant with the same prompt already exists\n * @param prompt The prompt to check\n * @param excludeId Optional ID to exclude from check (for updates)\n */\n function hasPrompt(prompt: string, excludeId?: string): boolean {\n return assistants.value.some(a => a.prompt === prompt && a.id !== excludeId)\n }\n\n /**\n * Check if an assistant with the same prompt already exists (excluding template assistants)\n * @param prompt The prompt to check\n * @param excludeId Optional ID to exclude from check (for updates)\n */\n function hasUserPrompt(prompt: string, excludeId?: string): boolean {\n return assistants.value.some(\n a => a.prompt === prompt && a.id !== excludeId && !a.id.startsWith('template-')\n )\n }\n\n /**\n * Update AI config (url, key, model) and persist to iCloud\n */\n async function updateAiConfig(url: string, key: string, model: string): Promise<void> {\n aiUrl.value = url\n aiKey.value = key\n aiModel.value = model\n await saveAssistants()\n }\n\n async function updateBaiduSearchKey(key: string): Promise<void> {\n baiduSearchKey.value = key\n await saveAssistants()\n }\n\n return {\n assistants,\n isLoaded,\n aiConfigExists,\n aiUrl,\n aiKey,\n aiModel,\n baiduSearchKey,\n loadAssistants,\n saveAssistants,\n addAssistant,\n updateAssistant,\n deleteAssistant,\n getAssistantById,\n hasPrompt,\n hasUserPrompt,\n updateAiConfig,\n updateBaiduSearchKey,\n }\n})\n"}, "1a583602b2aa814d0420b71d3c95c3bd59e58708": {"t": 1785759035.2492504, "n": 7273, "h": "10a05a5dcd0e5100", "c": "import { defineStore } from 'pinia'\nimport { ref } from 'vue'\nimport { invoke } from '@tauri-apps/api/core'\nimport { useFileSystem } from '@/composables/useFileSystem'\n\n// Assistant interface\nexport interface Assistant {\n id: string\n name: string\n prompt: string\n searchEnabled: boolean\n createdAt: number // timestamp in milliseconds\n}\n\nexport interface AiConfig {\n url: string\n key: string\n model: string\n}\n\n// Default template assistants - using string literals to avoid Pinia initialization issues\nexport const defaultAssistants: Assistant[] = [\n {\n id: 'template-1',\n name: '优化内容',\n prompt: '你是一个笔记优化助手,严格按照以下规则优化笔记内容,直接输出结果,不附加任何说明。\\n' +\n '输出格式\\n' +\n '返回纯字符串,不使用 ``` 代码块包裹\\n' +\n '内容处理规则\\n' +\n '删除信息来源(如\"来源:\"\"转自:\"等)\\n' +\n '删除所有 tag 标签(如 #标签)\\n' +\n '标题处理:全文仅保留一个 H2 标题;若无标题则在顶部生成一个;若已有标题则不新增\\n' +\n '链接处理:保留核心内容中的 URL;若为裸链接可转为 Markdown 格式;禁止修改链接本身;无链接时禁止生成链接\\n' +\n '禁止输出\"注:\"\"备注:\"\"注意:\"等注释性内容\\n' +\n '禁止输出\"已优化\"\"优化笔记\"\"以下是\"等无关话语',\n createdAt: 0,\n searchEnabled: true,\n },\n {\n id: 'template-2',\n name: '提取任务',\n prompt: '从以下文本中提取待办事项,按如下格式输出:\\n' +\n '第一部分:笔记摘要\\n' +\n '用 h1–h3 标题概括笔记主题,标题 10 字以内\\n' +\n '标题下方正文仅保留日期、时间及关键信息,无则省略\\n' +\n '可适当添加表情 🎯\\n' +\n '第二部分:任务列表\\n' +\n '每条任务以 - [ ] 开头,保留时间、日期等关键信息\\n' +\n '不使用有序或无序列表,只用 - [ ] 格式\\n' +\n '特殊情况\\n' +\n '若无法提取到任务,则对笔记进行格式优化后输出\\n' +\n '不要输出任何引导语(如\"以下是……\")',\n createdAt: 0,\n searchEnabled: true,\n },\n {\n id: 'template-3',\n name: '优化提示词',\n prompt: '你是一个提示词优化专家,用户会给你一段提示词,你需要对其进行优化并直接输出结果。\\n' +\n '优化原则\\n' +\n '保留用户的原始意图,不改变核心需求\\n' +\n '补全缺失的约束条件(格式、边界情况、禁止行为等)\\n' +\n '消除歧义表达,改为明确、可执行的指令\\n' +\n '合并重复或冲突的规则\\n' +\n '结构清晰,分块呈现\\n' +\n '输出格式\\n' +\n '直接输出优化后的提示词,不加任何说明\\n' +\n '不使用 ``` 包裹\\n' +\n '不输出\"以下是优化后的提示词\"等引导语\\n' +\n '特殊情况\\n' +\n '若用户的提示词过于简单,主动补全合理的默认规则\\n' +\n '若存在矛盾规则,以最后出现的为准并合并',\n createdAt: 0,\n searchEnabled: true,\n },\n]\n\nexport const defaultAiConfig: AiConfig = {\n url: 'https://api.deepseek.com/chat/completions',\n key: '',\n model: 'deepseek-chat',\n}\n\nexport const useAssistantsStore = defineStore('assistants', () => {\n // State\n const assistants = ref<Assistant[]>([])\n const isLoaded = ref(false)\n const aiUrl = ref(defaultAiConfig.url)\n const aiKey = ref(defaultAiConfig.key)\n const aiModel = ref(defaultAiConfig.model)\n const aiConfigExists = ref(false)\n const baiduSearchKey = ref('')\n\n // File system operations\n const { getICloudPath } = useFileSystem()\n\n /**\n * Generate a unique ID using crypto.randomUUID()\n */\n function generateId(): string {\n return crypto.randomUUID()\n }\n\n /**\n * Load assistants from iCloud file\n */\n async function loadAssistants(): Promise<void> {\n try {\n const path = await getICloudPath()\n const content = await invoke<string>('read_assistants', { basePath: path })\n\n if (content) {\n const parsed = JSON.parse(content)\n assistants.value = (parsed.assistants || []).map((a: Record<string, unknown>) => ({\n ...a,\n searchEnabled: a.searchEnabled === true,\n })) as Assistant[]\n\n // Load AI config from iCloud\n if (parsed.aiConfig) {\n aiUrl.value = parsed.aiConfig.url || defaultAiConfig.url\n aiKey.value = parsed.aiConfig.key || defaultAiConfig.key\n aiModel.value = parsed.aiConfig.model || defaultAiConfig.model\n aiConfigExists.value = true\n }\n\n // Load Baidu search key from iCloud\n if (parsed.baiduSearchKey) {\n baiduSearchKey.value = parsed.baiduSearchKey\n }\n }\n\n isLoaded.value = true\n } catch (e) {\n // If file doesn't exist or read fails, use default assistants\n console.error('Failed to load assistants, using defaults:', e)\n assistants.value = [...defaultAssistants]\n isLoaded.value = true\n }\n }\n\n /**\n * Save assistants and AI config to iCloud file\n */\n async function saveAssistants(): Promise<void> {\n try {\n const path = await getICloudPath()\n const content = JSON.stringify({\n version: 1,\n assistants: assistants.value,\n aiConfig: { url: aiUrl.value, key: aiKey.value, model: aiModel.value },\n baiduSearchKey: baiduSearchKey.value,\n }, null, 2)\n await invoke('write_assistants', { basePath: path, content })\n } catch (e) {\n console.error('Failed to save assistants:', e)\n }\n }\n\n /**\n * Add a new assistant\n */\n async function addAssistant(name: string, prompt: string, searchEnabled = false): Promise<Assistant> {\n const newAssistant: Assistant = {\n id: generateId(),\n name,\n prompt,\n searchEnabled,\n createdAt: Date.now(),\n }\n\n assistants.value.push(newAssistant)\n await saveAssistants()\n return newAssistant\n }\n\n /**\n * Update an existing assistant\n */\n async function updateAssistant(id: string, updates: Partial<Pick<Assistant, 'name' | 'prompt' | 'searchEnabled'>>): Promise<boolean> {\n const index = assistants.value.findIndex(a => a.id === id)\n if (index === -1) {\n return false\n }\n\n assistants.value[index] = {\n ...assistants.value[index],\n ...updates,\n }\n\n await saveAssistants()\n return true\n }\n\n /**\n * Delete an assistant\n */\n async function deleteAssistant(id: string): Promise<boolean> {\n const index = assistants.value.findIndex(a => a.id === id)\n if (index === -1) {\n return false\n }\n\n assistants.value.splice(index, 1)\n await saveAssistants()\n return true\n }\n\n /**\n * Get assistant by ID\n */\n function getAssistantById(id: string): Assistant | undefined {\n return assistants.value.find(a => a.id === id)\n }\n\n /**\n * Check if an assistant with the same prompt already exists\n * @param prompt The prompt to check\n * @param excludeId Optional ID to exclude from check (for updates)\n */\n function hasPrompt(prompt: string, excludeId?: string): boolean {\n return assistants.value.some(a => a.prompt === prompt && a.id !== excludeId)\n }\n\n /**\n * Check if an assistant with the same prompt already exists (excluding template assistants)\n * @param prompt The prompt to check\n * @param excludeId Optional ID to exclude from check (for updates)\n */\n function hasUserPrompt(prompt: string, excludeId?: string): boolean {\n return assistants.value.some(\n a => a.prompt === prompt && a.id !== excludeId && !a.id.startsWith('template-')\n )\n }\n\n /**\n * Update AI config (url, key, model) and persist to iCloud\n */\n async function updateAiConfig(url: string, key: string, model: string): Promise<void> {\n aiUrl.value = url\n aiKey.value = key\n aiModel.value = model\n await saveAssistants()\n }\n\n async function updateBaiduSearchKey(key: string): Promise<void> {\n baiduSearchKey.value = key\n await saveAssistants()\n }\n\n return {\n assistants,\n isLoaded,\n aiConfigExists,\n aiUrl,\n aiKey,\n aiModel,\n baiduSearchKey,\n loadAssistants,\n saveAssistants,\n addAssistant,\n updateAssistant,\n deleteAssistant,\n getAssistantById,\n hasPrompt,\n hasUserPrompt,\n updateAiConfig,\n updateBaiduSearchKey,\n }\n})\n"}, "5a5f2cb595ed65a6f7b50c44345e752ce1ce1b67": {"t": 1785759037.4990118, "n": 6869, "h": "07212cb2a5768235", "c": "import { defineStore } from 'pinia'\nimport { ref } from 'vue'\nimport { invoke } from '@tauri-apps/api/core'\nimport { useFileSystem } from '@/composables/useFileSystem'\n\n// Assistant interface\nexport interface Assistant {\n id: string\n name: string\n prompt: string\n searchEnabled: boolean\n createdAt: number // timestamp in milliseconds\n}\n\nexport interface AiConfig {\n url: string\n key: string\n model: string\n}\n\n// Default template assistants - using string literals to avoid Pinia initialization issues\nexport const defaultAssistants: Assistant[] = [\n {\n id: 'template-1',\n name: '优化内容',\n prompt: '你是一个笔记优化助手,严格按照以下规则优化笔记内容,直接输出结果,不附加任何说明。\\n' +\n '输出格式\\n' +\n '返回纯字符串,不使用 ``` 代码块包裹\\n' +\n '内容处理规则\\n' +\n '删除信息来源(如\"来源:\"\"转自:\"等)\\n' +\n '删除所有 tag 标签(如 #标签)\\n' +\n '标题处理:全文仅保留一个 H2 标题;若无标题则在顶部生成一个;若已有标题则不新增\\n' +\n '链接处理:保留核心内容中的 URL;若为裸链接可转为 Markdown 格式;禁止修改链接本身;无链接时禁止生成链接\\n' +\n '禁止输出\"注:\"\"备注:\"\"注意:\"等注释性内容\\n' +\n '禁止输出\"已优化\"\"优化笔记\"\"以下是\"等无关话语',\n createdAt: 0,\n searchEnabled: true,\n },\n {\n id: 'template-2',\n name: '提取任务',\n prompt: '从以下文本中提取待办事项,按如下格式输出:\\n' +\n '第一部分:笔记摘要\\n' +\n '用 h1–h3 标题概括笔记主题,标题 10 字以内\\n' +\n '标题下方正文仅保留日期、时间及关键信息,无则省略\\n' +\n '可适当添加表情 🎯\\n' +\n '第二部分:任务列表\\n' +\n '每条任务以 - [ ] 开头,保留时间、日期等关键信息\\n' +\n '不使用有序或无序列表,只用 - [ ] 格式\\n' +\n '特殊情况\\n' +\n '若无法提取到任务,则对笔记进行格式优化后输出\\n' +\n '不要输出任何引导语(如\"以下是……\")',\n createdAt: 0,\n searchEnabled: true,\n },\n {\n id: 'template-3',\n name: '优化提示词',\n prompt: '你是一个提示词优化专家,用户会给你一段提示词,你需要对其进行优化并直接输出结果。\\n' +\n '优化原则\\n' +\n '保留用户的原始意图,不改变核心需求\\n' +\n '补全缺失的约束条件(格式、边界情况、禁止行为等)\\n' +\n '消除歧义表达,改为明确、可执行的指令\\n' +\n '合并重复或冲突的规则\\n' +\n '结构清晰,分块呈现\\n' +\n '输出格式\\n' +\n '直接输出优化后的提示词,不加任何说明\\n' +\n '不使用 ``` 包裹\\n' +\n '不输出\"以下是优化后的提示词\"等引导语\\n' +\n '特殊情况\\n' +\n '若用户的提示词过于简单,主动补全合理的默认规则\\n' +\n '若存在矛盾规则,以最后出现的为准并合并',\n createdAt: 0,\n searchEnabled: true,\n },\n]\n\nexport const defaultAiConfig: AiConfig = {\n url: 'https://api.deepseek.com/chat/completions',\n key: '',\n model: 'deepseek-chat',\n}\n\nexport const useAssistantsStore = defineStore('assistants', () => {\n // State\n const assistants = ref<Assistant[]>([])\n const isLoaded = ref(false)\n const aiUrl = ref(defaultAiConfig.url)\n const aiKey = ref(defaultAiConfig.key)\n const aiModel = ref(defaultAiConfig.model)\n const aiConfigExists = ref(false)\n\n // File system operations\n const { getICloudPath } = useFileSystem()\n\n /**\n * Generate a unique ID using crypto.randomUUID()\n */\n function generateId(): string {\n return crypto.randomUUID()\n }\n\n /**\n * Load assistants from iCloud file\n */\n async function loadAssistants(): Promise<void> {\n try {\n const path = await getICloudPath()\n const content = await invoke<string>('read_assistants', { basePath: path })\n\n if (content) {\n const parsed = JSON.parse(content)\n assistants.value = (parsed.assistants || []).map((a: Record<string, unknown>) => ({\n ...a,\n searchEnabled: a.searchEnabled === true,\n })) as Assistant[]\n\n // Load AI config from iCloud\n if (parsed.aiConfig) {\n aiUrl.value = parsed.aiConfig.url || defaultAiConfig.url\n aiKey.value = parsed.aiConfig.key || defaultAiConfig.key\n aiModel.value = parsed.aiConfig.model || defaultAiConfig.model\n aiConfigExists.value = true\n }\n }\n\n isLoaded.value = true\n } catch (e) {\n // If file doesn't exist or read fails, use default assistants\n console.error('Failed to load assistants, using defaults:', e)\n assistants.value = [...defaultAssistants]\n isLoaded.value = true\n }\n }\n\n /**\n * Save assistants and AI config to iCloud file\n */\n async function saveAssistants(): Promise<void> {\n try {\n const path = await getICloudPath()\n const content = JSON.stringify({\n version: 1,\n assistants: assistants.value,\n aiConfig: { url: aiUrl.value, key: aiKey.value, model: aiModel.value },\n }, null, 2)\n await invoke('write_assistants', { basePath: path, content })\n } catch (e) {\n console.error('Failed to save assistants:', e)\n }\n }\n\n /**\n * Add a new assistant\n */\n async function addAssistant(name: string, prompt: string, searchEnabled = false): Promise<Assistant> {\n const newAssistant: Assistant = {\n id: generateId(),\n name,\n prompt,\n searchEnabled,\n createdAt: Date.now(),\n }\n\n assistants.value.push(newAssistant)\n await saveAssistants()\n return newAssistant\n }\n\n /**\n * Update an existing assistant\n */\n async function updateAssistant(id: string, updates: Partial<Pick<Assistant, 'name' | 'prompt' | 'searchEnabled'>>): Promise<boolean> {\n const index = assistants.value.findIndex(a => a.id === id)\n if (index === -1) {\n return false\n }\n\n assistants.value[index] = {\n ...assistants.value[index],\n ...updates,\n }\n\n await saveAssistants()\n return true\n }\n\n /**\n * Delete an assistant\n */\n async function deleteAssistant(id: string): Promise<boolean> {\n const index = assistants.value.findIndex(a => a.id === id)\n if (index === -1) {\n return false\n }\n\n assistants.value.splice(index, 1)\n await saveAssistants()\n return true\n }\n\n /**\n * Get assistant by ID\n */\n function getAssistantById(id: string): Assistant | undefined {\n return assistants.value.find(a => a.id === id)\n }\n\n /**\n * Check if an assistant with the same prompt already exists\n * @param prompt The prompt to check\n * @param excludeId Optional ID to exclude from check (for updates)\n */\n function hasPrompt(prompt: string, excludeId?: string): boolean {\n return assistants.value.some(a => a.prompt === prompt && a.id !== excludeId)\n }\n\n /**\n * Check if an assistant with the same prompt already exists (excluding template assistants)\n * @param prompt The prompt to check\n * @param excludeId Optional ID to exclude from check (for updates)\n */\n function hasUserPrompt(prompt: string, excludeId?: string): boolean {\n return assistants.value.some(\n a => a.prompt === prompt && a.id !== excludeId && !a.id.startsWith('template-')\n )\n }\n\n /**\n * Update AI config (url, key, model) and persist to iCloud\n */\n async function updateAiConfig(url: string, key: string, model: string): Promise<void> {\n aiUrl.value = url\n aiKey.value = key\n aiModel.value = model\n await saveAssistants()\n }\n\n return {\n assistants,\n isLoaded,\n aiConfigExists,\n aiUrl,\n aiKey,\n aiModel,\n loadAssistants,\n saveAssistants,\n addAssistant,\n updateAssistant,\n deleteAssistant,\n getAssistantById,\n hasPrompt,\n hasUserPrompt,\n updateAiConfig,\n }\n})\n"}, "f9681b307be973d9246a6fc16a35af2fca111574": {"t": 1785759038.81763, "n": 6572, "h": "ac17767d7c4ca3ce", "c": "import { defineStore } from 'pinia'\nimport { ref } from 'vue'\nimport { invoke } from '@tauri-apps/api/core'\nimport { useFileSystem } from '@/composables/useFileSystem'\n\n// Assistant interface\nexport interface Assistant {\n id: string\n name: string\n prompt: string\n createdAt: number // timestamp in milliseconds\n}\n\nexport interface AiConfig {\n url: string\n key: string\n model: string\n}\n\n// Default template assistants - using string literals to avoid Pinia initialization issues\nexport const defaultAssistants: Assistant[] = [\n {\n id: 'template-1',\n name: '优化内容',\n prompt: '你是一个笔记优化助手,严格按照以下规则优化笔记内容,直接输出结果,不附加任何说明。\\n' +\n '输出格式\\n' +\n '返回纯字符串,不使用 ``` 代码块包裹\\n' +\n '内容处理规则\\n' +\n '删除信息来源(如\"来源:\"\"转自:\"等)\\n' +\n '删除所有 tag 标签(如 #标签)\\n' +\n '标题处理:全文仅保留一个 H2 标题;若无标题则在顶部生成一个;若已有标题则不新增\\n' +\n '链接处理:保留核心内容中的 URL;若为裸链接可转为 Markdown 格式;禁止修改链接本身;无链接时禁止生成链接\\n' +\n '禁止输出\"注:\"\"备注:\"\"注意:\"等注释性内容\\n' +\n '禁止输出\"已优化\"\"优化笔记\"\"以下是\"等无关话语',\n createdAt: 0,\n },\n {\n id: 'template-2',\n name: '提取任务',\n prompt: '从以下文本中提取待办事项,按如下格式输出:\\n' +\n '第一部分:笔记摘要\\n' +\n '用 h1–h3 标题概括笔记主题,标题 10 字以内\\n' +\n '标题下方正文仅保留日期、时间及关键信息,无则省略\\n' +\n '可适当添加表情 🎯\\n' +\n '第二部分:任务列表\\n' +\n '每条任务以 - [ ] 开头,保留时间、日期等关键信息\\n' +\n '不使用有序或无序列表,只用 - [ ] 格式\\n' +\n '特殊情况\\n' +\n '若无法提取到任务,则对笔记进行格式优化后输出\\n' +\n '不要输出任何引导语(如\"以下是……\")',\n createdAt: 0,\n },\n {\n id: 'template-3',\n name: '优化提示词',\n prompt: '你是一个提示词优化专家,用户会给你一段提示词,你需要对其进行优化并直接输出结果。\\n' +\n '优化原则\\n' +\n '保留用户的原始意图,不改变核心需求\\n' +\n '补全缺失的约束条件(格式、边界情况、禁止行为等)\\n' +\n '消除歧义表达,改为明确、可执行的指令\\n' +\n '合并重复或冲突的规则\\n' +\n '结构清晰,分块呈现\\n' +\n '输出格式\\n' +\n '直接输出优化后的提示词,不加任何说明\\n' +\n '不使用 ``` 包裹\\n' +\n '不输出\"以下是优化后的提示词\"等引导语\\n' +\n '特殊情况\\n' +\n '若用户的提示词过于简单,主动补全合理的默认规则\\n' +\n '若存在矛盾规则,以最后出现的为准并合并',\n createdAt: 0,\n },\n]\n\nexport const defaultAiConfig: AiConfig = {\n url: 'https://api.deepseek.com/chat/completions',\n key: '',\n model: 'deepseek-chat',\n}\n\nexport const useAssistantsStore = defineStore('assistants', () => {\n // State\n const assistants = ref<Assistant[]>([])\n const isLoaded = ref(false)\n const aiUrl = ref(defaultAiConfig.url)\n const aiKey = ref(defaultAiConfig.key)\n const aiModel = ref(defaultAiConfig.model)\n const aiConfigExists = ref(false)\n\n // File system operations\n const { getICloudPath } = useFileSystem()\n\n /**\n * Generate a unique ID using crypto.randomUUID()\n */\n function generateId(): string {\n return crypto.randomUUID()\n }\n\n /**\n * Load assistants from iCloud file\n */\n async function loadAssistants(): Promise<void> {\n try {\n const path = await getICloudPath()\n const content = await invoke<string>('read_assistants', { basePath: path })\n\n if (content) {\n const parsed = JSON.parse(content)\n assistants.value = parsed.assistants || []\n\n // Load AI config from iCloud\n if (parsed.aiConfig) {\n aiUrl.value = parsed.aiConfig.url || defaultAiConfig.url\n aiKey.value = parsed.aiConfig.key || defaultAiConfig.key\n aiModel.value = parsed.aiConfig.model || defaultAiConfig.model\n aiConfigExists.value = true\n }\n }\n\n isLoaded.value = true\n } catch (e) {\n // If file doesn't exist or read fails, use default assistants\n console.error('Failed to load assistants, using defaults:', e)\n assistants.value = [...defaultAssistants]\n isLoaded.value = true\n }\n }\n\n /**\n * Save assistants and AI config to iCloud file\n */\n async function saveAssistants(): Promise<void> {\n try {\n const path = await getICloudPath()\n const content = JSON.stringify({\n version: 1,\n assistants: assistants.value,\n aiConfig: { url: aiUrl.value, key: aiKey.value, model: aiModel.value },\n }, null, 2)\n await invoke('write_assistants', { basePath: path, content })\n } catch (e) {\n console.error('Failed to save assistants:', e)\n }\n }\n\n /**\n * Add a new assistant\n */\n async function addAssistant(name: string, prompt: string): Promise<Assistant> {\n const newAssistant: Assistant = {\n id: generateId(),\n name,\n prompt,\n createdAt: Date.now(),\n }\n\n assistants.value.push(newAssistant)\n await saveAssistants()\n return newAssistant\n }\n\n /**\n * Update an existing assistant\n */\n async function updateAssistant(id: string, updates: Partial<Pick<Assistant, 'name' | 'prompt'>>): Promise<boolean> {\n const index = assistants.value.findIndex(a => a.id === id)\n if (index === -1) {\n return false\n }\n\n assistants.value[index] = {\n ...assistants.value[index],\n ...updates,\n }\n\n await saveAssistants()\n return true\n }\n\n /**\n * Delete an assistant\n */\n async function deleteAssistant(id: string): Promise<boolean> {\n const index = assistants.value.findIndex(a => a.id === id)\n if (index === -1) {\n return false\n }\n\n assistants.value.splice(index, 1)\n await saveAssistants()\n return true\n }\n\n /**\n * Get assistant by ID\n */\n function getAssistantById(id: string): Assistant | undefined {\n return assistants.value.find(a => a.id === id)\n }\n\n /**\n * Check if an assistant with the same prompt already exists\n * @param prompt The prompt to check\n * @param excludeId Optional ID to exclude from check (for updates)\n */\n function hasPrompt(prompt: string, excludeId?: string): boolean {\n return assistants.value.some(a => a.prompt === prompt && a.id !== excludeId)\n }\n\n /**\n * Check if an assistant with the same prompt already exists (excluding template assistants)\n * @param prompt The prompt to check\n * @param excludeId Optional ID to exclude from check (for updates)\n */\n function hasUserPrompt(prompt: string, excludeId?: string): boolean {\n return assistants.value.some(\n a => a.prompt === prompt && a.id !== excludeId && !a.id.startsWith('template-')\n )\n }\n\n /**\n * Update AI config (url, key, model) and persist to iCloud\n */\n async function updateAiConfig(url: string, key: string, model: string): Promise<void> {\n aiUrl.value = url\n aiKey.value = key\n aiModel.value = model\n await saveAssistants()\n }\n\n return {\n assistants,\n isLoaded,\n aiConfigExists,\n aiUrl,\n aiKey,\n aiModel,\n loadAssistants,\n saveAssistants,\n addAssistant,\n updateAssistant,\n deleteAssistant,\n getAssistantById,\n hasPrompt,\n hasUserPrompt,\n updateAiConfig,\n }\n})\n"}, "d7293c476cfef3d0088d3af28f71b053ffb930c9": {"t": 1785759040.1348577, "n": 5416, "h": "b2bf30db67b58153", "c": "import { defineStore } from 'pinia'\nimport { ref } from 'vue'\nimport { invoke } from '@tauri-apps/api/core'\nimport { useFileSystem } from '@/composables/useFileSystem'\n\n// Assistant interface\nexport interface Assistant {\n id: string\n name: string\n prompt: string\n createdAt: number // timestamp in milliseconds\n}\n\n// Default template assistants - using string literals to avoid Pinia initialization issues\nexport const defaultAssistants: Assistant[] = [\n {\n id: 'template-1',\n name: '优化内容',\n prompt: '你是一个笔记优化助手,严格按照以下规则优化笔记内容,直接输出结果,不附加任何说明。\\n' +\n '输出格式\\n' +\n '返回纯字符串,不使用 ``` 代码块包裹\\n' +\n '内容处理规则\\n' +\n '删除信息来源(如\"来源:\"\"转自:\"等)\\n' +\n '删除所有 tag 标签(如 #标签)\\n' +\n '标题处理:全文仅保留一个 H2 标题;若无标题则在顶部生成一个;若已有标题则不新增\\n' +\n '链接处理:保留核心内容中的 URL;若为裸链接可转为 Markdown 格式;禁止修改链接本身;无链接时禁止生成链接\\n' +\n '禁止输出\"注:\"\"备注:\"\"注意:\"等注释性内容\\n' +\n '禁止输出\"已优化\"\"优化笔记\"\"以下是\"等无关话语',\n createdAt: 0,\n },\n {\n id: 'template-2',\n name: '提取任务',\n prompt: '从以下文本中提取待办事项,按如下格式输出:\\n' +\n '第一部分:笔记摘要\\n' +\n '用 h1–h3 标题概括笔记主题,标题 10 字以内\\n' +\n '标题下方正文仅保留日期、时间及关键信息,无则省略\\n' +\n '可适当添加表情 🎯\\n' +\n '第二部分:任务列表\\n' +\n '每条任务以 - [ ] 开头,保留时间、日期等关键信息\\n' +\n '不使用有序或无序列表,只用 - [ ] 格式\\n' +\n '特殊情况\\n' +\n '若无法提取到任务,则对笔记进行格式优化后输出\\n' +\n '不要输出任何引导语(如\"以下是……\")',\n createdAt: 0,\n },\n {\n id: 'template-3',\n name: '优化提示词',\n prompt: '你是一个提示词优化专家,用户会给你一段提示词,你需要对其进行优化并直接输出结果。\\n' +\n '优化原则\\n' +\n '保留用户的原始意图,不改变核心需求\\n' +\n '补全缺失的约束条件(格式、边界情况、禁止行为等)\\n' +\n '消除歧义表达,改为明确、可执行的指令\\n' +\n '合并重复或冲突的规则\\n' +\n '结构清晰,分块呈现\\n' +\n '输出格式\\n' +\n '直接输出优化后的提示词,不加任何说明\\n' +\n '不使用 ``` 包裹\\n' +\n '不输出\"以下是优化后的提示词\"等引导语\\n' +\n '特殊情况\\n' +\n '若用户的提示词过于简单,主动补全合理的默认规则\\n' +\n '若存在矛盾规则,以最后出现的为准并合并',\n createdAt: 0,\n },\n]\n\nexport const useAssistantsStore = defineStore('assistants', () => {\n // State\n const assistants = ref<Assistant[]>([])\n const isLoaded = ref(false)\n\n // File system operations\n const { getICloudPath } = useFileSystem()\n\n /**\n * Generate a unique ID using crypto.randomUUID()\n */\n function generateId(): string {\n return crypto.randomUUID()\n }\n\n /**\n * Load assistants from iCloud file\n */\n async function loadAssistants(): Promise<void> {\n try {\n const path = await getICloudPath()\n const content = await invoke<string>('read_assistants', { basePath: path })\n\n if (content) {\n const parsed = JSON.parse(content)\n assistants.value = parsed.assistants || []\n }\n\n isLoaded.value = true\n } catch (e) {\n // If file doesn't exist or read fails, use default assistants\n console.error('Failed to load assistants, using defaults:', e)\n assistants.value = [...defaultAssistants]\n isLoaded.value = true\n }\n }\n\n /**\n * Save assistants to iCloud file\n */\n async function saveAssistants(): Promise<void> {\n try {\n const path = await getICloudPath()\n const content = JSON.stringify({ version: 1, assistants: assistants.value }, null, 2)\n await invoke('write_assistants', { basePath: path, content })\n } catch (e) {\n console.error('Failed to save assistants:', e)\n }\n }\n\n /**\n * Add a new assistant\n */\n async function addAssistant(name: string, prompt: string): Promise<Assistant> {\n const newAssistant: Assistant = {\n id: generateId(),\n name,\n prompt,\n createdAt: Date.now(),\n }\n\n assistants.value.push(newAssistant)\n await saveAssistants()\n return newAssistant\n }\n\n /**\n * Update an existing assistant\n */\n async function updateAssistant(id: string, updates: Partial<Pick<Assistant, 'name' | 'prompt'>>): Promise<boolean> {\n const index = assistants.value.findIndex(a => a.id === id)\n if (index === -1) {\n return false\n }\n\n assistants.value[index] = {\n ...assistants.value[index],\n ...updates,\n }\n\n await saveAssistants()\n return true\n }\n\n /**\n * Delete an assistant\n */\n async function deleteAssistant(id: string): Promise<boolean> {\n const index = assistants.value.findIndex(a => a.id === id)\n if (index === -1) {\n return false\n }\n\n assistants.value.splice(index, 1)\n await saveAssistants()\n return true\n }\n\n /**\n * Get assistant by ID\n */\n function getAssistantById(id: string): Assistant | undefined {\n return assistants.value.find(a => a.id === id)\n }\n\n /**\n * Check if an assistant with the same prompt already exists\n * @param prompt The prompt to check\n * @param excludeId Optional ID to exclude from check (for updates)\n */\n function hasPrompt(prompt: string, excludeId?: string): boolean {\n return assistants.value.some(a => a.prompt === prompt && a.id !== excludeId)\n }\n\n /**\n * Check if an assistant with the same prompt already exists (excluding template assistants)\n * @param prompt The prompt to check\n * @param excludeId Optional ID to exclude from check (for updates)\n */\n function hasUserPrompt(prompt: string, excludeId?: string): boolean {\n return assistants.value.some(\n a => a.prompt === prompt && a.id !== excludeId && !a.id.startsWith('template-')\n )\n }\n\n return {\n assistants,\n isLoaded,\n loadAssistants,\n saveAssistants,\n addAssistant,\n updateAssistant,\n deleteAssistant,\n getAssistantById,\n hasPrompt,\n hasUserPrompt,\n }\n})\n"}, "e2ee5f47ba76bb9feedeb18d50a7bd51fe959ee3": {"t": 1785759041.6421704, "n": 5387, "h": "5b2bb0f607b6d8ad", "c": "import { defineStore } from 'pinia'\nimport { ref } from 'vue'\nimport { invoke } from '@tauri-apps/api/core'\nimport { useFileSystem } from '@/composables/useFileSystem'\n\n// Assistant interface\nexport interface Assistant {\n id: string\n name: string\n prompt: string\n createdAt: number // timestamp in milliseconds\n}\n\n// Default template assistants - using string literals to avoid Pinia initialization issues\nexport const defaultAssistants: Assistant[] = [\n {\n id: 'template-1',\n name: '一号助手',\n prompt: '你是一个笔记优化助手,严格按照以下规则优化笔记内容,直接输出结果,不附加任何说明。\\n' +\n '输出格式\\n' +\n '返回纯字符串,不使用 ``` 代码块包裹\\n' +\n '内容处理规则\\n' +\n '删除信息来源(如\"来源:\"\"转自:\"等)\\n' +\n '删除所有 tag 标签(如 #标签)\\n' +\n '标题处理:全文仅保留一个 H2 标题;若无标题则在顶部生成一个;若已有标题则不新增\\n' +\n '链接处理:保留核心内容中的 URL;若为裸链接可转为 Markdown 格式;禁止修改链接本身;无链接时禁止生成链接\\n' +\n '禁止输出\"注:\"\"备注:\"\"注意:\"等注释性内容\\n' +\n '禁止输出\"已优化\"\"优化笔记\"\"以下是\"等无关话语',\n createdAt: 0,\n },\n {\n id: 'template-2',\n name: '二号助手',\n prompt: '从以下文本中提取待办事项,按如下格式输出:\\n' +\n '第一部分:笔记摘要\\n' +\n '用 h1–h3 标题概括笔记主题,标题 10 字以内\\n' +\n '标题下方正文仅保留日期、时间及关键信息,无则省略\\n' +\n '可适当添加表情 🎯\\n' +\n '第二部分:任务列表\\n' +\n '每条任务以 - [ ] 开头,保留时间、日期等关键信息\\n' +\n '不使用有序或无序列表,只用 - [ ] 格式\\n' +\n '特殊情况\\n' +\n '若无法提取到任务,则对笔记进行格式优化后输出\\n' +\n '不要输出任何引导语(如\"以下是……\")',\n createdAt: 0,\n },\n {\n id: 'template-3',\n name: '三号助手',\n prompt: '你是一个提示词优化专家,用户会给你一段提示词,你需要对其进行优化并直接输出结果。\\n' +\n '优化原则\\n' +\n '保留用户的原始意图,不改变核心需求\\n' +\n '补全缺失的约束条件(格式、边界情况、禁止行为等)\\n' +\n '消除歧义表达,改为明确、可执行的指令\\n' +\n '合并重复或冲突的规则\\n' +\n '结构清晰,分块呈现\\n' +\n '输出格式\\n' +\n '直接输出优化后的提示词,不加任何说明\\n' +\n '不使用 ``` 包裹\\n' +\n '不输出\"以下是优化后的提示词\"等引导语\\n' +\n '特殊情况\\n' +\n '若用户的提示词过于简单,主动补全合理的默认规则\\n' +\n '若存在矛盾规则,以最后出现的为准并合并',\n createdAt: 0,\n },\n]\n\nexport const useAssistantsStore = defineStore('assistants', () => {\n // State\n const assistants = ref<Assistant[]>([])\n const isLoaded = ref(false)\n\n // File system operations\n const { getICloudPath } = useFileSystem()\n\n /**\n * Generate a unique ID using crypto.randomUUID()\n */\n function generateId(): string {\n return crypto.randomUUID()\n }\n\n /**\n * Load assistants from iCloud file\n */\n async function loadAssistants(): Promise<void> {\n try {\n const path = await getICloudPath()\n const content = await invoke<string>('read_assistants', { basePath: path })\n\n if (content) {\n const parsed = JSON.parse(content)\n assistants.value = parsed.assistants || []\n }\n\n isLoaded.value = true\n } catch (e) {\n // If file doesn't exist or read fails, use default assistants\n console.error('Failed to load assistants, using defaults:', e)\n assistants.value = [...defaultAssistants]\n isLoaded.value = true\n }\n }\n\n /**\n * Save assistants to iCloud file\n */\n async function saveAssistants(): Promise<void> {\n try {\n const path = await getICloudPath()\n const content = JSON.stringify(assistants.value, null, 2)\n await invoke('write_assistants', { basePath: path, content })\n } catch (e) {\n console.error('Failed to save assistants:', e)\n }\n }\n\n /**\n * Add a new assistant\n */\n async function addAssistant(name: string, prompt: string): Promise<Assistant> {\n const newAssistant: Assistant = {\n id: generateId(),\n name,\n prompt,\n createdAt: Date.now(),\n }\n\n assistants.value.push(newAssistant)\n await saveAssistants()\n return newAssistant\n }\n\n /**\n * Update an existing assistant\n */\n async function updateAssistant(id: string, updates: Partial<Pick<Assistant, 'name' | 'prompt'>>): Promise<boolean> {\n const index = assistants.value.findIndex(a => a.id === id)\n if (index === -1) {\n return false\n }\n\n assistants.value[index] = {\n ...assistants.value[index],\n ...updates,\n }\n\n await saveAssistants()\n return true\n }\n\n /**\n * Delete an assistant\n */\n async function deleteAssistant(id: string): Promise<boolean> {\n const index = assistants.value.findIndex(a => a.id === id)\n if (index === -1) {\n return false\n }\n\n assistants.value.splice(index, 1)\n await saveAssistants()\n return true\n }\n\n /**\n * Get assistant by ID\n */\n function getAssistantById(id: string): Assistant | undefined {\n return assistants.value.find(a => a.id === id)\n }\n\n /**\n * Check if an assistant with the same prompt already exists\n * @param prompt The prompt to check\n * @param excludeId Optional ID to exclude from check (for updates)\n */\n function hasPrompt(prompt: string, excludeId?: string): boolean {\n return assistants.value.some(a => a.prompt === prompt && a.id !== excludeId)\n }\n\n /**\n * Check if an assistant with the same prompt already exists (excluding template assistants)\n * @param prompt The prompt to check\n * @param excludeId Optional ID to exclude from check (for updates)\n */\n function hasUserPrompt(prompt: string, excludeId?: string): boolean {\n return assistants.value.some(\n a => a.prompt === prompt && a.id !== excludeId && !a.id.startsWith('template-')\n )\n }\n\n return {\n assistants,\n isLoaded,\n loadAssistants,\n saveAssistants,\n addAssistant,\n updateAssistant,\n deleteAssistant,\n getAssistantById,\n hasPrompt,\n hasUserPrompt,\n }\n})\n"}}}} |