Update the package.json and pnpm-lock.yaml files by adding dependencies for sanitize-basename and unsanitize-basename, optimize the chat manager to support new filename formats, and improve code readability as well as user experience.

This commit is contained in:
duanfuxiang 2025-07-07 21:35:04 +08:00
parent 306817741f
commit d3271f85e9
6 changed files with 139 additions and 68 deletions

View File

@ -4,17 +4,26 @@
<a href="README.md" target="_blank"><b>English</b></a> | <a href="README_zh-CN.md" target="_blank"><b>中文</b></a>
## Latest Version
[0.5.0](https://github.com/infiolab/infio-copilot/releases/tag/0.5.0) Enhanced performance and stability improvements, added MCP support
## ✨ What's New
[0.7.2](https://github.com/infiolab/infio-copilot/releases/tag/0.7.2)
We're excited to announce a major update packed with new features to streamline your workflow and supercharge your knowledge management within Obsidian.
---
## Recent Updates
[0.2.4](https://github.com/infiolab/infio-copilot/releases/tag/0.2.4) Added multilingual support
* **🚀 Out-of-the-Box Embedding Model**
To help you get started faster, we now include a default local embedding model (`bge-micro-v2`). No more manual setup is required to use powerful semantic features!
[0.2.3](https://github.com/infiolab/infio-copilot/releases/tag/0.2.3) Add custom mode config, you can create you own agent now
* **🗂️ Workspaces**
Organize your projects, research, and personal notes with the new **Workspaces** feature. Keep your context clean and switch between different setups seamlessly.
[0.1.7](https://github.com/infiolab/infio-copilot/releases/tag/0.1.7) Added image selector modal, allowing users to search, select, and upload images in obsidian vault or local file browser
* **💡 Insights**
Go beyond simple notes with our new **Insights** feature. Synthesize information, discover connections, and gain a deeper understanding of your knowledge base.
* **🔍 Advanced Multi-Dimensional Queries**
Converse with your notes! You can now perform complex queries based on various dimensions like time, tasks, and other metadata. Finding the exact piece of information has never been easier.
* **✍️ New "Write" Mode**
We've rebuilt our **Write** mode from the ground up to provide a more intuitive, powerful, and distraction-free writing experience.
[0.1.6](https://github.com/infiolab/infio-copilot/releases/tag/0.1.6) update apply view, you can edit content in apply view
## Features
@ -24,10 +33,15 @@
| 📝 Autocomplete | Receive context-aware writing suggestions as you type |
| ✏️ Inline Editing | Edit your notes directly within the current file |
| 🔍 Vault Chat | Interact with your entire Obsidian vault using AI |
| 🖼️ Image Analysis | Upload and analyze images from your vault or local system |
| 🔍 Vault Search | Use semantic search to explore your entire vault |
| ⌨️ Commands | Create and manage custom commands for quick actions |
| 🎯 Custom Mode | Define personalized AI modes with specific behaviors |
| 🔌 MCP | Manage Model Context Protocol integrations |
| 🗂️ Workspaces | Organize projects, research, and personal notes with seamless context switching |
| 💡 Insights | Synthesize information, discover connections, and gain deeper understanding |
| 🔍 dataview query | Perform complex queries based on time, tasks, and metadata |
| ✍️ New Write Mode | Rebuilt writing experience with intuitive, powerful, and distraction-free interface |
### Chat & Edit Flow
@ -83,8 +97,8 @@ Leverage the power of AI to interact with your entire Obsidian vault, gaining in
* Infio Copilot: Infio add selection to chat -> cmd + shift + L
* Infio Copilot: Infio Inline Edit -> cmd + shift + K
![autocomplte](asserts/doc-set-hotkey.png)
7. If you need to chat with documents, you must configure an embedding model.
- Currently, only SiliconFlow, Alibaba, Google, and OpenAI platforms support embedding models.
7. **NEW: Out-of-the-Box Embedding Model** - The plugin now includes a default local embedding model (`bge-micro-v2`), so you can start using semantic features immediately! For enhanced performance, you can still configure additional embedding models:
- Currently, SiliconFlow, Alibaba, Google, and OpenAI platforms support embedding models.
## Feedback and Support
We value your input and want to ensure you can easily share your thoughts and report any issues:

View File

@ -10,17 +10,20 @@ Infio Copilot 是一款可高度个人定制化的 Obsidian AI 插件,旨在
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/felixduan)
## 最新版本
[0.5.0](https://github.com/infiolab/infio-copilot/releases/tag/0.5.0) 增强性能和稳定性改进, 增加了 MC P支持
# 🚀 新版本发布:引入工作区、洞察与本地模型!
## 最近更新
[0.2.4](https://github.com/infiolab/infio-copilot/releases/tag/0.2.4) 增加了多语言支持
我们很高兴地宣布一个重要更新,它将彻底改变您的知识管理体验。此版本引入了强大的新功能,如工作区、洞察、以及开箱即用的本地嵌入模型,让您更深入地与笔记互动。
[0.2.3](https://github.com/infiolab/infio-copilot/releases/tag/0.2.3) 增加了自定义模式配置,现在无法创建自己的 agent
---
* **🧠 内置本地嵌入模型**:现在默认包含 `LocalProdver(bge-micro-v2)` 模型。无需任何额外配置,即可享受强大的本地语义搜索和分析功能。
[0.1.7](https://github.com/infiolab/infio-copilot/releases/tag/0.1.7) 增加了图片选择器模态框,允许用户在 Obsidian vault 或本地文件浏览器中搜索、选择和上传图片
* **🗂️ 工作区 (Workspaces)**:引入全新的工作区功能,帮助您更好地组织和隔离不同的项目和知识领域,让您的工作流更加清晰。
[0.1.6](https://github.com/infiolab/infio-copilot/releases/tag/0.1.6) 更新了应用视图 (apply view),现在可以在应用视图中编辑内容
* **💡 洞察 (Insights)**:我们增加了强大的“洞察”功能。您可以从笔记中提取关键摘要、进行反思或生成内容大纲,从您的知识库中发现深层联系。
* **🔍 多维度查询与对话**:像与人交谈一样与您的笔记互动。现在您可以根据时间、任务状态等多种维度进行查询,轻松找到所需信息。
* **✍️ 全新 `write` 模式**:一个专为写作而生的新模式,提供更专注、更流畅的创作体验,帮助您将想法转化为结构清晰的文档。
## 功能特点
@ -30,10 +33,14 @@ Infio Copilot 是一款可高度个人定制化的 Obsidian AI 插件,旨在
| 📝 智能补全 | 在输入时获取上下文感知的写作建议 |
| ✏️ 内联编辑 | 直接在当前文件中编辑笔记 |
| 🔍 全库对话 | 使用 AI 与整个 Obsidian vault 交互 |
| 🖼️ 图片分析 | 上传并分析来自 vault 或本地系统的图片 |
| 语义搜索 | |
| ⌨️ 快捷命令 | 创建和管理自定义快捷命令,实现快速操作 |
| 🎯 自定义Mode | 定义具有特定行为的个性化 AI 模式 |
| 🔌 MCP | 管理模型上下文协议集成 |
| 🗂️ 工作空间 | 组织项目、研究和个人笔记,无缝切换上下文 |
| 💡 深度洞察 | 综合信息、发现连接、获得更深层次的理解 |
| 🔍 多维查询 | 基于时间、任务和元数据执行复杂查询 |
| ✍️ 新写作模式 | 重构的写作体验,提供直观、强大且无干扰的界面 |
### 🖋️ 内联编辑
@ -95,8 +102,6 @@ Infio Copilot 是一款可高度个人定制化的 Obsidian AI 插件,旨在
* Infio Copilot: Infio add selection to chat -> cmd + shift + L
* Infio Copilot: Infio Inline Edit -> cmd + shift + K
![autocomplte](asserts/doc-set-hotkey.png)
7. 如果需要 跟文档聊天 , 需要配置 embedding 模型
- 目前之后 SiliconFlow Alibaba Google OpenAI 平台支持嵌入模型
## 反馈与支持
我们重视您的意见,并希望确保您能轻松分享想法和报告问题:

View File

@ -120,11 +120,13 @@
"rehype-raw": "^7.0.0",
"remark-gfm": "^4.0.0",
"remove-markdown": "^0.6.2",
"sanitize-basename": "^2.0.2",
"shell-env": "^4.0.1",
"simple-git": "^3.27.0",
"smart-embed-model": "^1.0.7",
"string-similarity": "^4.0.4",
"styled-components": "^6.1.19",
"unsanitize-basename": "^2.0.1",
"uuid": "^10.0.0",
"zod": "3.24.2"
},

53
pnpm-lock.yaml generated
View File

@ -153,9 +153,6 @@ importers:
lucide-react:
specifier: ^0.447.0
version: 0.447.0(react@18.3.1)
markdown-to-text:
specifier: ^0.1.1
version: 0.1.1
mermaid:
specifier: ^11.6.0
version: 11.8.0
@ -213,6 +210,9 @@ importers:
remove-markdown:
specifier: ^0.6.2
version: 0.6.2
sanitize-basename:
specifier: ^2.0.2
version: 2.0.2
shell-env:
specifier: ^4.0.1
version: 4.0.1
@ -228,6 +228,9 @@ importers:
styled-components:
specifier: ^6.1.19
version: 6.1.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
unsanitize-basename:
specifier: ^2.0.1
version: 2.0.1
uuid:
specifier: ^10.0.0
version: 10.0.0
@ -580,8 +583,8 @@ packages:
'@codemirror/language@6.11.2':
resolution: {integrity: sha512-p44TsNArL4IVXDTbapUmEkAlvWs2CFQbcfc0ymDsis1kH2wh0gcY96AS29c/vp2d0y2Tquk1EDSaawpzilUiAw==}
'@codemirror/language@git+https://git@github.com:lishid/cm-language.git#6c1c5f5b677f6f6503d1ca2ec47f62f6406cda67':
resolution: {commit: 6c1c5f5b677f6f6503d1ca2ec47f62f6406cda67, repo: git@github.com:lishid/cm-language.git, type: git}
'@codemirror/language@https://codeload.github.com/lishid/cm-language/tar.gz/6c1c5f5b677f6f6503d1ca2ec47f62f6406cda67':
resolution: {tarball: https://codeload.github.com/lishid/cm-language/tar.gz/6c1c5f5b677f6f6503d1ca2ec47f62f6406cda67}
version: 6.10.8
'@codemirror/lint@0.20.3':
@ -2436,9 +2439,6 @@ packages:
'@types/babel__traverse@7.20.7':
resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==}
'@types/chai@4.3.20':
resolution: {integrity: sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==}
'@types/codemirror@5.60.8':
resolution: {integrity: sha512-VjFgDF/eB+Aklcy15TtOTLQeMjTo07k7KAjql8OK5Dirr7a6sJY4T1uVBDuTVG9VEmn1uUsohOpYnVfgC6/jyw==}
@ -2608,9 +2608,6 @@ packages:
resolution: {integrity: sha512-AlvLWYer6u4BkO4QzMkHo0t9RkvVIgqggVZmO+5snUiuX2caTKqtdqygX6GeE1VQa/TnXw9WoH0spcmHtG0inQ==}
deprecated: This is a stub types definition. mermaid provides its own type definitions, so you do not need this installed.
'@types/mocha@8.2.3':
resolution: {integrity: sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw==}
'@types/ms@2.1.0':
resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==}
@ -5027,9 +5024,6 @@ packages:
markdown-table@3.0.4:
resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
markdown-to-text@0.1.1:
resolution: {integrity: sha512-co/J5l8mJ2RK9wD/nQRGwO7JxoeyfvVNtOZll016EdAX2qYkwCWMdtYvJO42b41Ho7GFEJMuly9llf0Nj+ReQw==}
marked@15.0.12:
resolution: {integrity: sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==}
engines: {node: '>= 18'}
@ -5454,8 +5448,8 @@ packages:
'@codemirror/state': ^6.0.0
'@codemirror/view': ^6.0.0
obsidian@git+https://git@github.com:obsidianmd/obsidian-api.git#103ff76a0712a02dd0da28646b5a6b0ba6686d66:
resolution: {commit: 103ff76a0712a02dd0da28646b5a6b0ba6686d66, repo: git@github.com:obsidianmd/obsidian-api.git, type: git}
obsidian@https://codeload.github.com/obsidianmd/obsidian-api/tar.gz/103ff76a0712a02dd0da28646b5a6b0ba6686d66:
resolution: {tarball: https://codeload.github.com/obsidianmd/obsidian-api/tar.gz/103ff76a0712a02dd0da28646b5a6b0ba6686d66}
version: 1.8.7
peerDependencies:
'@codemirror/state': ^6.0.0
@ -6017,6 +6011,9 @@ packages:
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
sanitize-basename@2.0.2:
resolution: {integrity: sha512-zaOQiK4PPsUQZ0Nx3KCrT9p0oEx1dTef14qflYq7TdxPRI2RY9faLYuExCiF8LiJdeKVYb5o/KdF0fGEvvEZUA==}
saxes@6.0.0:
resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
engines: {node: '>=v12.22.7'}
@ -6514,6 +6511,9 @@ packages:
resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==}
engines: {node: '>= 0.8'}
unsanitize-basename@2.0.1:
resolution: {integrity: sha512-ywgB/ygePvtjszN3ZTK9H+OWF7Bt2AFbeLDxkx01/EjWuB4DhmdFpkLv2sg0twaZbELi+JQjLUwjZrVbgQSuJg==}
update-browserslist-db@1.1.3:
resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==}
hasBin: true
@ -7089,7 +7089,7 @@ snapshots:
'@lezer/lr': 1.4.2
style-mod: 4.1.2
'@codemirror/language@git+https://git@github.com:lishid/cm-language.git#6c1c5f5b677f6f6503d1ca2ec47f62f6406cda67':
'@codemirror/language@https://codeload.github.com/lishid/cm-language/tar.gz/6c1c5f5b677f6f6503d1ca2ec47f62f6406cda67':
dependencies:
'@codemirror/state': 6.5.2
'@codemirror/view': 6.38.0
@ -8967,8 +8967,6 @@ snapshots:
dependencies:
'@babel/types': 7.28.0
'@types/chai@4.3.20': {}
'@types/codemirror@5.60.8':
dependencies:
'@types/tern': 0.23.9
@ -9175,8 +9173,6 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@types/mocha@8.2.3': {}
'@types/ms@2.1.0': {}
'@types/node-fetch@2.6.12':
@ -12055,11 +12051,6 @@ snapshots:
markdown-table@3.0.4: {}
markdown-to-text@0.1.1:
dependencies:
'@types/chai': 4.3.20
'@types/mocha': 8.2.3
marked@15.0.12: {}
matcher@3.0.0:
@ -12604,7 +12595,7 @@ snapshots:
obsidian-daily-notes-interface@0.8.4(@codemirror/state@6.5.2)(@codemirror/view@6.38.0):
dependencies:
obsidian: git+https://git@github.com:obsidianmd/obsidian-api.git#103ff76a0712a02dd0da28646b5a6b0ba6686d66(@codemirror/state@6.5.2)(@codemirror/view@6.38.0)
obsidian: https://codeload.github.com/obsidianmd/obsidian-api/tar.gz/103ff76a0712a02dd0da28646b5a6b0ba6686d66(@codemirror/state@6.5.2)(@codemirror/view@6.38.0)
tslib: 2.1.0
transitivePeerDependencies:
- '@codemirror/state'
@ -12612,7 +12603,7 @@ snapshots:
obsidian-dataview@0.5.68:
dependencies:
'@codemirror/language': git+https://git@github.com:lishid/cm-language.git#6c1c5f5b677f6f6503d1ca2ec47f62f6406cda67
'@codemirror/language': https://codeload.github.com/lishid/cm-language/tar.gz/6c1c5f5b677f6f6503d1ca2ec47f62f6406cda67
'@codemirror/state': 6.5.2
'@codemirror/view': 6.38.0
emoji-regex: 10.4.0
@ -12631,7 +12622,7 @@ snapshots:
'@types/codemirror': 5.60.8
moment: 2.29.4
obsidian@git+https://git@github.com:obsidianmd/obsidian-api.git#103ff76a0712a02dd0da28646b5a6b0ba6686d66(@codemirror/state@6.5.2)(@codemirror/view@6.38.0):
obsidian@https://codeload.github.com/obsidianmd/obsidian-api/tar.gz/103ff76a0712a02dd0da28646b5a6b0ba6686d66(@codemirror/state@6.5.2)(@codemirror/view@6.38.0):
dependencies:
'@codemirror/state': 6.5.2
'@codemirror/view': 6.38.0
@ -13336,6 +13327,8 @@ snapshots:
safer-buffer@2.1.2: {}
sanitize-basename@2.0.2: {}
saxes@6.0.0:
dependencies:
xmlchars: 2.2.0
@ -13991,6 +13984,8 @@ snapshots:
unpipe@1.0.0: {}
unsanitize-basename@2.0.1: {}
update-browserslist-db@1.1.3(browserslist@4.25.1):
dependencies:
browserslist: 4.25.1

View File

@ -1,5 +1,7 @@
import { App } from 'obsidian'
import { v4 as uuidv4 } from 'uuid'
import sanitize from 'sanitize-basename'
import unsanitize from 'unsanitize-basename'
import { ChatConversationMeta } from '../../../types/chat'
import { AbstractJsonRepository } from '../base'
@ -12,7 +14,6 @@ import {
ChatConversation
} from './types'
export class ChatManager extends AbstractJsonRepository<
ChatConversation,
ChatConversationMeta
@ -25,22 +26,72 @@ export class ChatManager extends AbstractJsonRepository<
}
protected generateFileName(chat: ChatConversation): string {
// 新格式: v{schemaVersion}_{title}_{updatedAt}_{id}_{workspaceId}.json
// 新格式 v2: v{schemaVersion}_{sanitizedTitle}_{updatedAt}_{id}_{workspaceId}.json
const sanitizedTitle = sanitize(chat.title, { maxLength: 100 })
// 如果没有工作区,使用 'vault' 作为默认值
const encodedTitle = encodeURIComponent(chat.title)
const workspaceId = chat.workspace || 'vault'
return `v${chat.schemaVersion}_${encodedTitle}_${chat.updatedAt}_${chat.id}_${workspaceId}.json`
return `v${chat.schemaVersion}_${sanitizedTitle}_${chat.updatedAt}_${chat.id}_${workspaceId}.json`
}
protected parseFileName(fileName: string): ChatConversationMeta | null {
// 使用一个正则表达式,工作区部分为可选: v{schemaVersion}_{title}_{updatedAt}_{id}_{workspaceId}?.json
// 通过头两个字符判断版本
if (fileName.startsWith('v2_')) {
return this.parseFileNameV2(fileName)
} else if (fileName.startsWith('v1_')) {
return this.parseFileNameV1(fileName)
}
return null
}
/**
* (v2)
* 格式: v2_{sanitizedTitle}_{updatedAt}_{id}_{workspaceId}.json
*/
private parseFileNameV2(fileName: string): ChatConversationMeta | null {
const regex = new RegExp(
`^v${CHAT_SCHEMA_VERSION}_(.+)_(\\d+)_([0-9a-f-]+)(?:_([^_]+))?\\.json$`,
`^v2_(.+)_(\\d+)_([0-9a-f-]+)(?:_([^_]+))?\\.json$`,
)
const match = fileName.match(regex)
if (!match) return null
try {
// 使用 unsanitize-basename 还原原始标题
const title = unsanitize(match[1])
const updatedAt = parseInt(match[2], 10)
const id = match[3]
const workspaceId = match[4] // 可能为undefined老格式
return {
id,
schemaVersion: 2,
title,
updatedAt,
createdAt: 0,
// 如果没有工作区信息老格式则认为是vault全局消息
workspace: workspaceId === 'vault' ? undefined : workspaceId,
}
} catch (error) {
console.warn('Failed to unsanitize filename:', fileName, error)
return null
}
}
/**
* (v1)
* 格式: v1_{encodedTitle}_{updatedAt}_{id}_{workspaceId}.json
*/
private parseFileNameV1(fileName: string): ChatConversationMeta | null {
const regex = new RegExp(
`^v1_(.+)_(\\d+)_([0-9a-f-]+)(?:_([^_]+))?\\.json$`,
)
const match = fileName.match(regex)
if (!match) return null
try {
// 旧版本使用 decodeURIComponent
const title = decodeURIComponent(match[1])
const updatedAt = parseInt(match[2], 10)
const id = match[3]
@ -48,13 +99,17 @@ export class ChatManager extends AbstractJsonRepository<
return {
id,
schemaVersion: CHAT_SCHEMA_VERSION,
schemaVersion: 1,
title,
updatedAt,
createdAt: 0,
// 如果没有工作区信息老格式则认为是vault全局消息
workspace: workspaceId === 'vault' ? undefined : workspaceId,
}
} catch (error) {
console.warn('Failed to decode v1 filename:', fileName, error)
return null
}
}
public async createChat(

View File

@ -1,6 +1,6 @@
import { SerializedChatMessage } from '../../../types/chat'
export const CHAT_SCHEMA_VERSION = 1
export const CHAT_SCHEMA_VERSION = 2
export type ChatConversation = {
id: string