cherry-studio icon indicating copy to clipboard operation
cherry-studio copied to clipboard

feat: support dialog map mode

Open shiquda opened this issue 8 months ago • 30 comments

What this PR does

Before this PR:

After this PR: 添加节点对话支持。

https://github.com/user-attachments/assets/f1313e1f-459a-44a1-80da-a5b93d691d77

由于是用Cursor糊的代码,可能还需要进一步打磨和debug

https://github.com/CherryHQ/cherry-studio/discussions/4040

Why we need it and why it was done in this way

The following tradeoffs were made:

The following alternatives were considered:

Links to places where the discussion took place:

Breaking changes

If this PR introduces breaking changes, please describe the changes and the impact on users.

Special notes for your reviewer

Checklist

This checklist is not enforcing, but it's a reminder of items that could be relevant to every PR. Approvers are expected to review this list.

Release note


Summary by Sourcery

Introduce a dialog map feature to visualize conversation history as a branching tree, allowing users to explore and manage different conversational paths.

New Features:

  • Add a dialog map view to visualize conversation branches.
  • Allow selecting a specific path in the conversation tree.
  • Enable creating new conversation branches from existing messages.
  • Add a button in the header to open the dialog map view.

Chores:

  • Define data types (DialogMap, DialogMapNode) and database schema for storing dialog map data.
  • Implement a service (DialogMapService) to handle dialog map creation, updates, and data retrieval.
  • Add an event (MESSAGES_UPDATED) for message updates related to the map.
  • Include translations for the new feature.new translations for the dialog map feature.

Summary by Sourcery

Introduce a dialog map feature to visualize and manage conversation history as a branching tree.

New Features:

  • Add a dialog map view, accessible via a new header button, to visualize conversation branches.
  • Allow selecting a specific path in the conversation tree.
  • Enable creating new conversation branches from existing messages.
  • Support deleting conversation branches (nodes and their descendants).
  • Apply the selected path in the map to update the main conversation view.
  • Allow navigating from a map node back to the corresponding message in the main chat view (if the node is part of the current path).

Chores:

  • Define data structures (DialogMap, DialogMapNode) and update the database schema to store dialog map data.
  • Add translations for the dialog map feature.
  • Add a MESSAGES_UPDATED event for message updates related to the map.
  • Implement a DialogMapService to handle dialog map creation, updates, path selection, and data retrieval.
  • Add utility functions for dialog map data processing and layout calculations for the visualization.

shiquda avatar Apr 26 '25 17:04 shiquda

Reviewer's Guide by Sourcery

Introduces a dialog map feature to visualize and manage conversation history as a branching tree using React Flow. This allows users to explore different conversational paths, select paths to load into the chat, create new branches, navigate to specific messages, and delete branches.

No diagrams generated as the changes look simple and do not need a visual representation.

File-Level Changes

Change Details Files
Define data models and update database schema for storing dialog map data.
  • Add DialogMapNode type to represent individual messages in the map.
  • Add DialogMap type to represent the overall conversation tree structure.
  • Add a new 'dialogMaps' store to the Dexie database.
  • Increment the database version and include the new 'dialogMaps' store in the schema.
src/renderer/src/types/index.ts
src/renderer/src/databases/index.ts
Implement a service layer (DialogMapService) for managing dialog map data persistence and logic.
  • Add functions to create a dialog map from a topic's messages.
  • Add functions to retrieve, update, and set the selected path of a dialog map.
  • Add functions to merge new message paths into an existing map structure.
  • Add functions to delete nodes and their descendants from the map.
  • Add functions to generate message lists based on a selected path.
  • Add helper functions for path finding and manipulation within the map data.
src/renderer/src/services/DialogMapService.ts
Implement utility functions for processing and structuring dialog map data for visualization.
  • Add functions to calculate the depth (level) of nodes in the tree.
  • Add functions to find ancestor, descendant, and full paths of nodes.
  • Add logic to find the 'best' path based on a set of selected nodes.
  • Implement buildDialogMapFlowData to convert DialogMap data into React Flow nodes and edges.
  • Include logic for initial node positioning and basic collision detection in the flow data builder.
src/renderer/src/utils/dialogMapUtils.ts
Implement the main DialogMap UI component using React Flow to render the conversation tree.
  • Set up React Flow provider and component for rendering the graph.
  • Create a custom DialogMapNode component to display individual messages with styling, avatars, and content previews.
  • Add interaction handlers to nodes for selecting paths, adding branches, deleting nodes, and navigating to messages.
  • Implement state management for React Flow nodes, edges, loading state, and the dialog map data.
  • Use useEffect hooks to load dialog map data and listen for relevant events (MESSAGES_UPDATED).
  • Include React Flow Controls and MiniMap components.
  • Add styling for the flow container, nodes, tooltips, and empty state.
src/renderer/src/pages/home/Messages/DialogMap.tsx
Add a button to the header navbar to open the dialog map feature.
  • Create a new DialogMapButton component.
  • Add the DialogMapButton component to the HeaderNavbar.
  • Implement logic in DialogMapButton to control the visibility of the dialog map drawer.
  • Fetch the current topic data when the drawer is opened and pass it to the DialogMap component.
src/renderer/src/pages/home/Navbar.tsx
src/renderer/src/pages/home/components/DialogMapButton.tsx
Introduce a new event for signaling message updates relevant to the dialog map.
  • Add MESSAGES_UPDATED event name to the EventService constants.
  • Emit this event when messages are updated in a way that affects the dialog map structure or selected path.
  • Listen for this event in the DialogMap component to trigger a reload of the map data.
src/renderer/src/services/EventService.ts
Add internationalization support for the dialog map feature.
  • Add new keys and translations for dialog map titles, node labels, context menu items, and empty states in English and Chinese localization files.
src/renderer/src/i18n/locales/en-us.json
src/renderer/src/i18n/locales/zh-cn.json

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

  • Contact our support team for questions or feedback.
  • Visit our documentation for detailed guides and information.
  • Keep in touch with the Sourcery team by following us on X/Twitter, LinkedIn or GitHub.

sourcery-ai[bot] avatar Apr 26 '25 17:04 sourcery-ai[bot]

这个功能似乎有过一个实现:

  • #3772

首先将「对话导航按钮」改为「上下按钮」,然后最后一个就是「聊天历史」。

不过这个似乎是唯一的入口,但是我更常用的是「对话锚点」,所以要打开也是挺麻烦的。

pilgrimlyieu avatar Apr 27 '25 01:04 pilgrimlyieu

这个功能似乎有过一个实现:

首先将「对话导航按钮」改为「上下按钮」,然后最后一个就是「聊天历史」。

不过这个似乎是唯一的入口,但是我更常用的是「对话锚点」,所以要打开也是挺麻烦的。

对话历史只支持线性的对话显示,我现在做的是实现单个topic内的对话分支功能,差别还是比较大的,不过流程图部分的渲染参考了聊天历史的代码。要是感兴趣的话,可以看一下更新的demo视频,这样可能好理解一些

shiquda avatar Apr 27 '25 02:04 shiquda

@sourcery-ai review

shiquda avatar Apr 27 '25 02:04 shiquda

@kangfenmao 看看这个idea怎么样?

shiquda avatar Apr 27 '25 02:04 shiquda

PixPin_2025-04-28_22-45-20

现在是一个勉强能用的状态,还有一些bug没调,自己build先用上了😄。现在有一个的问题,如果对话很长的话,怎么样让用户快速找到需要的节点,而不显得太长或者太杂乱?看看大家有没有什么想法,UI怎么调整一下,比如可以折叠分支之类的

shiquda avatar Apr 28 '25 14:04 shiquda

PixPin_2025-04-28_22-45-20

现在是一个勉强能用的状态,还有一些bug没调,自己build先用上了😄。现在有一个的问题,如果对话很长的话,怎么样让用户快速找到需要的节点,而不显得太长或者太杂乱?看看大家有没有什么想法,UI怎么调整一下,比如可以折叠分支之类的

可以自定义Compact显示模式:

  1. 可以折叠模型的回答
  2. 只显示提问
  3. 箭头的长度也缩短。
  4. 模型的Logo缩小、直接与提问同一行。
  5. 减少框内部的padding。

CreatorZZY avatar Apr 30 '25 07:04 CreatorZZY

还不错 还需要添加触控板双指拖移 src/renderer/src/pages/home/Messages/DialogMap.tsx文件 panOnScroll={false}改 panOnScroll={true}

1411124232 avatar Apr 30 '25 09:04 1411124232

PixPin_2025-04-30_17-16-20

shiquda avatar Apr 30 '25 09:04 shiquda

有BUG 你新加的 点击卡片会自动收缩 第二个模型头像没有

1411124232 avatar Apr 30 '25 09:04 1411124232

还需要增加一个记录折叠状态 现在折叠过 每次重新点进去 都是全折叠状态

1411124232 avatar Apr 30 '25 10:04 1411124232

上面提到的应该都修了

shiquda avatar Apr 30 '25 12:04 shiquda

还有问题 修改后 优点烧CPU

1411124232 avatar Apr 30 '25 13:04 1411124232

问题找到了,是这个src/renderer/src/utils/dialogMapUtils.ts文件的问题 当大于2个图时 就开始烧cpu了 需要禁用这个动画animated: false,不然大于2个图就开始烧cpu

1411124232 avatar Apr 30 '25 15:04 1411124232

image 悬停时显示全白色,这个文件src/renderer/src/pages/home/Messages/DialogMapNode.tsx background-color: var(--color-primary-dark);改成background-color: var(--color-primary);

1411124232 avatar Apr 30 '25 16:04 1411124232

非常希望能增加一个功能,就是可以选择任意的聊天点,一起发送到一个新话题中(就是可以选择所有对话中,最重要,最高质量的问答一起生成一个新话题),这样可以高效避免太长的上下文和不重要的信息对AI思考进行的干扰。

demmosee avatar May 03 '25 12:05 demmosee

非常希望能增加一个功能,就是可以选择任意的聊天点,一起发送到一个新话题中(就是可以选择所有问答中,最重要,最高质量的问答一起生成一个新话题),这样可以高效避免太长的上下文和太多不重要的重复信息对AI思考进行的干扰。

demmosee avatar May 03 '25 12:05 demmosee

这个PR可能需要其他dev的帮助,我最近没有太多精力来开发这个功能,而且已有的代码大多是Cursor写的,估计存在不少坑。看看有没有对这个功能感兴趣的dev来帮助开发

shiquda avatar May 03 '25 13:05 shiquda

image

并没有绘制出新的branch。而是直接添加到最末尾的地方。

CreatorZZY avatar May 04 '25 14:05 CreatorZZY

image

并没有绘制出新的branch。而是直接添加到最末尾的地方。

如果只有一个子节点就按照正常垂直排列,这是合理的,如果在已有子节点的情况下在父节点点加号,才会有新的分支

shiquda avatar May 04 '25 14:05 shiquda

如果只有一个子节点就按照正常垂直排列,这是合理的,如果在已有子节点的情况下在父节点点加号,才会有新的分支

image

按道理来说,有三个节点的情况下,在第二个节点点击添加分支的时候,应该按照我画的路线进行才对。

CreatorZZY avatar May 04 '25 14:05 CreatorZZY

如果只有一个子节点就按照正常垂直排列,这是合理的,如果在已有子节点的情况下在父节点点加号,才会有新的分支

image

按道理来说,有三个节点的情况下,在第二个节点点击添加分支的时候,应该按照我画的路线进行才对。

你的意思是不是相对位置的问题?比如说现在是

1
|
2 
| 
3 

在2添加分支,预期是这样

1
|
2 - 
|    |
3   4
     |
     5

但实际可能是这样

1
|
2 - 
|    |
4   3
|
5

如果是的话,确实存在这个问题

shiquda avatar May 04 '25 14:05 shiquda

我也clone了一份实现类似的功能,我的思路简单来说是这样:

  1. 每次添加分支时把分支赋予branch-id为branch-{timestamp},默认无分支的情况下branch-id为undefined。
  2. 绘图的时候对同一个topic下的branch-{timestamp}进行排序,按顺序设置横坐标。遇到undefined的时候默认不调整横坐标。
  3. 新建或选择branch后,每一个新的Message都会带有对应branch-id、branch父节点的node-id信息,以方便回溯整个path。
  4. 新建或选择branch后,原有的ScrollContainer中的非branch-id被隐藏不显示、调用大模型api时不被包括作为背景。

CreatorZZY avatar May 04 '25 14:05 CreatorZZY

如果只有一个子节点就按照正常垂直排列,这是合理的,如果在已有子节点的情况下在父节点点加号,才会有新的分支

image 按道理来说,有三个节点的情况下,在第二个节点点击添加分支的时候,应该按照我画的路线进行才对。

你的意思是不是相对位置的问题?比如说现在是

1
|
2 
| 
3 

在2添加分支,预期是这样

1
|
2 - 
|    |
3   4
     |
     5

但实际可能是这样

1
|
2 - 
|    |
4   3
|
5

如果是的话,确实存在这个问题

就是这个意思

CreatorZZY avatar May 04 '25 14:05 CreatorZZY

我也clone了一份实现类似的功能,我的思路简单来说是这样:

  1. 每次添加分支时把分支赋予branch-id为branch-{timestamp},默认无分支的情况下branch-id为undefined。
  2. 绘图的时候对同一个topic下的branch-{timestamp}进行排序,按顺序设置横坐标。遇到undefined的时候默认不调整横坐标。
  3. 新建或选择branch后,每一个新的Message都会带有对应branch-id、branch父节点的node-id信息,以方便回溯整个path。
  4. 新建或选择branch后,原有的ScrollContainer中的非branch-id被隐藏不显示、调用大模型api时不被包括作为背景。

这样似乎会简单一些,看了一下你分支的type定义改动比较少

shiquda avatar May 04 '25 15:05 shiquda

BTW,message模块是不是重构了?我看我这个分支的历史记录都变成空白的了,新对话Map好像也无法正确识别对话内容

shiquda avatar May 04 '25 15:05 shiquda

我也clone了一份实现类似的功能,我的思路简单来说是这样:

  1. 每次添加分支时把分支赋予branch-id为branch-{timestamp},默认无分支的情况下branch-id为undefined。
  2. 绘图的时候对同一个topic下的branch-{timestamp}进行排序,按顺序设置横坐标。遇到undefined的时候默认不调整横坐标。
  3. 新建或选择branch后,每一个新的Message都会带有对应branch-id、branch父节点的node-id信息,以方便回溯整个path。
  4. 新建或选择branch后,原有的ScrollContainer中的非branch-id被隐藏不显示、调用大模型api时不被包括作为背景。

这样似乎会简单一些,看了一下你分支的type定义改动比较少

那是因为我还没改到Message的保存部分,现在是在探索到底咋为新建/选择branch之后所创建的message添加branchid属性。

CreatorZZY avatar May 04 '25 16:05 CreatorZZY

不好添加的话,直接拓展消息块数据结构,只要做好旧数据到新数据的转换就可以了

DeJeune avatar May 05 '25 05:05 DeJeune

message模块是不是重构了

我合并了一下主分支 粗略处理了一下类型报错 具体逻辑还没有看(现在确实无法识别了

Pleasurecruise avatar May 05 '25 07:05 Pleasurecruise

希望话题列表也以树形结构展示,把分支话题纳入管理,相关issue:#5477

toddyoe avatar May 16 '25 04:05 toddyoe