Skip to content

Conversation

@appflowy
Copy link
Contributor

@appflowy appflowy commented Dec 8, 2025

Description


Checklist

General

  • I've included relevant documentation or comments for the changes introduced.
  • I've tested the changes in multiple environments (e.g., different browsers, operating systems).

Testing

  • I've added or updated tests to validate the changes introduced for AppFlowy Web.

Feature-Specific

  • For feature additions, I've added a preview (video, screenshot, or demo) in the "Feature Preview" section.
  • I've verified that this feature integrates seamlessly with existing functionality.

Summary by Sourcery

Add a fully functional AI Meeting block with nested summary, notes, and transcription sub-blocks, including audio transcription, AI-powered summarization, and editor integration.

New Features:

  • Introduce AI Meeting block with tabbed Summary, Notes, and Transcript views and editable meeting metadata.
  • Support audio file upload and transcription with speaker diarization, plus generation of structured speaker blocks within the editor.
  • Enable AI-generated meeting summaries driven by configurable templates, detail levels, and languages with caching of templates.
  • Add dedicated sub-blocks for AI meeting notes, summary, transcription, and per-speaker content with tailored rendering and placeholders.
  • Expose the AI Meeting block via the slash menu with a "NEW" badge and initialize required child blocks on creation or conversion.

Enhancements:

  • Integrate AI Meeting-related container and speaker block types into Slate-Yjs conversion, block creation, and container handling, ensuring correct child structure and text behavior.
  • Refine block toolbar and hover controls to better handle AI Meeting container blocks when inserting or selecting neighboring content.
  • Add UI components for regenerate controls, template selection, empty-state onboarding, and audio upload, plus Tailwind animations to support these interactions.
  • Simplify the generic element error fallback by removing translation dependency and using a direct error message.

Build:

  • Include tailwindcss-animate and related fade-in/fade-out animations in the Tailwind configuration to support new UI transitions.

Tests:

  • Add Cypress selectors and end-to-end test scaffolding for AI Meeting block interactions, including creation, navigation, and content copying.
@sourcery-ai
Copy link

sourcery-ai bot commented Dec 8, 2025

Reviewer's Guide

Implements a fully functional AI Meeting block with summary/notes/transcript tabs, audio transcription, AI-generated summaries, new block types, editor/Yjs integration, UI components, and Cypress selectors/tests, replacing the previous unsupported placeholder.

Sequence diagram for AI meeting summary generation

sequenceDiagram
  actor User
  participant AIMeetingBlock
  participant TabActions
  participant RegenerateMenu
  participant AIMeetingService
  participant BackendAPI as Backend_API
  participant AIMeetingUtils

  User->>TabActions: click Regenerate
  TabActions->>AIMeetingBlock: onRegenerate()
  AIMeetingBlock->>AIMeetingBlock: handleRegenerate()
  AIMeetingBlock->>RegenerateMenu: get selectedTemplate, selectedInstruction
  AIMeetingBlock->>AIMeetingService: handleGenerateSummary(content,options,onMessage)
  activate AIMeetingService

  AIMeetingService->>BackendAPI: POST /api/ai/{workspaceId}/v2/complete/stream
  activate BackendAPI
  BackendAPI-->>AIMeetingService: streaming JSON chunks

  loop stream chunks
    AIMeetingService-->>AIMeetingBlock: onMessage(text,false)
    AIMeetingBlock->>AIMeetingUtils: updateSummaryContent(editor,meetingNode,text,false)
  end

  BackendAPI-->>AIMeetingService: final chunk
  AIMeetingService-->>AIMeetingBlock: onMessage(fullText,true)
  AIMeetingBlock->>AIMeetingUtils: updateSummaryContent(editor,meetingNode,fullText,true)
  AIMeetingBlock->>AIMeetingBlock: set isGeneratingSummary false
  deactivate BackendAPI
  deactivate AIMeetingService

  User->>TabActions: open RegenerateMenu
  TabActions->>RegenerateMenu: open menu
  User->>RegenerateMenu: select template or detail or language
  RegenerateMenu-->>AIMeetingBlock: onTemplateSelect or onDetailSelect or onLanguageSelect
  AIMeetingBlock->>AIMeetingBlock: optionally auto handleGenerateSummary()
Loading

Sequence diagram for audio upload and transcription

sequenceDiagram
  actor User
  participant AIMeetingBlock
  participant AudioUpload
  participant AIMeetingService
  participant BackendMeeting as Backend_meeting_API
  participant AIMeetingUtils

  User->>AIMeetingBlock: click Transcribe audio file
  AIMeetingBlock->>AudioUpload: open=true

  User->>AudioUpload: choose or drop audio file
  AudioUpload->>AudioUpload: validateFile(file)
  User->>AudioUpload: click Transcribe

  AudioUpload->>AIMeetingBlock: onUpload(file,options)
  AIMeetingBlock->>AIMeetingBlock: handleAudioUpload(file,options)
  AIMeetingBlock->>AIMeetingService: transcribeAudio(file,options)
  activate AIMeetingService

  AIMeetingService->>BackendMeeting: POST /api/meeting/{workspaceId}/transcribe-audio-file
  activate BackendMeeting
  BackendMeeting-->>AIMeetingService: APIResponse<TranscriptionResult>
  deactivate BackendMeeting

  AIMeetingService-->>AIMeetingBlock: TranscriptionResult
  deactivate AIMeetingService

  AIMeetingBlock->>AIMeetingUtils: createSpeakerNodesFromTranscription(editor,meetingNode,result)
  AIMeetingUtils->>AIMeetingUtils: replace transcription children with SpeakerNode and ParagraphNode
  AIMeetingUtils->>AIMeetingUtils: update speaker_name_map

  AIMeetingBlock-->>AudioUpload: resolve onUpload
  AudioUpload->>AudioUpload: close dialog
Loading

Class diagram for AI Meeting block components and types

classDiagram
  direction LR

  class AIMeetingBlock {
    +TabType activeTab
    +SummaryTemplateResult templates
    +boolean isGeneratingSummary
    +boolean isTranscribing
    +handleTitleChange(newTitle)
    +handleGenerateSummary(template,instruction,fixedPrompt)
    +handleRegenerate()
    +handleTemplateSelect(template,section)
    +handleDetailSelect(detail,instruction)
    +handleLanguageSelect(languageCode)
    +handleAudioUpload(file,options)
    +handleCopy()
    +handleNewNotes()
  }

  class AIMeetingService {
    -string workspaceId
    -AxiosInstance axiosInstance
    +AIMeetingService(workspaceId,axiosInstance)
    +getSummaryTemplates() SummaryTemplateResult
    +generateSummary(content,options,onMessage) StreamResponse
    +transcribeAudio(file,options) TranscriptionResult
  }

  class SummaryTemplateResult {
    +SummaryTemplateSection[] sections
    +SummaryInstruction[] instructions
    +string fixed_prompt
  }

  class SummaryTemplateSection {
    +string section_name
    +SummaryTemplate[] templates
  }

  class SummaryTemplate {
    +string prompt_name
    +string prompt
    +string icon
  }

  class SummaryInstruction {
    +string key
    +string value
  }

  class TranscriptionOptions {
    +TranscriptionModel model
    +string language
    +string prompt
    +number temperature
    +TranscriptionResponseFormat response_format
  }

  class TranscriptionResult {
    +string text
    +string language
    +number duration
    +TranscriptionSegment[] segments
  }

  class TranscriptionSegment {
    +string id
    +number start
    +number end
    +string text
    +string speaker
  }

  class RegenerateMenu {
    +boolean open
    +onOpenChange(open)
    +onTemplateSelect(template,section)
    +onDetailSelect(detail,instruction)
    +onLanguageSelect(languageCode)
  }

  class TabActions {
    +onRegenerate()
    +onCopy()
    +onTemplateSelect(template,section)
    +onDetailSelect(detail,instruction)
    +onLanguageSelect(languageCode)
  }

  class AudioUpload {
    +boolean open
    +onOpenChange(open)
    +onUpload(file,options)
  }

  class AIMeetingBlockData {
    +string title
    +string date
    +string audio_file_path
    +string recording_state
    +number duration
    +string summary_template
    +string summary_detail
    +string summary_language
    +string transcription_provider
    +string created_at
    +string last_modified
    +number selected_tab_index
    +Record~string,string~ speaker_name_map
  }

  class SpeakerBlockData {
    +string speaker_id
    +string speaker_name
    +number timestamp
  }

  class AIMeetingNode {
    +BlockType type
    +AIMeetingBlockData data
    +Node[] children
  }

  class AIMeetingSummaryNode {
    +BlockType type
    +AIMeetingSummaryData data
  }

  class AIMeetingNotesNode {
    +BlockType type
    +AIMeetingNotesData data
  }

  class AIMeetingTranscriptionNode {
    +BlockType type
    +AIMeetingTranscriptionData data
  }

  class SpeakerNode {
    +BlockType type
    +SpeakerBlockData data
  }

  class AIMeetingSummaryData
  class AIMeetingNotesData
  class AIMeetingTranscriptionData

  class AIMeetingUtils {
    +findParentAIMeetingNode(editor,node) AIMeetingNode
    +updateNodeData(editor,node,newData)
    +updateMeetingTitle(editor,meetingNode,newTitle)
    +updateSpeakerName(editor,meetingNode,speakerId,newName)
    +getSpeakerDisplayName(meetingNode,speakerId) string
    +extractMeetingContent(meetingNode) string
    +updateSummaryContent(editor,meetingNode,content,done)
    +createNotesContent(editor,meetingNode)
    +createSpeakerNodesFromTranscription(editor,meetingNode,result)
  }

  class TemplateCache {
    +getCachedTemplates() SummaryTemplateResult
    +isCacheExpired() boolean
    +setCachedTemplates(templates)
    +clearTemplateCache()
  }

  class BlockType {
    <<enum>>
    AIMeetingBlock
    AIMeetingSummary
    AIMeetingNotes
    AIMeetingTranscription
    SpeakerBlock
  }

  AIMeetingBlock --> AIMeetingNode
  AIMeetingBlock --> AIMeetingService
  AIMeetingBlock --> TabActions
  AIMeetingBlock --> AudioUpload
  AIMeetingBlock --> AIMeetingUtils

  TabActions --> RegenerateMenu
  RegenerateMenu --> SummaryTemplateResult

  AIMeetingService --> SummaryTemplateResult
  AIMeetingService --> TranscriptionResult

  TemplateCache --> SummaryTemplateResult

  AIMeetingNode --> AIMeetingSummaryNode
  AIMeetingNode --> AIMeetingNotesNode
  AIMeetingNode --> AIMeetingTranscriptionNode

  AIMeetingTranscriptionNode --> SpeakerNode
  SpeakerNode --> SpeakerBlockData

  AIMeetingNode --> AIMeetingBlockData
  AIMeetingSummaryNode --> AIMeetingSummaryData
  AIMeetingNotesNode --> AIMeetingNotesData
  AIMeetingTranscriptionNode --> AIMeetingTranscriptionData

  AIMeetingUtils --> AIMeetingNode
  AIMeetingUtils --> AIMeetingSummaryNode
  AIMeetingUtils --> AIMeetingTranscriptionNode
  AIMeetingUtils --> AIMeetingNotesNode
  AIMeetingUtils --> SpeakerNode

  AIMeetingNode --> BlockType
  AIMeetingSummaryNode --> BlockType
  AIMeetingNotesNode --> BlockType
  AIMeetingTranscriptionNode --> BlockType
  SpeakerNode --> BlockType
Loading

File-Level Changes

Change Details Files
Replace placeholder AI Meeting block with full-featured multi-tab meeting experience (summary, notes, transcript) including AI summary generation and audio transcription.
  • Rewrote AIMeetingBlock to manage tabs, streaming AI summary generation via AIMeetingService, template caching, language/detail/template selection, and clipboard copy.
  • Introduced EmptyState, TabActions, RegenerateMenu, AudioUpload, TemplateSelector helpers and Loading UI, plus date/title handling and content visibility CSS for child blocks.
  • Added new AIMeeting* child block components (summary, notes, transcription) and SpeakerBlock, with speaker name editing and notes placeholder behavior.
src/components/editor/components/blocks/ai-meeting/AIMeetingBlock.tsx
src/components/editor/components/blocks/ai-meeting/components/EmptyState.tsx
src/components/editor/components/blocks/ai-meeting/components/TabActions.tsx
src/components/editor/components/blocks/ai-meeting/components/RegenerateMenu.tsx
src/components/editor/components/blocks/ai-meeting/components/AudioUpload.tsx
src/components/editor/components/blocks/ai-meeting/components/TemplateSelector.tsx
src/components/editor/components/blocks/ai-meeting/utils.ts
src/components/editor/components/blocks/ai-meeting-summary/AIMeetingSummary.tsx
src/components/editor/components/blocks/ai-meeting-notes/AIMeetingNotes.tsx
src/components/editor/components/blocks/ai-meeting-transcription/AIMeetingTranscription.tsx
src/components/editor/components/blocks/speaker/SpeakerBlock.tsx
Extend document model and Yjs/editor plumbing to support AI Meeting container and child blocks, including automatic child creation and content migration.
  • Extended BlockType enum and editor node interfaces for AIMeetingSummary/Notes/Transcription and SpeakerBlock, marking them as container/text types where appropriate.
  • Updated Yjs convert/add/turnToBlock logic to create AI Meeting child blocks, migrate existing content into Notes, avoid text on container nodes, and auto-insert paragraph children when needed.
  • Adjusted editor Element mapping, CONTAINER_BLOCK_TYPES/TEXT_BLOCK_TYPES, and add-block hover/controls behavior so AI Meeting behaves like a structured container while keeping selection/hover robust.
src/application/types.ts
src/components/editor/editor.type.ts
src/application/slate-yjs/utils/yjs.ts
src/application/slate-yjs/utils/editor.ts
src/application/slate-yjs/utils/convert.ts
src/application/slate-yjs/command/const.ts
src/components/editor/components/element/Element.tsx
src/components/editor/components/toolbar/block-controls/ControlActions.tsx
src/components/editor/components/toolbar/block-controls/HoverControls.hooks.ts
Add AI meeting backend integration for templates, streaming summaries, transcription, and local template caching.
  • Implemented AIMeetingService to fetch summary templates, stream AI completions using existing chat infra, and send audio files for transcription (including diarization).
  • Defined typed models for summary templates, completion payloads, transcription options/results, and stream handling plus helper to build prompts compatible with Flutter backend.
  • Added localStorage-based template-cache utilities with TTL and stale-while-revalidate behavior for summary templates.
src/components/editor/components/blocks/ai-meeting/services/ai-meeting-service.ts
src/components/editor/components/blocks/ai-meeting/services/types.ts
src/components/editor/components/blocks/ai-meeting/services/template-cache.ts
src/components/editor/components/blocks/ai-meeting/services/index.ts
Expose AI Meeting as a slash-menu block, with improved slash menu badges and editor DOM safety.
  • Added an "AI Meeting Note" slash command that converts the current block into an AIMeetingBlock with initial title/date data and shows a NEW badge.
  • Extended slash panel option type to support disabled/badge, render badge in list items, and wrapped ReactEditor.toDOMNode calls in try/catch to avoid failing when editor DOM is missing.
src/components/editor/components/panels/slash-panel/SlashPanel.tsx
Improve toolbar and hover controls behavior around container blocks and AI Meeting specifically.
  • Updated ControlActions plus-button behavior so adding around an AI Meeting block always inserts a paragraph above/below instead of trying to select inside possibly DOM-less children.
  • Adjusted HoverControls to treat AI Meeting as a container, closing hover controls for blocks nested inside it and making DOM lookup resilient with try/catch.
src/components/editor/components/toolbar/block-controls/ControlActions.tsx
src/components/editor/components/toolbar/block-controls/HoverControls.hooks.ts
Add testing utilities and selectors for AI Meeting and wire up Tailwind animation support.
  • Extended BlockSelectors and added AIMeetingSelectors in Cypress support to target AI Meeting UI (tabs, title, actions, empty state).
  • Added new Cypress spec files placeholders for AI Meeting behaviors (block conversion, copy content, jump-to-block, plus-button, title editing).
  • Enabled tailwindcss-animate plugin and added fade-in/fade-out keyframes/animations used by dropdowns/menus; updated dependencies and AIMeeting stories import order; simplified ElementFallbackRender i18n usage.
cypress/support/selectors.ts
cypress/e2e/embeded/ai_meeting/block-conversion.cy.ts
cypress/e2e/embeded/ai_meeting/copy-content.cy.ts
cypress/e2e/embeded/ai_meeting/jump-to-block.cy.ts
cypress/e2e/embeded/ai_meeting/plus-button.cy.ts
cypress/e2e/embeded/ai_meeting/title-editing.cy.ts
tailwind.config.cjs
package.json
src/components/error/ElementFallbackRender.tsx
src/components/editor/components/blocks/ai-meeting/AIMeetingBlock.stories.tsx

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@github-actions
Copy link

github-actions bot commented Dec 8, 2025

🥷 Ninja i18n – 🛎��� Translations need to be updated

Project /project.inlang

lint rule new reports level link
Missing translation 868 warning contribute (via Fink 🐦)
@appflowy appflowy force-pushed the implement_meeting_block branch from 71b3286 to c05a2e3 Compare December 8, 2025 13:15
@appflowy appflowy force-pushed the implement_meeting_block branch from c05a2e3 to 7a3b8fc Compare December 8, 2025 13:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants