Skip to content

feat: Add AI module - #266

Merged
kagol merged 8 commits into
opentiny:mainfrom
chenxi-20:feat/ai-tool-20250409
Jul 24, 2025
Merged

feat: Add AI module#266
kagol merged 8 commits into
opentiny:mainfrom
chenxi-20:feat/ai-tool-20250409

Conversation

@chenxi-20

@chenxi-20 chenxi-20 commented Apr 16, 2025

Copy link
Copy Markdown
Contributor

PR

效果如下:

AI回答之后的效果:
image

点击完成之后的效果:
image

PR Checklist

Please check if your PR fulfills the following requirements:

  • The commit message follows our Commit Message Guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other... Please describe:

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Summary by CodeRabbit

  • New Features

    • Introduced AI-assisted text generation in the Fluent Editor with a new AI toolbar button.
    • Added an interactive AI input dialog supporting live streaming responses and controls to insert, regenerate, or close AI-generated content.
    • Integrated a dedicated AI icon and comprehensive UI styling for a seamless AI interaction experience.
    • Included a demo component and documentation to showcase AI capabilities within the editor.
  • Documentation

    • Added a new AI section and demo in the usage examples sidebar.

@coderabbitai

coderabbitai Bot commented Apr 16, 2025

Copy link
Copy Markdown

Walkthrough

This update introduces AI-assisted text generation capabilities to the Fluent Editor. It adds a new AI module, integrates an AI button into the editor toolbar, and provides a user interface for submitting prompts and inserting AI-generated content. Supporting changes include new SCSS styles for the AI dialog, icon additions, toolbar configuration updates, and documentation with a demo. The sidebar is updated to include an AI demo entry, and relevant assets and modules are imported and registered to enable the new feature.

Changes

File(s) Change Summary
packages/docs/fluent-editor/.vitepress/sidebar.ts Added a sidebar entry labeled "AI" linking to "/docs/demo/ai" under the "使用示例" section.
packages/docs/fluent-editor/demos/ai.vue,
packages/docs/fluent-editor/docs/demo/ai.md
Introduced a new Vue demo component and corresponding markdown documentation showcasing AI integration and configuration within the editor.
packages/fluent-editor/src/assets/ai.scss,
packages/fluent-editor/src/assets/style.scss
Added new SCSS styles for the AI dialog and imported them into the main style entry file.
packages/fluent-editor/src/fluent-editor.ts Imported and registered the new AI module in the FluentEditor registration system.
packages/fluent-editor/src/modules/ai/index.ts Added a new exported AI class implementing the AI-assisted text generation interface, including UI, event handling, streaming API calls, and editor integration.
packages/fluent-editor/src/themes/snow.ts Added a no-op handler for 'ai' to the toolbar handlers in the snow theme configuration.
packages/fluent-editor/src/ui/icons.config.ts,
packages/fluent-editor/src/ui/icons.ts
Added a new AI SVG icon constant and registered it in the icons configuration for use in the editor UI.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Editor (FluentEditor)
    participant AI Module
    participant AI Backend

    User->>Editor: Clicks AI button in toolbar
    Editor->>AI Module: Show AI input dialog
    User->>AI Module: Enters prompt and submits
    AI Module->>AI Backend: Sends prompt (streaming request)
    AI Backend-->>AI Module: Streams generated content
    AI Module->>User: Displays live AI response
    User->>AI Module: Chooses action (Insert/Regenerate/Close)
    AI Module->>Editor: Inserts content or closes dialog
Loading

Estimated code review effort

3 (90–240 minutes)

Poem

In the garden of code, a new seed is sown,
AI now whispers where ideas are grown.
With a click and a prompt, inspiration flows,
The editor listens, and creativity grows.
Icons gleam bright, dialogs appear—
Hopping ahead, the future is here!
🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d3e9cbb and 02e980d.

📒 Files selected for processing (2)
  • packages/fluent-editor/src/fluent-editor.ts (2 hunks)
  • packages/fluent-editor/src/ui/icons.config.ts (1 hunks)
🪛 GitHub Check: lint
packages/fluent-editor/src/ui/icons.config.ts

[failure] 328-328:
Unexpected tab character


[failure] 327-327:
Unexpected tab character


[failure] 326-326:
Unexpected tab character


[failure] 325-325:
Unexpected tab character


[failure] 324-324:
Unexpected tab character


[failure] 323-323:
Unexpected tab character


[failure] 322-322:
Unexpected tab character


[failure] 321-321:
Unexpected tab character


[failure] 320-320:
Unexpected tab character


[failure] 319-319:
Unexpected tab character

🪛 ESLint
packages/fluent-editor/src/ui/icons.config.ts

[error] 319-319: Unexpected tab character.

(style/no-tabs)


[error] 320-320: Unexpected tab character.

(style/no-tabs)


[error] 321-321: Unexpected tab character.

(style/no-tabs)


[error] 322-322: Unexpected tab character.

(style/no-tabs)


[error] 323-323: Unexpected tab character.

(style/no-tabs)


[error] 324-324: Unexpected tab character.

(style/no-tabs)


[error] 325-325: Unexpected tab character.

(style/no-tabs)


[error] 326-326: Unexpected tab character.

(style/no-tabs)


[error] 327-327: Unexpected tab character.

(style/no-tabs)


[error] 328-328: Unexpected tab character.

(style/no-tabs)


[error] 329-329: Unexpected tab character.

(style/no-tabs)

🪛 GitHub Actions: autofix.ci
packages/fluent-editor/src/ui/icons.config.ts

[error] 319-319: ESLint: Unexpected tab character (style/no-tabs)

🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/fluent-editor/src/fluent-editor.ts
🧰 Additional context used
🪛 GitHub Check: lint
packages/fluent-editor/src/ui/icons.config.ts

[failure] 328-328:
Unexpected tab character


[failure] 327-327:
Unexpected tab character


[failure] 326-326:
Unexpected tab character


[failure] 325-325:
Unexpected tab character


[failure] 324-324:
Unexpected tab character


[failure] 323-323:
Unexpected tab character


[failure] 322-322:
Unexpected tab character


[failure] 321-321:
Unexpected tab character


[failure] 320-320:
Unexpected tab character


[failure] 319-319:
Unexpected tab character

🪛 ESLint
packages/fluent-editor/src/ui/icons.config.ts

[error] 319-319: Unexpected tab character.

(style/no-tabs)


[error] 320-320: Unexpected tab character.

(style/no-tabs)


[error] 321-321: Unexpected tab character.

(style/no-tabs)


[error] 322-322: Unexpected tab character.

(style/no-tabs)


[error] 323-323: Unexpected tab character.

(style/no-tabs)


[error] 324-324: Unexpected tab character.

(style/no-tabs)


[error] 325-325: Unexpected tab character.

(style/no-tabs)


[error] 326-326: Unexpected tab character.

(style/no-tabs)


[error] 327-327: Unexpected tab character.

(style/no-tabs)


[error] 328-328: Unexpected tab character.

(style/no-tabs)


[error] 329-329: Unexpected tab character.

(style/no-tabs)

🪛 GitHub Actions: autofix.ci
packages/fluent-editor/src/ui/icons.config.ts

[error] 319-319: ESLint: Unexpected tab character (style/no-tabs)

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions Bot added the enhancement New feature or request label Apr 16, 2025
@chenxi-20
chenxi-20 force-pushed the feat/ai-tool-20250409 branch from a63221b to c312920 Compare April 16, 2025 09:29
@chenxi-20
chenxi-20 force-pushed the feat/ai-tool-20250409 branch from c312920 to 6c03f2e Compare April 16, 2025 09:32

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🧹 Nitpick comments (12)
packages/docs/fluent-editor/docs/demo/ai.md (1)

1-6: AI documentation is clear and references the demo correctly.

The new documentation introduces the AI feature and links to the demo as expected. Consider expanding the description for more context in the future.

packages/fluent-editor/src/fluent-editor.ts (1)

6-6: Consider adding a more descriptive comment.

The comment "// AI" is quite brief. Consider using a more descriptive comment to explain the purpose of this module, such as "// AI-assisted text generation module" to provide better context for other developers.

packages/fluent-editor/src/themes/snow.ts (1)

62-62: Consider adding a comment for the empty AI handler.

This empty handler function is intentional since the actual implementation is provided by the AI module in packages/fluent-editor/src/modules/ai/index.ts. Adding a comment explaining this would improve code clarity.

-        'ai': function () {},
+        'ai': function () {
+          // Actual handler implementation is in the AI module class
+        },
packages/fluent-editor/src/assets/ai.scss (3)

1-4: Consider adding additional positioning properties and z-index.

The absolute positioning only specifies the left position, but not top, which might cause positioning issues. The dialog also doesn't have a z-index, which could lead to layering problems with other editor elements.

.ql-ai-dialog {
  position: absolute;
  left: 15px;
+  z-index: 1001;
}

41-47: Avoid excessive use of !important for better maintainability.

The aggressive use of !important flags will make future customizations difficult and may override user-defined styles. Consider using more specific selectors instead.

.ql-ai-input input {
  flex: 1;
  padding: 8px;
-  border: none !important;
-  outline: none !important;
-  box-shadow: none !important;
+  border: none;
+  outline: none;
+  box-shadow: none;
}

90-101: Consider adding accessibility features to the send button.

The send button lacks appropriate accessibility attributes like role and aria-label, which are important for screen readers and keyboard navigation.

Include additional properties for the button in the JavaScript where this element is created:

sendButtonEl.setAttribute('role', 'button');
sendButtonEl.setAttribute('aria-label', 'Send prompt to AI');
sendButtonEl.setAttribute('tabindex', '0');
packages/fluent-editor/src/modules/ai/index.ts (6)

12-13: Use English comments for better code maintainability.

There's a Chinese comment "打断标记" (break flag). For international collaboration, it's better to use English for all comments.

-  isBreak: boolean = false // 打断标记
+  isBreak: boolean = false // break flag
   inputValue: string = '' // 存储输入框的值
+  // inputValue: string = '' // stores the input value

87-89: Comment doesn't match implementation.

The comment suggests replacing input with textarea, but an input element is actually created.

-    // 替换input为textarea
+    // Create input element
     this.inputEl = document.createElement('input')
     this.inputEl.type = 'text'
     this.inputEl.placeholder = '请输入内容'

46-54: Use textContent instead of innerText for better performance.

The innerText property triggers a reflow when accessed, which can be expensive for performance. Static analysis suggests using textContent instead.

    this.sendButtonEl.innerText = text
+    this.sendButtonEl.textContent = text

// And in the event listener:
-      if (e.target.innerText === '停止') {
+      if (e.target.textContent === '停止') {

Also applies to: 119-128

🧰 Tools
🪛 ESLint

[error] 52-52: Prefer .textContent over .innerText.

(unicorn/prefer-dom-node-text-content)


136-139: Remove console.log statement before production.

Console statements should be removed from production code. Consider using a proper logging system instead.

    try {
-      console.log('this.inputValue', this.inputValue)
      const ollama = new Ollama({ host: this.host })
🧰 Tools
🪛 ESLint

[error] 137-137: Unexpected console statement. Only these console methods are allowed: warn, error.

(no-console)


138-143: Consider adding request timeout handling.

The API call to Ollama doesn't have a timeout setting, which could lead to indefinite waiting if the server doesn't respond.

      const ollama = new Ollama({ host: this.host })
+     
+     // Set a timeout for the request
+     const timeoutPromise = new Promise((_, reject) => {
+       setTimeout(() => reject(new Error('Request timeout')), 30000);
+     });
+     
+     // Race between the actual request and the timeout
+     const requestPromise = ollama.generate({
        model: this.model,
        prompt: this.inputValue,
        stream: true,
      })
+     
+     const res = await Promise.race([requestPromise, timeoutPromise]);

228-235: Safely remove action menu in regenerateResponse.

The method doesn't check if the action menu is actually a child of the wrapper before removing it.

  private async regenerateResponse() {
-    this.wrapContainer.removeChild(this.actionMenu)
-    this.actionMenu = null
+    if (this.actionMenu && this.wrapContainer && this.wrapContainer.contains(this.actionMenu)) {
+      this.wrapContainer.removeChild(this.actionMenu)
+      this.actionMenu = null
+    }
    if (this.inputValue) {
      this.inputEl.value = '' // 清空输入框
      await this.queryAI()
    }
  }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f86f49a and 6c03f2e.

📒 Files selected for processing (11)
  • packages/docs/fluent-editor/.vitepress/sidebar.ts (1 hunks)
  • packages/docs/fluent-editor/demos/ai.vue (1 hunks)
  • packages/docs/fluent-editor/docs/demo/ai.md (1 hunks)
  • packages/fluent-editor/package.json (1 hunks)
  • packages/fluent-editor/src/assets/ai.scss (1 hunks)
  • packages/fluent-editor/src/assets/style.scss (1 hunks)
  • packages/fluent-editor/src/fluent-editor.ts (2 hunks)
  • packages/fluent-editor/src/modules/ai/index.ts (1 hunks)
  • packages/fluent-editor/src/themes/snow.ts (1 hunks)
  • packages/fluent-editor/src/ui/icons.config.ts (1 hunks)
  • packages/fluent-editor/src/ui/icons.ts (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
packages/fluent-editor/src/ui/icons.ts (1)
packages/fluent-editor/src/ui/icons.config.ts (1)
  • AI_ICON (310-314)
packages/fluent-editor/src/fluent-editor.ts (1)
packages/fluent-editor/src/modules/ai/index.ts (1)
  • AI (6-246)
packages/fluent-editor/src/modules/ai/index.ts (1)
packages/fluent-editor/src/ui/icons.config.ts (1)
  • AI_ICON (310-314)
🪛 ESLint
packages/docs/fluent-editor/demos/ai.vue

[error] 2-2: 'FluentEditor' is defined but never used.

(unused-imports/no-unused-imports)

packages/fluent-editor/src/modules/ai/index.ts

[error] 52-52: Prefer .textContent over .innerText.

(unicorn/prefer-dom-node-text-content)


[error] 62-62: Prefer .textContent over .innerText.

(unicorn/prefer-dom-node-text-content)


[error] 120-120: Prefer .textContent over .innerText.

(unicorn/prefer-dom-node-text-content)


[error] 133-133: Prefer .textContent over .innerText.

(unicorn/prefer-dom-node-text-content)


[error] 137-137: Unexpected console statement. Only these console methods are allowed: warn, error.

(no-console)


[error] 156-156: Prefer .textContent over .innerText.

(unicorn/prefer-dom-node-text-content)

🔇 Additional comments (8)
packages/fluent-editor/src/ui/icons.config.ts (1)

310-314: AI icon addition is correct and follows project conventions.

The new AI_ICON SVG constant is well-formed and consistent with other icon definitions. No issues found.

packages/fluent-editor/package.json (1)

36-36: Ollama dependency addition is appropriate for AI integration.

The "ollama" dependency is correctly added to support the new AI feature. Please ensure this package is actively maintained and free of known vulnerabilities.

Would you like to verify the security status and latest version of the "ollama" package?

packages/docs/fluent-editor/.vitepress/sidebar.ts (1)

28-28: Sidebar entry for AI demo is correct.

The new "AI" entry is properly added to the usage examples section and links to the correct documentation page.

packages/fluent-editor/src/assets/style.scss (1)

28-28: AI SCSS import is correctly added.

The import of ai.scss is well-placed and supports the new AI UI components.

packages/fluent-editor/src/fluent-editor.ts (1)

57-57: The AI module registration looks good.

The AI module is properly registered in the FluentEditor configuration under the key 'modules/ai'.

packages/fluent-editor/src/ui/icons.ts (2)

3-3: Import of the AI icon is correctly implemented.

The AI_ICON is properly imported from the icons.config file.


40-40: The AI icon is properly registered in the ICONS_CONFIG object.

Good placement of the AI icon at the top of the icons list, grouped with other action-related icons like undo, redo, and clean.

packages/docs/fluent-editor/demos/ai.vue (1)

23-27: Review AI configuration for production readiness.

The AI module is configured with hardcoded values that might not be suitable for production:

  1. The host is set to localhost, which won't work in production environments
  2. The model is hardcoded to a specific model name
  3. The API key is empty

Consider implementing a more flexible configuration approach that can be adjusted for different environments.

Comment thread packages/docs/fluent-editor/demos/ai.vue
Comment thread packages/docs/fluent-editor/demos/ai.vue
Comment thread packages/docs/fluent-editor/demos/ai.vue
Comment thread packages/docs/fluent-editor/demos/ai.vue
Comment thread packages/fluent-editor/src/assets/ai.scss
Comment thread packages/fluent-editor/src/modules/ai/index.ts
Comment thread packages/fluent-editor/src/modules/ai/index.ts Outdated
Comment thread packages/fluent-editor/src/modules/ai/index.ts
Comment thread packages/fluent-editor/src/modules/ai/index.ts Outdated
Comment thread packages/fluent-editor/src/modules/ai/index.ts
Comment thread packages/fluent-editor/src/modules/ai/index.ts Outdated
Comment thread packages/fluent-editor/src/modules/ai/index.ts Outdated
@kagol

kagol commented Apr 16, 2025

Copy link
Copy Markdown
Member

@chenxi-20 需要解决下冲突

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (7)
packages/fluent-editor/src/modules/ai/index.ts (7)

10-17: 🛠️ Refactor suggestion

Localize hardcoded strings for internationalization.

The class contains multiple hardcoded Chinese strings that should be extracted to a localization system for better internationalization support. These strings appear throughout the code and should be centralized.

-  SEND: string = '发送' // 发送按钮文字
-  BREAK: string = '停止' // 取消按钮文字
-  DONE: string = '完成'
-  REGENERATE: string = '重新生成'
-  CLOSE: string = '关闭'
+  SEND: string = this.options.translations?.send || '发送' 
+  BREAK: string = this.options.translations?.stop || '停止'
+  DONE: string = this.options.translations?.done || '完成'
+  REGENERATE: string = this.options.translations?.regenerate || '重新生成'
+  CLOSE: string = this.options.translations?.close || '关闭'

81-81: 🛠️ Refactor suggestion

Localize placeholder text.

The input placeholder is hardcoded in Chinese and should be localized.

-      this.inputEl.placeholder = '请输入内容'
+      this.inputEl.placeholder = this.options.translations?.inputPlaceholder || '请输入内容'

153-153: 🛠️ Refactor suggestion

Localize status message text.

The status message should be localized to support multiple languages.

-    this.aiPreTextEl.textContent = '按ESC退出 | 正在编写...' // 显示提示语
+    this.aiPreTextEl.textContent = this.options.translations?.writingStatus || '按ESC退出 | 正在编写...' // 显示提示语
🧰 Tools
🪛 ESLint

[error] 153-153: Prefer .textContent over .innerText.

(unicorn/prefer-dom-node-text-content)


211-214: 🛠️ Refactor suggestion

Improve error handling for user feedback.

The current error handling only logs to the console but doesn't provide any feedback to the user.

    catch (error) {
      console.error('AI查询失败:', error)
-      return 'AI查询失败,请重试'
+      const errorMessage = this.options.translations?.queryFailed || 'AI查询失败,请重试'
+      this.showErrorMessage(errorMessage)
+      return ''
    }

+ private showErrorMessage(message: string) {
+   if (this.resultPopupEl) {
+     this.resultPopupEl.innerHTML = `<div class="ql-ai-error">${message}</div>`;
+     this.resultPopupEl.style.display = 'block';
+     this.aiPreTextEl.textContent = '';
+     this.sendButtonEl.textContent = this.SEND;
+     this.sendButtonEl.style.display = 'block';
+   }
+ }

221-222: ⚠️ Potential issue

Sanitize HTML content before displaying.

Displaying raw HTML from an external source (AI response) could present security risks.

+import DOMPurify from 'dompurify';

// Then in showAIResponse method:
    // 显示结果
-    this.resultPopupEl.innerHTML = response
+    this.resultPopupEl.innerHTML = DOMPurify.sanitize(response)
    this.resultPopupEl.style.display = 'block'

259-270: ⚠️ Potential issue

Security risk with dangerouslyPasteHTML.

Using dangerouslyPasteHTML could lead to XSS vulnerabilities if the AI response contains malicious content.

+import DOMPurify from 'dompurify';

// Then in insertAIResponse method:
      // 使用HTML方式插入可以保留格式
      this.quill.clipboard.dangerouslyPasteHTML(
        range.index,
-        this.resultPopupEl.innerHTML,
+        DOMPurify.sanitize(this.resultPopupEl.innerHTML),
      )

Don't forget to add DOMPurify as a dependency to your project.


269-269: 🛠️ Refactor suggestion

Set cursor position after insertion.

After inserting the AI response, you should set the cursor position to the end of the inserted content.

      this.quill.clipboard.dangerouslyPasteHTML(
        range.index,
        DOMPurify.sanitize(this.resultPopupEl.innerHTML),
      )
+      // Move cursor to the end of inserted content
+      const sanitizedLength = DOMPurify.sanitize(this.resultPopupEl.innerHTML).length;
+      this.quill.setSelection(range.index + sanitizedLength, 0, 'api');
    }
🧹 Nitpick comments (12)
packages/fluent-editor/src/modules/ai/index.ts (12)

60-62: Fix coding style issues.

There are a few coding style issues in the file that were identified by static analysis tools.

-    if(!this.dialogContainerEl) {
+    if (!this.dialogContainerEl) {
🧰 Tools
🪛 ESLint

[error] 60-60: Expected space(s) after "if".

(style/keyword-spacing)


100-101: Fix trailing spaces and prefer textContent over innerText.

There are trailing spaces in the code, and innerText should be replaced with textContent for better performance and consistency.

-    
-    this.aiPreTextEl.innerText = `${this.model}帮你写:`
+
+    this.aiPreTextEl.textContent = `${this.model}帮你写:`
🧰 Tools
🪛 ESLint

[error] 100-100: Trailing spaces not allowed.

(style/no-trailing-spaces)


[error] 100-100: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 101-101: Prefer .textContent over .innerText.

(unicorn/prefer-dom-node-text-content)


102-102: Replace innerText with textContent.

For better performance and consistency, use textContent instead of innerText.

-    this.sendButtonEl.innerText = this.SEND
+    this.sendButtonEl.textContent = this.SEND
🧰 Tools
🪛 ESLint

[error] 102-102: Prefer .textContent over .innerText.

(unicorn/prefer-dom-node-text-content)


116-120: Extract shared query logic.

The event handler for Enter key and click events both call queryAI but with different logic. This should be refactored to avoid code duplication.

     // 监听发送事件
     this.inputEl.addEventListener('keydown', async (e) => {
       if (e.key === 'Enter') {
-        await this.queryAI()
+        await this.handleInputSubmit()
       }
     })

And add a new method:

private async handleInputSubmit() {
  this.inputValue = this.inputEl.value
  this.inputEl.value = '' // 清空输入框
  await this.queryAI()
}

121-128: Fix conditional check using textContent.

The button text check should use textContent instead of innerText for consistency.

     this.sendButtonEl.addEventListener('click', async (e) => {
-      if (e.target.innerText === this.BREAK) {
+      if (e.target.textContent === this.BREAK) {
         this.isBreak = true
       }
       else {
-        await this.queryAI()
+        await this.handleInputSubmit()
       }
     })
🧰 Tools
🪛 ESLint

[error] 122-122: Prefer .textContent over .innerText.

(unicorn/prefer-dom-node-text-content)


145-147: Fix spacing and add early return for empty input.

The if statement is missing proper spacing, and the return statement doesn't have a return value when expected.

-    if(this.inputValue.trim() === '') {
-      return
+    if (this.inputValue.trim() === '') {
+      return ''
     }
🧰 Tools
🪛 ESLint

[error] 145-145: Expected space(s) after "if".

(style/keyword-spacing)


151-153: Replace innerText with textContent.

Continue using textContent instead of innerText throughout the codebase for consistency.

-    this.sendButtonEl.innerText = this.BREAK
+    this.sendButtonEl.textContent = this.BREAK
     this.sendButtonEl.style.display = 'block'
-    this.aiPreTextEl.innerText = '按ESC退出 | 正在编写...' // 显示提示语
+    this.aiPreTextEl.textContent = '按ESC退出 | 正在编写...' // 显示提示语
🧰 Tools
🪛 ESLint

[error] 151-151: Prefer .textContent over .innerText.

(unicorn/prefer-dom-node-text-content)


[error] 153-153: Prefer .textContent over .innerText.

(unicorn/prefer-dom-node-text-content)


196-197: Improve error handling for parsing errors.

The parsing error is logged to the console but not handled properly. Consider adding user feedback for parsing errors.

          catch (e) {
            console.error('解析错误:', e)
+           // Show parsing error in the result popup
+           this.showParsingError()
          }

Add a new method:

private showParsingError() {
  if (this.resultPopupEl) {
    this.resultPopupEl.innerHTML += '<div class="ql-ai-error">解析错误,请重试</div>';
  }
}

204-207: Replace innerText with textContent.

Continue using textContent instead of innerText for all text-related operations.

-        this.aiPreTextEl.innerText = '' // 清空提示语
+        this.aiPreTextEl.textContent = '' // 清空提示语
         // 隐藏发送按钮
-        this.sendButtonEl.innerText = this.SEND
+        this.sendButtonEl.textContent = this.SEND
🧰 Tools
🪛 ESLint

[error] 204-204: Prefer .textContent over .innerText.

(unicorn/prefer-dom-node-text-content)


[error] 206-206: Prefer .textContent over .innerText.

(unicorn/prefer-dom-node-text-content)


230-230: Use class constants for action names.

The action names are already defined as class constants, so use them directly.

-      const actions = [this.DONE, this.REGENERATE, this.CLOSE]
+      const actions = [this.DONE, this.REGENERATE, this.CLOSE]

This line is actually correct as it uses the class constants, so we're keeping it as is.


272-275: Add loading state during regeneration.

When regenerating a response, the user should see a loading indicator or message.

  private async regenerateResponse() {
    this.actionMenuEl.style.display = 'none'
+   this.resultPopupEl.innerHTML = '<div class="ql-ai-loading">Loading...</div>'
+   this.aiPreTextEl.textContent = this.options.translations?.writingStatus || '按ESC退出 | 正在编写...'
    await this.queryAI(this.inputValue)
  }

277-282: Clean up event listeners on panel close.

The event listeners should be properly cleaned up when the panel is closed to prevent memory leaks.

  private closeAIPanel() {
    this.isBreak = true // 停止查询
+   // Clean up any remaining event listeners
+   if (this.inputEl) {
+     this.inputEl.removeEventListener('keydown', this.handleKeyDown)
+   }
+   if (this.sendButtonEl) {
+     this.sendButtonEl.removeEventListener('click', this.handleSendClick)
+   }
    this.quill.container.removeChild(this.dialogContainerEl)
    this.dialogContainerEl = null
    this.actionMenuEl = null
  }

This requires refactoring the event handlers to be class methods that can be referenced for removal:

private handleKeyDown = async (e: KeyboardEvent) => {
  if (e.key === 'Enter') {
    await this.handleInputSubmit()
  }
}

private handleSendClick = async (e: MouseEvent) => {
  if ((e.target as HTMLElement).textContent === this.BREAK) {
    this.isBreak = true
  } else {
    await this.handleInputSubmit()
  }
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6c03f2e and 2d7b1a7.

📒 Files selected for processing (2)
  • packages/docs/fluent-editor/demos/ai.vue (1 hunks)
  • packages/fluent-editor/src/modules/ai/index.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/docs/fluent-editor/demos/ai.vue
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/fluent-editor/src/modules/ai/index.ts (1)
packages/fluent-editor/src/ui/icons.config.ts (1)
  • AI_ICON (310-314)
🪛 ESLint
packages/fluent-editor/src/modules/ai/index.ts

[error] 60-60: Expected space(s) after "if".

(style/keyword-spacing)


[error] 86-87: More than 1 blank line not allowed.

(style/no-multiple-empty-lines)


[error] 100-100: Trailing spaces not allowed.

(style/no-trailing-spaces)


[error] 100-100: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 101-101: Prefer .textContent over .innerText.

(unicorn/prefer-dom-node-text-content)


[error] 102-102: Prefer .textContent over .innerText.

(unicorn/prefer-dom-node-text-content)


[error] 114-114: Trailing spaces not allowed.

(style/no-trailing-spaces)


[error] 114-114: Trailing spaces not allowed.

(no-trailing-spaces)


[error] 122-122: Prefer .textContent over .innerText.

(unicorn/prefer-dom-node-text-content)


[error] 137-139: Block must not be padded by blank lines.

(style/padded-blocks)


[error] 145-145: Expected space(s) after "if".

(style/keyword-spacing)


[error] 151-151: Prefer .textContent over .innerText.

(unicorn/prefer-dom-node-text-content)


[error] 153-153: Prefer .textContent over .innerText.

(unicorn/prefer-dom-node-text-content)


[error] 204-204: Prefer .textContent over .innerText.

(unicorn/prefer-dom-node-text-content)


[error] 206-206: Prefer .textContent over .innerText.

(unicorn/prefer-dom-node-text-content)

Comment thread packages/docs/fluent-editor/docs/demo/ai.md
@chenxi-20
chenxi-20 force-pushed the feat/ai-tool-20250409 branch from aecc691 to 1ef81d1 Compare July 21, 2025 06:49
kagol
kagol previously approved these changes Jul 23, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ef81d1 and d3e9cbb.

📒 Files selected for processing (1)
  • packages/fluent-editor/src/ui/icons.config.ts (1 hunks)
🪛 ESLint
packages/fluent-editor/src/ui/icons.config.ts

[error] 311-311: Unexpected tab character.

(style/no-tabs)


[error] 312-312: Unexpected tab character.

(style/no-tabs)


[error] 313-313: Unexpected tab character.

(style/no-tabs)


[error] 314-314: Unexpected tab character.

(style/no-tabs)


[error] 315-315: Unexpected tab character.

(style/no-tabs)


[error] 316-316: Unexpected tab character.

(style/no-tabs)


[error] 317-317: Unexpected tab character.

(style/no-tabs)


[error] 318-318: Unexpected tab character.

(style/no-tabs)


[error] 319-319: Unexpected tab character.

(style/no-tabs)


[error] 320-320: Unexpected tab character.

(style/no-tabs)


[error] 321-321: Unexpected tab character.

(style/no-tabs)

🧰 Additional context used
🪛 ESLint
packages/fluent-editor/src/ui/icons.config.ts

[error] 311-311: Unexpected tab character.

(style/no-tabs)


[error] 312-312: Unexpected tab character.

(style/no-tabs)


[error] 313-313: Unexpected tab character.

(style/no-tabs)


[error] 314-314: Unexpected tab character.

(style/no-tabs)


[error] 315-315: Unexpected tab character.

(style/no-tabs)


[error] 316-316: Unexpected tab character.

(style/no-tabs)


[error] 317-317: Unexpected tab character.

(style/no-tabs)


[error] 318-318: Unexpected tab character.

(style/no-tabs)


[error] 319-319: Unexpected tab character.

(style/no-tabs)


[error] 320-320: Unexpected tab character.

(style/no-tabs)


[error] 321-321: Unexpected tab character.

(style/no-tabs)

Comment on lines +310 to +323
export const AI_ICON = `<svg viewBox="0 0 24 24.0023" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24.0022736" fill="none" customFrame="#000000">
<defs>
<linearGradient id="paint_linear_1" x1="2.50000095" x2="12.0000048" y1="0" y2="23.9999962" gradientUnits="userSpaceOnUse">
<stop stop-color="rgb(250,100,1)" offset="0.263296664" stop-opacity="1" />
<stop stop-color="rgb(249.9,102.687,1)" offset="0.349490285" stop-opacity="1" />
<stop stop-color="rgb(247,181,1)" offset="0.494946986" stop-opacity="1" />
<stop stop-color="rgb(11,184,178)" offset="0.690560162" stop-opacity="1" />
<stop stop-color="rgb(1,145,255)" offset="0.858591199" stop-opacity="1" />
<stop stop-color="rgb(182,32,224)" offset="1" stop-opacity="1" />
</linearGradient>
</defs>
<path id="矢量 54" d="M12.9196 5.92509L6.52253 12.3221C6.30963 12.5349 6.14215 12.7787 6.01959 13.0536C5.89703 13.3284 5.8277 13.6161 5.81207 13.9166L5.71637 15.7208C5.63971 17.1667 6.83308 18.3601 8.27938 18.2835L10.0831 18.188C10.3839 18.1721 10.6715 18.1029 10.9464 17.9804C11.2213 17.8579 11.465 17.6903 11.6779 17.4775L18.9079 10.2475C19.3942 10.9692 19.7898 11.7495 20.0944 12.5884C20.2961 13.1437 20.448 13.7009 20.5495 14.2597C20.6428 14.7731 20.6897 15.2605 20.6897 15.7225C20.6897 16.4805 20.4992 17.1292 20.1179 17.6686C19.7619 18.1717 19.2678 18.5486 18.6359 18.7997C17.9894 19.0561 17.2853 19.1496 16.5231 19.0801C15.7233 19.0073 14.9669 18.763 14.2545 18.3471C14.1144 18.2653 13.9557 18.2223 13.7941 18.2223C13.2819 18.2223 12.8663 18.6465 12.8663 19.1698C12.8663 19.2533 12.8771 19.3354 12.8981 19.416C12.9196 19.4967 12.9508 19.5731 12.9918 19.6453C13.0328 19.7176 13.0822 19.7831 13.1403 19.842C13.1793 19.8813 13.2208 19.9168 13.2653 19.9483L13.3336 19.9924C13.8068 20.2686 14.3029 20.4897 14.8229 20.6555C15.3239 20.8158 15.8356 20.9198 16.3586 20.9676C16.8722 21.0144 17.3776 21.0043 17.8747 20.9373C18.3771 20.8694 18.8552 20.7456 19.3078 20.5658C19.7761 20.3802 20.2024 20.1407 20.5871 19.8474C20.9904 19.5403 21.3352 19.1839 21.6223 18.7779C21.9216 18.3542 22.1496 17.8888 22.3054 17.3818C22.4656 16.8605 22.5456 16.3074 22.5456 15.7225C22.5456 15.1442 22.4885 14.5412 22.3743 13.9136C22.2532 13.2479 22.073 12.5866 21.8347 11.9295C21.5764 11.218 21.2575 10.5358 20.8786 9.88306C20.6838 9.54703 20.4743 9.22121 20.2502 8.90559L23.2864 5.86926C24.238 4.91748 24.238 3.37431 23.2864 2.42253L21.5779 0.713837C20.6257 -0.237946 19.0827 -0.237946 18.1306 0.713837L14.4083 4.43634C12.5861 3.74113 10.5411 3.39346 8.27499 3.39346C7.76229 3.39346 7.34724 3.81766 7.34724 4.34097C7.34724 4.86429 7.76229 5.28848 8.27499 5.28848C9.97178 5.28865 11.5196 5.50081 12.9196 5.92509ZM7.91903 14.0282C7.92244 13.9442 7.95418 13.8728 8.01473 13.8142L17.3937 4.43512L19.6228 6.54848L19.5256 6.64574L10.1856 15.9854C10.1271 16.0456 10.0558 16.0774 9.97178 16.0808L8.16756 16.1763C8.07039 16.1815 7.98739 16.1496 7.91903 16.0809C7.85018 16.0122 7.81844 15.9294 7.82381 15.8324L7.91903 14.0282ZM21.7942 4.37717L20.8239 5.34731L18.653 3.1759L19.6228 2.20593C19.6867 2.14209 19.7639 2.11012 19.8542 2.11012C19.8991 2.10941 19.9406 2.1169 19.9792 2.1326L20.0857 2.20593L21.7942 3.91463C21.8581 3.97856 21.8899 4.05559 21.8899 4.14589C21.8913 4.2368 21.8596 4.31389 21.7942 4.37717ZM0.381352 6.34212C-0.126954 6.2448 -0.126954 5.50148 0.381352 5.40408L0.451665 5.39062C0.521978 5.37715 0.591315 5.36131 0.660651 5.34309C0.744636 5.32089 0.827645 5.29515 0.910165 5.26588C1.06007 5.21257 1.20509 5.14813 1.34523 5.07259C1.48537 4.99702 1.61916 4.91119 1.74709 4.81508C1.87453 4.71898 1.99465 4.61366 2.10647 4.49916C2.21877 4.38464 2.3218 4.26222 2.41604 4.1319C2.4468 4.08905 2.47659 4.0455 2.50588 4.00127L2.54495 3.93964L2.57473 3.89056C2.60745 3.83527 2.6387 3.77893 2.668 3.72156C2.74222 3.57832 2.8052 3.43025 2.85745 3.27734C2.9097 3.12442 2.95023 2.96838 2.97952 2.80922L2.98733 2.76753C3.07913 2.26801 3.78226 2.27577 3.86381 2.7771C3.88969 2.93764 3.92729 3.09518 3.97709 3.24979C4.0269 3.40439 4.08793 3.5542 4.1602 3.69925C4.23198 3.84428 4.31499 3.98286 4.40776 4.11496C4.50102 4.24706 4.60307 4.37114 4.71489 4.4872C4.82671 4.60326 4.94634 4.70993 5.07378 4.80724C5.20171 4.90453 5.33599 4.99132 5.47662 5.06758C5.61724 5.14384 5.76324 5.20869 5.91363 5.26215C6.06403 5.31558 6.21784 5.35699 6.37458 5.38635L6.47516 5.4053C6.98396 5.50072 6.98396 6.24556 6.47516 6.34097L6.37458 6.35992C6.21784 6.3893 6.06403 6.43069 5.91363 6.48413C5.76324 6.53758 5.61724 6.60243 5.47662 6.6787C5.33599 6.75494 5.20171 6.84174 5.07378 6.93903C4.94634 7.03632 4.82671 7.14301 4.71489 7.25905C4.60307 7.37511 4.50102 7.49918 4.40776 7.63127C4.37749 7.67439 4.34819 7.71822 4.32036 7.76273C4.26225 7.85454 4.20903 7.94928 4.1602 8.04697C4.08793 8.19202 4.0269 8.34183 3.97709 8.49641C3.92729 8.651 3.88969 8.80856 3.86381 8.96909C3.78226 9.4706 3.07913 9.47827 2.98733 8.97874L2.97952 8.93706C2.95023 8.77789 2.9097 8.62186 2.85745 8.46895C2.8052 8.31604 2.74222 8.16797 2.668 8.02473C2.62893 7.94897 2.58694 7.87502 2.54251 7.80286C2.50247 7.7386 2.46047 7.67578 2.41604 7.6144C2.3218 7.48405 2.21877 7.36163 2.10647 7.24713C1.99465 7.13263 1.87453 7.02731 1.74709 6.9312C1.61916 6.8351 1.48537 6.74925 1.34523 6.67371C1.20509 6.59814 1.06007 6.53371 0.910165 6.48041C0.760262 6.42711 0.607428 6.38551 0.451665 6.35567L0.381352 6.34212ZM2.26418 14.218C2.62259 15.5594 3.22367 16.7893 4.06694 17.9076C4.9063 19.0207 5.92242 19.9394 7.11531 20.6639C8.34188 21.409 9.66807 21.8938 11.0953 22.1182C11.1495 22.1268 11.2028 22.1401 11.2545 22.1583C11.3068 22.1765 11.3566 22.1992 11.4049 22.2265C11.4528 22.2537 11.4982 22.2851 11.5406 22.3206C11.5836 22.3561 11.6227 22.3951 11.6583 22.4377C11.6945 22.4803 11.7262 22.5258 11.754 22.5742C11.7819 22.6226 11.8053 22.6731 11.8243 22.7258C11.8434 22.7784 11.858 22.8324 11.8678 22.8876C11.8771 22.9429 11.882 22.9986 11.882 23.0547C11.882 23.5781 11.4669 24.0023 10.9542 24.0023C10.9068 24.0023 10.86 23.9986 10.8107 23.9909C9.14804 23.7294 7.59969 23.1631 6.16608 22.2925C4.77056 21.4447 3.5806 20.3685 2.59671 19.0638C1.60402 17.7478 0.896493 16.2987 0.474126 14.7167C0.03418 13.0693 -0.0654303 11.39 0.176271 9.67772L0.192873 9.58968L0.214358 9.51338L0.254885 9.41016L0.280276 9.35857C0.306644 9.30896 0.337406 9.26216 0.372074 9.21817C0.406742 9.17416 0.445317 9.13367 0.486821 9.09666C0.528814 9.05966 0.573736 9.02673 0.6211 8.99791L0.734871 8.93944L0.770516 8.92503C0.822274 8.90529 0.875497 8.89041 0.929697 8.88037C0.984385 8.87035 1.03907 8.86533 1.09474 8.86533C1.60695 8.86533 2.02248 9.28952 2.02248 9.81284C2.02248 9.85803 2.01955 9.90323 2.0132 9.94795C1.80812 11.4 1.89211 12.8234 2.26418 14.218Z" fill="url(#paint_linear_1)" fill-rule="evenodd" />
</svg>
`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix indentation formatting to use spaces instead of tabs.

The AI_ICON implementation looks good and properly integrates with the AI feature. However, ESLint is flagging tab characters used for indentation, which violates the project's style guidelines.

Apply this diff to replace tabs with spaces:

-export const AI_ICON = `<svg viewBox="0 0 24 24.0023" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24.0022736" fill="none" customFrame="#000000">
-	<defs>
-		<linearGradient id="paint_linear_1" x1="2.50000095" x2="12.0000048" y1="0" y2="23.9999962" gradientUnits="userSpaceOnUse">
-			<stop stop-color="rgb(250,100,1)" offset="0.263296664" stop-opacity="1" />
-			<stop stop-color="rgb(249.9,102.687,1)" offset="0.349490285" stop-opacity="1" />
-			<stop stop-color="rgb(247,181,1)" offset="0.494946986" stop-opacity="1" />
-			<stop stop-color="rgb(11,184,178)" offset="0.690560162" stop-opacity="1" />
-			<stop stop-color="rgb(1,145,255)" offset="0.858591199" stop-opacity="1" />
-			<stop stop-color="rgb(182,32,224)" offset="1" stop-opacity="1" />
-		</linearGradient>
-	</defs>
-	<path id="矢量 54" d="M12.9196 5.92509L6.52253 12.3221C6.30963 12.5349 6.14215 12.7787 6.01959 13.0536C5.89703 13.3284 5.8277 13.6161 5.81207 13.9166L5.71637 15.7208C5.63971 17.1667 6.83308 18.3601 8.27938 18.2835L10.0831 18.188C10.3839 18.1721 10.6715 18.1029 10.9464 17.9804C11.2213 17.8579 11.465 17.6903 11.6779 17.4775L18.9079 10.2475C19.3942 10.9692 19.7898 11.7495 20.0944 12.5884C20.2961 13.1437 20.448 13.7009 20.5495 14.2597C20.6428 14.7731 20.6897 15.2605 20.6897 15.7225C20.6897 16.4805 20.4992 17.1292 20.1179 17.6686C19.7619 18.1717 19.2678 18.5486 18.6359 18.7997C17.9894 19.0561 17.2853 19.1496 16.5231 19.0801C15.7233 19.0073 14.9669 18.763 14.2545 18.3471C14.1144 18.2653 13.9557 18.2223 13.7941 18.2223C13.2819 18.2223 12.8663 18.6465 12.8663 19.1698C12.8663 19.2533 12.8771 19.3354 12.8981 19.416C12.9196 19.4967 12.9508 19.5731 12.9918 19.6453C13.0328 19.7176 13.0822 19.7831 13.1403 19.842C13.1793 19.8813 13.2208 19.9168 13.2653 19.9483L13.3336 19.9924C13.8068 20.2686 14.3029 20.4897 14.8229 20.6555C15.3239 20.8158 15.8356 20.9198 16.3586 20.9676C16.8722 21.0144 17.3776 21.0043 17.8747 20.9373C18.3771 20.8694 18.8552 20.7456 19.3078 20.5658C19.7761 20.3802 20.2024 20.1407 20.5871 19.8474C20.9904 19.5403 21.3352 19.1839 21.6223 18.7779C21.9216 18.3542 22.1496 17.8888 22.3054 17.3818C22.4656 16.8605 22.5456 16.3074 22.5456 15.7225C22.5456 15.1442 22.4885 14.5412 22.3743 13.9136C22.2532 13.2479 22.073 12.5866 21.8347 11.9295C21.5764 11.218 21.2575 10.5358 20.8786 9.88306C20.6838 9.54703 20.4743 9.22121 20.2502 8.90559L23.2864 5.86926C24.238 4.91748 24.238 3.37431 23.2864 2.42253L21.5779 0.713837C20.6257 -0.237946 19.0827 -0.237946 18.1306 0.713837L14.4083 4.43634C12.5861 3.74113 10.5411 3.39346 8.27499 3.39346C7.76229 3.39346 7.34724 3.81766 7.34724 4.34097C7.34724 4.86429 7.76229 5.28848 8.27499 5.28848C9.97178 5.28865 11.5196 5.50081 12.9196 5.92509ZM7.91903 14.0282C7.92244 13.9442 7.95418 13.8728 8.01473 13.8142L17.3937 4.43512L19.6228 6.54848L19.5256 6.64574L10.1856 15.9854C10.1271 16.0456 10.0558 16.0774 9.97178 16.0808L8.16756 16.1763C8.07039 16.1815 7.98739 16.1496 7.91903 16.0809C7.85018 16.0122 7.81844 15.9294 7.82381 15.8324L7.91903 14.0282ZM21.7942 4.37717L20.8239 5.34731L18.653 3.1759L19.6228 2.20593C19.6867 2.14209 19.7639 2.11012 19.8542 2.11012C19.8991 2.10941 19.9406 2.1169 19.9792 2.1326L20.0857 2.20593L21.7942 3.91463C21.8581 3.97856 21.8899 4.05559 21.8899 4.14589C21.8913 4.2368 21.8596 4.31389 21.7942 4.37717ZM0.381352 6.34212C-0.126954 6.2448 -0.126954 5.50148 0.381352 5.40408L0.451665 5.39062C0.521978 5.37715 0.591315 5.36131 0.660651 5.34309C0.744636 5.32089 0.827645 5.29515 0.910165 5.26588C1.06007 5.21257 1.20509 5.14813 1.34523 5.07259C1.48537 4.99702 1.61916 4.91119 1.74709 4.81508C1.87453 4.71898 1.99465 4.61366 2.10647 4.49916C2.21877 4.38464 2.3218 4.26222 2.41604 4.1319C2.4468 4.08905 2.47659 4.0455 2.50588 4.00127L2.54495 3.93964L2.57473 3.89056C2.60745 3.83527 2.6387 3.77893 2.668 3.72156C2.74222 3.57832 2.8052 3.43025 2.85745 3.27734C2.9097 3.12442 2.95023 2.96838 2.97952 2.80922L2.98733 2.76753C3.07913 2.26801 3.78226 2.27577 3.86381 2.7771C3.88969 2.93764 3.92729 3.09518 3.97709 3.24979C4.0269 3.40439 4.08793 3.5542 4.1602 3.69925C4.23198 3.84428 4.31499 3.98286 4.40776 4.11496C4.50102 4.24706 4.60307 4.37114 4.71489 4.4872C4.82671 4.60326 4.94634 4.70993 5.07378 4.80724C5.20171 4.90453 5.33599 4.99132 5.47662 5.06758C5.61724 5.14384 5.76324 5.20869 5.91363 5.26215C6.06403 5.31558 6.21784 5.35699 6.37458 5.38635L6.47516 5.4053C6.98396 5.50072 6.98396 6.24556 6.47516 6.34097L6.37458 6.35992C6.21784 6.3893 6.06403 6.43069 5.91363 6.48413C5.76324 6.53758 5.61724 6.60243 5.47662 6.6787C5.33599 6.75494 5.20171 6.84174 5.07378 6.93903C4.94634 7.03632 4.82671 7.14301 4.71489 7.25905C4.60307 7.37511 4.50102 7.49918 4.40776 7.63127C4.37749 7.67439 4.34819 7.71822 4.32036 7.76273C4.26225 7.85454 4.20903 7.94928 4.1602 8.04697C4.08793 8.19202 4.0269 8.34183 3.97709 8.49641C3.92729 8.651 3.88969 8.80856 3.86381 8.96909C3.78226 9.4706 3.07913 9.47827 2.98733 8.97874L2.97952 8.93706C2.95023 8.77789 2.9097 8.62186 2.85745 8.46895C2.8052 8.31604 2.74222 8.16797 2.668 8.02473C2.62893 7.94897 2.58694 7.87502 2.54251 7.80286C2.50247 7.7386 2.46047 7.67578 2.41604 7.6144C2.3218 7.48405 2.21877 7.36163 2.10647 7.24713C1.99465 7.13263 1.87453 7.02731 1.74709 6.9312C1.61916 6.8351 1.48537 6.74925 1.34523 6.67371C1.20509 6.59814 1.06007 6.53371 0.910165 6.48041C0.760262 6.42711 0.607428 6.38551 0.451665 6.35567L0.381352 6.34212ZM2.26418 14.218C2.62259 15.5594 3.22367 16.7893 4.06694 17.9076C4.9063 19.0207 5.92242 19.9394 7.11531 20.6639C8.34188 21.409 9.66807 21.8938 11.0953 22.1182C11.1495 22.1268 11.2028 22.1401 11.2545 22.1583C11.3068 22.1765 11.3566 22.1992 11.4049 22.2265C11.4528 22.2537 11.4982 22.2851 11.5406 22.3206C11.5836 22.3561 11.6227 22.3951 11.6583 22.4377C11.6945 22.4803 11.7262 22.5258 11.754 22.5742C11.7819 22.6226 11.8053 22.6731 11.8243 22.7258C11.8434 22.7784 11.858 22.8324 11.8678 22.8876C11.8771 22.9429 11.882 22.9986 11.882 23.0547C11.882 23.5781 11.4669 24.0023 10.9542 24.0023C10.9068 24.0023 10.86 23.9986 10.8107 23.9909C9.14804 23.7294 7.59969 23.1631 6.16608 22.2925C4.77056 21.4447 3.5806 20.3685 2.59671 19.0638C1.60402 17.7478 0.896493 16.2987 0.474126 14.7167C0.03418 13.0693 -0.0654303 11.39 0.176271 9.67772L0.192873 9.58968L0.214358 9.51338L0.254885 9.41016L0.280276 9.35857C0.306644 9.30896 0.337406 9.26216 0.372074 9.21817C0.406742 9.17416 0.445317 9.13367 0.486821 9.09666C0.528814 9.05966 0.573736 9.02673 0.6211 8.99791L0.734871 8.93944L0.770516 8.92503C0.822274 8.90529 0.875497 8.89041 0.929697 8.88037C0.984385 8.87035 1.03907 8.86533 1.09474 8.86533C1.60695 8.86533 2.02248 9.28952 2.02248 9.81284C2.02248 9.85803 2.01955 9.90323 2.0132 9.94795C1.80812 11.4 1.89211 12.8234 2.26418 14.218Z" fill="url(#paint_linear_1)" fill-rule="evenodd" />
-</svg>
-`
+export const AI_ICON = `<svg viewBox="0 0 24 24.0023" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24.0022736" fill="none" customFrame="#000000">
+  <defs>
+    <linearGradient id="paint_linear_1" x1="2.50000095" x2="12.0000048" y1="0" y2="23.9999962" gradientUnits="userSpaceOnUse">
+      <stop stop-color="rgb(250,100,1)" offset="0.263296664" stop-opacity="1" />
+      <stop stop-color="rgb(249.9,102.687,1)" offset="0.349490285" stop-opacity="1" />
+      <stop stop-color="rgb(247,181,1)" offset="0.494946986" stop-opacity="1" />
+      <stop stop-color="rgb(11,184,178)" offset="0.690560162" stop-opacity="1" />
+      <stop stop-color="rgb(1,145,255)" offset="0.858591199" stop-opacity="1" />
+      <stop stop-color="rgb(182,32,224)" offset="1" stop-opacity="1" />
+    </linearGradient>
+  </defs>
+  <path id="矢量 54" d="M12.9196 5.92509L6.52253 12.3221C6.30963 12.5349 6.14215 12.7787 6.01959 13.0536C5.89703 13.3284 5.8277 13.6161 5.81207 13.9166L5.71637 15.7208C5.63971 17.1667 6.83308 18.3601 8.27938 18.2835L10.0831 18.188C10.3839 18.1721 10.6715 18.1029 10.9464 17.9804C11.2213 17.8579 11.465 17.6903 11.6779 17.4775L18.9079 10.2475C19.3942 10.9692 19.7898 11.7495 20.0944 12.5884C20.2961 13.1437 20.448 13.7009 20.5495 14.2597C20.6428 14.7731 20.6897 15.2605 20.6897 15.7225C20.6897 16.4805 20.4992 17.1292 20.1179 17.6686C19.7619 18.1717 19.2678 18.5486 18.6359 18.7997C17.9894 19.0561 17.2853 19.1496 16.5231 19.0801C15.7233 19.0073 14.9669 18.763 14.2545 18.3471C14.1144 18.2653 13.9557 18.2223 13.7941 18.2223C13.2819 18.2223 12.8663 18.6465 12.8663 19.1698C12.8663 19.2533 12.8771 19.3354 12.8981 19.416C12.9196 19.4967 12.9508 19.5731 12.9918 19.6453C13.0328 19.7176 13.0822 19.7831 13.1403 19.842C13.1793 19.8813 13.2208 19.9168 13.2653 19.9483L13.3336 19.9924C13.8068 20.2686 14.3029 20.4897 14.8229 20.6555C15.3239 20.8158 15.8356 20.9198 16.3586 20.9676C16.8722 21.0144 17.3776 21.0043 17.8747 20.9373C18.3771 20.8694 18.8552 20.7456 19.3078 20.5658C19.7761 20.3802 20.2024 20.1407 20.5871 19.8474C20.9904 19.5403 21.3352 19.1839 21.6223 18.7779C21.9216 18.3542 22.1496 17.8888 22.3054 17.3818C22.4656 16.8605 22.5456 16.3074 22.5456 15.7225C22.5456 15.1442 22.4885 14.5412 22.3743 13.9136C22.2532 13.2479 22.073 12.5866 21.8347 11.9295C21.5764 11.218 21.2575 10.5358 20.8786 9.88306C20.6838 9.54703 20.4743 9.22121 20.2502 8.90559L23.2864 5.86926C24.238 4.91748 24.238 3.37431 23.2864 2.42253L21.5779 0.713837C20.6257 -0.237946 19.0827 -0.237946 18.1306 0.713837L14.4083 4.43634C12.5861 3.74113 10.5411 3.39346 8.27499 3.39346C7.76229 3.39346 7.34724 3.81766 7.34724 4.34097C7.34724 4.86429 7.76229 5.28848 8.27499 5.28848C9.97178 5.28865 11.5196 5.50081 12.9196 5.92509ZM7.91903 14.0282C7.92244 13.9442 7.95418 13.8728 8.01473 13.8142L17.3937 4.43512L19.6228 6.54848L19.5256 6.64574L10.1856 15.9854C10.1271 16.0456 10.0558 16.0774 9.97178 16.0808L8.16756 16.1763C8.07039 16.1815 7.98739 16.1496 7.91903 16.0809C7.85018 16.0122 7.81844 15.9294 7.82381 15.8324L7.91903 14.0282ZM21.7942 4.37717L20.8239 5.34731L18.653 3.1759L19.6228 2.20593C19.6867 2.14209 19.7639 2.11012 19.8542 2.11012C19.8991 2.10941 19.9406 2.1169 19.9792 2.1326L20.0857 2.20593L21.7942 3.91463C21.8581 3.97856 21.8899 4.05559 21.8899 4.14589C21.8913 4.2368 21.8596 4.31389 21.7942 4.37717ZM0.381352 6.34212C-0.126954 6.2448 -0.126954 5.50148 0.381352 5.40408L0.451665 5.39062C0.521978 5.37715 0.591315 5.36131 0.660651 5.34309C0.744636 5.32089 0.827645 5.29515 0.910165 5.26588C1.06007 5.21257 1.20509 5.14813 1.34523 5.07259C1.48537 4.99702 1.61916 4.91119 1.74709 4.81508C1.87453 4.71898 1.99465 4.61366 2.10647 4.49916C2.21877 4.38464 2.3218 4.26222 2.41604 4.1319C2.4468 4.08905 2.47659 4.0455 2.50588 4.00127L2.54495 3.93964L2.57473 3.89056C2.60745 3.83527 2.6387 3.77893 2.668 3.72156C2.74222 3.57832 2.8052 3.43025 2.85745 3.27734C2.9097 3.12442 2.95023 2.96838 2.97952 2.80922L2.98733 2.76753C3.07913 2.26801 3.78226 2.27577 3.86381 2.7771C3.88969 2.93764 3.92729 3.09518 3.97709 3.24979C4.0269 3.40439 4.08793 3.5542 4.1602 3.69925C4.23198 3.84428 4.31499 3.98286 4.40776 4.11496C4.50102 4.24706 4.60307 4.37114 4.71489 4.4872C4.82671 4.60326 4.94634 4.70993 5.07378 4.80724C5.20171 4.90453 5.33599 4.99132 5.47662 5.06758C5.61724 5.14384 5.76324 5.20869 5.91363 5.26215C6.06403 5.31558 6.21784 5.35699 6.37458 5.38635L6.47516 5.4053C6.98396 5.50072 6.98396 6.24556 6.47516 6.34097L6.37458 6.35992C6.21784 6.3893 6.06403 6.43069 5.91363 6.48413C5.76324 6.53758 5.61724 6.60243 5.47662 6.6787C5.33599 6.75494 5.20171 6.84174 5.07378 6.93903C4.94634 7.03632 4.82671 7.14301 4.71489 7.25905C4.60307 7.37511 4.50102 7.49918 4.40776 7.63127C4.37749 7.67439 4.34819 7.71822 4.32036 7.76273C4.26225 7.85454 4.20903 7.94928 4.1602 8.04697C4.08793 8.19202 4.0269 8.34183 3.97709 8.49641C3.92729 8.651 3.88969 8.80856 3.86381 8.96909C3.78226 9.4706 3.07913 9.47827 2.98733 8.97874L2.97952 8.93706C2.95023 8.77789 2.9097 8.62186 2.85745 8.46895C2.8052 8.31604 2.74222 8.16797 2.668 8.02473C2.62893 7.94897 2.58694 7.87502 2.54251 7.80286C2.50247 7.7386 2.46047 7.67578 2.41604 7.6144C2.3218 7.48405 2.21877 7.36163 2.10647 7.24713C1.99465 7.13263 1.87453 7.02731 1.74709 6.9312C1.61916 6.8351 1.48537 6.74925 1.34523 6.67371C1.20509 6.59814 1.06007 6.53371 0.910165 6.48041C0.760262 6.42711 0.607428 6.38551 0.451665 6.35567L0.381352 6.34212ZM2.26418 14.218C2.62259 15.5594 3.22367 16.7893 4.06694 17.9076C4.9063 19.0207 5.92242 19.9394 7.11531 20.6639C8.34188 21.409 9.66807 21.8938 11.0953 22.1182C11.1495 22.1268 11.2028 22.1401 11.2545 22.1583C11.3068 22.1765 11.3566 22.1992 11.4049 22.2265C11.4528 22.2537 11.4982 22.2851 11.5406 22.3206C11.5836 22.3561 11.6227 22.3951 11.6583 22.4377C11.6945 22.4803 11.7262 22.5258 11.754 22.5742C11.7819 22.6226 11.8053 22.6731 11.8243 22.7258C11.8434 22.7784 11.858 22.8324 11.8678 22.8876C11.8771 22.9429 11.882 22.9986 11.882 23.0547C11.882 23.5781 11.4669 24.0023 10.9542 24.0023C10.9068 24.0023 10.86 23.9986 10.8107 23.9909C9.14804 23.7294 7.59969 23.1631 6.16608 22.2925C4.77056 21.4447 3.5806 20.3685 2.59671 19.0638C1.60402 17.7478 0.896493 16.2987 0.474126 14.7167C0.03418 13.0693 -0.0654303 11.39 0.176271 9.67772L0.192873 9.58968L0.214358 9.51338L0.254885 9.41016L0.280276 9.35857C0.306644 9.30896 0.337406 9.26216 0.372074 9.21817C0.406742 9.17416 0.445317 9.13367 0.486821 9.09666C0.528814 9.05966 0.573736 9.02673 0.6211 8.99791L0.734871 8.93944L0.770516 8.92503C0.822274 8.90529 0.875497 8.89041 0.929697 8.88037C0.984385 8.87035 1.03907 8.86533 1.09474 8.86533C1.60695 8.86533 2.02248 9.28952 2.02248 9.81284C2.02248 9.85803 2.01955 9.90323 2.0132 9.94795C1.80812 11.4 1.89211 12.8234 2.26418 14.218Z" fill="url(#paint_linear_1)" fill-rule="evenodd" />
+</svg>
+`

The SVG structure is well-formed and the gradient design effectively represents the AI feature with its orange-to-purple transition.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const AI_ICON = `<svg viewBox="0 0 24 24.0023" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24.0022736" fill="none" customFrame="#000000">
<defs>
<linearGradient id="paint_linear_1" x1="2.50000095" x2="12.0000048" y1="0" y2="23.9999962" gradientUnits="userSpaceOnUse">
<stop stop-color="rgb(250,100,1)" offset="0.263296664" stop-opacity="1" />
<stop stop-color="rgb(249.9,102.687,1)" offset="0.349490285" stop-opacity="1" />
<stop stop-color="rgb(247,181,1)" offset="0.494946986" stop-opacity="1" />
<stop stop-color="rgb(11,184,178)" offset="0.690560162" stop-opacity="1" />
<stop stop-color="rgb(1,145,255)" offset="0.858591199" stop-opacity="1" />
<stop stop-color="rgb(182,32,224)" offset="1" stop-opacity="1" />
</linearGradient>
</defs>
<path id="矢量 54" d="M12.9196 5.92509L6.52253 12.3221C6.30963 12.5349 6.14215 12.7787 6.01959 13.0536C5.89703 13.3284 5.8277 13.6161 5.81207 13.9166L5.71637 15.7208C5.63971 17.1667 6.83308 18.3601 8.27938 18.2835L10.0831 18.188C10.3839 18.1721 10.6715 18.1029 10.9464 17.9804C11.2213 17.8579 11.465 17.6903 11.6779 17.4775L18.9079 10.2475C19.3942 10.9692 19.7898 11.7495 20.0944 12.5884C20.2961 13.1437 20.448 13.7009 20.5495 14.2597C20.6428 14.7731 20.6897 15.2605 20.6897 15.7225C20.6897 16.4805 20.4992 17.1292 20.1179 17.6686C19.7619 18.1717 19.2678 18.5486 18.6359 18.7997C17.9894 19.0561 17.2853 19.1496 16.5231 19.0801C15.7233 19.0073 14.9669 18.763 14.2545 18.3471C14.1144 18.2653 13.9557 18.2223 13.7941 18.2223C13.2819 18.2223 12.8663 18.6465 12.8663 19.1698C12.8663 19.2533 12.8771 19.3354 12.8981 19.416C12.9196 19.4967 12.9508 19.5731 12.9918 19.6453C13.0328 19.7176 13.0822 19.7831 13.1403 19.842C13.1793 19.8813 13.2208 19.9168 13.2653 19.9483L13.3336 19.9924C13.8068 20.2686 14.3029 20.4897 14.8229 20.6555C15.3239 20.8158 15.8356 20.9198 16.3586 20.9676C16.8722 21.0144 17.3776 21.0043 17.8747 20.9373C18.3771 20.8694 18.8552 20.7456 19.3078 20.5658C19.7761 20.3802 20.2024 20.1407 20.5871 19.8474C20.9904 19.5403 21.3352 19.1839 21.6223 18.7779C21.9216 18.3542 22.1496 17.8888 22.3054 17.3818C22.4656 16.8605 22.5456 16.3074 22.5456 15.7225C22.5456 15.1442 22.4885 14.5412 22.3743 13.9136C22.2532 13.2479 22.073 12.5866 21.8347 11.9295C21.5764 11.218 21.2575 10.5358 20.8786 9.88306C20.6838 9.54703 20.4743 9.22121 20.2502 8.90559L23.2864 5.86926C24.238 4.91748 24.238 3.37431 23.2864 2.42253L21.5779 0.713837C20.6257 -0.237946 19.0827 -0.237946 18.1306 0.713837L14.4083 4.43634C12.5861 3.74113 10.5411 3.39346 8.27499 3.39346C7.76229 3.39346 7.34724 3.81766 7.34724 4.34097C7.34724 4.86429 7.76229 5.28848 8.27499 5.28848C9.97178 5.28865 11.5196 5.50081 12.9196 5.92509ZM7.91903 14.0282C7.92244 13.9442 7.95418 13.8728 8.01473 13.8142L17.3937 4.43512L19.6228 6.54848L19.5256 6.64574L10.1856 15.9854C10.1271 16.0456 10.0558 16.0774 9.97178 16.0808L8.16756 16.1763C8.07039 16.1815 7.98739 16.1496 7.91903 16.0809C7.85018 16.0122 7.81844 15.9294 7.82381 15.8324L7.91903 14.0282ZM21.7942 4.37717L20.8239 5.34731L18.653 3.1759L19.6228 2.20593C19.6867 2.14209 19.7639 2.11012 19.8542 2.11012C19.8991 2.10941 19.9406 2.1169 19.9792 2.1326L20.0857 2.20593L21.7942 3.91463C21.8581 3.97856 21.8899 4.05559 21.8899 4.14589C21.8913 4.2368 21.8596 4.31389 21.7942 4.37717ZM0.381352 6.34212C-0.126954 6.2448 -0.126954 5.50148 0.381352 5.40408L0.451665 5.39062C0.521978 5.37715 0.591315 5.36131 0.660651 5.34309C0.744636 5.32089 0.827645 5.29515 0.910165 5.26588C1.06007 5.21257 1.20509 5.14813 1.34523 5.07259C1.48537 4.99702 1.61916 4.91119 1.74709 4.81508C1.87453 4.71898 1.99465 4.61366 2.10647 4.49916C2.21877 4.38464 2.3218 4.26222 2.41604 4.1319C2.4468 4.08905 2.47659 4.0455 2.50588 4.00127L2.54495 3.93964L2.57473 3.89056C2.60745 3.83527 2.6387 3.77893 2.668 3.72156C2.74222 3.57832 2.8052 3.43025 2.85745 3.27734C2.9097 3.12442 2.95023 2.96838 2.97952 2.80922L2.98733 2.76753C3.07913 2.26801 3.78226 2.27577 3.86381 2.7771C3.88969 2.93764 3.92729 3.09518 3.97709 3.24979C4.0269 3.40439 4.08793 3.5542 4.1602 3.69925C4.23198 3.84428 4.31499 3.98286 4.40776 4.11496C4.50102 4.24706 4.60307 4.37114 4.71489 4.4872C4.82671 4.60326 4.94634 4.70993 5.07378 4.80724C5.20171 4.90453 5.33599 4.99132 5.47662 5.06758C5.61724 5.14384 5.76324 5.20869 5.91363 5.26215C6.06403 5.31558 6.21784 5.35699 6.37458 5.38635L6.47516 5.4053C6.98396 5.50072 6.98396 6.24556 6.47516 6.34097L6.37458 6.35992C6.21784 6.3893 6.06403 6.43069 5.91363 6.48413C5.76324 6.53758 5.61724 6.60243 5.47662 6.6787C5.33599 6.75494 5.20171 6.84174 5.07378 6.93903C4.94634 7.03632 4.82671 7.14301 4.71489 7.25905C4.60307 7.37511 4.50102 7.49918 4.40776 7.63127C4.37749 7.67439 4.34819 7.71822 4.32036 7.76273C4.26225 7.85454 4.20903 7.94928 4.1602 8.04697C4.08793 8.19202 4.0269 8.34183 3.97709 8.49641C3.92729 8.651 3.88969 8.80856 3.86381 8.96909C3.78226 9.4706 3.07913 9.47827 2.98733 8.97874L2.97952 8.93706C2.95023 8.77789 2.9097 8.62186 2.85745 8.46895C2.8052 8.31604 2.74222 8.16797 2.668 8.02473C2.62893 7.94897 2.58694 7.87502 2.54251 7.80286C2.50247 7.7386 2.46047 7.67578 2.41604 7.6144C2.3218 7.48405 2.21877 7.36163 2.10647 7.24713C1.99465 7.13263 1.87453 7.02731 1.74709 6.9312C1.61916 6.8351 1.48537 6.74925 1.34523 6.67371C1.20509 6.59814 1.06007 6.53371 0.910165 6.48041C0.760262 6.42711 0.607428 6.38551 0.451665 6.35567L0.381352 6.34212ZM2.26418 14.218C2.62259 15.5594 3.22367 16.7893 4.06694 17.9076C4.9063 19.0207 5.92242 19.9394 7.11531 20.6639C8.34188 21.409 9.66807 21.8938 11.0953 22.1182C11.1495 22.1268 11.2028 22.1401 11.2545 22.1583C11.3068 22.1765 11.3566 22.1992 11.4049 22.2265C11.4528 22.2537 11.4982 22.2851 11.5406 22.3206C11.5836 22.3561 11.6227 22.3951 11.6583 22.4377C11.6945 22.4803 11.7262 22.5258 11.754 22.5742C11.7819 22.6226 11.8053 22.6731 11.8243 22.7258C11.8434 22.7784 11.858 22.8324 11.8678 22.8876C11.8771 22.9429 11.882 22.9986 11.882 23.0547C11.882 23.5781 11.4669 24.0023 10.9542 24.0023C10.9068 24.0023 10.86 23.9986 10.8107 23.9909C9.14804 23.7294 7.59969 23.1631 6.16608 22.2925C4.77056 21.4447 3.5806 20.3685 2.59671 19.0638C1.60402 17.7478 0.896493 16.2987 0.474126 14.7167C0.03418 13.0693 -0.0654303 11.39 0.176271 9.67772L0.192873 9.58968L0.214358 9.51338L0.254885 9.41016L0.280276 9.35857C0.306644 9.30896 0.337406 9.26216 0.372074 9.21817C0.406742 9.17416 0.445317 9.13367 0.486821 9.09666C0.528814 9.05966 0.573736 9.02673 0.6211 8.99791L0.734871 8.93944L0.770516 8.92503C0.822274 8.90529 0.875497 8.89041 0.929697 8.88037C0.984385 8.87035 1.03907 8.86533 1.09474 8.86533C1.60695 8.86533 2.02248 9.28952 2.02248 9.81284C2.02248 9.85803 2.01955 9.90323 2.0132 9.94795C1.80812 11.4 1.89211 12.8234 2.26418 14.218Z" fill="url(#paint_linear_1)" fill-rule="evenodd" />
</svg>
`
export const AI_ICON = `<svg viewBox="0 0 24 24.0023" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24.0022736" fill="none" customFrame="#000000">
<defs>
<linearGradient id="paint_linear_1" x1="2.50000095" x2="12.0000048" y1="0" y2="23.9999962" gradientUnits="userSpaceOnUse">
<stop stop-color="rgb(250,100,1)" offset="0.263296664" stop-opacity="1" />
<stop stop-color="rgb(249.9,102.687,1)" offset="0.349490285" stop-opacity="1" />
<stop stop-color="rgb(247,181,1)" offset="0.494946986" stop-opacity="1" />
<stop stop-color="rgb(11,184,178)" offset="0.690560162" stop-opacity="1" />
<stop stop-color="rgb(1,145,255)" offset="0.858591199" stop-opacity="1" />
<stop stop-color="rgb(182,32,224)" offset="1" stop-opacity="1" />
</linearGradient>
</defs>
<path id="矢量 54" d="M12.9196 5.92509L6.52253 12.3221C6.30963 12.5349 6.14215 12.7787 6.01959 13.0536C5.89703 13.3284 5.8277 13.6161 5.81207 13.9166L5.71637 15.7208C5.63971 17.1667 6.83308 18.3601 8.27938 18.2835L10.0831 18.188C10.3839 18.1721 10.6715 18.1029 10.9464 17.9804C11.2213 17.8579 11.465 17.6903 11.6779 17.4775L18.9079 10.2475C19.3942 10.9692 19.7898 11.7495 20.0944 12.5884C20.2961 13.1437 20.448 13.7009 20.5495 14.2597C20.6428 14.7731 20.6897 15.2605 20.6897 15.7225C20.6897 16.4805 20.4992 17.1292 20.1179 17.6686C19.7619 18.1717 19.2678 18.5486 18.6359 18.7997C17.9894 19.0561 17.2853 19.1496 16.5231 19.0801C15.7233 19.0073 14.9669 18.763 14.2545 18.3471C14.1144 18.2653 13.9557 18.2223 13.7941 18.2223C13.2819 18.2223 12.8663 18.6465 12.8663 19.1698C12.8663 19.2533 12.8771 19.3354 12.8981 19.416C12.9196 19.4967 12.9508 19.5731 12.9918 19.6453C13.0328 19.7176 13.0822 19.7831 13.1403 19.842C13.1793 19.8813 13.2208 19.9168 13.2653 19.9483L13.3336 19.9924C13.8068 20.2686 14.3029 20.4897 14.8229 20.6555C15.3239 20.8158 15.8356 20.9198 16.3586 20.9676C16.8722 21.0144 17.3776 21.0043 17.8747 20.9373C18.3771 20.8694 18.8552 20.7456 19.3078 20.5658C19.7761 20.3802 20.2024 20.1407 20.5871 19.8474C20.9904 19.5403 21.3352 19.1839 21.6223 18.7779C21.9216 18.3542 22.1496 17.8888 22.3054 17.3818C22.4656 16.8605 22.5456 16.3074 22.5456 15.7225C22.5456 15.1442 22.4885 14.5412 22.3743 13.9136C22.2532 13.2479 22.073 12.5866 21.8347 11.9295C21.5764 11.218 21.2575 10.5358 20.8786 9.88306C20.6838 9.54703 20.4743 9.22121 20.2502 8.90559L23.2864 5.86926C24.238 4.91748 24.238 3.37431 23.2864 2.42253L21.5779 0.713837C20.6257 -0.237946 19.0827 -0.237946 18.1306 0.713837L14.4083 4.43634C12.5861 3.74113 10.5411 3.39346 8.27499 3.39346C7.76229 3.39346 7.34724 3.81766 7.34724 4.34097C7.34724 4.86429 7.76229 5.28848 8.27499 5.28848C9.97178 5.28865 11.5196 5.50081 12.9196 5.92509ZM7.91903 14.0282C7.92244 13.9442 7.95418 13.8728 8.01473 13.8142L17.3937 4.43512L19.6228 6.54848L19.5256 6.64574L10.1856 15.9854C10.1271 16.0456 10.0558 16.0774 9.97178 16.0808L8.16756 16.1763C8.07039 16.1815 7.98739 16.1496 7.91903 16.0809C7.85018 16.0122 7.81844 15.9294 7.82381 15.8324L7.91903 14.0282ZM21.7942 4.37717L20.8239 5.34731L18.653 3.1759L19.6228 2.20593C19.6867 2.14209 19.7639 2.11012 19.8542 2.11012C19.8991 2.10941 19.9406 2.1169 19.9792 2.1326L20.0857 2.20593L21.7942 3.91463C21.8581 3.97856 21.8899 4.05559 21.8899 4.14589C21.8913 4.2368 21.8596 4.31389 21.7942 4.37717ZM0.381352 6.34212C-0.126954 6.2448 -0.126954 5.50148 0.381352 5.40408L0.451665 5.39062C0.521978 5.37715 0.591315 5.36131 0.660651 5.34309C0.744636 5.32089 0.827645 5.29515 0.910165 5.26588C1.06007 5.21257 1.20509 5.14813 1.34523 5.07259C1.48537 4.99702 1.61916 4.91119 1.74709 4.81508C1.87453 4.71898 1.99465 4.61366 2.10647 4.49916C2.21877 4.38464 2.3218 4.26222 2.41604 4.1319C2.4468 4.08905 2.47659 4.0455 2.50588 4.00127L2.54495 3.93964L2.57473 3.89056C2.60745 3.83527 2.6387 3.77893 2.668 3.72156C2.74222 3.57832 2.8052 3.43025 2.85745 3.27734C2.9097 3.12442 2.95023 2.96838 2.97952 2.80922L2.98733 2.76753C3.07913 2.26801 3.78226 2.27577 3.86381 2.7771C3.88969 2.93764 3.92729 3.09518 3.97709 3.24979C4.0269 3.40439 4.08793 3.5542 4.1602 3.69925C4.23198 3.84428 4.31499 3.98286 4.40776 4.11496C4.50102 4.24706 4.60307 4.37114 4.71489 4.4872C4.82671 4.60326 4.94634 4.70993 5.07378 4.80724C5.20171 4.90453 5.33599 4.99132 5.47662 5.06758C5.61724 5.14384 5.76324 5.20869 5.91363 5.26215C6.06403 5.31558 6.21784 5.35699 6.37458 5.38635L6.47516 5.4053C6.98396 5.50072 6.98396 6.24556 6.47516 6.34097L6.37458 6.35992C6.21784 6.3893 6.06403 6.43069 5.91363 6.48413C5.76324 6.53758 5.61724 6.60243 5.47662 6.6787C5.33599 6.75494 5.20171 6.84174 5.07378 6.93903C4.94634 7.03632 4.82671 7.14301 4.71489 7.25905C4.60307 7.37511 4.50102 7.49918 4.40776 7.63127C4.37749 7.67439 4.34819 7.71822 4.32036 7.76273C4.26225 7.85454 4.20903 7.94928 4.1602 8.04697C4.08793 8.19202 4.0269 8.34183 3.97709 8.49641C3.92729 8.651 3.88969 8.80856 3.86381 8.96909C3.78226 9.4706 3.07913 9.47827 2.98733 8.97874L2.97952 8.93706C2.95023 8.77789 2.9097 8.62186 2.85745 8.46895C2.8052 8.31604 2.74222 8.16797 2.668 8.02473C2.62893 7.94897 2.58694 7.87502 2.54251 7.80286C2.50247 7.7386 2.46047 7.67578 2.41604 7.6144C2.3218 7.48405 2.21877 7.36163 2.10647 7.24713C1.99465 7.13263 1.87453 7.02731 1.74709 6.9312C1.61916 6.8351 1.48537 6.74925 1.34523 6.67371C1.20509 6.59814 1.06007 6.53371 0.910165 6.48041C0.760262 6.42711 0.607428 6.38551 0.451665 6.35567L0.381352 6.34212ZM2.26418 14.218C2.62259 15.5594 3.22367 16.7893 4.06694 17.9076C4.9063 19.0207 5.92242 19.9394 7.11531 20.6639C8.34188 21.409 9.66807 21.8938 11.0953 22.1182C11.1495 22.1268 11.2028 22.1401 11.2545 22.1583C11.3068 22.1765 11.3566 22.1992 11.4049 22.2265C11.4528 22.2537 11.4982 22.2851 11.5406 22.3206C11.5836 22.3561 11.6227 22.3951 11.6583 22.4377C11.6945 22.4803 11.7262 22.5258 11.754 22.5742C11.7819 22.6226 11.8053 22.6731 11.8243 22.7258C11.8434 22.7784 11.858 22.8324 11.8678 22.8876C11.8771 22.9429 11.882 22.9986 11.882 23.0547C11.882 23.5781 11.4669 24.0023 10.9542 24.0023C10.9068 24.0023 10.86 23.9986 10.8107 23.9909C9.14804 23.7294 7.59969 23.1631 6.16608 22.2925C4.77056 21.4447 3.5806 20.3685 2.59671 19.0638C1.60402 17.7478 0.896493 16.2987 0.474126 14.7167C0.03418 13.0693 -0.0654303 11.39 0.176271 9.67772L0.192873 9.58968L0.214358 9.51338L0.254885 9.41016L0.280276 9.35857C0.306644 9.30896 0.337406 9.26216 0.372074 9.21817C0.406742 9.17416 0.445317 9.13367 0.486821 9.09666C0.528814 9.05966 0.573736 9.02673 0.6211 8.99791L0.734871 8.93944L0.770516 8.92503C0.822274 8.90529 0.875497 8.89041 0.929697 8.88037C0.984385 8.87035 1.03907 8.86533 1.09474 8.86533C1.60695 8.86533 2.02248 9.28952 2.02248 9.81284C2.02248 9.85803 2.01955 9.90323 2.0132 9.94795C1.80812 11.4 1.89211 12.8234 2.26418 14.218Z" fill="url(#paint_linear_1)" fill-rule="evenodd" />
</svg>
`
🧰 Tools
🪛 ESLint

[error] 311-311: Unexpected tab character.

(style/no-tabs)


[error] 312-312: Unexpected tab character.

(style/no-tabs)


[error] 313-313: Unexpected tab character.

(style/no-tabs)


[error] 314-314: Unexpected tab character.

(style/no-tabs)


[error] 315-315: Unexpected tab character.

(style/no-tabs)


[error] 316-316: Unexpected tab character.

(style/no-tabs)


[error] 317-317: Unexpected tab character.

(style/no-tabs)


[error] 318-318: Unexpected tab character.

(style/no-tabs)


[error] 319-319: Unexpected tab character.

(style/no-tabs)


[error] 320-320: Unexpected tab character.

(style/no-tabs)


[error] 321-321: Unexpected tab character.

(style/no-tabs)

🤖 Prompt for AI Agents
In packages/fluent-editor/src/ui/icons.config.ts around lines 310 to 323, the
indentation uses tab characters which violates the project's ESLint style
guidelines. Replace all tab characters with spaces for indentation throughout
the AI_ICON SVG string to comply with the style rules and avoid linting errors.

@kagol
kagol merged commit 1f8f90f into opentiny:main Jul 24, 2025
1 of 2 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Jul 29, 2025
13 tasks
@kagol

kagol commented Oct 20, 2025

Copy link
Copy Markdown
Member

@all-contributors please add @chenxi-20 for code.

@allcontributors

Copy link
Copy Markdown
Contributor

@kagol

I've put up a pull request to add @chenxi-20! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants