mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: add openAI plugin
This commit is contained in:
parent
34d4ea3e54
commit
494e31993b
@ -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.
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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';
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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';
|
||||
|
@ -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';
|
||||
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user