feat: add openAI plugin

This commit is contained in:
Lucas.Xu 2023-01-07 11:24:14 +08:00
parent 34d4ea3e54
commit 494e31993b
11 changed files with 145 additions and 20 deletions

View File

@ -1,3 +1,12 @@
## 0.0.9
* Support customize the text color and text background color.
* Fix some bugs.
## 0.0.8
* Fix the toolbar display issue.
* Fix the copy/paste issue on Windows.
* Minor Updates.
## 0.0.7
* Refactor theme customizer, and support dark mode.
* Support export and import markdown.

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor_plugins/appflowy_editor_plugins.dart';
import 'package:example/plugin/text_robot.dart';
import 'package:flutter/material.dart';
class SimpleEditor extends StatelessWidget {
@ -64,6 +65,8 @@ class SimpleEditor extends StatelessWidget {
codeBlockMenuItem,
// Emoji
emojiMenuItem,
// Text Robot
textRobotMenuItem,
],
);
} else {

View File

@ -0,0 +1,68 @@
import 'package:http/http.dart' as http;
import 'dart:async';
import 'dart:convert';
Future<void> getGPT3Completion(
String apiKey,
String prompt,
String suffix,
int maxTokens,
double temperature,
Function(String) onData, // callback function to handle streaming data
) async {
final data = {
'prompt': prompt,
'suffix': suffix,
'max_tokens': maxTokens,
'temperature': temperature,
'stream': true, // set stream parameter to true
};
final headers = {
'Authorization': apiKey,
'Content-Type': 'application/json',
};
final request = http.Request(
'POST',
Uri.parse('https://api.openai.com/v1/engines/text-davinci-003/completions'),
);
request.body = json.encode(data);
request.headers.addAll(headers);
final httpResponse = await request.send();
if (httpResponse.statusCode == 200) {
await for (final chunk in httpResponse.stream) {
var result = utf8.decode(chunk).split('text": "');
var text = '';
if (result.length > 1) {
result = result[1].split('",');
if (result.isNotEmpty) {
text = result.first;
}
}
final processedText = text
.replaceAll('\\n', '\n')
.replaceAll('\\r', '\r')
.replaceAll('\\t', '\t')
.replaceAll('\\b', '\b')
.replaceAll('\\f', '\f')
.replaceAll('\\v', '\v')
.replaceAll('\\\'', '\'')
.replaceAll('"', '"')
.replaceAll('\\0', '0')
.replaceAll('\\1', '1')
.replaceAll('\\2', '2')
.replaceAll('\\3', '3')
.replaceAll('\\4', '4')
.replaceAll('\\5', '5')
.replaceAll('\\6', '6')
.replaceAll('\\7', '7')
.replaceAll('\\8', '8')
.replaceAll('\\9', '9');
onData(processedText);
}
}
}

View File

@ -1,4 +1,57 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:example/plugin/AI/getgpt3completions.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
SelectionMenuItem textRobotMenuItem = SelectionMenuItem(
name: () => 'Open AI',
icon: (editorState, onSelected) => Icon(
Icons.rocket,
size: 18.0,
color: onSelected
? editorState.editorStyle.selectionMenuItemSelectedIconColor
: editorState.editorStyle.selectionMenuItemIconColor,
),
keywords: ['open ai', 'gpt3', 'ai'],
handler: ((editorState, menuService, context) async {
showDialog(
context: context,
builder: (context) {
final controller = TextEditingController(text: '');
return AlertDialog(
content: RawKeyboardListener(
focusNode: FocusNode(),
child: TextField(
autofocus: true,
controller: controller,
maxLines: null,
decoration: const InputDecoration(
border: OutlineInputBorder(),
hintText: 'Please input something...',
),
),
onKey: (key) {
if (key is! RawKeyDownEvent) return;
if (key.logicalKey == LogicalKeyboardKey.enter) {
Navigator.of(context).pop();
// fetch the result and insert it
// Please fill in your own API key
getGPT3Completion('', controller.text, '', 200, .3,
(result) async {
await editorState.insertTextAtCurrentSelection(
result,
);
});
} else if (key.logicalKey == LogicalKeyboardKey.escape) {
Navigator.of(context).pop();
}
},
),
);
},
);
}),
);
enum TextRobotInputType {
character,
@ -19,31 +72,24 @@ class TextRobot {
TextRobotInputType inputType = TextRobotInputType.character,
}) async {
final lines = text.split('\n');
var path = 0;
for (final line in lines) {
switch (inputType) {
case TextRobotInputType.character:
var index = 0;
final iterator = line.runes.iterator;
while (iterator.moveNext()) {
// await editorState.insertText(
// index,
// iterator.currentAsString,
// path: [path],
// );
await editorState.insertTextAtCurrentSelection(
iterator.currentAsString,
);
index += iterator.currentSize;
await Future.delayed(delay);
}
path += 1;
break;
default:
}
// insert new line
await editorState.insertNewLine(editorState, [path]);
if (lines.length > 1) {
await editorState.insertNewLine(editorState);
}
}
}
}

View File

@ -47,6 +47,7 @@ dependencies:
flutter_math_fork: ^0.6.3+1
appflowy_editor_plugins:
path: ../../../packages/appflowy_editor_plugins
http: ^0.13.5
dev_dependencies:
flutter_test:

View File

@ -110,14 +110,15 @@ extension TextCommands on EditorState {
}
Future<void> insertNewLine(
EditorState editorState,
Path path,
) async {
EditorState editorState, {
Path? path,
}) async {
return futureCommand(() async {
final p = path ?? getSelection(null).start.path.next;
final transaction = editorState.transaction;
transaction.insertNode(path, TextNode.empty());
transaction.insertNode(p, TextNode.empty());
transaction.afterSelection = Selection.single(
path: path,
path: p,
startOffset: 0,
);
apply(transaction);

View File

@ -1,5 +1,4 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/commands/text/text_commands.dart';
import 'package:appflowy_editor/src/render/rich_text/built_in_text_widget.dart';
import 'package:appflowy_editor/src/extensions/text_style_extension.dart';

View File

@ -96,7 +96,7 @@ class _SelectionMenuWidgetState extends State<SelectionMenuWidget> {
final items = widget.items
.where(
(item) => item.keywords.any((keyword) {
final value = keyword.contains(newKeyword);
final value = keyword.contains(newKeyword.toLowerCase());
if (value) {
maxKeywordLength = max(maxKeywordLength, keyword.length);
}

View File

@ -1,5 +1,4 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/commands/text/text_commands.dart';
import 'package:appflowy_editor/src/extensions/url_launcher_extension.dart';
import 'package:appflowy_editor/src/flutter/overlay.dart';
import 'package:appflowy_editor/src/infra/clipboard.dart';

View File

@ -1,5 +1,4 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/commands/text/text_commands.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

View File

@ -1,6 +1,6 @@
name: appflowy_editor
description: A highly customizable rich-text editor for Flutter
version: 0.0.7
version: 0.0.9
homepage: https://github.com/AppFlowy-IO/AppFlowy
platforms: