From a722e2ca40eeb8887343490741a4066c2a8af171 Mon Sep 17 00:00:00 2001 From: duanfuxiang Date: Thu, 24 Apr 2025 20:41:32 +0800 Subject: [PATCH] fix lint type error --- CHANGELOG.yaml | 5 + manifest.json | 2 +- src/components/chat-view/CommandsView.tsx | 4 +- .../chat-view/chat-input/ModelSelect.tsx | 10 +- src/database/json/chat/ChatManager.ts | 172 +++++++++--------- src/hooks/use-chat-history.ts | 67 ++++--- src/settings/SettingTab.tsx | 1 - src/types/settings.test.ts | 2 + src/utils/api.ts | 41 ++++- 9 files changed, 166 insertions(+), 138 deletions(-) diff --git a/CHANGELOG.yaml b/CHANGELOG.yaml index 58c62c0..2069167 100644 --- a/CHANGELOG.yaml +++ b/CHANGELOG.yaml @@ -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" diff --git a/manifest.json b/manifest.json index e9d90c0..0f28986 100644 --- a/manifest.json +++ b/manifest.json @@ -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", diff --git a/src/components/chat-view/CommandsView.tsx b/src/components/chat-view/CommandsView.tsx index 87ff091..e98f6ef 100644 --- a/src/components/chat-view/CommandsView.tsx +++ b/src/components/chat-view/CommandsView.tsx @@ -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 = ( diff --git a/src/components/chat-view/chat-input/ModelSelect.tsx b/src/components/chat-view/chat-input/ModelSelect.tsx index c1bbb4e..2821d5b 100644 --- a/src/components/chat-view/chat-input/ModelSelect.tsx +++ b/src/components/chat-view/chat-input/ModelSelect.tsx @@ -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() { - {/* 收藏的模型区域 - 所有providers的收藏模型 */} + {/* collected models */} {settings.collectedChatModels?.length > 0 && (
@@ -292,8 +291,7 @@ export function ModelSelect() { { e.stopPropagation(); e.preventDefault(); - - // 从收藏中删除 + // delete const newCollectedModels = settings.collectedChatModels.filter( item => !(item.provider === collectedModel.provider && item.modelId === collectedModel.modelId) ); diff --git a/src/database/json/chat/ChatManager.ts b/src/database/json/chat/ChatManager.ts index 9cf29c0..af46776 100644 --- a/src/database/json/chat/ChatManager.ts +++ b/src/database/json/chat/ChatManager.ts @@ -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, - ): Promise { - if (initialData.title && initialData.title.length === 0) { - throw new EmptyChatTitleException() - } + public async createChat( + initialData: Partial, + ): Promise { + 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 { - const allMetadata = await this.listMetadata() - const targetMetadata = allMetadata.find((meta) => meta.id === id) + public async findById(id: string): Promise { + 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 - >, - ): Promise { - const chat = await this.findById(id) - if (!chat) return null + public async updateChat( + id: string, + updates: Partial< + Omit + >, + ): Promise { + 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 { - const allMetadata = await this.listMetadata() - const targetMetadata = allMetadata.find((meta) => meta.id === id) - if (!targetMetadata) return false + public async deleteChat(id: string): Promise { + 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 { - const metadata = await this.listMetadata() - return metadata.sort((a, b) => b.updatedAt - a.updatedAt) - } + public async listChats(): Promise { + const metadata = await this.listMetadata() + return metadata.sort((a, b) => b.updatedAt - a.updatedAt) + } } diff --git a/src/hooks/use-chat-history.ts b/src/hooks/use-chat-history.ts index f3e1664..20d6dbf 100644 --- a/src/hooks/use-chat-history.ts +++ b/src/hooks/use-chat-history.ts @@ -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 - deleteConversation: (id: string) => Promise - getChatMessagesById: (id: string) => Promise - updateConversationTitle: (id: string, title: string) => Promise - chatList: ChatConversationMetadata[] + createOrUpdateConversation: ( + id: string, + messages: ChatMessage[], + ) => Promise + deleteConversation: (id: string) => Promise + getChatMessagesById: (id: string) => Promise + updateConversationTitle: (id: string, title: string) => Promise + 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([]) + const [chatList, setChatList] = useState([]) - 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 => { - await chatManager.deleteChat(id) - await fetchChatList() - }, - [chatManager, fetchChatList], - ) + const deleteConversation = useCallback( + async (id: string): Promise => { + await chatManager.deleteChat(id) + await fetchChatList() + }, + [chatManager, fetchChatList], + ) const getChatMessagesById = useCallback( async (id: string): Promise => { @@ -112,11 +111,11 @@ export function useChatHistory(): UseChatHistory { [chatManager, fetchChatList], ) - return { - createOrUpdateConversation, - deleteConversation, - getChatMessagesById, - updateConversationTitle, - chatList, - } + return { + createOrUpdateConversation, + deleteConversation, + getChatMessagesById, + updateConversationTitle, + chatList, + } } diff --git a/src/settings/SettingTab.tsx b/src/settings/SettingTab.tsx index f529aae..031b4a2 100644 --- a/src/settings/SettingTab.tsx +++ b/src/settings/SettingTab.tsx @@ -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'; diff --git a/src/types/settings.test.ts b/src/types/settings.test.ts index 3858423..a81fd1f 100644 --- a/src/types/settings.test.ts +++ b/src/types/settings.test.ts @@ -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: '', diff --git a/src/utils/api.ts b/src/utils/api.ts index 594fd8a..c2fbad1 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -222,10 +222,29 @@ async function fetchOpenRouterModels(): Promise> { // 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,