Compare commits

...

310 Commits

Author SHA1 Message Date
kangfenmao
98704fdb28 docs: Update translations and UI for better readability.
- Updated English translations in internationalization resources to simplify search assistant placeholder.
- Removed unused import, improved text search UI and adjusted font sizes for better readability.
2024-09-11 19:39:27 +08:00
kangfenmao
fd5cba5219 chore(version): 0.6.13 2024-09-11 19:22:34 +08:00
kangfenmao
be5aaa2b66 feat: Add Cohere model support and binary asset.
- Added new binary asset 'cohere.webp'.
- Added Cohere model support to the application.
2024-09-11 19:19:09 +08:00
kangfenmao
7e8687decd feat: Added GitHub provider support and models.
- Added a new SVG logo for the GitHub provider.
- Added a new social media platform provider to the SYSTEM_MODELS configuration.
- Added support for Github provider in the application configuration.
- Added two new translation keys: 'github' with 'GitHub Models' and updated the existing key 'graphrag-kylin-mountain'.
- Added width parameter to EditModelsPopup configuration.
- Added GitHub-specific model handling to OpenAIProvider class.
- Incremented the application version to 25.
- Added support for a new LLM model type.
- Added a new migration step to configure and enable a GitHub LLM provider.
2024-09-11 19:08:40 +08:00
kangfenmao
4c96324ef7 docs: Update release notes for Electron application.
- Updated release notes for Electron application now include additional features and fixes.
2024-09-11 17:36:37 +08:00
kangfenmao
dd3c81ec5f feat: Enhanced search functionality with user interaction and command shortcuts.
- Improved functionality to search Assistants with enhanced user interaction and command shortcuts.
- Implemented search functionality with runtime state management.
- Added functionality to return default assistant settings and updated conversion of agents to assistants to include default settings.
- Added a new 'searching' boolean field and corresponding state update action to the runtime store.
2024-09-11 17:29:46 +08:00
kangfenmao
42f0b5f8fc feat: Update temperature slider maximum value to 2 #62
- Increased the maximum temperature value in the settings slider.
- Increased the temperature slider maximum value from 1.2 to 2.
2024-09-11 16:24:07 +08:00
kangfenmao
11b2cd88b7 feat: Added configurable Droppable component props to DragableList, updated translations and implemented search functionality.
- Added support for configurable Droppable component props to the DragableList component.
- Updated translations for multiple components and languages.
- Implemented search functionality in the Assistants page.
2024-09-11 16:14:06 +08:00
kangfenmao
6bf98f6db3 fix: Corrected deletions and added API host reset for editable providers.
- Corrected deletions of the 'editable' property for multiple providers.
- Added ability to reset API host for editable providers when not empty.
2024-09-11 15:25:44 +08:00
kangfenmao
10b4e3c634 feat: enable Math support in Markdown rendering.
- Enabled Math support in Markdown rendering without single dollar text math.
2024-09-10 15:31:32 +08:00
kangfenmao
a3f5223b4c fix: disable math formula conversion in Markdown.
- Disabled math formula conversion in Markdown rendering.
2024-09-10 15:25:18 +08:00
kangfenmao
2855575b36 style: Refine UI styles and layout.
- Adjusted various font and layout styles to refine the user interface.
- Updated the minimum width of the NavbarRightContainer to match the var(--topic-list-width) setting.
- Added logic to synchronize local _activeTopic with activeTopic state.
- Improve logic for dynamically updating tab state in RightSidebar component based on position and topic settings.
- Removed unneeded console statement from font size slider's onChangeComplete event.
- Adjusted the width of the SettingMenus component to utilize the --settings-width variable.
2024-09-10 15:20:59 +08:00
kangfenmao
1f0ba20523 feat: Added platform-specific functionality to GeneralSettings page.
- Added platform-specific functionality to GeneralSettings page.
2024-09-10 13:52:50 +08:00
kangfenmao
2f53416e09 docs: Update agent-related translations to use 'assistant' term.
- "All agent-related translations have been updated to use the term 'assistant' instead of 'agent'."
2024-09-10 13:51:47 +08:00
kangfenmao
ddbf266a3f style: Updated component styles and layouts.
- Added new styles for the business smart assistant icon.
- Adjusted the sizes and positions of the ArrowRightButton components.
- Removed conditional style for NavbarLeft component.
- Implemented logic to resolve tab initialization based on component position.
2024-09-10 13:50:20 +08:00
kangfenmao
d815415f36 style: Adjusted layout and styling of right sidebar.
- Modified color border variable to a lighter grayish white.
- Adjusted the layout and styling of the right sidebar.
2024-09-10 13:28:34 +08:00
kangfenmao
cdacc56fd7 chore(version): 0.6.12 2024-09-09 17:34:30 +08:00
kangfenmao
455d909c74 style: Centered buttons and modals.
- Added the centered property to the OK button on the AgentsPage.
- Added centered option to modal confirmation dialog.
- Centred the delete button in the ProvidersList component.
- Added centered confirmation to reset modal.
2024-09-09 17:16:14 +08:00
kangfenmao
52d84afed6 feat: Update release notes with new features and bug fixes. 2024-09-09 17:01:02 +08:00
kangfenmao
f06d1d4d9a style: Centered layout updates across components.
- Centered the 'Add Assistant' popup in the chat modal.
- Added centered alignment to the AssistantSettingPopup component.
- The text area prompt input field now has a larger height.
- Updated the positioning of the Manage Agents popup to be centered.
- Added a centered attribute to the AddModelPopup modal footer.
- Added centered positioning to ProviderSettings AddProviderPopup.
- Centered layout has been added to the SearchContainer.
2024-09-09 16:57:20 +08:00
kangfenmao
805a65bbaa Revert "refactor: Migrate DeepSeek models to v2 naming convention"
This reverts commit 9ff65441ef.
2024-09-09 16:33:29 +08:00
kangfenmao
f217950b13 style: Adjusted dropdown menu maxHeight to 55vh. #52
- Adjusted the maxHeight property of the dropdown menu to 55vh from 80vh.
2024-09-09 13:03:51 +08:00
kangfenmao
9ff65441ef refactor: Migrate DeepSeek models to v2 naming convention
- Updated DeepSeek models to use version 2 naming convention.
2024-09-09 11:58:18 +08:00
kangfenmao
2b20282a41 feat: Add Zhihu app support and image asset.
- A new image file 'zhihu.png' has been added.
- Added support for Zhihu app in the minapp configuration.
2024-09-09 11:20:02 +08:00
kangfenmao
96ad2de896 chore(version): 0.6.11 2024-09-08 22:59:12 +08:00
kangfenmao
e1ea875c21 feat: Add list styling and optimize DragableList component
- Added list styling functionality to the DragableList component.
- Removed unused imports and updated container height to accommodate additional content.
2024-09-08 22:55:58 +08:00
kangfenmao
500e91977c feat: Show all topics on drag start
- Enforce the drag and drop functionality to show all topics on drag start.
2024-09-08 22:35:34 +08:00
kangfenmao
bd194ff955 refactor: Simplify import and topic deletion logic
- Updated import statement to remove unused type reference.
- Improved handling of deleting a topic.
2024-09-08 22:25:56 +08:00
kangfenmao
828bd71f22 feat: Remove activeAssistant dependency, add assistant dependency
- Updated the `onEditAssistant` function to remove dependency on `activeAssistant` variable and add `assistant` as a dependency.
2024-09-08 20:57:49 +08:00
kangfenmao
5991f692b2 feat: Edit assistant settings with real-time sync.
- Added support for editing an assistant's settings with real-time synchronization to the agent.
2024-09-08 16:09:17 +08:00
kangfenmao
200d78a140 feat: Enhanced UI/UX with design updates, i18n, and feature enhancements.
- Updated design styles for segmented tabs and size adjustments for assistive elements.
- Added internationalization translations for English and Chinese.
- Removed unused import and functionality for switching topics sidebar.
- Added functionality to hide or show the right sidebar in the Chat page.
- Renamed Assistants component to RightSidebar.
- Improved functionality for showing and toggling topics and settings in the input bar.
- Removed unused imports and refactored Navbar component layout.
- Updated existing right sidebar functionality to allow for custom position and show topic settings.
- Removed inline styles for width from Settings component Container styles.
- Added new features for managing topics in the home page, including drag and drop functionality, a "show all" button for viewing more topics, and improved handling of large topic lists.
2024-09-08 15:56:16 +08:00
kangfenmao
9a502b5e47 refactor: Improve code reusability and model service logic
- Improved code reusability in ModelSettings component by utilizing the hasModel function and Memoization.
- Refactored model service to include logic for checking if a model exists and retrieving its unique ID.
2024-09-08 10:13:15 +08:00
kangfenmao
97ef3772ea chore(version): 0.6.10 2024-09-07 18:21:30 +08:00
kangfenmao
eb18be200e feat: Improved UI components and added new features
- Replaced 'CopyOutlined' icon with custom 'CopyIcon'.
- Replaced Topics component with RightSidebar component to match topicPosition settings.
- Removed unused imports and updated UI components in the Inputbar.
- Implemented a new Token Count component for displaying context and estimated token information in the input bar.
- Adjusted the height of code block header.
- Added functionality to toggle theme opacity.
- Added functionality to dynamically change the sidebar border style based on stored settings.
- Updated CSS styles for dynamic topic list width and padding adjustments.
- Removed unused import and styles to improve code efficiency and reduce clutter.
2024-09-07 18:11:27 +08:00
kangfenmao
467e97ff4b feat: Improved model selection and unique id generation
- Improved dropdown menu selection logic for models.
- Changes improve ModelSettings component to use getModelUniqId function for model identifiers.
- Added modeling service functionality to generate unique model identifiers.
2024-09-07 18:11:13 +08:00
kangfenmao
27b802d3c2 chore(version): 0.6.9 2024-09-06 18:04:11 +08:00
kangfenmao
37b0a175f7 feat: Add theme switching to Navbar
- Added a new theme switching functionality to the Navbar.
2024-09-06 18:03:06 +08:00
kangfenmao
b2b79f12a2 feat: Enhanced code block styling in Markdown editor
- Added styles for code blocks in markdown to match the application's design.
- Improved the rendering of code blocks in the Markdown editor by adding a border and changing the default display in dark mode.
2024-09-06 17:58:15 +08:00
kangfenmao
885c578582 chore(version): 0.6.8 2024-09-06 15:54:44 +08:00
kangfenmao
e61e4b109a refactor: Remove unused CSS classes and optimize conditional styling
- Removed unused CSS classes and optimized code for conditional styling.
2024-09-06 15:53:58 +08:00
kangfenmao
f3bafbeb52 feat: Update UI components and styling for consistency and readability.
- Updated icon font asset reference URL to reflect a new timestamp.
- Updated icon-fonts file asset.
- Updated markdown styling to adjust margins and padding of pre-formatted text elements.
- Added Windows-specific styling to the Inputbar component.
- Improved the rendering of code blocks with a focus on readability and theming consistency.
- Added new 'plain' attribute to Divider component for 'clear' message type.
- Minor adjustments made to the navigation bar styles and layout.
2024-09-06 15:41:46 +08:00
kangfenmao
e55c0cdcef feat: Update context count logic
- Updated logic for determining context count based on clear messages.
2024-09-06 14:17:22 +08:00
kangfenmao
e73bbf4d6a style: Update toolbar button hover and active states
- Updated styles and icons for hover and active states of toolbar buttons.
2024-09-06 14:12:01 +08:00
kangfenmao
3859289218 style: Update styling and input bar characters.
- Updated styling and characters added to input bar.
2024-09-06 14:07:45 +08:00
kangfenmao
591bb45a4e feat: Improved chat UI with context handling and filtering #43
- Updated default context count from 5 to 6.
- Updated string translations for multiple languages.
- Added functionality to handle new context and update context count in Inputbar component.
- Added support for displaying new chat context divider for 'clear' type messages.
- Added functionality to emit estimated token count with context count when the estimated token count event is triggered.
- Improved filtering and processing of user messages for the AnthropicProvider class.
- Updated message filtering logic with context consideration.
- Improved filtering of user messages to include only context-relevant messages.
- Updated logic to pass messages directly to AI.completions and AI.suggestions API requests instead of filtered messages.
- Added new event names for handling topic sidebar and context switching.
- Improved handling of message filtering and context counting.
- Added new valid value 'clear' to type option in Message type.
2024-09-06 13:54:48 +08:00
kangfenmao
b31f518fca fix: Handle Enter key press event in input field
- Updated handling for Enter key press event in input field to match shortcut settings.
2024-09-06 11:34:55 +08:00
kangfenmao
dfbdb989db feat: Update icon font and navigation buttons
- Updated icon font references and added new icon font glyphs.
- Updated icon font file for improved rendering.
- Updated icon font sizes and hover animations for navigation buttons.
- Removed border styles from styled Container component.
- Removed unused import and updated icon for '/settings/model' menu item.
2024-09-06 10:00:18 +08:00
kangfenmao
f194ebbc20 chore(version): 0.6.7 2024-09-05 23:53:47 +08:00
kangfenmao
ab0e7e1e07 feat: change topics position 2024-09-05 23:53:47 +08:00
kangfenmao
d809f50c0e feat: Update Content-Security-Policy to allow file: frame-src #38
- Updated Content-Security-Policy directive to allow frame-src from file: in the HTML document.
2024-09-05 17:19:17 +08:00
kangfenmao
a48d24de26 refactor: renamed and refactored topic properties and added date-time tracking
- Renamed localforage topic item property from topic object to id.
- Added date-time tracking for assistant topics.
- Incremented the store version to 24.
- Refactored migrate function to add support for local storage and update topics timestamps.
- Added createdAt and updatedAt properties to Topic type.
2024-09-05 16:15:48 +08:00
kangfenmao
0dacc20e74 docs(DragableList): improve types and props documentation for DragDropContext responders 2024-09-05 15:30:26 +08:00
kangfenmao
08df6cb4f8 feat: highlight acitve topic icon 2024-09-05 14:36:19 +08:00
kangfenmao
0676ac8942 feat: quickly edit the asistant on edit title #42 2024-09-05 13:41:47 +08:00
kangfenmao
c257e8f0fe fix: anthropic first message must use the user role #39
{"type":"error","error":{"type":"invalid_request_error","message":"messages: first message must use the "user" role"}}
2024-09-05 13:35:16 +08:00
kangfenmao
521670f683 fix: assistant and topic list style 2024-09-05 00:04:35 +08:00
kangfenmao
87216b5d91 chore(version): 0.6.6 2024-09-04 22:33:15 +08:00
kangfenmao
e6122a3d36 fix: left sidebar icon 2024-09-04 22:31:39 +08:00
kangfenmao
e6e1502308 feat: remove hashtag title 2024-09-04 21:57:23 +08:00
kangfenmao
7f5be3a688 chore(version): 0.6.5 2024-09-04 21:29:56 +08:00
kangfenmao
4dde49a9f0 feat: new chat style 2024-09-04 21:29:16 +08:00
kangfenmao
ce830b692b revert: fold topics 2024-09-04 15:37:39 +08:00
kangfenmao
563472f3a9 wip 2024-09-04 13:26:51 +08:00
kangfenmao
14acd45927 feat: transparent window settings 2024-09-04 11:23:45 +08:00
kangfenmao
9e2c7a08df feat: change assistant sidebar width 2024-09-03 23:37:40 +08:00
kangfenmao
f10c8dc379 chore(version): 0.6.4 2024-09-03 22:14:12 +08:00
kangfenmao
fdd815879a feat: double click to change assistat view 2024-09-03 22:13:25 +08:00
kangfenmao
635f238576 chore(version): 0.6.3 2024-09-03 20:50:46 +08:00
kangfenmao
615e337e3f fix: assistant nav style 2024-09-03 20:50:37 +08:00
kangfenmao
acd5d4b192 feat: change default avatar 2024-09-03 20:39:27 +08:00
kangfenmao
9a41b697c6 fix: inputbar height 2024-09-03 20:11:25 +08:00
kangfenmao
5cb67e00a6 feat: change default provider 2024-09-03 20:11:20 +08:00
kangfenmao
350f13e97c fix: backup and restore i18n 2024-09-03 19:30:21 +08:00
kangfenmao
4d6cbf5073 refactor: provider sdk 2024-09-03 19:00:24 +08:00
kangfenmao
8d7b10d21e refactor: remove modal enabled key 2024-09-03 13:17:55 +08:00
kangfenmao
6753a93c0d fix: use webview replace iframe 2024-09-03 13:17:38 +08:00
kangfenmao
9ee763337d refactor: remove models config enabled 2024-09-03 11:40:46 +08:00
kangfenmao
ace0cb7823 feat: merge assistant and topics 2024-09-03 11:36:57 +08:00
kangfenmao
44e518ef03 refactor: assistant drap and drop 2024-09-02 20:48:31 +08:00
kangfenmao
e28b96b45e feat: expand inputbar height 2024-09-02 15:38:48 +08:00
kangfenmao
11427a980c feat: auto change inputbar height 2024-09-02 14:09:03 +08:00
kangfenmao
cb95562e58 feat: add attachment button 2024-09-01 23:22:21 +08:00
kangfenmao
89bdab58f7 feat: hide entry for local ai 2024-08-28 18:11:35 +08:00
kangfenmao
d42ee59335 fix: https://github.com/electron/notarize/issues/193 2024-08-27 19:42:39 +08:00
kangfenmao
88e7ab211d fix: electron-builder files path 2024-08-27 19:42:32 +08:00
kangfenmao
5347bdfa83 refactor: change env file path 2024-08-27 11:58:19 +08:00
kangfenmao
c8711c5804 feat: add local module 2024-08-27 11:31:05 +08:00
kangfenmao
24cf3bb043 chore(version): 0.6.2 2024-08-26 18:30:05 +08:00
kangfenmao
0531ecf3cf fix: electron builder ignore files 2024-08-26 18:19:01 +08:00
kangfenmao
0cbfd26883 build: remove sentry 2024-08-26 18:06:07 +08:00
kangfenmao
ee398489de build: remove electron-devtools-installer 2024-08-26 18:02:20 +08:00
kangfenmao
71d7c2c738 fix: workspace config 2024-08-26 17:49:19 +08:00
kangfenmao
b98f7298a2 build: add yarn workspace config 2024-08-25 22:12:31 +08:00
kangfenmao
de4f2599be refactor: remove unnecessary logs 2024-08-25 21:37:13 +08:00
kangfenmao
93b32e8e21 feat: update user data path 2024-08-25 18:39:53 +08:00
kangfenmao
e353d0f8ee fix: default assistant name 2024-08-23 21:41:16 +08:00
kangfenmao
dfd42fe9a6 feat: add devv referral code 2024-08-23 20:57:54 +08:00
kangfenmao
a2dc325896 chore(version): 0.6.1 2024-08-22 19:17:35 +08:00
kangfenmao
b131d320ea feat: more ai minapp 2024-08-22 18:45:06 +08:00
kangfenmao
b88f4a869e wip 2024-08-22 16:36:04 +08:00
kangfenmao
461458e5ec refactor: remove minapp.html 2024-08-22 13:04:24 +08:00
kangfenmao
4c2014f1d6 chore(version): 0.6.0 2024-08-21 10:28:31 +08:00
kangfenmao
647dd3e751 feat: add minapps 2024-08-21 10:14:04 +08:00
kangfenmao
4225312d4a chore(version): 0.5.9 2024-08-20 13:42:50 +08:00
kangfenmao
c2a4613e32 fix: windows minapp control button 2024-08-18 23:37:09 +08:00
kangfenmao
5d5c1eee74 feat: change sidebar width 2024-08-18 22:20:09 +08:00
kangfenmao
c1b5e6b183 feat: new input status bar style 2024-08-18 20:44:55 +08:00
kangfenmao
fd37ba18dc chore(version): 0.5.8 2024-08-18 18:06:56 +08:00
kangfenmao
4a26f7ce78 feat: add minimax provider 2024-08-18 18:06:21 +08:00
kangfenmao
8b38ebcac4 fix: hmr recycle 2024-08-18 17:10:59 +08:00
kangfenmao
e8dac28787 fix: graph rag model id 2024-08-17 21:54:34 +08:00
kangfenmao
3ccebb503f fix: input text 2024-08-17 21:30:28 +08:00
kangfenmao
42327836de fix: graphrag node url 2024-08-17 21:30:04 +08:00
kangfenmao
4d7a3bb8c3 feat: add minapp window 2024-08-17 17:11:48 +08:00
kangfenmao
1996e163c9 feat: add minapp window 2024-08-17 13:30:54 +08:00
kangfenmao
e43f7f87ab feat: window.app add app path 2024-08-16 22:44:00 +08:00
kangfenmao
47a83fa67f fix: minapp title null 2024-08-16 22:43:18 +08:00
kangfenmao
5e954566c9 chore(version): 0.5.7 2024-08-16 17:41:30 +08:00
kangfenmao
b8960ef02c fix: windows frame background color 2024-08-16 17:41:14 +08:00
kangfenmao
1866b00265 feat: add user edit modal & add prompt block 2024-08-16 17:19:18 +08:00
kangfenmao
be0799a4c6 chore(version): 0.5.6 2024-08-14 21:32:14 +08:00
kangfenmao
d0f5547419 feat: new windows and linux sidebar style 2024-08-14 21:28:44 +08:00
kangfenmao
076011b02b fix: anthropic message generating error 2024-08-14 20:35:57 +08:00
kangfenmao
ba5c70c45a feat: add minapp popup 2024-08-14 19:47:58 +08:00
kangfenmao
ebe74ffd05 chore(version): 0.5.5 2024-08-13 21:10:04 +08:00
kangfenmao
d0bea0491f fix(settings): provider list scroll 2024-08-13 21:04:04 +08:00
kangfenmao
514e1a4796 chore: remove ahooks 2024-08-13 20:50:54 +08:00
kangfenmao
2ffedadee4 Revert "feat(translate): use full screen input"
This reverts commit b0c479190c.
2024-08-13 20:48:51 +08:00
kangfenmao
7b72783ae7 feat: add graphrag provider 2024-08-13 20:48:38 +08:00
kangfenmao
4485a00395 feat: add doubao provider 2024-08-13 19:41:01 +08:00
kangfenmao
77c0952635 feat: add stepfun provider 2024-08-13 18:02:00 +08:00
kangfenmao
e1c7a25b87 feat: add gemini provider 2024-08-13 16:51:52 +08:00
kangfenmao
b0c479190c feat(translate): use full screen input 2024-08-13 14:57:46 +08:00
kangfenmao
c7c3d28893 chore(version): 0.5.4 2024-08-12 22:37:09 +08:00
kangfenmao
994ee8d7df feat: change sidebar opacity 2024-08-12 22:35:35 +08:00
kangfenmao
57f9550891 feat: add font size options to assistant settings pannel 2024-08-12 22:21:47 +08:00
kangfenmao
0c0d1560db feat: about page add icons 2024-08-12 22:03:16 +08:00
kangfenmao
145d7ee748 refactor: slider onChange event 2024-08-12 21:48:59 +08:00
kangfenmao
52af23b931 feat: enable anthropic api host edit 2024-08-12 21:31:32 +08:00
kangfenmao
f7151bd066 feat: add change message font size feature #22
支持消息字体大小调节
2024-08-12 21:28:18 +08:00
kangfenmao
744a1fedba style(Inputbar): add width: auto to Textarea 2024-08-11 16:18:06 +08:00
kangfenmao
978432d910 fix: clear topic white generating 2024-08-11 16:11:31 +08:00
kangfenmao
b6cb1e4d84 refactor: code format 2024-08-11 15:49:08 +08:00
kangfenmao
0096783f26 chore(version): 0.5.3 2024-08-09 18:58:58 +08:00
kangfenmao
4fc53d7c19 feat: new inputbar style 2024-08-09 18:56:45 +08:00
亢奋猫
34d99b711c Update README.md 2024-08-09 11:30:56 +08:00
kangfenmao
5dd74a1018 chore(version): 0.5.2 2024-08-08 23:53:18 +08:00
kangfenmao
e028d0600f fix: windows style 2024-08-08 23:30:55 +08:00
kangfenmao
64ee3f2108 chore(version): 0.5.1 2024-08-08 18:13:47 +08:00
kangfenmao
30a082b979 fix: filter empty user messages 2024-08-08 18:13:15 +08:00
kangfenmao
5a0927393d feat(message): add error tips 2024-08-08 17:57:57 +08:00
kangfenmao
16c68dcdcb fix: inputbar height 2024-08-08 17:21:00 +08:00
kangfenmao
b6500977b0 fix: model settings crash 2024-08-08 17:16:45 +08:00
kangfenmao
78cf33e8bc feat(AssistantSettings.tsx): fix reset functionality 2024-08-08 16:49:18 +08:00
kangfenmao
2f62f04adf feat(ModelSettings.tsx): sorting model names and capitalizing first letter 2024-08-08 16:36:36 +08:00
kangfenmao
84915b1ede feat(AboutSettings.tsx): add GithubOutlined icon linking to project repository for better user navigation and project visibility 2024-08-08 16:12:42 +08:00
亢奋猫
248c7ea20e Update README.md 2024-08-08 15:43:01 +08:00
kangfenmao
1031d40ddb docs(README.md): add star history chart for project visibility 2024-08-08 15:38:31 +08:00
kangfenmao
3d44fc2208 fix: navbar style on linux 2024-08-08 14:50:36 +08:00
kangfenmao
22e3c0e270 build: add linux target 2024-08-08 11:31:15 +08:00
kangfenmao
5d81874166 fix(i18n): update default assistant emoji from 😀 to 🔆 2024-08-08 09:18:33 +08:00
kangfenmao
f7ef895ce6 chore(version): 0.5.0 2024-08-07 21:55:51 +08:00
kangfenmao
beb40f5baf feat: fix add assistant search keywords format 2024-08-07 20:57:31 +08:00
kangfenmao
07613e65f5 feat: add max token limit #18 2024-08-07 20:49:21 +08:00
kangfenmao
6185068353 feat: use ubuntu font as default 2024-08-07 14:28:29 +08:00
kangfenmao
61934cd65c feat add agent popup #14 2024-08-07 13:23:29 +08:00
kangfenmao
41f65b66ba chore(version): 0.4.9 2024-08-06 20:41:34 +08:00
kangfenmao
5edb53ef7d feat: add ollama settings 2024-08-06 20:38:01 +08:00
kangfenmao
167988927b feat: add custom agent #14 2024-08-06 19:18:17 +08:00
kangfenmao
a39beb3841 fix(AboutSettings.tsx): handle errors in update check by setting loading state 2024-08-05 16:15:58 +08:00
kangfenmao
8719d5c330 chore(version): 0.4.8 2024-08-05 13:20:55 +08:00
kangfenmao
a7427d6cb6 feat(i18n): new topic 2024-08-05 13:14:57 +08:00
kangfenmao
8759a50727 fix: estimate history token count 2024-08-05 13:09:13 +08:00
kangfenmao
7ffa42caa0 feat: input status use tag 2024-08-05 13:00:18 +08:00
kangfenmao
b0a3d705ff feat: @model regenerate message 2024-08-05 12:39:37 +08:00
kangfenmao
de41199f7e feat: quick regenerate with new model 2024-08-04 14:04:11 +08:00
kangfenmao
cbd9f60cfc fix: markdown link color 2024-08-04 13:30:15 +08:00
kangfenmao
8a0e2890dd fix: math code format 2024-08-04 13:23:35 +08:00
kangfenmao
a8f3e2be6b chore(release.yml): add CSC_LINK and CSC_KEY_PASSWORD environment variables for windows build to enable code signing 2024-08-02 15:17:21 +08:00
kangfenmao
297539bab7 chore(version): 0.4.7 2024-08-02 11:32:29 +08:00
kangfenmao
911c2d0202 fix: footnote style 2024-08-02 11:30:06 +08:00
kangfenmao
2969a05f10 feat: enhance markdown style 2024-08-02 10:39:13 +08:00
kangfenmao
5d90489a04 style: change import order 2024-08-02 10:11:18 +08:00
kangfenmao
18fa1c92a4 feat(provider): sillicon api key use referrer link 2024-08-02 09:24:31 +08:00
kangfenmao
937e62bf9d feat(provider): add gpt-4o-mini model 2024-08-02 09:24:00 +08:00
kangfenmao
6291a463d8 perf(messages): usememo & usecallback message component 2024-08-01 23:55:51 +08:00
kangfenmao
681c93f5eb chore(version): 0.4.6 2024-08-01 15:36:07 +08:00
kangfenmao
23687f119d fix(SendMessageButton.tsx): remove unnecessary placement prop from SendMessageButton to prevent potential UI alignment issues 2024-08-01 15:23:12 +08:00
kangfenmao
0bcdffc159 fix(SettingsTab.tsx): correct the temperature label 2024-08-01 15:19:45 +08:00
kangfenmao
b04b0cc8a6 feat: add markdown footnote 2024-08-01 15:18:09 +08:00
kangfenmao
c9a964d8f8 feat: add markdown plugins remark-gfm remark-math rehype-katex 2024-08-01 14:51:20 +08:00
kangfenmao
86fc4676ba feat: add link component 2024-08-01 14:28:18 +08:00
kangfenmao
527afa1357 chore(version): 0.4.5 2024-08-01 00:05:16 +08:00
kangfenmao
384178c617 style(Message.tsx): increase padding in MessageContainer 2024-08-01 00:04:47 +08:00
kangfenmao
c53e35db76 feat: use poppins fonts 2024-07-31 23:20:28 +08:00
kangfenmao
c36075f0b5 fix: optimize interface display style 2024-07-31 21:04:09 +08:00
kangfenmao
5c95373a37 feat: new window style 2024-07-31 17:30:17 +08:00
kangfenmao
29d6d607da chore(version): 0.4.4 2024-07-31 13:54:04 +08:00
kangfenmao
e64375a74c feat(Inputbar.tsx): change height to min-height for Inputbar 2024-07-31 13:41:02 +08:00
kangfenmao
4689bb53e9 chore(package.json): add publish script to automate the release and patch version push process 2024-07-31 13:11:31 +08:00
kangfenmao
e00c66e54a chore(version): 0.4.3 2024-07-31 13:08:19 +08:00
kangfenmao
62b0908dfa feat: add send message button 2024-07-31 13:07:02 +08:00
kangfenmao
cb0b9de1e9 feat: default enable new added provider 2024-07-31 12:21:46 +08:00
kangfenmao
d8d4afbc0d feat: add message suggestions 2024-07-31 12:13:03 +08:00
kangfenmao
c50ff4585a chore(version): 0.4.2 2024-07-30 17:53:45 +08:00
kangfenmao
a5ee8548f3 feat(AboutSettings): implement functionality to open license page from about settings 2024-07-30 16:33:58 +08:00
kangfenmao
15b286a095 doc: update LICENSE 2024-07-30 16:13:32 +08:00
kangfenmao
d47d4a158d docs: change offical website url 2024-07-30 15:31:17 +08:00
kangfenmao
cd85dcddf8 remove: website 2024-07-30 15:30:35 +08:00
kangfenmao
925a9fb8ec fix: delete provider crash 2024-07-30 15:30:09 +08:00
kangfenmao
17c3437e02 chore(version): 0.4.1 2024-07-29 18:18:03 +08:00
kangfenmao
69293846fc fix: model list text color 2024-07-29 18:17:50 +08:00
kangfenmao
20a7fbfc48 fix(ProviderSDK.ts): translation message 2024-07-29 17:45:08 +08:00
kangfenmao
64d4b8450a style(website): adjust border-radius of images to 20% 2024-07-29 17:36:27 +08:00
kangfenmao
f080fc5048 chore(version): 0.4.0 2024-07-29 17:33:09 +08:00
kangfenmao
50f08124d7 feat: add dark and light theme 2024-07-29 17:14:49 +08:00
kangfenmao
b91081ef99 docs(index.html): update website URLs from easys.run to cherry-ai.com 2024-07-29 09:55:24 +08:00
kangfenmao
d869ec9a9b chore(version): 0.3.9 2024-07-29 09:16:46 +08:00
kangfenmao
70c4354d6c feat: add model logo on select model dropdown 2024-07-28 15:10:36 +08:00
kangfenmao
527c4e77dc fix(Message.tsx): add optional chaining to assistant.name to prevent potential undefined errors 2024-07-28 11:16:16 +08:00
kangfenmao
2483ce3bb4 chore(version): 0.3.8 2024-07-28 02:28:48 +08:00
kangfenmao
db3f8b8bee refactor(TranslatePage.tsx): simplify OutputText styling for cleaner code structure 2024-07-28 02:28:48 +08:00
kangfenmao
45bf3d4e86 fix(index.html): update Content-Security-Policy to allow fonts 2024-07-28 01:37:43 +08:00
kangfenmao
59b39dc41a feat(TranslatePage.tsx): add markdown style to handle whitespace properly in translation output 2024-07-28 01:32:03 +08:00
kangfenmao
a267a8d4c3 feat: add translation module 2024-07-28 01:07:15 +08:00
kangfenmao
5b123f2c33 fix(markdown.scss): replace :first-of-type with :first-child for consistent styling of first elements 2024-07-26 18:02:50 +08:00
kangfenmao
fe34fb3c25 fix(api.ts): modify provider apiKey check to exclude 'ollama' provider 2024-07-26 18:02:32 +08:00
kangfenmao
e6359d2048 feat(markdown.scss): add white-space: pre-wrap to code elements 2024-07-26 17:22:48 +08:00
kangfenmao
aa3b2d6290 chore(version): 0.3.7 2024-07-26 11:04:02 +08:00
kangfenmao
c0e51c3992 feat(ProviderSetting.tsx): add remove icon for models to allow deletion 2024-07-26 10:40:53 +08:00
kangfenmao
8c80cc00b3 feat(provider.ts): add API endpoint configuration for each provider with editable status 2024-07-26 10:34:55 +08:00
kangfenmao
f961accd86 fix(SettingsTab.tsx): reposition reset button to align with model settings title for better visibility 2024-07-26 10:10:34 +08:00
kangfenmao
7de91d236d feat(NavigationCenter.tsx): add CodeSandboxOutlined icon to model selection 2024-07-26 10:04:59 +08:00
kangfenmao
2fdf0acec6 feat: add global _activeAssistant and_activeTopic variable to persist state across re-renders 2024-07-26 09:57:49 +08:00
kangfenmao
40e76f3e53 feat: save file to disk 2024-07-26 09:53:07 +08:00
kangfenmao
d7b8721848 refactor: remove conditional devTools enabling 2024-07-25 18:04:12 +08:00
kangfenmao
b91b0dd8e4 fix(api.ts): add null return if provider apiKey is missing to prevent unauthorized requests 2024-07-25 18:00:32 +08:00
kangfenmao
bb9b053924 docs(assistants.json): simplify prompts for clarity and consistency #6 2024-07-25 17:50:26 +08:00
kangfenmao
5743046200 refactor: use —narbar-background 2024-07-25 15:55:23 +08:00
kangfenmao
a507776c1e fix: default assistant name is empty 2024-07-25 14:03:54 +08:00
kangfenmao
e74c828379 feat: set provider as default setting entry 2024-07-25 13:45:43 +08:00
kangfenmao
4b264c6a6b 0.3.6 2024-07-24 19:19:35 +08:00
kangfenmao
d21a4dce92 feat(ui): optimize messages ui styles 2024-07-24 19:17:58 +08:00
kangfenmao
74df29604b chore(version): v0.3.5 2024-07-24 18:37:48 +08:00
kangfenmao
8807783aa6 feat: switch topic tab on change assistant 2024-07-24 18:28:23 +08:00
kangfenmao
f81b38a362 perf(mermaid): lazy load mermaid 2024-07-24 18:19:43 +08:00
kangfenmao
d0280186bc feat: add setting panel 2024-07-24 18:08:05 +08:00
kangfenmao
9d96b826e2 feat(settings): add input status show switch 2024-07-24 13:08:30 +08:00
kangfenmao
ec20750e64 fix: sidebar mac style 2024-07-24 12:28:56 +08:00
kangfenmao
51f4653cde feat(settings): add messageFont setting 2024-07-24 12:25:36 +08:00
kangfenmao
3625eefec4 fix: prevent navigate to new url 2024-07-23 19:08:36 +08:00
亢奋猫
1e1414d659 Update README.md 2024-07-23 18:39:06 +08:00
亢奋猫
b7162663f2 Update README.md 2024-07-23 18:24:12 +08:00
kangfenmao
1dd1bb5804 0.3.4 2024-07-23 18:10:33 +08:00
kangfenmao
4dd6c46035 fix: message style 2024-07-23 18:10:25 +08:00
kangfenmao
4036c36753 feat: add Mermaid render 2024-07-23 18:05:14 +08:00
kangfenmao
764aadd234 feat: change message font 2024-07-23 17:42:52 +08:00
kangfenmao
3d801f1552 feat: optimize message style 2024-07-23 17:32:06 +08:00
kangfenmao
bd865f0270 fix: windows title style 2024-07-23 16:55:32 +08:00
kangfenmao
93505a4bc6 feat: hide window title 2024-07-23 16:40:06 +08:00
kangfenmao
c43be11d20 feat: add username and message divider line settings 2024-07-23 15:16:34 +08:00
kangfenmao
8535edbdd1 feat: messages styles optimization 2024-07-23 14:59:09 +08:00
kangfenmao
731fb7860b 0.3.3 2024-07-23 12:37:40 +08:00
kangfenmao
4a32976483 fix: proxy check 2024-07-23 12:37:12 +08:00
kangfenmao
dedabe320e feat: new navbar style 2024-07-23 12:29:20 +08:00
kangfenmao
235b481645 feat: change icons 2024-07-23 10:42:58 +08:00
kangfenmao
58c5ace678 fix: inputbar setShowRightSidebar 2024-07-23 10:20:57 +08:00
kangfenmao
973d24271b feat(settings): add proxy setting 2024-07-23 00:28:41 +08:00
kangfenmao
f434fe1231 feat: add show or hide assistant sidebar 2024-07-22 21:57:39 +08:00
kangfenmao
a0c147ae3f feat(website): fetch github release info 2024-07-22 15:40:30 +08:00
kangfenmao
8d7cde1231 0.3.2 2024-07-22 14:52:54 +08:00
kangfenmao
87c04408de feat: add contextCount to inputbar 2024-07-22 14:50:40 +08:00
kangfenmao
2592448c74 feat: add email to about titles 2024-07-22 14:26:35 +08:00
kangfenmao
6f054874e8 chore: remove change log component 2024-07-22 14:25:15 +08:00
kangfenmao
40d687104e feat: new about page 2024-07-22 14:24:14 +08:00
kangfenmao
ac3cfe2878 fix: disable switch while assistant generating message 2024-07-22 11:28:26 +08:00
kangfenmao
e9a7735fce feat: add updateAssistantSettings to useAssistant hook 2024-07-22 11:15:10 +08:00
kangfenmao
c1a8198575 fix(ProviderSDK): clarify instruction for session summary to avoid punctuation marks and special characters 2024-07-22 10:49:10 +08:00
kangfenmao
8b45548b79 refactor: topic component code 2024-07-22 10:38:00 +08:00
kangfenmao
3f3b930819 fix: disabled switch topic while generating message 2024-07-22 10:22:47 +08:00
kangfenmao
a5d6e2c5c5 0.3.1 2024-07-21 23:44:09 +08:00
kangfenmao
2993ab8dc1 fix: topic missing bug and delete assistant crash 2024-07-21 23:43:17 +08:00
kangfenmao
117069e450 chore(version): 0.3.0 2024-07-21 22:03:49 +08:00
kangfenmao
c5965dc696 fix: assistant settings bugs 2024-07-21 21:57:08 +08:00
kangfenmao
4169a2ef35 feat: add asistant model temperature maxTokens contextCount 2024-07-21 17:50:50 +08:00
kangfenmao
75c37632d4 feat: change default assistant name
# Conflicts:
#	src/renderer/src/i18n/index.ts
2024-07-21 10:51:33 +08:00
亢奋猫
3f5c151a11 Update README.md 2024-07-20 15:10:49 +08:00
kangfenmao
d049e36c46 0.2.9 2024-07-20 12:47:29 +08:00
kangfenmao
d05fc1c9be chore(version): v0.2.9 2024-07-20 12:47:19 +08:00
kangfenmao
f33317a3fb fix: send message setting position 2024-07-20 11:34:52 +08:00
kangfenmao
f2b5ed09c0 feat(provider): add AiHubMix provider 2024-07-20 11:29:24 +08:00
kangfenmao
81e66dde0e 0.2.8 2024-07-20 00:57:02 +08:00
kangfenmao
f76388d979 chore(version): v0.2.8 2024-07-20 00:56:52 +08:00
kangfenmao
9e542f813c feat: add custom llm provider 2024-07-20 00:50:46 +08:00
kangfenmao
5ede95cf2e 0.2.7 2024-07-19 15:57:16 +08:00
kangfenmao
fd8b15ebbe chore(version): 0.2.7 2024-07-19 15:52:52 +08:00
kangfenmao
5a636e7614 refactor: ProviderSDK 2024-07-19 15:49:08 +08:00
kangfenmao
13c73a3de1 fix: use activeAssistant's id for fetching assistant and model data 2024-07-19 15:39:49 +08:00
kangfenmao
31284a6e23 feat: add anthropic provider 2024-07-19 15:34:34 +08:00
kangfenmao
c4394b925d feat(settings/components): introduce password input for API key to enhance security 2024-07-19 13:38:44 +08:00
kangfenmao
93a5739d87 feat(assistants.json): Introduce new assistants for translation and summarization 2024-07-19 13:34:21 +08:00
kangfenmao
f23c4a0afa feat: add DashScope provider 2024-07-19 12:28:00 +08:00
kangfenmao
8723c251b1 Update Website 2024-07-19 09:38:29 +08:00
亢奋猫
a9634fd684 Update README.md 2024-07-18 16:46:33 +08:00
亢奋猫
53757626f2 Update README.md 2024-07-18 16:41:09 +08:00
kangfenmao
83af70e460 feat(website): cherry studio -> cherry ai 2024-07-18 13:02:46 +08:00
亢奋猫
3377aae0ff Update README.md 2024-07-17 23:08:13 +08:00
kangfenmao
2c4d18843b 0.2.6 2024-07-17 17:50:07 +08:00
kangfenmao
244cce0b65 chore(version): 0.2.6 2024-07-17 17:49:47 +08:00
kangfenmao
af41cebe18 feat: new agent center 2024-07-17 17:45:29 +08:00
212 changed files with 11077 additions and 4406 deletions

View File

@@ -6,4 +6,4 @@ indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
trim_trailing_whitespace = true

View File

@@ -1,5 +1,5 @@
module.exports = {
plugins: ['unused-imports'],
plugins: ['unused-imports', 'simple-import-sort'],
extends: [
'eslint:recommended',
'plugin:react/recommended',
@@ -14,12 +14,7 @@ module.exports = {
'unused-imports/no-unused-imports': 'error',
'@typescript-eslint/no-non-null-asserted-optional-chain': 'off',
'react/prop-types': 'off',
'sort-imports': [
'error',
{
ignoreCase: true,
ignoreDeclarationSort: true
}
]
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error'
}
}

View File

@@ -14,7 +14,7 @@ jobs:
strategy:
matrix:
os: [macos-latest, windows-latest]
os: [macos-latest, windows-latest, ubuntu-latest]
steps:
- name: Check out Git repository
@@ -60,7 +60,7 @@ jobs:
- name: Release
uses: softprops/action-gh-release@v2
with:
draft: false
draft: true
files: |
dist/*.exe
dist/*.zip

6
.gitignore vendored
View File

@@ -34,6 +34,9 @@ npm/*/*
!.yarn/sdks
!.yarn/versions
# Windows
Thumbs.db
# Project
node_modules
dist
@@ -42,3 +45,6 @@ out
# ENV
.env
.env.*
# Local
local

View File

@@ -0,0 +1,53 @@
diff --git a/lib/check-signature.js b/lib/check-signature.js
index 324568af71bcc4372c9f959131ecd24122848c86..677348e0a138ff608b2ac41f592d813b15ee4956 100644
--- a/lib/check-signature.js
+++ b/lib/check-signature.js
@@ -41,16 +41,12 @@ const spawn_1 = require("./spawn");
const debug_1 = __importDefault(require("debug"));
const d = (0, debug_1.default)('electron-notarize');
const codesignDisplay = (opts) => __awaiter(void 0, void 0, void 0, function* () {
- const result = yield (0, spawn_1.spawn)('codesign', ['-dv', '-vvvv', '--deep', path.basename(opts.appPath)], {
- cwd: path.dirname(opts.appPath),
- });
+ const result = yield (0, spawn_1.spawn)('codesign', ['-dv', '-vvvv', '--deep', opts.appPath]);
return result;
});
const codesign = (opts) => __awaiter(void 0, void 0, void 0, function* () {
d('attempting to check codesign of app:', opts.appPath);
- const result = yield (0, spawn_1.spawn)('codesign', ['-vvv', '--deep', '--strict', path.basename(opts.appPath)], {
- cwd: path.dirname(opts.appPath),
- });
+ const result = yield (0, spawn_1.spawn)('codesign', ['-vvv', '--deep', '--strict', opts.appPath]);
return result;
});
function checkSignatures(opts) {
diff --git a/lib/notarytool.js b/lib/notarytool.js
index 1ab090efb2101fc8bee5553445e0349c54474421..a5ddfd922197449fc56078e4a7e9a2ee5d8d207d 100644
--- a/lib/notarytool.js
+++ b/lib/notarytool.js
@@ -92,9 +92,7 @@ function notarizeAndWaitForNotaryTool(opts) {
else {
filePath = path.resolve(dir, `${path.parse(opts.appPath).name}.zip`);
d('zipping application to:', filePath);
- const zipResult = yield (0, spawn_1.spawn)('ditto', ['-c', '-k', '--sequesterRsrc', '--keepParent', path.basename(opts.appPath), filePath], {
- cwd: path.dirname(opts.appPath),
- });
+ const zipResult = yield (0, spawn_1.spawn)('ditto', ['-c', '-k', '--sequesterRsrc', '--keepParent', opts.appPath, filePath]);
if (zipResult.code !== 0) {
throw new Error(`Failed to zip application, exited with code: ${zipResult.code}\n\n${zipResult.output}`);
}
diff --git a/lib/staple.js b/lib/staple.js
index 47dbd85b2fc279d999b57f47fb8171e1cc674436..f8829e6ac54fcd630a730d12d75acc1591b953b6 100644
--- a/lib/staple.js
+++ b/lib/staple.js
@@ -43,9 +43,7 @@ const d = (0, debug_1.default)('electron-notarize:staple');
function stapleApp(opts) {
return __awaiter(this, void 0, void 0, function* () {
d('attempting to staple app:', opts.appPath);
- const result = yield (0, spawn_1.spawn)('xcrun', ['stapler', 'staple', '-v', path.basename(opts.appPath)], {
- cwd: path.dirname(opts.appPath),
- });
+ const result = yield (0, spawn_1.spawn)('xcrun', ['stapler', 'staple', '-v', opts.appPath]);
if (result.code !== 0) {
throw new Error(`Failed to staple your application with code: ${result.code}\n\n${result.output}`);
}

View File

@@ -1,2 +1,5 @@
nodeLinker: node-modules
enableImmutableInstalls: false
httpTimeout: 300000
nodeLinker: node-modules

114
LICENSE
View File

@@ -1,21 +1,101 @@
MIT License
### Cherry Studio 商业许可协议
Copyright (c) 2024 亢奋猫
---
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
#### 中文版
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
**Cherry Studio 商业许可协议**
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
本协议(以下简称“协议”)由以下双方签订:
- 许可方王谦kangfenmao@qq.com
- 被许可方:[被许可方名称]
**1. 定义**
- “软件”指 Cherry Studio 软件,网址为 https://cherry-ai.com。
- “商业用途”指任何以盈利为目的的使用。
**2. 许可**
- 未经许可方明确书面许可,被许可方不得将软件用于商业用途。
- 未经许可方事先书面同意,被许可方不得将软件全部或部分用于商业用途分发。
- 未经许可方明确授权,被许可方不得再许可、租赁、销售、出租或以其他方式将软件转让给任何第三方用于商业用途。
**3. 责任限制**
开发者不对因使用本软件而产生的任何直接或间接损失承担责任。用户应自行承担使用本软件的风险。
**4. 许可协议生效日期**
本许可协议自用户首次下载或使用本软件之日起生效。
**5. 许可终止**
如发现用户违反上述条款,开发者有权随时终止本许可,并要求用户停止使用本软件及删除所有相关副本。
**6. 其他**
本协议的解释、效力及争议的解决,均适用中华人民共和国法律。
**7. 联系信息**
- 许可方联系方式:
- 手机号18539907620
- 邮箱kangfenmao@qq.com
**许可方(签字):**
**日期:**
**被许可方(签字):**
**日期:**
---
#### English Version
**Cherry Studio Commercial License Agreement**
This Agreement ("Agreement") is entered into by and between:
- Licensor: Wang Qian (kangfenmao)
- Licensee: [Licensee Name]
**1. Definitions**
- "Software" refers to the Cherry Studio software, available at https://cherry-ai.com.
- "Commercial Use" refers to any use for profit.
**2. License**
- The Licensee may not use the Software for Commercial Use without the Licensor's explicit written permission.
- The Licensee may not distribute the Software in whole or in part for Commercial Use without the Licensor's prior written consent.
- The Licensee may not sublicense, lease, sell, rent, or otherwise transfer the Software to any third party for Commercial Use without the Licensor's explicit authorization.
**3. Termination of License**
The developer reserves the right to terminate this license at any time if the terms are violated, and may require the user to cease using the software and delete all related copies.
**4. Effective Date of License Agreement**
This license agreement becomes effective from the date the user first downloads or uses the software.
**5. Termination of License**
The developer reserves the right to terminate this license at any time if the terms are violated, and may require the user to cease using the software and delete all related copies.
**6. Miscellaneous**
This Agreement shall be governed by and construed in accordance with the laws of the People's Republic of China.
**7. Contact Information**
- Licensor's Contact Details:
- Phone: 18539907620
- Email: kangfenmao@qq.com
**Licensor (Signature):**
**Date:**
**Licensee (Signature):**
**Date:**

View File

@@ -1,23 +1,27 @@
# Cherry Studio
# 🍒 Cherry Studio
Cherry Studio is a desktop client for multiple cutting-edge LLM models, available on Windows, Mac and Linux.
Cherry Studio is a desktop client that supports for multiple LLM providers, available on Windows, Mac and Linux.
# Screenshot
# 🌠 Screenshot
![image.png](https://s2.loli.net/2024/07/16/IAVSOorsfFQyGhM.png)
![](https://github.com/user-attachments/assets/e24d1e7d-126a-4647-bd98-f470bfe26fde)
![image.png](https://s2.loli.net/2024/07/16/IQPz12OajfNoBTV.png)
![](https://github.com/user-attachments/assets/3f3f0bfa-cb88-4abf-923a-a0859fa3c912)
# Feature
![](https://github.com/user-attachments/assets/288560c1-d218-437c-87c2-2a5e87b43b93)
1. Supports multiple large language model service providers.
# 🌟 Features
1. Support for Multiple LLM Providers.
2. Allows creation of multiple Assistants.
3. Enables creation of multiple topics.
4. Allows using multiple models to answer questions in the same conversation.
5. Supports drag-and-drop sorting.
6. Code highlighting.
7. Mermaid chart
# 🖥️ Develop
# Develop
## Recommended IDE Setup
- [VSCode](https://code.visualstudio.com/) + [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) + [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)
@@ -48,3 +52,11 @@ $ yarn build:mac
# For Linux
$ yarn build:linux
```
# ⭐️ Star History
[![Star History Chart](https://api.star-history.com/svg?repos=kangfenmao/cherry-studio&type=Timeline)](https://star-history.com/#kangfenmao/cherry-studio&Timeline)
# 📃 License
[LICENSE](./LICENSE)

View File

@@ -3,12 +3,13 @@ productName: Cherry Studio
directories:
buildResources: build
files:
- '!**/.vscode/*'
- '!src/*'
- '!{.vscode,.yarn,.github}'
- '!electron.vite.config.{js,ts,mjs,cjs}'
- '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
- '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
- '!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}'
- '!src/*'
- '!local'
asarUnpack:
- resources/**
win:
@@ -40,8 +41,8 @@ dmg:
linux:
target:
- AppImage
- snap
- deb
# - snap
# - deb
maintainer: electronjs.org
category: Utility
appImage:
@@ -56,6 +57,14 @@ electronDownload:
afterSign: scripts/notarize.js
releaseInfo:
releaseNotes: |
🆕 新增百川AI服务商
📢 全新的智能体页面,新增多种职业助手
🌐 多语言问题修复,细节优化
本次更新:
支持行内公式
支持编辑所有集成的服务商API地址
新增智能体搜索功能(>10个)
修复正则表达式显示错误
修复默认模型参数不生效
修复暗黑模式下分界线不明显问题
近期更新:
智能助理和消息列表合并
优化输入框样式
提升小程序稳定性

View File

@@ -1,10 +1,15 @@
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
import react from '@vitejs/plugin-react'
import { defineConfig, externalizeDepsPlugin } from 'electron-vite'
import { resolve } from 'path'
export default defineConfig({
main: {
plugins: [externalizeDepsPlugin()]
plugins: [externalizeDepsPlugin()],
resolve: {
alias: {
ollama: resolve('ollama/src')
}
}
},
preload: {
plugins: [externalizeDepsPlugin()]
@@ -15,10 +20,6 @@ export default defineConfig({
'@renderer': resolve('src/renderer/src')
}
},
plugins: [react()],
assetsInclude: ['**/*.md'],
server: {
host: '0.0.0.0'
}
plugins: [react()]
}
})

View File

@@ -1,10 +1,16 @@
{
"name": "cherry-studio",
"version": "0.2.5",
"name": "CherryStudio",
"version": "0.6.13",
"private": true,
"description": "A powerful AI assistant for producer.",
"main": "./out/main/index.js",
"author": "kangfenmao@qq.com",
"homepage": "https://github.com/kangfenmao/cherry-studio",
"workspaces": {
"packages": [
"local"
]
},
"scripts": {
"format": "prettier --write .",
"lint": "eslint . --ext .js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix",
@@ -18,21 +24,24 @@
"build:unpack": "dotenv npm run build && electron-builder --dir",
"build:win": "dotenv npm run build && electron-builder --win --publish never",
"build:mac": "dotenv electron-vite build && electron-builder --mac --publish never",
"build:linux": "dotenv electron-vite build && electron-builder --linux --publish never"
"build:linux": "dotenv electron-vite build && electron-builder --linux --publish never",
"release": "node scripts/version.js",
"publish": "yarn release patch push"
},
"dependencies": {
"@electron-toolkit/preload": "^3.0.0",
"@electron-toolkit/utils": "^3.0.0",
"@sentry/electron": "^5.2.0",
"electron-log": "^5.1.5",
"electron-store": "^8.2.0",
"electron-updater": "^6.1.7",
"electron-window-state": "^5.0.3"
},
"devDependencies": {
"@anthropic-ai/sdk": "^0.24.3",
"@electron-toolkit/eslint-config-prettier": "^2.0.0",
"@electron-toolkit/eslint-config-ts": "^1.0.1",
"@electron-toolkit/tsconfig": "^1.0.1",
"@fontsource/inter": "^5.0.18",
"@google/generative-ai": "^0.16.0",
"@hello-pangea/dnd": "^16.6.0",
"@kangfenmao/keyv-storage": "^0.1.0",
"@reduxjs/toolkit": "^2.2.5",
@@ -41,20 +50,22 @@
"@types/react": "^18.2.48",
"@types/react-dom": "^18.2.18",
"@vitejs/plugin-react": "^4.2.1",
"ahooks": "^3.8.0",
"antd": "^5.18.3",
"axios": "^1.7.3",
"browser-image-compression": "^2.0.2",
"dayjs": "^1.11.11",
"dotenv-cli": "^7.4.2",
"electron": "^28.2.0",
"electron": "^28.3.3",
"electron-builder": "^24.9.1",
"electron-devtools-installer": "^3.2.0",
"electron-vite": "^2.0.0",
"emittery": "^1.0.3",
"emoji-picker-element": "^1.22.1",
"eslint": "^8.56.0",
"eslint-plugin-react": "^7.34.3",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-simple-import-sort": "^12.1.1",
"eslint-plugin-unused-imports": "^4.0.0",
"gpt-tokens": "^1.3.6",
"i18next": "^23.11.5",
"localforage": "^1.10.0",
"lodash": "^4.17.21",
@@ -67,8 +78,13 @@
"react-redux": "^9.1.2",
"react-router": "6",
"react-router-dom": "6",
"react-spinners": "^0.14.1",
"react-syntax-highlighter": "^15.5.0",
"redux": "^5.0.1",
"redux-persist": "^6.0.0",
"rehype-katex": "^7.0.0",
"remark-gfm": "^4.0.0",
"remark-math": "^6.0.0",
"sass": "^1.77.2",
"styled-components": "^6.1.11",
"typescript": "^5.3.3",
@@ -80,7 +96,8 @@
"react-dom": "^17.0.0 || ^18.0.0"
},
"resolutions": {
"@electron/notarize": "2.3.2"
"@electron/notarize": "2.3.2",
"@electron/notarize@npm:2.2.1": "patch:@electron/notarize@npm%3A2.3.2#~/.yarn/patches/@electron-notarize-npm-2.3.2-535908a4bd.patch"
},
"packageManager": "yarn@4.3.1"
}

68
resources/graphrag.html Normal file
View File

@@ -0,0 +1,68 @@
<head>
<style>
body {
margin: 0;
}
</style>
<script src="https://unpkg.com/3d-force-graph"></script>
</head>
<body>
<div id="3d-graph"></div>
<script src="./js/bridge.js"></script>
<script type="module">
import { getQueryParam } from './js/utils.js'
const apiUrl = getQueryParam('apiUrl')
const modelId = getQueryParam('modelId')
const jsonUrl = `${apiUrl}/v1/global_graph/${modelId}`
const infoCard = document.createElement('div')
infoCard.style.position = 'fixed'
infoCard.style.backgroundColor = 'rgba(255, 255, 255, 0.9)'
infoCard.style.padding = '8px'
infoCard.style.borderRadius = '4px'
infoCard.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)'
infoCard.style.fontSize = '12px'
infoCard.style.maxWidth = '200px'
infoCard.style.display = 'none'
infoCard.style.zIndex = '1000'
document.body.appendChild(infoCard)
document.addEventListener('mousemove', (event) => {
infoCard.style.left = `${event.clientX + 10}px`
infoCard.style.top = `${event.clientY + 10}px`
})
const elem = document.getElementById('3d-graph')
const Graph = ForceGraph3D()(elem)
.jsonUrl(jsonUrl)
.nodeAutoColorBy((node) => node.properties.type || 'default')
.nodeVal((node) => node.properties.degree)
.linkWidth((link) => link.properties.weight)
.onNodeHover((node) => {
if (node) {
infoCard.innerHTML = `
<div style="font-weight: bold; margin-bottom: 4px; color: #333;">
${node.properties.title}
</div>
<div style="color: #666;">
${node.properties.description}
</div>`
infoCard.style.display = 'block'
} else {
infoCard.style.display = 'none'
}
})
.onNodeClick((node) => {
const url = `${apiUrl}/v1/references/${modelId}/entities/${node.properties.human_readable_id}`
window.api.minApp({
url,
windowOptions: {
title: node.properties.title,
width: 500,
height: 800
}
})
})
</script>
</body>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 KiB

36
resources/js/bridge.js Normal file
View File

@@ -0,0 +1,36 @@
;(() => {
let messageId = 0
const pendingCalls = new Map()
function api(method, ...args) {
const id = messageId++
return new Promise((resolve, reject) => {
pendingCalls.set(id, { resolve, reject })
window.parent.postMessage({ id, type: 'api-call', method, args }, '*')
})
}
window.addEventListener('message', (event) => {
if (event.data.type === 'api-response') {
const { id, result, error } = event.data
const pendingCall = pendingCalls.get(id)
if (pendingCall) {
if (error) {
pendingCall.reject(new Error(error))
} else {
pendingCall.resolve(result)
}
pendingCalls.delete(id)
}
}
})
window.api = new Proxy(
{},
{
get: (target, prop) => {
return (...args) => api(prop, ...args)
}
}
)
})()

5
resources/js/utils.js Normal file
View File

@@ -0,0 +1,5 @@
export function getQueryParam(paramName) {
const url = new URL(window.location.href)
const params = new URLSearchParams(url.search)
return params.get(paramName)
}

40
scripts/version.js Normal file
View File

@@ -0,0 +1,40 @@
const { execSync } = require('child_process')
const fs = require('fs')
// 执行命令并返回输出
function exec(command) {
return execSync(command, { encoding: 'utf8' }).trim()
}
// 获取命令行参数
const args = process.argv.slice(2)
const versionType = args[0] || 'patch'
const shouldPush = args.includes('push')
// 验证版本类型
if (!['patch', 'minor', 'major'].includes(versionType)) {
console.error('Invalid version type. Use patch, minor, or major.')
process.exit(1)
}
// 更新版本
exec(`yarn version ${versionType} --immediate`)
// 读取更新后的 package.json 获取新版本号
const updatedPackageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'))
const newVersion = updatedPackageJson.version
// Git 操作
exec('git add .')
exec(`git commit -m "chore(version): ${newVersion}"`)
exec(`git tag -a v${newVersion} -m "Version ${newVersion}"`)
console.log(`Version bumped to ${newVersion}`)
if (shouldPush) {
console.log('Pushing to remote...')
exec('git push && git push --tags')
console.log('Pushed to remote.')
} else {
console.log('Changes are committed locally. Use "git push && git push --tags" to push to remote.')
}

15
src/main/config.ts Normal file
View File

@@ -0,0 +1,15 @@
import Store from 'electron-store'
export const appConfig = new Store()
export const titleBarOverlayDark = {
height: 41,
color: '#00000000',
symbolColor: '#ffffff'
}
export const titleBarOverlayLight = {
height: 41,
color: '#00000000',
symbolColor: '#000000'
}

View File

@@ -1,75 +1,16 @@
import { electronApp, is, optimizer } from '@electron-toolkit/utils'
import * as Sentry from '@sentry/electron/main'
import { app, BrowserWindow, ipcMain, Menu, MenuItem, shell } from 'electron'
import installExtension, { REDUX_DEVTOOLS } from 'electron-devtools-installer'
import windowStateKeeper from 'electron-window-state'
import { join } from 'path'
import icon from '../../resources/icon.png?asset'
import AppUpdater from './updater'
import { electronApp, optimizer } from '@electron-toolkit/utils'
import { app, BrowserWindow } from 'electron'
function createWindow() {
// Load the previous state with fallback to defaults
const mainWindowState = windowStateKeeper({
defaultWidth: 1080,
defaultHeight: 670
})
// Create the browser window.
const mainWindow = new BrowserWindow({
x: mainWindowState.x,
y: mainWindowState.y,
width: mainWindowState.width,
height: mainWindowState.height,
minWidth: 1080,
minHeight: 500,
show: true,
autoHideMenuBar: true,
titleBarStyle: 'hiddenInset',
trafficLightPosition: { x: 8, y: 12 },
...(process.platform === 'linux' ? { icon } : {}),
webPreferences: {
preload: join(__dirname, '../preload/index.js'),
sandbox: false,
devTools: !app.isPackaged
}
})
mainWindowState.manage(mainWindow)
mainWindow.webContents.on('context-menu', () => {
const menu = new Menu()
menu.append(new MenuItem({ label: '复制', role: 'copy', sublabel: '⌘ + C' }))
menu.append(new MenuItem({ label: '粘贴', role: 'paste', sublabel: '⌘ + V' }))
menu.append(new MenuItem({ label: '剪切', role: 'cut', sublabel: '⌘ + X' }))
menu.append(new MenuItem({ type: 'separator' }))
menu.append(new MenuItem({ label: '全选', role: 'selectAll', sublabel: '⌘ + A' }))
menu.popup()
})
mainWindow.on('ready-to-show', () => {
mainWindow.show()
})
mainWindow.webContents.setWindowOpenHandler((details) => {
shell.openExternal(details.url)
return { action: 'deny' }
})
// HMR for renderer base on electron-vite cli.
// Load the remote URL for development or the local html file for production.
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
} else {
mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
}
return mainWindow
}
import { registerIpc } from './ipc'
import { updateUserDataPath } from './utils/upgrade'
import { createMainWindow } from './window'
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.whenReady().then(() => {
app.whenReady().then(async () => {
await updateUserDataPath()
// Set app user model id for windows
electronApp.setAppUserModelId('com.kangfenmao.CherryStudio')
@@ -83,33 +24,12 @@ app.whenReady().then(() => {
app.on('activate', function () {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
if (BrowserWindow.getAllWindows().length === 0) createMainWindow()
})
const mainWindow = createWindow()
const mainWindow = createMainWindow()
const { autoUpdater } = new AppUpdater(mainWindow)
// IPC
ipcMain.handle('get-app-info', () => ({
version: app.getVersion(),
isPackaged: app.isPackaged
}))
ipcMain.handle('open-website', (_, url: string) => {
shell.openExternal(url)
})
// 触发检查更新(此方法用于被渲染线程调用,例如页面点击检查更新按钮来调用此方法)
ipcMain.handle('check-for-update', async () => {
autoUpdater.logger?.info('触发检查更新')
return {
currentVersion: autoUpdater.currentVersion,
update: await autoUpdater.checkForUpdates()
}
})
installExtension(REDUX_DEVTOOLS)
registerIpc(mainWindow, app)
})
// Quit when all windows are closed, except on macOS. There, it's common
@@ -123,6 +43,3 @@ app.on('window-all-closed', () => {
// In this file you can include the rest of your app"s specific main process
// code. You can also put them in separate files and require them here.
Sentry.init({
dsn: 'https://f0e972deff79c2df3e887e232d8a46a3@o4507610668007424.ingest.us.sentry.io/4507610670563328'
})

58
src/main/ipc.ts Normal file
View File

@@ -0,0 +1,58 @@
import { BrowserWindow, ipcMain, session, shell } from 'electron'
import { appConfig, titleBarOverlayDark, titleBarOverlayLight } from './config'
import AppUpdater from './updater'
import { openFile, saveFile } from './utils/file'
import { compress, decompress } from './utils/zip'
import { createMinappWindow } from './window'
export function registerIpc(mainWindow: BrowserWindow, app: Electron.App) {
const { autoUpdater } = new AppUpdater(mainWindow)
// IPC
ipcMain.handle('get-app-info', () => ({
version: app.getVersion(),
isPackaged: app.isPackaged,
appPath: app.getAppPath()
}))
ipcMain.handle('open-website', (_, url: string) => {
shell.openExternal(url)
})
ipcMain.handle('set-proxy', (_, proxy: string) => {
session.defaultSession.setProxy(proxy ? { proxyRules: proxy } : {})
})
ipcMain.handle('save-file', saveFile)
ipcMain.handle('open-file', openFile)
ipcMain.handle('reload', () => mainWindow.reload())
ipcMain.handle('zip:compress', (_, text: string) => compress(text))
ipcMain.handle('zip:decompress', (_, text: Buffer) => decompress(text))
ipcMain.handle('minapp', (_, args) => {
createMinappWindow({
url: args.url,
parent: mainWindow,
windowOptions: {
...mainWindow.getBounds(),
...args.windowOptions
}
})
})
ipcMain.handle('set-theme', (_, theme: 'light' | 'dark') => {
appConfig.set('theme', theme)
mainWindow?.setTitleBarOverlay &&
mainWindow.setTitleBarOverlay(theme === 'dark' ? titleBarOverlayDark : titleBarOverlayLight)
})
// 触发检查更新(此方法用于被渲染线程调用,例如页面点击检查更新按钮来调用此方法)
ipcMain.handle('check-for-update', async () => {
return {
currentVersion: autoUpdater.currentVersion,
update: await autoUpdater.checkForUpdates()
}
})
}

View File

@@ -1,6 +1,6 @@
import { AppUpdater as _AppUpdater, autoUpdater, UpdateInfo } from 'electron-updater'
import logger from 'electron-log'
import { BrowserWindow, dialog } from 'electron'
import logger from 'electron-log'
import { AppUpdater as _AppUpdater, autoUpdater, UpdateInfo } from 'electron-updater'
export default class AppUpdater {
autoUpdater: _AppUpdater = autoUpdater
@@ -17,11 +17,6 @@ export default class AppUpdater {
mainWindow.webContents.send('update-error', error)
})
// 检测是否需要更新
autoUpdater.on('checking-for-update', () => {
logger.info('正在检查更新……')
})
autoUpdater.on('update-available', (releaseInfo: UpdateInfo) => {
autoUpdater.logger?.info('检测到新版本,确认是否下载')
mainWindow.webContents.send('update-available', releaseInfo)
@@ -59,7 +54,6 @@ export default class AppUpdater {
// 检测到不需要更新时
autoUpdater.on('update-not-available', () => {
logger.info('现在使用的就是最新版本,不用更新')
mainWindow.webContents.send('update-not-available')
})

24
src/main/utils/aes.ts Normal file
View File

@@ -0,0 +1,24 @@
import * as crypto from 'crypto'
// 定义密钥和初始化向量IV
const secretKey = 'kDQvWz5slot3syfucoo53X6KKsEUJoeFikpiUWRJTLIo3zcUPpFvEa009kK13KCr'
const iv = Buffer.from('Cherry Studio', 'hex')
// 加密函数
export function encrypt(text: string): { iv: string; encryptedData: string } {
const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(secretKey), iv)
let encrypted = cipher.update(text, 'utf8', 'hex')
encrypted += cipher.final('hex')
return {
iv: iv.toString('hex'),
encryptedData: encrypted
}
}
// 解密函数
export function decrypt(encryptedData: string, iv: string): string {
const decipher = crypto.createDecipheriv('aes-256-cbc', Buffer.from(secretKey), Buffer.from(iv, 'hex'))
let decrypted = decipher.update(encryptedData, 'hex', 'utf8')
decrypted += decipher.final('utf8')
return decrypted
}

55
src/main/utils/file.ts Normal file
View File

@@ -0,0 +1,55 @@
import { dialog, OpenDialogOptions, OpenDialogReturnValue, SaveDialogOptions, SaveDialogReturnValue } from 'electron'
import logger from 'electron-log'
import { writeFile } from 'fs'
import { readFile } from 'fs/promises'
export async function saveFile(
_: Electron.IpcMainInvokeEvent,
fileName: string,
content: string,
options?: SaveDialogOptions
): Promise<void> {
try {
const result: SaveDialogReturnValue = await dialog.showSaveDialog({
title: '保存文件',
defaultPath: fileName,
...options
})
if (!result.canceled && result.filePath) {
writeFile(result.filePath, content, { encoding: 'utf-8' }, (err) => {
if (err) {
logger.error('[IPC - Error]', 'An error occurred saving the file:', err)
}
})
}
} catch (err) {
logger.error('[IPC - Error]', 'An error occurred saving the file:', err)
}
}
export async function openFile(
_: Electron.IpcMainInvokeEvent,
options: OpenDialogOptions
): Promise<{ fileName: string; content: Buffer } | null> {
try {
const result: OpenDialogReturnValue = await dialog.showOpenDialog({
title: '打开文件',
properties: ['openFile'],
filters: [{ name: '所有文件', extensions: ['*'] }],
...options
})
if (!result.canceled && result.filePaths.length > 0) {
const filePath = result.filePaths[0]
const fileName = filePath.split('/').pop() || ''
const content = await readFile(filePath)
return { fileName, content }
}
return null
} catch (err) {
logger.error('[IPC - Error]', 'An error occurred opening the file:', err)
return null
}
}

77
src/main/utils/upgrade.ts Normal file
View File

@@ -0,0 +1,77 @@
import { spawn } from 'child_process'
import { app, dialog } from 'electron'
import Logger from 'electron-log'
import fs from 'fs'
import path from 'path'
export async function updateUserDataPath() {
const currentPath = app.getPath('userData')
const oldPath = currentPath.replace('CherryStudio', 'cherry-studio')
if (currentPath !== oldPath && fs.existsSync(oldPath)) {
Logger.log('Update userData path')
try {
if (process.platform === 'win32') {
// Windows 系统:创建 bat 文件
const batPath = await createWindowsBatFile(oldPath, currentPath)
await promptRestartAndExecute(batPath)
} else {
// 其他系统:直接更新
fs.rmSync(currentPath, { recursive: true, force: true })
fs.renameSync(oldPath, currentPath)
Logger.log(`Directory renamed: ${currentPath}`)
await promptRestart()
}
} catch (error: any) {
Logger.error('Error updating userData path:', error)
dialog.showErrorBox('错误', `更新用户数据目录时发生错误: ${error.message}`)
}
} else {
Logger.log('userData path does not need to be updated')
}
}
async function createWindowsBatFile(oldPath: string, currentPath: string): Promise<string> {
const batPath = path.join(app.getPath('temp'), 'rename_userdata.bat')
const appPath = app.getPath('exe')
const batContent = `
@echo off
timeout /t 2 /nobreak
rmdir /s /q "${currentPath}"
rename "${oldPath}" "${path.basename(currentPath)}"
start "" "${appPath}"
del "%~f0"
`
fs.writeFileSync(batPath, batContent)
return batPath
}
async function promptRestartAndExecute(batPath: string) {
await dialog.showMessageBox({
type: 'info',
title: '应用需要重启',
message: '用户数据目录将在重启后更新。请重启应用以应用更改。',
buttons: ['手动重启']
})
// 执行 bat 文件
spawn('cmd.exe', ['/c', batPath], {
detached: true,
stdio: 'ignore'
})
app.exit(0)
}
async function promptRestart() {
await dialog.showMessageBox({
type: 'info',
title: '应用需要重启',
message: '用户数据目录已更新。请重启应用以应用更改。',
buttons: ['重启']
})
app.relaunch()
app.exit(0)
}

39
src/main/utils/zip.ts Normal file
View File

@@ -0,0 +1,39 @@
import util from 'node:util'
import zlib from 'node:zlib'
import logger from 'electron-log'
// 将 zlib 的 gzip 和 gunzip 方法转换为 Promise 版本
const gzipPromise = util.promisify(zlib.gzip)
const gunzipPromise = util.promisify(zlib.gunzip)
/**
* 压缩字符串
* @param {string} string - 要压缩的 JSON 字符串
* @returns {Promise<Buffer>} 压缩后的 Buffer
*/
export async function compress(str) {
try {
const buffer = Buffer.from(str, 'utf-8')
const compressedBuffer = await gzipPromise(buffer)
return compressedBuffer
} catch (error) {
logger.error('Compression failed:', error)
throw error
}
}
/**
* 解压缩 Buffer 到 JSON 字符串
* @param {Buffer} compressedBuffer - 压缩的 Buffer
* @returns {Promise<string>} 解压缩后的 JSON 字符串
*/
export async function decompress(compressedBuffer) {
try {
const buffer = await gunzipPromise(compressedBuffer)
return buffer.toString('utf-8')
} catch (error) {
logger.error('Decompression failed:', error)
throw error
}
}

125
src/main/window.ts Normal file
View File

@@ -0,0 +1,125 @@
import { is } from '@electron-toolkit/utils'
import { BrowserWindow, Menu, MenuItem, shell } from 'electron'
import windowStateKeeper from 'electron-window-state'
import { join } from 'path'
import icon from '../../build/icon.png?asset'
import { appConfig, titleBarOverlayDark, titleBarOverlayLight } from './config'
export function createMainWindow() {
// Load the previous state with fallback to defaults
const mainWindowState = windowStateKeeper({
defaultWidth: 1080,
defaultHeight: 670
})
const theme = appConfig.get('theme') || 'light'
// Create the browser window.
const mainWindow = new BrowserWindow({
x: mainWindowState.x,
y: mainWindowState.y,
width: mainWindowState.width,
height: mainWindowState.height,
minWidth: 1080,
minHeight: 600,
show: true,
autoHideMenuBar: true,
transparent: process.platform === 'darwin',
vibrancy: 'fullscreen-ui',
titleBarStyle: 'hidden',
titleBarOverlay: theme === 'dark' ? titleBarOverlayDark : titleBarOverlayLight,
trafficLightPosition: { x: 8, y: 12 },
...(process.platform === 'linux' ? { icon } : {}),
webPreferences: {
preload: join(__dirname, '../preload/index.js'),
sandbox: false,
webSecurity: false,
webviewTag: true
// devTools: !app.isPackaged,
}
})
mainWindowState.manage(mainWindow)
mainWindow.webContents.on('context-menu', () => {
const menu = new Menu()
menu.append(new MenuItem({ label: '复制', role: 'copy', sublabel: '⌘ + C' }))
menu.append(new MenuItem({ label: '粘贴', role: 'paste', sublabel: '⌘ + V' }))
menu.append(new MenuItem({ label: '剪切', role: 'cut', sublabel: '⌘ + X' }))
menu.append(new MenuItem({ type: 'separator' }))
menu.append(new MenuItem({ label: '全选', role: 'selectAll', sublabel: '⌘ + A' }))
menu.popup()
})
mainWindow.on('ready-to-show', () => {
mainWindow.show()
})
mainWindow.webContents.on('will-navigate', (event, url) => {
event.preventDefault()
shell.openExternal(url)
})
mainWindow.webContents.setWindowOpenHandler((details) => {
shell.openExternal(details.url)
return { action: 'deny' }
})
mainWindow.webContents.session.webRequest.onHeadersReceived({ urls: ['*://*/*'] }, (details, callback) => {
if (details.responseHeaders?.['X-Frame-Options']) {
delete details.responseHeaders['X-Frame-Options']
}
if (details.responseHeaders?.['x-frame-options']) {
delete details.responseHeaders['x-frame-options']
}
if (details.responseHeaders?.['Content-Security-Policy']) {
delete details.responseHeaders['Content-Security-Policy']
}
if (details.responseHeaders?.['content-security-policy']) {
delete details.responseHeaders['content-security-policy']
}
callback({ cancel: false, responseHeaders: details.responseHeaders })
})
// HMR for renderer base on electron-vite cli.
// Load the remote URL for development or the local html file for production.
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
} else {
mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
}
return mainWindow
}
export function createMinappWindow({
url,
parent,
windowOptions
}: {
url: string
parent?: BrowserWindow
windowOptions?: Electron.BrowserWindowConstructorOptions
}) {
const width = windowOptions?.width || 1000
const height = windowOptions?.height || 680
const minappWindow = new BrowserWindow({
width,
height,
autoHideMenuBar: true,
title: 'Cherry Studio',
...windowOptions,
parent,
webPreferences: {
preload: join(__dirname, '../preload/minapp.js'),
sandbox: false,
contextIsolation: false
}
})
minappWindow.loadURL(url)
return minappWindow
}

View File

@@ -1,4 +1,5 @@
import { ElectronAPI } from '@electron-toolkit/preload'
import type { OpenDialogOptions } from 'electron'
declare global {
interface Window {
@@ -7,9 +8,18 @@ declare global {
getAppInfo: () => Promise<{
version: string
isPackaged: boolean
appPath: string
}>
checkForUpdate: () => void
openWebsite: (url: string) => void
setProxy: (proxy: string | undefined) => void
saveFile: (path: string, content: string | NodeJS.ArrayBufferView, options?: SaveDialogOptions) => void
openFile: (options?: OpenDialogOptions) => Promise<{ fileName: string; content: Buffer } | null>
setTheme: (theme: 'light' | 'dark') => void
minApp: (options: { url: string; windowOptions?: Electron.BrowserWindowConstructorOptions }) => void
reload: () => void
compress: (text: string) => Promise<Buffer>
decompress: (text: Buffer) => Promise<string>
}
}
}

View File

@@ -1,11 +1,21 @@
import { contextBridge, ipcRenderer } from 'electron'
import { electronAPI } from '@electron-toolkit/preload'
import { contextBridge, ipcRenderer } from 'electron'
// Custom APIs for renderer
const api = {
getAppInfo: () => ipcRenderer.invoke('get-app-info'),
checkForUpdate: () => ipcRenderer.invoke('check-for-update'),
openWebsite: (url: string) => ipcRenderer.invoke('open-website', url)
openWebsite: (url: string) => ipcRenderer.invoke('open-website', url),
setProxy: (proxy: string) => ipcRenderer.invoke('set-proxy', proxy),
setTheme: (theme: 'light' | 'dark') => ipcRenderer.invoke('set-theme', theme),
minApp: (url: string) => ipcRenderer.invoke('minapp', url),
openFile: (options?: { decompress: boolean }) => ipcRenderer.invoke('open-file', options),
reload: () => ipcRenderer.invoke('reload'),
saveFile: (path: string, content: string, options?: { compress: boolean }) => {
ipcRenderer.invoke('save-file', path, content, options)
},
compress: (text: string) => ipcRenderer.invoke('zip:compress', text),
decompress: (text: Buffer) => ipcRenderer.invoke('zip:decompress', text)
}
// Use `contextBridge` APIs to expose Electron APIs to

View File

@@ -2,15 +2,12 @@
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>Cherry Studio</title>
<meta name="viewport" content="initial-scale=1, width=device-width" />
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; connect-src *; script-src 'self'; worker-src 'self' blob:; style-src 'self' 'unsafe-inline' *; font-src 'self' *; img-src 'self' data:" />
content="default-src 'self'; connect-src *; script-src 'self' *; worker-src 'self' blob:; style-src 'self' 'unsafe-inline' *; font-src 'self' data: *; img-src 'self' data: *; frame-src * file:" />
</head>
<body theme-mode="dark">
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>

View File

@@ -1,34 +1,40 @@
import '@fontsource/inter'
import store, { persistor } from '@renderer/store'
import { ConfigProvider } from 'antd'
import { Provider } from 'react-redux'
import { HashRouter, Route, Routes } from 'react-router-dom'
import { PersistGate } from 'redux-persist/integration/react'
import Sidebar from './components/app/Sidebar'
import TopViewContainer from './components/TopView'
import { AntdThemeConfig, getAntdLocale } from './config/antd'
import AntdProvider from './context/AntdProvider'
import { ThemeProvider } from './context/ThemeProvider'
import AgentsPage from './pages/agents/AgentsPage'
import AppsPage from './pages/apps/AppsPage'
import HomePage from './pages/home/HomePage'
import SettingsPage from './pages/settings/SettingsPage'
import TranslatePage from './pages/translate/TranslatePage'
function App(): JSX.Element {
return (
<ConfigProvider theme={AntdThemeConfig} locale={getAntdLocale()}>
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<TopViewContainer>
<HashRouter>
<Sidebar />
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/apps" element={<AppsPage />} />
<Route path="/settings/*" element={<SettingsPage />} />
</Routes>
</HashRouter>
</TopViewContainer>
</PersistGate>
</Provider>
</ConfigProvider>
<Provider store={store}>
<ThemeProvider>
<AntdProvider>
<PersistGate loading={null} persistor={persistor}>
<TopViewContainer>
<HashRouter>
<Sidebar />
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/agents" element={<AgentsPage />} />
<Route path="/translate" element={<TranslatePage />} />
<Route path="/apps" element={<AppsPage />} />
<Route path="/settings/*" element={<SettingsPage />} />
</Routes>
</HashRouter>
</TopViewContainer>
</PersistGate>
</AntdProvider>
</ThemeProvider>
</Provider>
)
}

View File

@@ -1,31 +0,0 @@
# CHANGES LOG
### v0.2.5 - 2024-07-17
- 🆕 Baichuan AI Service Providers
- 📢 New Intelligent Agent Page with Multiple Professional Assistants
- 🌐 Multilingual Issue Fixes and Detailed Optimizations
### v0.2.4 - 2024-07-16
- Fixed the issue of the update log page cannot be scrolled
- Added a check for updates button
### v0.2.3 - 2024-07-16
- Fixed multi-language prompt errors
- Fixed default model error issues with ZHIPU AI
- Fixed OpenRouter API detection error issues
- Fixed multi-language translation errors with model providers
### v0.2.2 - 2024-07-15
- Fix the issue where the default assistant name is empty.
- Fix the problem with default language detection during the first installation.
- Adjust the changelog style.
### v0.2.1 - 2024-07-15
- **Feature**: Add new feature for pausing message sending
- **Fix**: Resolve incomplete translation issue upon language switch
- **Build**: Support for macOS Intel architecture

View File

@@ -1,32 +0,0 @@
# 更新日志
### v0.2.5 - 2024-07-17
- 🆕 新增百川AI服务商
- 📢 全新的智能体页面,新增多种职业助手
- 🌐 多语言问题修复,细节优化
### v0.2.4 - 2024-07-16
- 修复更新日志页面不能滚动问题
- 新增检查更新按钮
### v0.2.3 - 2024-07-16
- 修复多语言提示错误
- 修复智谱AI默认模型错误问题
- 修复 OpenRouter API 检测出错问题
- 修复模型提供商多语言翻译错误问题
### v0.2.2 - 2024-07-15
- 修复默认助理名称为空的问题
- 修复首次安装默认语言检测问题
- 更新日志样式微调
### v0.2.1 - 2024-07-15
- 【功能】新增消息暂停发送功能
- 【修复】修复多语言切换不彻底问题
- 【构建】支持 macOS Intel 架构

View File

@@ -0,0 +1,88 @@
@font-face {
font-family: 'iconfont'; /* Project id 4563475 */
src: url('iconfont.woff2?t=1725606177995') format('woff2');
}
.iconfont {
font-family: 'iconfont' !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-a-darkmode:before {
content: '\e6cd';
}
.icon-ai-model:before {
content: '\e827';
}
.icon-ai-model1:before {
content: '\ec09';
}
.icon-gridlines:before {
content: '\e942';
}
.icon-grid-row-2copy:before {
content: '\e681';
}
.icon-inbox:before {
content: '\e869';
}
.icon-business-smart-assistant:before {
content: '\e601';
}
.icon-copy:before {
content: '\e6ae';
}
.icon-ic_send:before {
content: '\e795';
}
.icon-dark1:before {
content: '\e72f';
}
.icon-theme-light:before {
content: '\e6b7';
}
.icon-translate_line:before {
content: '\e7de';
}
.icon-history:before {
content: '\e758';
}
.icon-hide-sidebar:before {
content: '\e8eb';
}
.icon-show-sidebar:before {
content: '\e944';
}
.icon-a-addchat:before {
content: '\e658';
}
.icon-appstore:before {
content: '\e792';
}
.icon-chat:before {
content: '\e615';
}
.icon-setting:before {
content: '\e78e';
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,55 @@
@font-face {
font-family: 'Ubuntu';
src: url('Ubuntu-Regular.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'Ubuntu';
src: url('Ubuntu-Italic.ttf') format('truetype');
font-weight: normal;
font-style: italic;
}
@font-face {
font-family: 'Ubuntu';
src: url('Ubuntu-Bold.ttf') format('truetype');
font-weight: bold;
font-style: normal;
}
@font-face {
font-family: 'Ubuntu';
src: url('Ubuntu-BoldItalic.ttf') format('truetype');
font-weight: bold;
font-style: italic;
}
@font-face {
font-family: 'Ubuntu';
src: url('Ubuntu-Light.ttf') format('truetype');
font-weight: 300;
font-style: normal;
}
@font-face {
font-family: 'Ubuntu';
src: url('Ubuntu-LightItalic.ttf') format('truetype');
font-weight: 300;
font-style: italic;
}
@font-face {
font-family: 'Ubuntu';
src: url('Ubuntu-Medium.ttf') format('truetype');
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'Ubuntu';
src: url('Ubuntu-MediumItalic.ttf') format('truetype');
font-weight: 500;
font-style: italic;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Standard_product_icon__x28_1:1_x29_"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="192px" height="192px"
viewBox="0 0 192 192" enable-background="new 0 0 192 192" xml:space="preserve">
<symbol id="material_x5F_product_x5F_standard_x5F_icon_x5F_keylines_00000077318920148093339210000006245950728745084294_" viewBox="-96 -96 192 192">
<g opacity="0.4">
<defs>
<path id="SVGID_1_" opacity="0.4" d="M-96,96V-96H96V96H-96z"/>
</defs>
<clipPath id="SVGID_00000071517564283228984050000017848131202901217410_">
<use xlink:href="#SVGID_1_" overflow="visible"/>
</clipPath>
<g clip-path="url(#SVGID_00000071517564283228984050000017848131202901217410_)">
<g>
<path d="M95.75,95.75v-191.5h-191.5v191.5H95.75 M96,96H-96V-96H96V96L96,96z"/>
</g>
<circle fill="none" stroke="#000000" stroke-width="0.25" stroke-miterlimit="10" cx="0" cy="0" r="64"/>
</g>
<circle clip-path="url(#SVGID_00000071517564283228984050000017848131202901217410_)" fill="none" stroke="#000000" stroke-width="0.25" stroke-miterlimit="10" cx="0" cy="0" r="88"/>
<path clip-path="url(#SVGID_00000071517564283228984050000017848131202901217410_)" fill="none" stroke="#000000" stroke-width="0.25" stroke-miterlimit="10" d="
M64,76H-64c-6.6,0-12-5.4-12-12V-64c0-6.6,5.4-12,12-12H64c6.6,0,12,5.4,12,12V64C76,70.6,70.6,76,64,76z"/>
<path clip-path="url(#SVGID_00000071517564283228984050000017848131202901217410_)" fill="none" stroke="#000000" stroke-width="0.25" stroke-miterlimit="10" d="
M52,88H-52c-6.6,0-12-5.4-12-12V-76c0-6.6,5.4-12,12-12H52c6.6,0,12,5.4,12,12V76C64,82.6,58.6,88,52,88z"/>
<path clip-path="url(#SVGID_00000071517564283228984050000017848131202901217410_)" fill="none" stroke="#000000" stroke-width="0.25" stroke-miterlimit="10" d="
M76,64H-76c-6.6,0-12-5.4-12-12V-52c0-6.6,5.4-12,12-12H76c6.6,0,12,5.4,12,12V52C88,58.6,82.6,64,76,64z"/>
</g>
</symbol>
<rect id="bounding_box_1_" display="none" fill="none" width="192" height="192"/>
<g id="art_layer">
<g>
<path fill="#F9AB00" d="M96,181.92L96,181.92c6.63,0,12-5.37,12-12v-104H84v104C84,176.55,89.37,181.92,96,181.92z"/>
<g>
<path fill="#5BB974" d="M143.81,103.87C130.87,90.94,111.54,88.32,96,96l51.37,51.37c2.12,2.12,5.77,1.28,6.67-1.57
C158.56,131.49,155.15,115.22,143.81,103.87z"/>
</g>
<g>
<path fill="#129EAF" d="M48.19,103.87C61.13,90.94,80.46,88.32,96,96l-51.37,51.37c-2.12,2.12-5.77,1.28-6.67-1.57
C33.44,131.49,36.85,115.22,48.19,103.87z"/>
</g>
<g>
<path fill="#AF5CF7" d="M140,64c-20.44,0-37.79,13.4-44,32h81.24c3.33,0,5.55-3.52,4.04-6.49C173.56,74.36,157.98,64,140,64z"/>
</g>
<g>
<path fill="#FF8BCB" d="M104.49,42.26C90.03,56.72,87.24,78.45,96,96l57.45-57.45c2.36-2.36,1.44-6.42-1.73-7.45
C135.54,25.85,117.2,29.55,104.49,42.26z"/>
</g>
<g>
<path fill="#FA7B17" d="M87.51,42.26C101.97,56.72,104.76,78.45,96,96L38.55,38.55c-2.36-2.36-1.44-6.42,1.73-7.45
C56.46,25.85,74.8,29.55,87.51,42.26z"/>
</g>
<g>
<g>
<path fill="#4285F4" d="M52,64c20.44,0,37.79,13.4,44,32H14.76c-3.33,0-5.55-3.52-4.04-6.49C18.44,74.36,34.02,64,52,64z"/>
</g>
</g>
</g>
</g>
<g id="keylines" display="none">
<use xlink:href="#material_x5F_product_x5F_standard_x5F_icon_x5F_keylines_00000077318920148093339210000006245950728745084294_" width="192" height="192" id="material_x5F_product_x5F_standard_x5F_icon_x5F_keylines" x="-96" y="-96" transform="matrix(1 0 0 -1 96 96)" display="inline" overflow="visible"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -1,7 +0,0 @@
<svg width="600" height="600" viewBox="0 0 600 600" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="300" cy="300" r="300" fill="white"/>
<rect x="409.733" y="340.032" width="42.3862" height="151.648" rx="21.1931" fill="#003425"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M422.005 133.354C413.089 125.771 399.714 126.851 392.131 135.768L273.699 275.021C270.643 278.614 268.994 282.932 268.698 287.302C268.532 288.371 268.446 289.466 268.446 290.581V468.603C268.446 480.308 277.934 489.796 289.639 489.796C301.344 489.796 310.832 480.308 310.832 468.603V296.784L424.419 163.228C432.002 154.312 430.921 140.937 422.005 133.354Z" fill="#003425"/>
<rect x="113.972" y="134.25" width="42.3862" height="174.745" rx="21.1931" transform="rotate(-39.3441 113.972 134.25)" fill="#003425"/>
<circle cx="460.126" cy="279.278" r="25.9027" fill="#00DD20"/>
</svg>

Before

Width:  |  Height:  |  Size: 869 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View File

@@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 0C7.16 0 0 7.16 0 16C0 23.08 4.58 29.06 10.94 31.18C11.74 31.32 12.04 30.84 12.04 30.42C12.04 30.04 12.02 28.78 12.02 27.44C8 28.18 6.96 26.46 6.64 25.56C6.46 25.1 5.68 23.68 5 23.3C4.44 23 3.64 22.26 4.98 22.24C6.24 22.22 7.14 23.4 7.44 23.88C8.88 26.3 11.18 25.62 12.1 25.2C12.24 24.16 12.66 23.46 13.12 23.06C9.56 22.66 5.84 21.28 5.84 15.16C5.84 13.42 6.46 11.98 7.48 10.86C7.32 10.46 6.76 8.82 7.64 6.62C7.64 6.62 8.98 6.2 12.04 8.26C13.32 7.9 14.68 7.72 16.04 7.72C17.4 7.72 18.76 7.9 20.04 8.26C23.1 6.18 24.44 6.62 24.44 6.62C25.32 8.82 24.76 10.46 24.6 10.86C25.62 11.98 26.24 13.4 26.24 15.16C26.24 21.3 22.5 22.66 18.94 23.06C19.52 23.56 20.02 24.52 20.02 26.02C20.02 28.16 20 29.88 20 30.42C20 30.84 20.3 31.34 21.1 31.18C27.42 29.06 32 23.06 32 16C32 7.16 24.84 0 16 0V0Z" fill="#24292E"/>
</svg>

After

Width:  |  Height:  |  Size: 959 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -1,7 +0,0 @@
<svg width="600" height="600" viewBox="0 0 600 600" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="300" cy="300" r="300" fill="#003425"/>
<rect x="409.733" y="340.031" width="42.3862" height="151.648" rx="21.1931" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M422.005 133.354C413.089 125.771 399.714 126.851 392.131 135.767L273.699 275.021C270.643 278.614 268.994 282.932 268.698 287.302C268.532 288.371 268.446 289.466 268.446 290.581V468.603C268.446 480.308 277.934 489.796 289.639 489.796C301.344 489.796 310.832 480.308 310.832 468.603V296.784L424.419 163.228C432.002 154.312 430.921 140.937 422.005 133.354Z" fill="white"/>
<rect x="113.972" y="134.25" width="42.3862" height="174.745" rx="21.1931" transform="rotate(-39.3441 113.972 134.25)" fill="white"/>
<circle cx="460.126" cy="279.278" r="25.9027" fill="#00FF25"/>
</svg>

Before

Width:  |  Height:  |  Size: 865 B

View File

@@ -1,10 +1,7 @@
@import 'https://at.alicdn.com/t/c/font_4563475_hrx8c92awui.css';
@import './markdown.scss';
// @font-face {
// font-family: 'Playwrite';
// src: url(../fonts/Playwrite.ttf) format('truetype');
// }
@import './scrollbar.scss';
@import '../fonts/icon-fonts/iconfont.css';
@import '../fonts/ubuntu/ubuntu.css';
:root {
--color-white: #ffffff;
@@ -12,7 +9,7 @@
--color-white-mute: #f2f2f2;
--color-black: #1b1b1f;
--color-black-soft: #303030;
--color-black-soft: #262626;
--color-black-mute: #363636;
--color-gray-1: #515c67;
@@ -27,18 +24,74 @@
--color-background-soft: var(--color-black-soft);
--color-background-mute: var(--color-black-mute);
--color-primary: #135200;
--color-primary-soft: #13520099;
--color-primary-mute: #13520033;
--color-text: var(--color-text-1);
--color-icon: #ffffff99;
--color-icon-white: #ffffff;
--color-border: #ffffff20;
--color-border-soft: #ffffff20;
--color-error: #f44336;
--color-link: #1677ff;
--color-code-background: #323232;
--color-scrollbar-thumb: rgba(255, 255, 255, 0.08);
--color-scrollbar-thumb-hover: rgba(255, 255, 255, 0.15);
--navbar-background-mac: rgba(30, 30, 30, 0.8);
--navbar-background: rgba(30, 30, 30);
--input-bar-background: rgba(255, 255, 255, 0.02);
--navbar-height: 42px;
--sidebar-width: 55px;
--assistants-width: 235px;
--topic-list-width: 250px;
--settings-width: var(--assistants-width);
--sidebar-width: 52px;
--status-bar-height: 40px;
--input-bar-height: 120px;
--input-bar-height: 85px;
--assistants-width: 280px;
--topic-list-width: 280px;
--settings-width: 260px;
}
body[theme-mode='light'] {
--color-white: #ffffff;
--color-white-soft: #f8f8f8;
--color-white-mute: #efefef;
--color-black: #1b1b1f;
--color-black-soft: #262626;
--color-black-mute: #363636;
--color-gray-1: #8e8e93;
--color-gray-2: #aeaeb2;
--color-gray-3: #c7c7cc;
--color-text-1: rgba(0, 0, 0, 1);
--color-text-2: rgba(0, 0, 0, 0.6);
--color-text-3: rgba(0, 0, 0, 0.38);
--color-background: #ffffff;
--color-background-soft: var(--color-white-soft);
--color-background-mute: var(--color-white-mute);
--color-primary: #00b96b;
--color-primary-soft: #00b96b99;
--color-primary-mute: #00b96b33;
--color-text: var(--color-text-1);
--color-icon: #00000099;
--color-icon-white: #000000;
--color-border: #00000028;
--color-border-soft: #00000028;
--color-error: #f44336;
--color-link: #1677ff;
--color-code-background: #e3e3e3;
--color-scrollbar-thumb: rgba(0, 0, 0, 0.08);
--color-scrollbar-thumb-hover: rgba(0, 0, 0, 0.15);
--navbar-background-mac: rgba(255, 255, 255, 0.75);
--navbar-background: rgba(255, 255, 255);
--input-bar-background: rgba(0, 0, 0, 0.02);
}
*,
@@ -49,6 +102,14 @@
font-weight: normal;
}
*:focus {
outline: none;
}
* {
-webkit-tap-highlight-color: transparent;
}
ul {
list-style: none;
}
@@ -57,23 +118,12 @@ body {
display: flex;
min-height: 100vh;
color: var(--color-text);
background: var(--color-background);
font-size: 14px;
line-height: 1.6;
overflow: hidden;
background-size: cover;
font-family:
Inter,
-apple-system,
BlinkMacSystemFont,
'Segoe UI',
Roboto,
Oxygen,
Ubuntu,
Cantarell,
'Fira Sans',
'Droid Sans',
'Helvetica Neue',
sans-serif;
background: transparent !important;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans',
'Helvetica Neue', sans-serif;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@@ -102,29 +152,82 @@ body,
resize: none;
}
/* 全局初始化滚动条样式 */
::-webkit-scrollbar {
width: 5px;
height: 5px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.2);
border-radius: 10px;
}
::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.4);
}
/* Safari 和 Chrome */
@media screen and (-webkit-min-device-pixel-ratio: 0) {
body {
scrollbar-width: thin; /* 告诉 FF 用细滚动条 */
scrollbar-color: rgba(0, 0, 0, 0.4) rgba(0, 0, 0, 0.1); /* FF 前面色后面色 */
.chat-nav-dropdown {
.ant-dropdown-menu {
padding-bottom: 12px;
}
}
.loader {
width: 16px;
height: 16px;
border-radius: 50%;
background-color: #000;
box-shadow:
32px 0 #000,
-32px 0 #000;
position: relative;
animation: flash 0.5s ease-out infinite alternate;
}
.ant-segmented-group {
gap: 4px;
}
.drag {
-webkit-app-region: drag;
}
.nodrag {
-webkit-app-region: no-drag;
}
.minapp-drawer {
.ant-drawer-content-wrapper {
box-shadow: none;
}
.ant-drawer-header {
position: absolute;
-webkit-app-region: drag;
min-height: calc(var(--navbar-height) + 0.5px);
background: var(--navbar-background);
width: calc(100vw - var(--sidebar-width));
border-bottom: 0.5px solid var(--color-border);
margin-top: -0.5px;
}
.ant-drawer-body {
padding: 0;
margin-top: var(--navbar-height);
overflow: hidden;
}
.minapp-mask {
background-color: transparent !important;
}
}
.ant-drawer-header {
-webkit-app-region: no-drag;
}
.segmented-tab {
.ant-segmented-item-label {
align-items: center;
display: flex;
flex-direction: row;
justify-content: center;
font-size: 13px;
}
.iconfont {
font-size: 13px;
margin-left: -2px;
}
.anticon-setting {
font-size: 12px;
}
.icon-business-smart-assistant {
margin-right: -2px;
}
.ant-segmented-item-icon + * {
margin-left: 4px;
}
}

View File

@@ -1,20 +1,15 @@
.markdown {
color: #fff;
font-size: 15px;
color: var(--color-text);
line-height: 1.6;
user-select: text;
margin-top: 4px;
word-break: break-word;
p:first-of-type {
margin-top: 0;
}
h1:first-of-type,
h2:first-of-type,
h3:first-of-type,
h4:first-of-type,
h5:first-of-type,
h6:first-of-type {
h1:first-child,
h2:first-child,
h3:first-child,
h4:first-child,
h5:first-child,
h6:first-child {
margin-top: 0;
}
@@ -26,62 +21,234 @@
h6 {
margin: 1em 0 1em 0;
font-weight: 800;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans',
'Helvetica Neue', sans-serif;
}
h1 {
font-size: 2em;
color: #fff;
border-bottom: 0.5px solid var(--color-border);
padding-bottom: 0.3em;
}
h2 {
font-size: 1.5em;
color: #fff;
border-bottom: 0.5px solid var(--color-border);
padding-bottom: 0.3em;
}
h3 {
font-size: 1.2em;
color: #fff;
}
h4 {
font-size: 1em;
color: #fff;
}
h5 {
font-size: 0.9em;
color: #fff;
}
h6 {
font-size: 0.8em;
color: #fff;
}
p {
margin: 1em 0;
color: #fff;
&:last-child {
margin-bottom: 5px;
}
&:first-child {
margin-top: 0;
}
}
ul,
ol {
padding-left: 1.5em;
margin: 1em 0;
color: #ccc;
}
li {
margin-bottom: 0.5em;
pre {
margin: 1.5em 0;
}
&::marker {
color: var(--color-text-3);
}
}
li > ul,
li > ol {
margin: 0.5em 0;
}
hr {
border: none;
border-top: 1px solid #555;
border-top: 0.5px solid var(--color-border);
margin: 20px 0;
background-color: #555;
background-color: var(--color-border);
}
span {
word-break: break-all;
}
code {
white-space: pre-wrap !important;
font-family: 'Courier New', Courier, monospace;
}
p code,
li code {
background: var(--color-background-mute);
padding: 3px 5px;
border-radius: 5px;
}
pre {
white-space: pre-wrap !important;
border-radius: 5px;
overflow-x: auto;
font-family: 'Fira Code', 'Courier New', Courier, monospace;
background-color: var(--color-background-mute);
&:not(pre pre) {
> code:not(pre pre > code) {
padding: 15px;
display: block;
}
}
pre {
margin: 0 !important;
code {
background: none;
padding: 0;
border-radius: 0;
}
}
}
blockquote {
margin: 1em 0;
padding-left: 1em;
color: var(--color-text-light);
border-left: 4px solid var(--color-border);
font-family: Georgia, 'Times New Roman', Times, serif;
}
table {
border-collapse: collapse;
margin: 1em 0;
width: 100%;
}
th,
td {
border: 0.5px solid var(--color-border);
padding: 0.5em;
}
th {
background-color: var(--color-background-mute);
font-weight: bold;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans',
'Helvetica Neue', sans-serif;
}
img {
max-width: 100%;
height: auto;
}
a,
.link {
color: var(--color-link);
text-decoration: none;
cursor: pointer;
&:hover {
text-decoration: underline;
}
}
strong {
font-weight: bold;
}
em {
font-style: italic;
}
del {
text-decoration: line-through;
}
sup,
sub {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
.footnote-ref {
font-size: 0.8em;
vertical-align: super;
line-height: 0;
margin: 0 2px;
color: var(--color-primary);
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
.footnotes {
margin-top: 1em;
padding-top: 1em;
border-top: 1px solid var(--color-border);
ol {
padding-left: 1em;
}
li {
font-size: 0.9em;
margin-bottom: 0.5em;
color: var(--color-text-light);
p {
display: inline;
margin: 0;
}
}
.footnote-backref {
font-size: 0.8em;
vertical-align: super;
line-height: 0;
margin-left: 5px;
color: var(--color-primary);
text-decoration: none;
&:hover {
text-decoration: underline;
}
}
}
}
emoji-picker {
--border-size: 0;
}

View File

@@ -0,0 +1,16 @@
/* 全局初始化滚动条样式 */
::-webkit-scrollbar {
width: 2px;
height: 2px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background: var(--color-scrollbar-thumb);
&:hover {
background: var(--color-scrollbar-thumb-hover);
}
}

View File

@@ -0,0 +1,24 @@
import { getModelLogo } from '@renderer/config/provider'
import { Model } from '@renderer/types'
import { Avatar, AvatarProps } from 'antd'
import { first } from 'lodash'
import { FC } from 'react'
interface Props {
model: Model
size: number
props?: AvatarProps
}
const ModelAvatar: FC<Props> = ({ model, size, props }) => {
return (
<Avatar
src={getModelLogo(model?.id || '')}
style={{ width: size, height: size, display: 'flex', alignItems: 'center', justifyContent: 'center' }}
{...props}>
{first(model?.name)}
</Avatar>
)
}
export default ModelAvatar

View File

@@ -0,0 +1,70 @@
import {
DragDropContext,
Draggable,
Droppable,
DroppableProps,
DropResult,
OnDragEndResponder,
OnDragStartResponder,
ResponderProvided
} from '@hello-pangea/dnd'
import { droppableReorder } from '@renderer/utils'
import { FC } from 'react'
interface Props<T> {
list: T[]
style?: React.CSSProperties
listStyle?: React.CSSProperties
children: (item: T, index: number) => React.ReactNode
onUpdate: (list: T[]) => void
onDragStart?: OnDragStartResponder
onDragEnd?: OnDragEndResponder
droppableProps?: Partial<DroppableProps>
}
const DragableList: FC<Props<any>> = ({
children,
list,
style,
listStyle,
droppableProps,
onDragStart,
onUpdate,
onDragEnd
}) => {
const _onDragEnd = (result: DropResult, provided: ResponderProvided) => {
onDragEnd?.(result, provided)
if (result.destination) {
const sourceIndex = result.source.index
const destIndex = result.destination.index
const reorderAgents = droppableReorder(list, sourceIndex, destIndex)
onUpdate(reorderAgents)
}
}
return (
<DragDropContext onDragStart={onDragStart} onDragEnd={_onDragEnd}>
<Droppable droppableId="droppable" {...droppableProps}>
{(provided) => (
<div {...provided.droppableProps} ref={provided.innerRef} style={{ ...style }}>
{list.map((item, index) => (
<Draggable key={`draggable_${item.id}_${index}`} draggableId={item.id} index={index} {...droppableProps}>
{(provided) => (
<div
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
style={{ ...provided.draggableProps.style, marginBottom: 8, ...listStyle }}>
{children(item, index)}
</div>
)}
</Draggable>
))}
</div>
)}
</Droppable>
</DragDropContext>
)
}
export default DragableList

View File

@@ -0,0 +1,25 @@
import { useTheme } from '@renderer/context/ThemeProvider'
import { FC, useEffect, useRef } from 'react'
interface Props {
onEmojiClick: (emoji: string) => void
}
const EmojiPicker: FC<Props> = ({ onEmojiClick }) => {
const { theme } = useTheme()
const ref = useRef<HTMLDivElement>(null)
useEffect(() => {
if (ref.current) {
ref.current.addEventListener('emoji-click', (event: any) => {
event.stopPropagation()
onEmojiClick(event.detail.emoji.unicode)
})
}
}, [onEmojiClick])
// @ts-ignore next-line
return <emoji-picker ref={ref} class={theme === 'dark' ? 'dark' : 'light'} style={{ border: 'none' }} />
}
export default EmojiPicker

View File

@@ -0,0 +1,7 @@
import { FC } from 'react'
const CopyIcon: FC<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>> = (props) => {
return <i {...props} className={`iconfont icon-copy ${props.className}`} />
}
export default CopyIcon

View File

@@ -150,11 +150,12 @@ export const BaseTypography = styled(Box)<{
`
export const TypographyNormal = styled(BaseTypography)`
font-family: 'Poppins';
font-family: 'Ubuntu';
`
export const TypographyBold = styled(BaseTypography)`
font-family: 'Poppins Bold';
font-family: 'Ubuntu';
font-weight: bold;
`
export const Container = styled.main<ContainerProps>`

View File

@@ -0,0 +1,185 @@
/* eslint-disable react/no-unknown-property */
import { CloseOutlined, ExportOutlined, ReloadOutlined } from '@ant-design/icons'
import { isMac, isWindows } from '@renderer/config/constant'
import { useBridge } from '@renderer/hooks/useBridge'
import store from '@renderer/store'
import { setMinappShow } from '@renderer/store/runtime'
import { MinAppType } from '@renderer/types'
import { Drawer } from 'antd'
import { WebviewTag } from 'electron'
import { useEffect, useRef, useState } from 'react'
import styled from 'styled-components'
import { TopView } from '../TopView'
interface Props {
app: MinAppType
resolve: (data: any) => void
}
const PopupContainer: React.FC<Props> = ({ app, resolve }) => {
const [open, setOpen] = useState(true)
const webviewRef = useRef<WebviewTag | null>(null)
useBridge()
const canOpenExternalLink = app.url.startsWith('http://') || app.url.startsWith('https://')
const onClose = () => {
setOpen(false)
setTimeout(() => resolve({}), 300)
}
const onReload = () => {
if (webviewRef.current) {
webviewRef.current.src = app.url
}
}
const onOpenLink = () => {
window.api.openWebsite(app.url)
}
const Title = () => {
return (
<TitleContainer style={{ justifyContent: 'space-between' }}>
<TitleText>{app.name}</TitleText>
<ButtonsGroup className={isWindows ? 'windows' : ''}>
<Button onClick={onReload}>
<ReloadOutlined />
</Button>
{canOpenExternalLink && (
<Button onClick={onOpenLink}>
<ExportOutlined />
</Button>
)}
<Button onClick={onClose}>
<CloseOutlined />
</Button>
</ButtonsGroup>
</TitleContainer>
)
}
useEffect(() => {
const webview = webviewRef.current
if (webview) {
const handleNewWindow = (event: any) => {
event.preventDefault()
if (webview.loadURL) {
webview.loadURL(event.url)
}
}
webview.addEventListener('new-window', handleNewWindow)
return () => {
webview.removeEventListener('new-window', handleNewWindow)
}
}
return () => {}
}, [])
return (
<Drawer
title={<Title />}
placement="bottom"
onClose={onClose}
open={open}
mask={true}
rootClassName="minapp-drawer"
maskClassName="minapp-mask"
height={'100%'}
maskClosable={false}
closeIcon={null}
style={{ marginLeft: 'var(--sidebar-width)' }}>
<webview src={app.url} ref={webviewRef} style={WebviewStyle} allowpopups={'true' as any} />
</Drawer>
)
}
const WebviewStyle: React.CSSProperties = {
width: 'calc(100vw - var(--sidebar-width))',
height: 'calc(100vh - var(--navbar-height))',
backgroundColor: 'white',
display: 'inline-flex'
}
const TitleContainer = styled.div`
display: flex;
flex-direction: row;
align-items: center;
padding-left: ${isMac ? '20px' : '15px'};
padding-right: 10px;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
`
const TitleText = styled.div`
font-weight: bold;
font-size: 14px;
color: var(--color-text-1);
margin-right: 10px;
user-select: none;
`
const ButtonsGroup = styled.div`
display: flex;
flex-direction: row;
align-items: center;
gap: 5px;
-webkit-app-region: no-drag;
&.windows {
margin-right: ${isWindows ? '130px' : 0};
background-color: var(--color-background-mute);
border-radius: 50px;
padding: 0 3px;
overflow: hidden;
}
`
const Button = styled.div`
cursor: pointer;
width: 30px;
height: 30px;
border-radius: 5px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
color: var(--color-text-2);
transition: all 0.2s ease;
font-size: 14px;
&:hover {
color: var(--color-text-1);
background-color: var(--color-background-mute);
}
`
export default class MinApp {
static topviewId = 0
static close() {
TopView.hide('MinApp')
store.dispatch(setMinappShow(false))
}
static start(app: MinAppType) {
store.dispatch(setMinappShow(true))
return new Promise<any>((resolve) => {
TopView.show(
<PopupContainer
app={app}
resolve={(v) => {
resolve(v)
this.close()
}}
/>,
'MinApp'
)
})
}
}

View File

@@ -0,0 +1,137 @@
import { TopView } from '@renderer/components/TopView'
import systemAgents from '@renderer/config/agents.json'
import { useAgents } from '@renderer/hooks/useAgents'
import { useAssistants, useDefaultAssistant } from '@renderer/hooks/useAssistant'
import { covertAgentToAssistant } from '@renderer/services/assistant'
import { EVENT_NAMES, EventEmitter } from '@renderer/services/event'
import { Agent, Assistant } from '@renderer/types'
import { Input, Modal, Tag } from 'antd'
import { useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
interface Props {
resolve: (value: Assistant | undefined) => void
}
const PopupContainer: React.FC<Props> = ({ resolve }) => {
const [open, setOpen] = useState(true)
const { t } = useTranslation()
const { agents: userAgents } = useAgents()
const [searchText, setSearchText] = useState('')
const { defaultAssistant } = useDefaultAssistant()
const { assistants, addAssistant } = useAssistants()
const defaultAgent: Agent = useMemo(
() => ({
id: defaultAssistant.id,
name: defaultAssistant.name,
emoji: defaultAssistant.emoji || '',
prompt: defaultAssistant.prompt,
group: 'system'
}),
[defaultAssistant.emoji, defaultAssistant.id, defaultAssistant.name, defaultAssistant.prompt]
)
const agents = useMemo(() => {
const allAgents = [...userAgents, ...systemAgents] as Agent[]
const list = [defaultAgent, ...allAgents.filter((agent) => !assistants.map((a) => a.id).includes(agent.id))]
return searchText
? list.filter((agent) => agent.name.toLowerCase().includes(searchText.trim().toLocaleLowerCase()))
: list
}, [assistants, defaultAgent, searchText, userAgents])
const onCreateAssistant = (agent: Agent) => {
if (agent.id !== 'default') {
if (assistants.map((a) => a.id).includes(String(agent.id))) {
return
}
}
const assistant = covertAgentToAssistant(agent)
addAssistant(assistant)
setTimeout(() => EventEmitter.emit(EVENT_NAMES.SHOW_ASSISTANTS), 0)
resolve(assistant)
setOpen(false)
}
const onCancel = () => {
setOpen(false)
}
const onClose = async () => {
resolve(undefined)
AddAssistantPopup.hide()
}
return (
<Modal
centered
title={t('chat.add.assistant.title')}
open={open}
onCancel={onCancel}
afterClose={onClose}
transitionName="ant-move-down"
maskTransitionName="ant-fade"
footer={null}>
<Input
placeholder={t('common.search')}
value={searchText}
onChange={(e) => setSearchText(e.target.value)}
allowClear
autoFocus
style={{ marginBottom: 16 }}
/>
<Container>
{agents.map((agent) => (
<AgentItem key={agent.id} onClick={() => onCreateAssistant(agent)}>
{agent.emoji} {agent.name}
{agent.group === 'system' && <Tag color="orange">{t('agents.tag.system')}</Tag>}
{agent.group === 'user' && <Tag color="green">{t('agents.tag.user')}</Tag>}
</AgentItem>
))}
</Container>
</Modal>
)
}
const Container = styled.div`
height: 50vh;
overflow-y: auto;
&::-webkit-scrollbar {
display: none;
}
`
const AgentItem = styled.div`
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 8px;
border-radius: 8px;
user-select: none;
background-color: var(--color-background-soft);
margin-bottom: 8px;
cursor: pointer;
.anticon {
font-size: 16px;
color: var(--color-icon);
}
&:hover {
background-color: var(--color-background-mute);
}
`
export default class AddAssistantPopup {
static topviewId = 0
static hide() {
TopView.hide('AddAssistantPopup')
}
static show() {
return new Promise<Assistant | undefined>((resolve) => {
TopView.show(<PopupContainer resolve={resolve} />, 'AddAssistantPopup')
})
}
}

View File

@@ -1,11 +1,12 @@
import { Input, Modal } from 'antd'
import { useState } from 'react'
import { TopView } from '../TopView'
import { Box } from '../Layout'
import { Assistant } from '@renderer/types'
import { Input, Modal } from 'antd'
import TextArea from 'antd/es/input/TextArea'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Box } from '../Layout'
import { TopView } from '../TopView'
interface AssistantSettingPopupShowParams {
assistant: Assistant
}
@@ -33,7 +34,15 @@ const AssistantSettingPopupContainer: React.FC<Props> = ({ assistant, resolve })
}
return (
<Modal title={assistant.name} open={open} onOk={onOk} onCancel={handleCancel} afterClose={onClose}>
<Modal
title={assistant.name}
open={open}
onOk={onOk}
onCancel={handleCancel}
afterClose={onClose}
transitionName="ant-move-down"
maskTransitionName="ant-fade"
centered>
<Box mb={8}>{t('common.name')}</Box>
<Input
placeholder={t('common.assistant') + t('common.name')}
@@ -44,7 +53,7 @@ const AssistantSettingPopupContainer: React.FC<Props> = ({ assistant, resolve })
{t('common.prompt')}
</Box>
<TextArea
rows={4}
rows={10}
placeholder={t('common.assistant') + t('common.prompt')}
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
@@ -56,18 +65,19 @@ const AssistantSettingPopupContainer: React.FC<Props> = ({ assistant, resolve })
export default class AssistantSettingPopup {
static topviewId = 0
static hide() {
TopView.hide(this.topviewId)
TopView.hide('AssistantSettingPopup')
}
static show(props: AssistantSettingPopupShowParams) {
return new Promise<Assistant>((resolve) => {
this.topviewId = TopView.show(
TopView.show(
<AssistantSettingPopupContainer
{...props}
resolve={(v) => {
resolve(v)
this.hide()
}}
/>
/>,
'AssistantSettingPopup'
)
})
}

View File

@@ -1,7 +1,8 @@
import { Input, InputProps, Modal } from 'antd'
import { useState } from 'react'
import { TopView } from '../TopView'
import { Box } from '../Layout'
import { TopView } from '../TopView'
interface PromptPopupShowParams {
title: string
@@ -57,18 +58,19 @@ const PromptPopupContainer: React.FC<Props> = ({
export default class PromptPopup {
static topviewId = 0
static hide() {
TopView.hide(this.topviewId)
TopView.hide('PromptPopup')
}
static show(props: PromptPopupShowParams) {
return new Promise<string>((resolve) => {
this.topviewId = TopView.show(
TopView.show(
<PromptPopupContainer
{...props}
resolve={(v) => {
resolve(v)
this.hide()
}}
/>
/>,
'PromptPopup'
)
})
}

Some files were not shown because too many files have changed in this diff Show More