-
Notifications
You must be signed in to change notification settings - Fork 416
Auto tagging #1331
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Auto tagging #1331
Conversation
📝 WalkthroughWalkthroughImplements automatic tag generation after title creation in the editor flow, adds new tag-generation utilities and templates, updates UI to display tag counts when space-constrained, and conditionally renders a header border in the transcript view. Introduces a QueryClient parameter to refresh session tag queries after assigning up to two generated tags. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant EditorArea
participant generateTitleDirect
participant TagGen as autoTagGeneration
participant Store as Tag/Session Store
participant QC as QueryClient
User->>EditorArea: Enhance note
EditorArea->>generateTitleDirect: enhancedContent, sessionId, sessions, queryClient
generateTitleDirect->>TagGen: sessionId
TagGen->>Store: Fetch session, tags, history
TagGen-->>generateTitleDirect: Suggested tags [up to 5]
generateTitleDirect->>Store: Upsert/reuse tags (max 2) and assign to session
generateTitleDirect->>QC: Invalidate session-tags query
generateTitleDirect-->>EditorArea: Title (and tagging complete)
EditorArea-->>User: UI refreshed (tags updated)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cubic analysis
1 issue found across 7 files • Review in cubic
React with 👍 or 👎 to teach cubic. You can also tag @cubic-dev-ai to give feedback, ask questions, or re-run the review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🔭 Outside diff range comments (1)
apps/desktop/src/utils/tag-generation.ts (1)
79-148: Code duplication betweengenerateTagsForSessionandautoTagGeneration.The two functions are nearly identical, differing only in the template names used. This violates the DRY principle and will make maintenance harder.
Consider extracting the common logic into a shared function:
-export async function generateTagsForSession(sessionId: string): Promise<string[]> { +async function generateTagsWithTemplate( + sessionId: string, + systemTemplate: string, + userTemplate: string +): Promise<string[]> { try { const { type: connectionType } = await connectorCommands.getLlmConnection(); const config = await dbCommands.getConfig(); const session = await dbCommands.getSession({ id: sessionId }); if (!session) { throw new Error("Session not found"); } const historicalTags = await dbCommands.listAllTags(); const currentTags = await dbCommands.listSessionTags(sessionId); const extractHashtags = (text: string): string[] => { const hashtagRegex = /#(\w+)/g; return Array.from(text.matchAll(hashtagRegex), match => match[1]); }; const existingHashtags = extractHashtags(session.raw_memo_html); const systemPrompt = await templateCommands.render( - "suggest_tags.system", + systemTemplate, { config, type: connectionType }, ); let contentToUse = session.enhanced_memo_html ?? session.raw_memo_html; const userPrompt = await templateCommands.render( - "suggest_tags.user", + userTemplate, { title: session.title, content: contentToUse, existing_hashtags: existingHashtags, formal_tags: currentTags.map(t => t.name), historical_tags: historicalTags.slice(0, 20).map(t => t.name), }, ); const provider = await modelProvider(); const model = provider.languageModel("defaultModel"); const result = await generateText({ model, messages: [ { role: "system", content: systemPrompt }, { role: "user", content: userPrompt }, ], providerOptions: { [localProviderName]: { metadata: { grammar: { task: "tags", } satisfies Grammar, }, }, }, }); const schema = z.preprocess( (val) => (typeof val === "string" ? JSON.parse(val) : val), z.array(z.string().min(1)).min(1).max(5), ); const parsed = schema.safeParse(result.text); return parsed.success ? parsed.data : []; } catch (error) { console.error("Tag generation failed:", error); return []; } } +export async function generateTagsForSession(sessionId: string): Promise<string[]> { + return generateTagsWithTemplate(sessionId, "suggest_tags.system", "suggest_tags.user"); +} + export async function autoTagGeneration(sessionId: string): Promise<string[]> { - try { - const { type: connectionType } = await connectorCommands.getLlmConnection(); - - const config = await dbCommands.getConfig(); - const session = await dbCommands.getSession({ id: sessionId }); - if (!session) { - throw new Error("Session not found"); - } - - const historicalTags = await dbCommands.listAllTags(); - const currentTags = await dbCommands.listSessionTags(sessionId); - - const extractHashtags = (text: string): string[] => { - const hashtagRegex = /#(\w+)/g; - return Array.from(text.matchAll(hashtagRegex), match => match[1]); - }; - - const existingHashtags = extractHashtags(session.raw_memo_html); - - const systemPrompt = await templateCommands.render( - "auto_generate_tags.system", - { config, type: connectionType }, - ); - - let contentToUse = session.enhanced_memo_html ?? session.raw_memo_html; - - const userPrompt = await templateCommands.render( - "auto_generate_tags.user", - { - title: session.title, - content: contentToUse, - existing_hashtags: existingHashtags, - formal_tags: currentTags.map(t => t.name), - historical_tags: historicalTags.slice(0, 20).map(t => t.name), - }, - ); - - const provider = await modelProvider(); - const model = provider.languageModel("defaultModel"); - - const result = await generateText({ - model, - messages: [ - { role: "system", content: systemPrompt }, - { role: "user", content: userPrompt }, - ], - providerOptions: { - [localProviderName]: { - metadata: { - grammar: { - task: "tags", - } satisfies Grammar, - }, - }, - }, - }); - - const schema = z.preprocess( - (val) => (typeof val === "string" ? JSON.parse(val) : val), - z.array(z.string().min(1)).min(1).max(5), - ); - - const parsed = schema.safeParse(result.text); - return parsed.success ? parsed.data : []; - } catch (error) { - console.error("Tag generation failed:", error); - return []; - } + return generateTagsWithTemplate(sessionId, "auto_generate_tags.system", "auto_generate_tags.user"); }
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
apps/desktop/src/components/editor-area/index.tsx(5 hunks)apps/desktop/src/components/editor-area/note-header/chips/tag-chip.tsx(1 hunks)apps/desktop/src/components/right-panel/views/transcript-view.tsx(1 hunks)apps/desktop/src/utils/tag-generation.ts(1 hunks)crates/template/assets/auto_generate_tags.system.jinja(1 hunks)crates/template/assets/auto_generate_tags.user.jinja(1 hunks)crates/template/src/lib.rs(4 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,ts,tsx,rs}
⚙️ CodeRabbit Configuration File
**/*.{js,ts,tsx,rs}: 1. No error handling.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".
Files:
apps/desktop/src/components/right-panel/views/transcript-view.tsxapps/desktop/src/components/editor-area/note-header/chips/tag-chip.tsxapps/desktop/src/utils/tag-generation.tsapps/desktop/src/components/editor-area/index.tsxcrates/template/src/lib.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: cubic · AI code reviewer
- GitHub Check: ci (macos, macos-latest)
- GitHub Check: ci (windows, windows-latest)
🔇 Additional comments (13)
apps/desktop/src/components/right-panel/views/transcript-view.tsx (1)
151-155: The dynamic className approach is correct and improves the UI consistency.The conditional border styling based on
showEmptyMessageis a good pattern for responsive UI design.apps/desktop/src/components/editor-area/note-header/chips/tag-chip.tsx (1)
44-47: Good simplification of the narrow display logic.Showing just the count when the space is constrained is a clean approach that matches the behavior of other chips in the UI.
crates/template/assets/auto_generate_tags.user.jinja (1)
1-30: Template structure is well-organized and follows Jinja best practices.The conditional rendering for existing hashtags, formal tags, and historical tags prevents empty sections. The formatting with comma separators is clean and consistent.
crates/template/assets/auto_generate_tags.system.jinja (1)
1-24: Comprehensive system prompt with clear guidelines.The prompt effectively guides the model to generate relevant tags by prioritizing historical tags, excluding already-present tags, and providing sensible defaults. The instructions are clear and should produce consistent results.
apps/desktop/src/components/editor-area/index.tsx (5)
1-1: Typed QueryClient import is appropriateImporting QueryClient as a type-only import keeps the runtime bundle lean and satisfies TS typing needs.
11-11: New autoTagGeneration import is usedImport is utilized in generateTitleDirect; no unused import issues.
81-86: Confirm crypto.randomUUID availability in your runtimeEnsure crypto.randomUUID exists in your Electron/TS target. If not, fallback to Node’s crypto or a UUID lib.
If needed, you can adapt with one of the following:
- Node: import { randomUUID } from "crypto" and use randomUUID().
- Lib: import { v4 as uuid } from "uuid" and use uuid().
147-147: Good: useQueryClient instance to pass into title/tag flowUsing the shared QueryClient allows targeted invalidation after tag assignment.
31-36: Signature change verified: all call sites updatedA search for
generateTitleDirect(across the codebase returned only its definition and the single invocation inapps/desktop/src/components/editor-area/index.tsxat line 155, which correctly passesqueryClient. No other callers found—no action needed.crates/template/src/lib.rs (4)
47-50: Enum variants for auto-generate-tags are well-definedNew PredefinedTemplate variants align with desired serialized names.
73-78: From mapping updated correctlyNew variants are included in the Template::from mapping; no missing arms.
130-139: Templates registered in environmentBoth auto-generate-tags templates are added to the Jinja environment; consistent with other registrations.
90-93: Asset constants paths verifiedBoth
include_str!paths incrates/template/src/lib.rs(lines 90–93) point to existing files:
- crates/template/assets/auto_generate_tags.system.jinja
- crates/template/assets/auto_generate_tags.user.jinja
No further action required.
Summary by cubic
Added automatic tag generation for notes, suggesting relevant tags based on note content and user history. Improved responsive UI for tag chips and transcript view.
New Features
Notes now get up to two suggested tags assigned automatically after title generation.
Tag suggestions use note content, existing tags, and historical tags.
Bug Fixes
Tag chip display is more consistent on narrow screens.
Transcript header styling is improved for empty states.