mirror of
https://github.com/EthanMarti/infio-copilot.git
synced 2026-01-16 08:21:55 +00:00
fix lint type error
This commit is contained in:
parent
0178a9b024
commit
a722e2ca40
@ -1,4 +1,9 @@
|
||||
releases:
|
||||
- version: "0.1.6"
|
||||
features:
|
||||
- "update model select in chat view, add collected models "
|
||||
- "fix vault obsidian sync error"
|
||||
- "update apply view, you can edit content in apply view"
|
||||
- version: "0.1.5"
|
||||
features:
|
||||
- "hotfix command view style"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"id": "infio-copilot",
|
||||
"name": "Infio Copilot",
|
||||
"version": "0.1.5",
|
||||
"version": "0.1.6",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "A Cursor-inspired AI assistant for notes that offers smart autocomplete and interactive chat with your selected notes",
|
||||
"author": "Felix.D",
|
||||
|
||||
@ -17,8 +17,8 @@ export interface QuickCommand {
|
||||
name: string
|
||||
content: TemplateContent
|
||||
contentText: string
|
||||
createdAt: Date | undefined
|
||||
updatedAt: Date | undefined
|
||||
createdAt: number
|
||||
updatedAt: number
|
||||
}
|
||||
|
||||
const CommandsView = (
|
||||
|
||||
@ -212,7 +212,6 @@ export function ModelSelect() {
|
||||
return results
|
||||
}, [searchableItems, searchTerm, fuse])
|
||||
|
||||
// 添加或删除收藏
|
||||
const toggleCollected = (id: string, e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
@ -224,12 +223,12 @@ export function ModelSelect() {
|
||||
let newCollectedModels = settings.collectedChatModels || [];
|
||||
|
||||
if (isCurrentlyCollected) {
|
||||
// 移除收藏
|
||||
// remove
|
||||
newCollectedModels = newCollectedModels.filter(
|
||||
item => !(item.provider === modelProvider && item.modelId === id)
|
||||
);
|
||||
} else {
|
||||
// 添加收藏
|
||||
// add
|
||||
newCollectedModels = [...newCollectedModels, { provider: modelProvider, modelId: id }];
|
||||
}
|
||||
|
||||
@ -253,7 +252,7 @@ export function ModelSelect() {
|
||||
|
||||
<DropdownMenu.Portal>
|
||||
<DropdownMenu.Content className="infio-popover infio-llm-setting-combobox-dropdown">
|
||||
{/* 收藏的模型区域 - 所有providers的收藏模型 */}
|
||||
{/* collected models */}
|
||||
{settings.collectedChatModels?.length > 0 && (
|
||||
<div className="infio-model-section">
|
||||
<div className="infio-model-section-title">
|
||||
@ -292,8 +291,7 @@ export function ModelSelect() {
|
||||
<Star size={16} className="infio-star-active" onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
// 从收藏中删除
|
||||
// delete
|
||||
const newCollectedModels = settings.collectedChatModels.filter(
|
||||
item => !(item.provider === collectedModel.provider && item.modelId === collectedModel.modelId)
|
||||
);
|
||||
|
||||
@ -1,115 +1,117 @@
|
||||
import { App } from 'obsidian'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
import { ChatConversationMeta } from '../../../types/chat'
|
||||
import { AbstractJsonRepository } from '../base'
|
||||
import { CHAT_DIR, ROOT_DIR } from '../constants'
|
||||
import { EmptyChatTitleException } from '../exception'
|
||||
|
||||
import {
|
||||
CHAT_SCHEMA_VERSION,
|
||||
ChatConversation,
|
||||
ChatConversationMetadata,
|
||||
CHAT_SCHEMA_VERSION,
|
||||
ChatConversation
|
||||
} from './types'
|
||||
|
||||
|
||||
export class ChatManager extends AbstractJsonRepository<
|
||||
ChatConversation,
|
||||
ChatConversationMetadata
|
||||
ChatConversation,
|
||||
ChatConversationMeta
|
||||
> {
|
||||
constructor(app: App) {
|
||||
super(app, `${ROOT_DIR}/${CHAT_DIR}`)
|
||||
}
|
||||
constructor(app: App) {
|
||||
super(app, `${ROOT_DIR}/${CHAT_DIR}`)
|
||||
}
|
||||
|
||||
protected generateFileName(chat: ChatConversation): string {
|
||||
// Format: v{schemaVersion}_{title}_{updatedAt}_{id}.json
|
||||
const encodedTitle = encodeURIComponent(chat.title)
|
||||
return `v${chat.schemaVersion}_${encodedTitle}_${chat.updatedAt}_${chat.id}.json`
|
||||
}
|
||||
protected generateFileName(chat: ChatConversation): string {
|
||||
// Format: v{schemaVersion}_{title}_{updatedAt}_{id}.json
|
||||
const encodedTitle = encodeURIComponent(chat.title)
|
||||
return `v${chat.schemaVersion}_${encodedTitle}_${chat.updatedAt}_${chat.id}.json`
|
||||
}
|
||||
|
||||
protected parseFileName(fileName: string): ChatConversationMetadata | null {
|
||||
// Parse: v{schemaVersion}_{title}_{updatedAt}_{id}.json
|
||||
const regex = new RegExp(
|
||||
`^v${CHAT_SCHEMA_VERSION}_(.+)_(\\d+)_([0-9a-f-]+)\\.json$`,
|
||||
)
|
||||
const match = fileName.match(regex)
|
||||
if (!match) return null
|
||||
protected parseFileName(fileName: string): ChatConversationMeta | null {
|
||||
// Parse: v{schemaVersion}_{title}_{updatedAt}_{id}.json
|
||||
const regex = new RegExp(
|
||||
`^v${CHAT_SCHEMA_VERSION}_(.+)_(\\d+)_([0-9a-f-]+)\\.json$`,
|
||||
)
|
||||
const match = fileName.match(regex)
|
||||
if (!match) return null
|
||||
|
||||
const title = decodeURIComponent(match[1])
|
||||
const updatedAt = parseInt(match[2], 10)
|
||||
const id = match[3]
|
||||
const title = decodeURIComponent(match[1])
|
||||
const updatedAt = parseInt(match[2], 10)
|
||||
const id = match[3]
|
||||
|
||||
return {
|
||||
id,
|
||||
schemaVersion: CHAT_SCHEMA_VERSION,
|
||||
title,
|
||||
updatedAt,
|
||||
}
|
||||
}
|
||||
return {
|
||||
id,
|
||||
schemaVersion: CHAT_SCHEMA_VERSION,
|
||||
title,
|
||||
updatedAt,
|
||||
createdAt: 0,
|
||||
}
|
||||
}
|
||||
|
||||
public async createChat(
|
||||
initialData: Partial<ChatConversation>,
|
||||
): Promise<ChatConversation> {
|
||||
if (initialData.title && initialData.title.length === 0) {
|
||||
throw new EmptyChatTitleException()
|
||||
}
|
||||
public async createChat(
|
||||
initialData: Partial<ChatConversation>,
|
||||
): Promise<ChatConversation> {
|
||||
if (initialData.title && initialData.title.length === 0) {
|
||||
throw new EmptyChatTitleException()
|
||||
}
|
||||
|
||||
const now = Date.now()
|
||||
const newChat: ChatConversation = {
|
||||
id: uuidv4(),
|
||||
title: 'New chat',
|
||||
messages: [],
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
schemaVersion: CHAT_SCHEMA_VERSION,
|
||||
...initialData,
|
||||
}
|
||||
const now = Date.now()
|
||||
const newChat: ChatConversation = {
|
||||
id: uuidv4(),
|
||||
title: 'New chat',
|
||||
messages: [],
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
schemaVersion: CHAT_SCHEMA_VERSION,
|
||||
...initialData,
|
||||
}
|
||||
|
||||
await this.create(newChat)
|
||||
return newChat
|
||||
}
|
||||
await this.create(newChat)
|
||||
return newChat
|
||||
}
|
||||
|
||||
public async findById(id: string): Promise<ChatConversation | null> {
|
||||
const allMetadata = await this.listMetadata()
|
||||
const targetMetadata = allMetadata.find((meta) => meta.id === id)
|
||||
public async findById(id: string): Promise<ChatConversation | null> {
|
||||
const allMetadata = await this.listMetadata()
|
||||
const targetMetadata = allMetadata.find((meta) => meta.id === id)
|
||||
|
||||
if (!targetMetadata) return null
|
||||
if (!targetMetadata) return null
|
||||
|
||||
return this.read(targetMetadata.fileName)
|
||||
}
|
||||
return this.read(targetMetadata.fileName)
|
||||
}
|
||||
|
||||
public async updateChat(
|
||||
id: string,
|
||||
updates: Partial<
|
||||
Omit<ChatConversation, 'id' | 'createdAt' | 'updatedAt' | 'schemaVersion'>
|
||||
>,
|
||||
): Promise<ChatConversation | null> {
|
||||
const chat = await this.findById(id)
|
||||
if (!chat) return null
|
||||
public async updateChat(
|
||||
id: string,
|
||||
updates: Partial<
|
||||
Omit<ChatConversation, 'id' | 'createdAt' | 'updatedAt' | 'schemaVersion'>
|
||||
>,
|
||||
): Promise<ChatConversation | null> {
|
||||
const chat = await this.findById(id)
|
||||
if (!chat) return null
|
||||
|
||||
if (updates.title !== undefined && updates.title.length === 0) {
|
||||
throw new EmptyChatTitleException()
|
||||
}
|
||||
if (updates.title !== undefined && updates.title.length === 0) {
|
||||
throw new EmptyChatTitleException()
|
||||
}
|
||||
|
||||
const updatedChat: ChatConversation = {
|
||||
...chat,
|
||||
...updates,
|
||||
updatedAt: Date.now(),
|
||||
}
|
||||
const updatedChat: ChatConversation = {
|
||||
...chat,
|
||||
...updates,
|
||||
updatedAt: Date.now(),
|
||||
}
|
||||
|
||||
await this.update(chat, updatedChat)
|
||||
return updatedChat
|
||||
}
|
||||
await this.update(chat, updatedChat)
|
||||
return updatedChat
|
||||
}
|
||||
|
||||
public async deleteChat(id: string): Promise<boolean> {
|
||||
const allMetadata = await this.listMetadata()
|
||||
const targetMetadata = allMetadata.find((meta) => meta.id === id)
|
||||
if (!targetMetadata) return false
|
||||
public async deleteChat(id: string): Promise<boolean> {
|
||||
const allMetadata = await this.listMetadata()
|
||||
const targetMetadata = allMetadata.find((meta) => meta.id === id)
|
||||
if (!targetMetadata) return false
|
||||
|
||||
await this.delete(targetMetadata.fileName)
|
||||
return true
|
||||
}
|
||||
await this.delete(targetMetadata.fileName)
|
||||
return true
|
||||
}
|
||||
|
||||
public async listChats(): Promise<ChatConversationMetadata[]> {
|
||||
const metadata = await this.listMetadata()
|
||||
return metadata.sort((a, b) => b.updatedAt - a.updatedAt)
|
||||
}
|
||||
public async listChats(): Promise<ChatConversationMeta[]> {
|
||||
const metadata = await this.listMetadata()
|
||||
return metadata.sort((a, b) => b.updatedAt - a.updatedAt)
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,35 +5,34 @@ import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { editorStateToPlainText } from '../components/chat-view/chat-input/utils/editor-state-to-plain-text'
|
||||
import { useApp } from '../contexts/AppContext'
|
||||
import { ChatManager } from '../database/json/chat/ChatManager'
|
||||
import { ChatConversationMetadata } from '../database/json/chat/types'
|
||||
import { deserializeChatMessage, serializeChatMessage } from '../database/json/utils'
|
||||
import { ChatMessage } from '../types/chat'
|
||||
import { ChatConversationMeta, ChatMessage, ChatUserMessage } from '../types/chat'
|
||||
|
||||
type UseChatHistory = {
|
||||
createOrUpdateConversation: (
|
||||
id: string,
|
||||
messages: ChatMessage[],
|
||||
) => Promise<void>
|
||||
deleteConversation: (id: string) => Promise<void>
|
||||
getChatMessagesById: (id: string) => Promise<ChatMessage[] | null>
|
||||
updateConversationTitle: (id: string, title: string) => Promise<void>
|
||||
chatList: ChatConversationMetadata[]
|
||||
createOrUpdateConversation: (
|
||||
id: string,
|
||||
messages: ChatMessage[],
|
||||
) => Promise<void>
|
||||
deleteConversation: (id: string) => Promise<void>
|
||||
getChatMessagesById: (id: string) => Promise<ChatMessage[] | null>
|
||||
updateConversationTitle: (id: string, title: string) => Promise<void>
|
||||
chatList: ChatConversationMeta[]
|
||||
}
|
||||
|
||||
export function useChatHistory(): UseChatHistory {
|
||||
const app = useApp()
|
||||
const chatManager = useMemo(() => new ChatManager(app), [app])
|
||||
const app = useApp()
|
||||
const chatManager = useMemo(() => new ChatManager(app), [app])
|
||||
|
||||
const [chatList, setChatList] = useState<ChatConversationMetadata[]>([])
|
||||
const [chatList, setChatList] = useState<ChatConversationMeta[]>([])
|
||||
|
||||
const fetchChatList = useCallback(async () => {
|
||||
const fetchChatList = useCallback(async () => {
|
||||
const conversations = await chatManager.listChats()
|
||||
setChatList(conversations)
|
||||
}, [chatManager])
|
||||
setChatList(conversations)
|
||||
}, [chatManager])
|
||||
|
||||
useEffect(() => {
|
||||
void fetchChatList()
|
||||
}, [fetchChatList])
|
||||
useEffect(() => {
|
||||
void fetchChatList()
|
||||
}, [fetchChatList])
|
||||
|
||||
const createOrUpdateConversation = useMemo(
|
||||
() =>
|
||||
@ -50,7 +49,7 @@ export function useChatHistory(): UseChatHistory {
|
||||
messages: serializedMessages,
|
||||
})
|
||||
} else {
|
||||
const firstUserMessage = messages.find((v) => v.role === 'user')
|
||||
const firstUserMessage = messages.find((v) => v.role === 'user') as ChatUserMessage
|
||||
|
||||
await chatManager.createChat({
|
||||
id,
|
||||
@ -74,13 +73,13 @@ export function useChatHistory(): UseChatHistory {
|
||||
[chatManager, fetchChatList],
|
||||
)
|
||||
|
||||
const deleteConversation = useCallback(
|
||||
async (id: string): Promise<void> => {
|
||||
await chatManager.deleteChat(id)
|
||||
await fetchChatList()
|
||||
},
|
||||
[chatManager, fetchChatList],
|
||||
)
|
||||
const deleteConversation = useCallback(
|
||||
async (id: string): Promise<void> => {
|
||||
await chatManager.deleteChat(id)
|
||||
await fetchChatList()
|
||||
},
|
||||
[chatManager, fetchChatList],
|
||||
)
|
||||
|
||||
const getChatMessagesById = useCallback(
|
||||
async (id: string): Promise<ChatMessage[] | null> => {
|
||||
@ -112,11 +111,11 @@ export function useChatHistory(): UseChatHistory {
|
||||
[chatManager, fetchChatList],
|
||||
)
|
||||
|
||||
return {
|
||||
createOrUpdateConversation,
|
||||
deleteConversation,
|
||||
getChatMessagesById,
|
||||
updateConversationTitle,
|
||||
chatList,
|
||||
}
|
||||
return {
|
||||
createOrUpdateConversation,
|
||||
deleteConversation,
|
||||
getChatMessagesById,
|
||||
updateConversationTitle,
|
||||
chatList,
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,7 +16,6 @@ import { findFilesMatchingPatterns } from '../utils/glob-utils';
|
||||
import AdvancedSettings from './components/AdvancedSettings';
|
||||
import BasicAutoCompleteSettings from './components/BasicAutoCompleteSettings';
|
||||
import DangerZoneSettings from './components/DangerZoneSettings';
|
||||
import ModelParametersSettings from './components/ModelParametersSettings';
|
||||
import CustomProviderSettings from './components/ModelProviderSettings';
|
||||
import PostprocessingSettings from './components/PostprocessingSettings';
|
||||
import PreprocessingSettings from './components/PreprocessingSettings';
|
||||
|
||||
@ -18,6 +18,7 @@ describe('parseSmartCopilotSettings', () => {
|
||||
groqApiKey: '',
|
||||
deepseekApiKey: '',
|
||||
chatModelId: '',
|
||||
collectedChatModels: [],
|
||||
chatModelProvider: 'OpenRouter',
|
||||
applyModelId: '',
|
||||
applyModelProvider: 'OpenRouter',
|
||||
@ -198,6 +199,7 @@ describe('settings migration', () => {
|
||||
geminiApiKey: '',
|
||||
groqApiKey: '',
|
||||
deepseekApiKey: '',
|
||||
collectedChatModels: [],
|
||||
chatModelId: '',
|
||||
chatModelProvider: 'OpenRouter',
|
||||
applyModelId: '',
|
||||
|
||||
@ -222,10 +222,29 @@ async function fetchOpenRouterModels(): Promise<Record<string, ModelInfo>> {
|
||||
// Gemini
|
||||
// https://ai.google.dev/gemini-api/docs/models/gemini
|
||||
export type GeminiModelId = keyof typeof geminiModels
|
||||
export const geminiDefaultModelId: GeminiModelId = "gemini-2.0-flash-001"
|
||||
export const geminiDefaultModelId: GeminiModelId = "gemini-2.5-flash-preview-04-17"
|
||||
export const geminiModels = {
|
||||
"gemini-2.5-flash-preview-04-17:thinking": {
|
||||
maxTokens: 65_535,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0.15,
|
||||
outputPrice: 3.5,
|
||||
thinking: true,
|
||||
// maxThinkingTokens: 24_576,
|
||||
},
|
||||
"gemini-2.5-flash-preview-04-17": {
|
||||
maxTokens: 65_535,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0.15,
|
||||
outputPrice: 0.6,
|
||||
thinking: false,
|
||||
},
|
||||
"gemini-2.5-pro-exp-03-25": {
|
||||
maxTokens: 65_536,
|
||||
maxTokens: 65_535,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
@ -236,17 +255,21 @@ export const geminiModels = {
|
||||
maxTokens: 65_535,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 2.5,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 2.5, // This is the pricing for prompts above 200k tokens.
|
||||
outputPrice: 15,
|
||||
cacheReadsPrice: 0.625,
|
||||
cacheWritesPrice: 4.5,
|
||||
},
|
||||
"gemini-2.0-flash-001": {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 1_048_576,
|
||||
supportsImages: true,
|
||||
supportsPromptCache: false,
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
supportsPromptCache: true,
|
||||
inputPrice: 0.1,
|
||||
outputPrice: 0.4,
|
||||
cacheReadsPrice: 0.025,
|
||||
cacheWritesPrice: 1.0,
|
||||
},
|
||||
"gemini-2.0-flash-lite-preview-02-05": {
|
||||
maxTokens: 8192,
|
||||
@ -1404,7 +1427,7 @@ export const grokModels = {
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
},
|
||||
"grok-2-vision": {
|
||||
"grok-2-latest": {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 131072,
|
||||
supportsImages: true,
|
||||
@ -1412,7 +1435,7 @@ export const grokModels = {
|
||||
inputPrice: 0,
|
||||
outputPrice: 0,
|
||||
},
|
||||
"grok-2-image": {
|
||||
"grok-2": {
|
||||
maxTokens: 8192,
|
||||
contextWindow: 131072,
|
||||
supportsImages: true,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user