|
@@ -1,5 +1,5 @@
|
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
|
-import 'package:example/plugin/AI/getgpt3completions.dart';
|
|
|
|
|
|
+import 'package:example/plugin/AI/gpt3.dart';
|
|
import 'package:example/plugin/AI/text_robot.dart';
|
|
import 'package:example/plugin/AI/text_robot.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/material.dart';
|
|
|
|
|
|
@@ -14,35 +14,96 @@ SelectionMenuItem continueToWriteMenuItem = SelectionMenuItem(
|
|
),
|
|
),
|
|
keywords: ['continue to write'],
|
|
keywords: ['continue to write'],
|
|
handler: ((editorState, menuService, context) async {
|
|
handler: ((editorState, menuService, context) async {
|
|
- // get the current text
|
|
|
|
|
|
+ // Two cases
|
|
|
|
+ // 1. if there is content in the text node where the cursor is located,
|
|
|
|
+ // then we use the current text content as data.
|
|
|
|
+ // 2. if there is no content in the text node where the cursor is located,
|
|
|
|
+ // then we use the previous / next text node's content as data.
|
|
|
|
+
|
|
final selection =
|
|
final selection =
|
|
editorState.service.selectionService.currentSelection.value;
|
|
editorState.service.selectionService.currentSelection.value;
|
|
- final textNodes = editorState.service.selectionService.currentSelectedNodes;
|
|
|
|
- if (selection == null || !selection.isCollapsed || textNodes.length != 1) {
|
|
|
|
|
|
+ if (selection == null || !selection.isCollapsed) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ final textNodes = editorState.service.selectionService.currentSelectedNodes
|
|
|
|
+ .whereType<TextNode>();
|
|
|
|
+ if (textNodes.isEmpty) {
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
- final textNode = textNodes.first as TextNode;
|
|
|
|
- final prompt = textNode.delta.slice(0, selection.startIndex).toPlainText();
|
|
|
|
- final suffix = textNode.delta
|
|
|
|
- .slice(
|
|
|
|
- selection.endIndex,
|
|
|
|
- textNode.toPlainText().length,
|
|
|
|
- )
|
|
|
|
- .toPlainText();
|
|
|
|
|
|
+
|
|
final textRobot = TextRobot(editorState: editorState);
|
|
final textRobot = TextRobot(editorState: editorState);
|
|
- getGPT3Completion(
|
|
|
|
- apiKey,
|
|
|
|
|
|
+ const gpt3 = GPT3APIClient(apiKey: apiKey);
|
|
|
|
+ final textNode = textNodes.first;
|
|
|
|
+
|
|
|
|
+ var prompt = '';
|
|
|
|
+ var suffix = '';
|
|
|
|
+
|
|
|
|
+ void continueToWriteInSingleLine() {
|
|
|
|
+ prompt = textNode.delta.slice(0, selection.startIndex).toPlainText();
|
|
|
|
+ suffix = textNode.delta
|
|
|
|
+ .slice(
|
|
|
|
+ selection.endIndex,
|
|
|
|
+ textNode.toPlainText().length,
|
|
|
|
+ )
|
|
|
|
+ .toPlainText();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void continueToWriteInMulitLines() {
|
|
|
|
+ final parent = textNode.parent;
|
|
|
|
+ if (parent != null) {
|
|
|
|
+ for (final node in parent.children) {
|
|
|
|
+ if (node is! TextNode || node.toPlainText().isEmpty) continue;
|
|
|
|
+ if (node.path < textNode.path) {
|
|
|
|
+ prompt += '${node.toPlainText()}\n';
|
|
|
|
+ } else if (node.path > textNode.path) {
|
|
|
|
+ suffix += '${node.toPlainText()}\n';
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (textNodes.first.toPlainText().isNotEmpty) {
|
|
|
|
+ continueToWriteInSingleLine();
|
|
|
|
+ } else {
|
|
|
|
+ continueToWriteInMulitLines();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (prompt.isEmpty && suffix.isEmpty) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ late final BuildContext diglogContext;
|
|
|
|
+
|
|
|
|
+ showDialog(
|
|
|
|
+ context: context,
|
|
|
|
+ builder: (context) {
|
|
|
|
+ diglogContext = context;
|
|
|
|
+ return AlertDialog(
|
|
|
|
+ content: Column(
|
|
|
|
+ mainAxisSize: MainAxisSize.min,
|
|
|
|
+ children: const [
|
|
|
|
+ CircularProgressIndicator(),
|
|
|
|
+ SizedBox(height: 10),
|
|
|
|
+ Text('Loading'),
|
|
|
|
+ ],
|
|
|
|
+ ),
|
|
|
|
+ );
|
|
|
|
+ },
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ gpt3.getGPT3Completion(
|
|
prompt,
|
|
prompt,
|
|
suffix,
|
|
suffix,
|
|
- (result) async {
|
|
|
|
- if (result == '\\n') {
|
|
|
|
- await editorState.insertNewLineAtCurrentSelection();
|
|
|
|
- } else {
|
|
|
|
- await textRobot.insertText(
|
|
|
|
- result,
|
|
|
|
- inputType: TextRobotInputType.word,
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
|
|
+ onResult: (result) async {
|
|
|
|
+ Navigator.of(diglogContext).pop(true);
|
|
|
|
+ await textRobot.insertText(
|
|
|
|
+ result,
|
|
|
|
+ inputType: TextRobotInputType.word,
|
|
|
|
+ );
|
|
|
|
+ },
|
|
|
|
+ onError: () async {
|
|
|
|
+ Navigator.of(diglogContext).pop(true);
|
|
},
|
|
},
|
|
);
|
|
);
|
|
}),
|
|
}),
|