-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #16 from tidbcloud/playground
feat(ai-widget): implement ai-widget extension
- Loading branch information
Showing
19 changed files
with
7,255 additions
and
4,577 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
# @tidbcloud/codemirror-extension-ai-widget | ||
|
||
// TODO: video | ||
|
||
## Features | ||
|
||
// TODO | ||
|
||
## Installation | ||
|
||
```shell | ||
npm install @tidbcloud/codemirror-extension-ai-widget | ||
``` | ||
|
||
You need to install its peer dependencies as well: | ||
|
||
```shell | ||
npm install @codemirror/view @codemirror/state @codemirror/merge | ||
``` | ||
|
||
## Usage | ||
|
||
```ts | ||
import { EditorView } from '@codemirror/view' | ||
import { EditorState } from '@codemirror/state' | ||
import { aiWidget } from '@tidbcloud/codemirror-extension-ai-widget' | ||
|
||
const editorView = new EditorView({ | ||
state: EditorState.create({ | ||
doc, | ||
extensions: [ | ||
aiWidget({ | ||
chat: async () => { | ||
// replace it by yourself chat to AI api in production | ||
await delay(2000) | ||
return { status: 'success', message: 'select * from test;' } | ||
}, | ||
cancelChat: () => {}, | ||
getDbList: () => { | ||
return ['test1', 'test2'] | ||
} | ||
}) | ||
] | ||
}) | ||
}) | ||
``` | ||
|
||
## API | ||
|
||
```ts | ||
type ChatReq = { | ||
prompt: string | ||
refContent: string | ||
extra?: {} | ||
} | ||
|
||
type ChatRes = { | ||
status: 'success' | 'error' | ||
message: string | ||
extra?: {} | ||
} | ||
|
||
type AiWidgetOptions = { | ||
/* hotkey to trigger ai widget, default is 'Mod-i' */ | ||
hotkey?: string | ||
|
||
/* prompt input configuration */ | ||
/* default: 'AI results may be incorrect' */ | ||
promptInputTipsNormal?: string | ||
/* default: 'Fetching results...' */ | ||
promptInputTipsRequesting?: string | ||
/* default: 'Ask AI to write anything...' */ | ||
promptInputPlaceholderNormal?: string | ||
/* default: 'Error occurred. Please try to regenerate or input another instruction.' */ | ||
promptInputPlaceholderError?: string | ||
|
||
/* placeholder configuration */ | ||
/* default: 'Press 'Command + I' or <span>click here</span> to use AI' */ | ||
placeholderEmptyDocElement?: string | ||
/* default: 'Press 'Command + I' to use AI' */ | ||
placeholderNormalElement?: string | ||
|
||
/* tooltip hint configuration */ | ||
/* default: 'Press <code><b>Command</b> + <b>I</b></code> to rewrite SQL by AI' */ | ||
tooltipHintElement?: string | ||
|
||
/* chat with AI */ | ||
chat: (view: EditorView, chatId: string, req: ChatReq) => Promise<ChatRes> | ||
cancelChat: (chatId: string) => void | ||
|
||
/* event call, for telemetry if you need */ | ||
onEvent?: (view: EditorView, type: EventType, payload?: {}) => void | ||
|
||
/* for auto add `use {db};` statement if miss it */ | ||
getDbList: () => string[] | ||
} | ||
|
||
function aiWidget(options: AiWidgetOptions): Extension | ||
|
||
/* check whether prompt input widget is active */ | ||
function isPromptInputActive(state: EditorState): boolean | ||
/* check whether diff view is active */ | ||
function isUnifiedMergeViewActive(state: EditorState): boolean | ||
/* trigger the prompt input widget to show */ | ||
function activePromptInput( | ||
view: EditorView, | ||
defPrompt?: string, | ||
immediate?: boolean, | ||
/* where is this method called from */ | ||
/* the value maybe: 'hotkey', 'placeholder', 'fix_sql_button', ... */ | ||
/* default value is 'hotkey' */ | ||
source?: string, | ||
pos?: Pos | ||
): void | ||
``` | ||
|
||
## Try it | ||
|
||
Try it in [playground](https://tisqleditor-playground.netlify.app/) or [example](https://tisqleditor-playground.netlify.app/?example=ai-widget) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
{ | ||
"name": "@tidbcloud/codemirror-extension-ai-widget", | ||
"version": "0.0.1", | ||
"description": "tisqleditor extensions", | ||
"type": "module", | ||
"main": "dist/index.js", | ||
"module": "dist/index.js", | ||
"types": "dist/index.d.ts", | ||
"files": [ | ||
"dist/*.js", | ||
"dist/*.ts", | ||
"package.json", | ||
"README.md" | ||
], | ||
"scripts": { | ||
"tsc:watch": "tsc --watch", | ||
"rollup:watch": "rollup -c --watch", | ||
"dev": "concurrently --kill-others \"pnpm tsc:watch\" \"pnpm rollup:watch\"", | ||
"build": "tsc && rollup -c" | ||
}, | ||
"keywords": [], | ||
"author": "", | ||
"license": "MIT", | ||
"devDependencies": { | ||
"@codemirror/merge": "^6.6.3", | ||
"@codemirror/state": "^6.4.1", | ||
"@codemirror/view": "^6.26.3", | ||
"@rollup/plugin-typescript": "^11.1.6", | ||
"rollup": "^4.18.0", | ||
"tslib": "^2.6.3", | ||
"typescript": "^5.4.5" | ||
}, | ||
"peerDependencies": { | ||
"@codemirror/merge": "^6.6.3", | ||
"@codemirror/state": "^6.4.1", | ||
"@codemirror/view": "^6.26.3" | ||
}, | ||
"dependencies": { | ||
"@tidbcloud/codemirror-extension-cur-sql": "workspace:^" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import typescript from '@rollup/plugin-typescript' | ||
|
||
export default { | ||
input: './src/index.ts', | ||
output: { | ||
dir: './dist', | ||
format: 'es' | ||
}, | ||
plugins: [typescript()] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { Decoration, EditorView, ViewPlugin } from '@codemirror/view' | ||
|
||
import { hideTooltip } from './tooltip-hint' | ||
|
||
// `Escape` hotkey can't be registered by `keymap.of([])` method | ||
export const escapeListener = ViewPlugin.fromClass( | ||
class { | ||
escapeListener = (e: KeyboardEvent) => { | ||
if (e.key === 'Escape') { | ||
// dismiss tooltip | ||
hideTooltip(this.view) | ||
|
||
// dismiss prompt input widget | ||
document.dispatchEvent( | ||
new CustomEvent('dismiss_ai_widget', { | ||
detail: { source: 'esc_key' } | ||
}) | ||
) | ||
} | ||
} | ||
|
||
constructor(public view: EditorView) { | ||
document.addEventListener('keydown', this.escapeListener) | ||
} | ||
|
||
update() {} | ||
|
||
destroy() { | ||
document.removeEventListener('keydown', this.escapeListener) | ||
} | ||
}, | ||
{ | ||
decorations: () => Decoration.none | ||
} | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
export const ICON_PROMPT = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"> | ||
<path d="M10.3672 4.26563L10.518 5.00031L10.3672 4.26563ZM11.5432 3.60523L11.0747 3.01958L11.0747 3.01958L11.5432 3.60523ZM10.875 4.08749L11.2162 4.75538L10.875 4.08749ZM13.9272 2.12539L13.341 2.59328L13.9272 2.12539ZM13.1335 2.333L13.602 2.91865L13.602 2.91865L13.1335 2.333ZM13.6663 2L13.6655 1.25L13.6663 2ZM2.21799 5.39848L1.54973 5.05799L2.21799 5.39848ZM3.09202 4.52444L2.75153 3.85619L3.09202 4.52444ZM3.09202 14.0885L2.75153 14.7567L3.09202 14.0885ZM2.21799 13.2144L1.54973 13.5549L2.21799 13.2144ZM12.908 14.0885L13.2485 14.7567L12.908 14.0885ZM13.782 13.2144L14.4503 13.5549L13.782 13.2144ZM6.08333 8.66665C6.08333 8.25243 5.74755 7.91665 5.33333 7.91665C4.91912 7.91665 4.58333 8.25243 4.58333 8.66665H6.08333ZM4.58333 9.99998C4.58333 10.4142 4.91912 10.75 5.33333 10.75C5.74755 10.75 6.08333 10.4142 6.08333 9.99998H4.58333ZM10.75 8.66665C10.75 8.25243 10.4142 7.91665 10 7.91665C9.58579 7.91665 9.25 8.25243 9.25 8.66665H10.75ZM9.25 9.99998C9.25 10.4142 9.58579 10.75 10 10.75C10.4142 10.75 10.75 10.4142 10.75 9.99998H9.25ZM10.8 13.5565H5.2V15.0565H10.8V13.5565ZM2.75 11.1065V7.50646H1.25V11.1065H2.75ZM13.25 2.74946V11.1065H14.75V2.74946H13.25ZM5.2 5.05646H9.54417V3.55646H5.2V5.05646ZM12.0117 4.19089L13.602 2.91865L12.665 1.74735L11.0747 3.01958L12.0117 4.19089ZM9.54417 5.05646C9.93015 5.05646 10.2272 5.06 10.518 5.00031L10.2164 3.53094C10.1093 3.55292 9.99025 3.55646 9.54417 3.55646V5.05646ZM11.0747 3.01958C10.7263 3.29826 10.6312 3.36986 10.5338 3.41961L11.2162 4.75538C11.4806 4.62031 11.7103 4.432 12.0117 4.19089L11.0747 3.01958ZM10.518 5.00031C10.7607 4.9505 10.9956 4.86811 11.2162 4.75538L10.5338 3.41961C10.4335 3.47084 10.3267 3.50829 10.2164 3.53094L10.518 5.00031ZM14.75 2.74946C14.75 2.5868 14.7507 2.41285 14.7378 2.27058C14.7262 2.14214 14.6945 1.88449 14.5133 1.6575L13.341 2.59328C13.2834 2.52111 13.2589 2.45449 13.2494 2.42186C13.2409 2.3926 13.2417 2.38167 13.244 2.40627C13.2461 2.42931 13.2479 2.46643 13.249 2.52746C13.25 2.58792 13.25 2.65878 13.25 2.74946H14.75ZM13.602 2.91865C13.6728 2.862 13.7282 2.81775 13.776 2.78077C13.8243 2.74344 13.8545 2.72172 13.8738 2.70896C13.8944 2.69534 13.8864 2.70286 13.8582 2.71446C13.8268 2.72739 13.7595 2.7499 13.6671 2.75L13.6655 1.25C13.3751 1.25031 13.1541 1.38658 13.0465 1.4577C12.9274 1.53648 12.792 1.64573 12.665 1.74735L13.602 2.91865ZM14.5133 1.6575C14.3075 1.39967 13.9954 1.24964 13.6655 1.25L13.6671 2.75C13.5402 2.75014 13.4202 2.69243 13.341 2.59328L14.5133 1.6575ZM2.75 7.50646C2.75 6.93403 2.75058 6.54982 2.77476 6.25394C2.79822 5.96681 2.8401 5.82953 2.88624 5.73897L1.54973 5.05799C1.37789 5.39525 1.31078 5.7519 1.27974 6.13179C1.24942 6.50292 1.25 6.95878 1.25 7.50646H2.75ZM5.2 3.55646C4.65232 3.55646 4.19646 3.55587 3.82533 3.5862C3.44545 3.61723 3.08879 3.68435 2.75153 3.85619L3.43251 5.1927C3.52307 5.14656 3.66035 5.10467 3.94748 5.08122C4.24336 5.05704 4.62757 5.05646 5.2 5.05646V3.55646ZM2.88624 5.73897C3.00608 5.50377 3.19731 5.31254 3.43251 5.1927L2.75153 3.85619C2.23408 4.11984 1.81338 4.54054 1.54973 5.05799L2.88624 5.73897ZM5.2 13.5565C4.62757 13.5565 4.24336 13.5559 3.94748 13.5317C3.66035 13.5082 3.52307 13.4664 3.43251 13.4202L2.75153 14.7567C3.08879 14.9286 3.44545 14.9957 3.82533 15.0267C4.19646 15.057 4.65232 15.0565 5.2 15.0565V13.5565ZM1.25 11.1065C1.25 11.6541 1.24942 12.11 1.27974 12.4811C1.31078 12.861 1.37789 13.2177 1.54973 13.5549L2.88624 12.8739C2.8401 12.7834 2.79822 12.6461 2.77476 12.359C2.75058 12.0631 2.75 11.6789 2.75 11.1065H1.25ZM3.43251 13.4202C3.19731 13.3004 3.00608 13.1091 2.88624 12.8739L1.54973 13.5549C1.81338 14.0724 2.23408 14.4931 2.75153 14.7567L3.43251 13.4202ZM10.8 15.0565C11.3477 15.0565 11.8035 15.057 12.1747 15.0267C12.5546 14.9957 12.9112 14.9286 13.2485 14.7567L12.5675 13.4202C12.4769 13.4664 12.3396 13.5082 12.0525 13.5317C11.7566 13.5559 11.3724 13.5565 10.8 13.5565V15.0565ZM13.25 11.1065C13.25 11.6789 13.2494 12.0631 13.2252 12.359C13.2018 12.6461 13.1599 12.7834 13.1138 12.8739L14.4503 13.5549C14.6221 13.2177 14.6892 12.861 14.7203 12.4811C14.7506 12.11 14.75 11.6541 14.75 11.1065H13.25ZM13.2485 14.7567C13.7659 14.4931 14.1866 14.0724 14.4503 13.5549L13.1138 12.8739C12.9939 13.1091 12.8027 13.3004 12.5675 13.4202L13.2485 14.7567ZM4.58333 8.66665V9.99998H6.08333V8.66665H4.58333ZM9.25 8.66665V9.99998H10.75V8.66665H9.25Z" fill="#54C0F5"/></svg>` | ||
|
||
export const ICON_SEND = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"> | ||
<g clip-path="url(#clip0_3123_4854)"> | ||
<path d="M6.99952 9.00012L13.9995 2.00012M7.08457 9.21883L8.83665 13.7242C8.991 14.1211 9.06817 14.3195 9.17937 14.3774C9.27577 14.4277 9.39061 14.4277 9.48706 14.3776C9.59833 14.3198 9.67574 14.1215 9.83056 13.7247L14.2241 2.46625C14.3639 2.10813 14.4337 1.92907 14.3955 1.81465C14.3623 1.71528 14.2844 1.6373 14.185 1.60411C14.0706 1.56588 13.8915 1.63576 13.5334 1.77552L2.27489 6.16908C1.87817 6.32389 1.67981 6.4013 1.62201 6.51257C1.5719 6.60903 1.57196 6.72386 1.62219 6.82026C1.68013 6.93146 1.87858 7.00864 2.27547 7.16299L6.78081 8.91506C6.86137 8.94639 6.90166 8.96206 6.93558 8.98625C6.96564 9.0077 6.99193 9.03399 7.01338 9.06406C7.03758 9.09798 7.05324 9.13826 7.08457 9.21883Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> | ||
</g> | ||
<defs> | ||
<clipPath id="clip0_3123_4854"> | ||
<rect width="16" height="16" fill="none"/> | ||
</clipPath> | ||
</defs> | ||
</svg>` | ||
|
||
export const ICON_LOADING = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"> | ||
<g clip-path="url(#clip0_3123_3257)"> | ||
<path d="M8.00016 1.33337V4.00004M8.00016 12V14.6667M4.00016 8.00004H1.3335M14.6668 8.00004H12.0002M12.7191 12.719L10.8335 10.8334M12.7191 3.33334L10.8335 5.21895M3.28121 12.719L5.16683 10.8334M3.28121 3.33334L5.16683 5.21895" stroke="#54C0F5" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> | ||
</g> | ||
<defs> | ||
<clipPath id="clip0_3123_3257"> | ||
<rect width="16" height="16" fill="white"/> | ||
</clipPath> | ||
</defs> | ||
</svg>` | ||
|
||
export const ICON_ERROR = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none"> | ||
<g clip-path="url(#clip0_3123_5585)"> | ||
<path d="M8.00016 5.33325V7.99992M8.00016 10.6666H8.00683M14.6668 7.99992C14.6668 11.6818 11.6821 14.6666 8.00016 14.6666C4.31826 14.6666 1.3335 11.6818 1.3335 7.99992C1.3335 4.31802 4.31826 1.33325 8.00016 1.33325C11.6821 1.33325 14.6668 4.31802 14.6668 7.99992Z" stroke="#E65C5C" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> | ||
</g> | ||
<defs> | ||
<clipPath id="clip0_3123_5585"> | ||
<rect width="16" height="16" fill="white"/> | ||
</clipPath> | ||
</defs> | ||
</svg>` | ||
|
||
export const ICON_STOP = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
<path d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | ||
<path d="M8 9.6C8 9.03995 8 8.75992 8.10899 8.54601C8.20487 8.35785 8.35785 8.20487 8.54601 8.10899C8.75992 8 9.03995 8 9.6 8H14.4C14.9601 8 15.2401 8 15.454 8.10899C15.6422 8.20487 15.7951 8.35785 15.891 8.54601C16 8.75992 16 9.03995 16 9.6V14.4C16 14.9601 16 15.2401 15.891 15.454C15.7951 15.6422 15.6422 15.7951 15.454 15.891C15.2401 16 14.9601 16 14.4 16H9.6C9.03995 16 8.75992 16 8.54601 15.891C8.35785 15.7951 8.20487 15.6422 8.10899 15.454C8 15.2401 8 14.9601 8 14.4V9.6Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | ||
</svg>` | ||
|
||
export const ICON_CLOSE = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
<path d="M18 6L6 18M6 6L18 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | ||
</svg>` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { Extension } from '@codemirror/state' | ||
|
||
import { AiWidgetOptions } from './type' | ||
import { escapeListener } from './esc-listener' | ||
import { aiPlaceholder } from './placeholder' | ||
import { aiCursorTooltip } from './tooltip-hint' | ||
import { aiPromptInput } from './prompt-input' | ||
|
||
export function aiWidget(options: AiWidgetOptions): Extension { | ||
return [ | ||
escapeListener, | ||
aiPlaceholder(), | ||
aiCursorTooltip(options.hotkey), | ||
aiPromptInput(options) | ||
] | ||
} | ||
|
||
export * from './prompt-input' | ||
export * from './type' |
Oops, something went wrong.