-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
20 changed files
with
958 additions
and
5 deletions.
There are no files selected for viewing
70 changes: 70 additions & 0 deletions
70
packages/libro-ai-native/src/ai-widget/ai-widget-command-contribution.ts
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,70 @@ | ||
import { LibroCellView } from '@difizen/libro-jupyter'; | ||
import type { CommandRegistry } from '@difizen/mana-app'; | ||
import { CommandContribution, inject, singleton } from '@difizen/mana-app'; | ||
import { l10n } from '@difizen/mana-l10n'; | ||
|
||
import { LibroAINativeService } from '../ai-native-service.js'; | ||
|
||
import { AIWidgetCommandRegister } from './ai-widget-command-register.js'; | ||
import { AIWidgetCommands } from './command.js'; | ||
|
||
@singleton({ contrib: CommandContribution }) | ||
export class AIWidgetCommandContribution implements CommandContribution { | ||
@inject(AIWidgetCommandRegister) | ||
protected readonly widgetCommandRegister: AIWidgetCommandRegister; | ||
|
||
@inject(LibroAINativeService) libroAINativeService: LibroAINativeService; | ||
|
||
registerCommands(command: CommandRegistry) { | ||
this.widgetCommandRegister.registerAIWidgetCommand( | ||
command, | ||
AIWidgetCommands['Optimize'], | ||
{ | ||
execute: async (code, cell, libro) => { | ||
if (!cell || !(cell instanceof LibroCellView)) { | ||
return; | ||
} | ||
const libroAINativeForCellView = | ||
await this.libroAINativeService.getOrCreateLibroAINativeForCellView( | ||
cell.id, | ||
cell, | ||
); | ||
libroAINativeForCellView.showAI = true; | ||
|
||
const inCode = | ||
l10n.getLang() === 'en-US' | ||
? `Could you please optimize this piece of code?:${code}` | ||
: `帮忙优化一下这段代码:${code}`; | ||
libroAINativeForCellView.chatStream({ | ||
content: inCode, | ||
}); | ||
}, | ||
}, | ||
); | ||
this.widgetCommandRegister.registerAIWidgetCommand( | ||
command, | ||
AIWidgetCommands['Explain'], | ||
{ | ||
execute: async (code, cell) => { | ||
if (!cell || !(cell instanceof LibroCellView)) { | ||
return; | ||
} | ||
const libroAINativeForCellView = | ||
await this.libroAINativeService.getOrCreateLibroAINativeForCellView( | ||
cell.id, | ||
cell, | ||
); | ||
libroAINativeForCellView.showAI = true; | ||
|
||
const inCode = | ||
l10n.getLang() === 'en-US' | ||
? `Could you please optimize this piece of code?:${code}` | ||
: `帮忙解释一下这段代码:${code}`; | ||
libroAINativeForCellView.chatStream({ | ||
content: inCode, | ||
}); | ||
}, | ||
}, | ||
); | ||
} | ||
} |
137 changes: 137 additions & 0 deletions
137
packages/libro-ai-native/src/ai-widget/ai-widget-command-register.ts
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,137 @@ | ||
import { LibroService } from '@difizen/libro-jupyter'; | ||
import type { CellView, NotebookView } from '@difizen/libro-jupyter'; | ||
import type { | ||
Command, | ||
CommandHandler, | ||
CommandRegistry, | ||
CommandHandlerWithContext, | ||
} from '@difizen/mana-app'; | ||
import { inject, singleton } from '@difizen/mana-app'; | ||
|
||
export interface GeneralAIWidgetCommandHandler extends CommandHandler { | ||
execute: ( | ||
code?: string, | ||
cell?: CellView, | ||
libro?: NotebookView, | ||
position?: string, | ||
options?: any, | ||
) => void; | ||
isVisible?: ( | ||
code?: string, | ||
cell?: CellView, | ||
libro?: NotebookView, | ||
position?: string, | ||
options?: any, | ||
) => boolean; | ||
isEnabled?: ( | ||
code?: string, | ||
cell?: CellView, | ||
libro?: NotebookView, | ||
position?: string, | ||
options?: any, | ||
) => boolean; | ||
isActive?: ( | ||
code?: string, | ||
cell?: CellView, | ||
libro?: NotebookView, | ||
position?: string, | ||
options?: any, | ||
) => boolean; | ||
} | ||
|
||
@singleton() | ||
export class AIWidgetCommandRegister { | ||
@inject(LibroService) protected readonly libroService: LibroService; | ||
|
||
toGeneralCommandArgs = ( | ||
ctx: AIWidgetCommandRegister, | ||
code?: string, | ||
cell?: CellView, | ||
libro?: NotebookView, | ||
position?: string, | ||
options?: any, | ||
): [ | ||
string | undefined, | ||
CellView | undefined, | ||
NotebookView | undefined, | ||
string | undefined, | ||
any, | ||
] => { | ||
const libroView = libro || ctx.libroService.active; | ||
const cellView = cell || libroView?.model?.active; | ||
return [code, cellView, libroView, position, options]; | ||
}; | ||
|
||
registerAIWidgetCommand( | ||
registry: CommandRegistry, | ||
command: Command, | ||
handler: GeneralAIWidgetCommandHandler, | ||
) { | ||
const commandHandler: CommandHandlerWithContext<AIWidgetCommandRegister> = { | ||
execute: ( | ||
ctx, | ||
code?: string, | ||
cell?: CellView, | ||
libro?: NotebookView, | ||
position?: string, | ||
options?: any, | ||
) => { | ||
return handler.execute( | ||
...this.toGeneralCommandArgs(ctx, code, cell, libro, position, options), | ||
); | ||
}, | ||
}; | ||
if (handler.isEnabled) { | ||
commandHandler.isEnabled = ( | ||
ctx, | ||
code?: string, | ||
cell?: CellView, | ||
libro?: NotebookView, | ||
position?: string, | ||
options?: any, | ||
) => { | ||
if (!handler.isEnabled) { | ||
return true; | ||
} | ||
return handler.isEnabled( | ||
...this.toGeneralCommandArgs(ctx, code, cell, libro, position, options), | ||
); | ||
}; | ||
} | ||
if (handler.isVisible) { | ||
commandHandler.isVisible = ( | ||
ctx, | ||
code?: string, | ||
cell?: CellView, | ||
libro?: NotebookView, | ||
position?: string, | ||
options?: any, | ||
) => { | ||
if (!handler.isVisible) { | ||
return true; | ||
} | ||
return handler.isVisible( | ||
...this.toGeneralCommandArgs(ctx, code, cell, libro, position, options), | ||
); | ||
}; | ||
} | ||
if (handler.isActive) { | ||
commandHandler.isActive = ( | ||
ctx, | ||
code?: string, | ||
cell?: CellView, | ||
libro?: NotebookView, | ||
position?: string, | ||
options?: any, | ||
) => { | ||
if (!handler.isActive) { | ||
return false; | ||
} | ||
return handler.isActive( | ||
...this.toGeneralCommandArgs(ctx, code, cell, libro, position, options), | ||
); | ||
}; | ||
} | ||
registry.registerCommandWithContext(command, this, commandHandler); | ||
} | ||
} |
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,111 @@ | ||
import type { | ||
WidgetActionItem, | ||
WidgetActionHandlerItem, | ||
} from '@difizen/libro-code-editor'; | ||
import { EditorWidgetContribution } from '@difizen/libro-code-editor'; | ||
import { CommandRegistry } from '@difizen/mana-app'; | ||
import { inject, singleton } from '@difizen/mana-app'; | ||
|
||
import { AIWidgetCommands } from './command.js'; | ||
|
||
@singleton({ contrib: [EditorWidgetContribution] }) | ||
export class AIWidget implements EditorWidgetContribution { | ||
private actionsMap: Map<string, WidgetActionItem> = new Map(); | ||
private handlerMap: Map<string, WidgetActionHandlerItem> = new Map(); | ||
|
||
canHandle = () => { | ||
return 100; | ||
}; | ||
|
||
@inject(CommandRegistry) protected readonly commandRegistry: CommandRegistry; | ||
|
||
constructor() { | ||
this.registerEditorInlineChat( | ||
{ | ||
id: 'ai-comments', | ||
name: 'Comments', | ||
title: 'add comments(readable stream example)', | ||
renderType: 'button', | ||
codeAction: { | ||
isPreferred: true, | ||
kind: 'refactor.rewrite', | ||
}, | ||
}, | ||
{ | ||
execute: async (code: string) => { | ||
this.commandRegistry.executeCommand(AIWidgetCommands['Explain'].id, code); | ||
}, | ||
}, | ||
); | ||
this.registerEditorInlineChat( | ||
{ | ||
id: 'ai-optimize', | ||
name: 'Optimize', | ||
renderType: 'button', | ||
codeAction: { | ||
isPreferred: true, | ||
kind: 'refactor.rewrite', | ||
}, | ||
}, | ||
{ | ||
execute: async (code: string) => { | ||
this.commandRegistry.executeCommand(AIWidgetCommands['Optimize'].id, code); | ||
}, | ||
}, | ||
); | ||
} | ||
public getAction(id: string): WidgetActionItem | undefined { | ||
return this.actionsMap.get(id); | ||
} | ||
|
||
public registerEditorInlineChat( | ||
operational: WidgetActionItem, | ||
handler: WidgetActionHandlerItem, | ||
) { | ||
const isCollect = this.collectActions(operational); | ||
|
||
if (isCollect) { | ||
this.handlerMap.set(operational.id, handler); | ||
} | ||
} | ||
|
||
private collectActions(operational: WidgetActionItem): boolean { | ||
const { id } = operational; | ||
|
||
if (this.actionsMap.has(id)) { | ||
return false; | ||
} | ||
|
||
if (!operational.renderType) { | ||
operational.renderType = 'button'; | ||
} | ||
|
||
if (!operational.order) { | ||
operational.order = 0; | ||
} | ||
|
||
this.actionsMap.set(id, operational); | ||
|
||
return true; | ||
} | ||
|
||
// show & hide | ||
show: () => void; | ||
hide: () => void; | ||
|
||
public getActionButtons(): WidgetActionItem[] { | ||
const actions = Array.from(this.handlerMap.keys()) | ||
.filter((id) => { | ||
const actions_find = this.actionsMap.get(id); | ||
return actions_find && actions_find.renderType === 'button'; | ||
}) | ||
.map((id) => this.actionsMap.get(id)) | ||
.sort((a, b) => (a?.order ?? 0) - (b?.order ?? 0)); | ||
|
||
return actions as WidgetActionItem[]; | ||
} | ||
|
||
getActionHandler(actionId: string) { | ||
return this.handlerMap.get(actionId); | ||
} | ||
} |
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,12 @@ | ||
import type { Command } from '@difizen/mana-app'; | ||
|
||
export const AIWidgetCommands: Record<string, Command & { keybind?: string }> = { | ||
Explain: { | ||
id: 'ai-widget:explain', | ||
label: 'EXPLAIN', | ||
}, | ||
Optimize: { | ||
id: 'ai-widget:optimize', | ||
label: 'Optimize', | ||
}, | ||
}; |
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,3 @@ | ||
export * from './ai-widget-command-contribution.js'; | ||
export * from './ai-widget-command-register.js'; | ||
export * from './command.js'; |
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 { CodeEditorModule } from '@difizen/libro-code-editor'; | ||
import { ManaModule } from '@difizen/mana-app'; | ||
|
||
import { AIWidgetCommandContribution } from './ai-widget-command-contribution.js'; | ||
import { AIWidgetCommandRegister } from './ai-widget-command-register.js'; | ||
import { AIWidget } from './ai-widget.js'; | ||
|
||
export const LibroAIWidgetModule = ManaModule.create() | ||
.register(AIWidget, AIWidgetCommandRegister, AIWidgetCommandContribution) | ||
.dependOn(CodeEditorModule); |
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
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
Oops, something went wrong.