From b19f9b414e7bf9b6ab1265579f53dc4cec99e43e Mon Sep 17 00:00:00 2001 From: xiaoshuyui <528490652@qq.com> Date: Sun, 19 May 2024 10:21:44 +0800 Subject: [PATCH 1/2] feat: ui update --- assets/llm.json | 4 +- assets/llm/compose.png | 3 + assets/llm/template.png | 3 + lib/layout/components/animated_sidebar.dart | 16 +- lib/layout/layout.dart | 4 +- ...t_screen.dart => ai_assistant_screen.dart} | 15 +- lib/llm/editor/compose_screen.dart | 60 +++++ .../desktop_editor.dart} | 156 +---------- lib/llm/editor/editor.dart | 152 +++++++++++ .../models/datasource.dart | 0 lib/llm/langchain/components/chat_ui.dart | 6 +- lib/llm/langchain/components/tools_item.dart | 11 +- .../langchain/components/tools_screen.dart | 249 +++++++++++++----- lib/llm/langchain/models/tool_model.dart | 19 +- lib/llm/template_editor/template_editor.dart | 6 +- pubspec.yaml | 2 +- 16 files changed, 454 insertions(+), 252 deletions(-) create mode 100644 assets/llm/compose.png create mode 100644 assets/llm/template.png rename lib/llm/{langchain/langchain_chat_screen.dart => ai_assistant_screen.dart} (75%) create mode 100644 lib/llm/editor/compose_screen.dart rename lib/llm/{template_editor/components/editor.dart => editor/desktop_editor.dart} (63%) create mode 100644 lib/llm/editor/editor.dart rename lib/llm/{template_editor => editor}/models/datasource.dart (100%) diff --git a/assets/llm.json b/assets/llm.json index 5dd4f00..e525a2b 100644 --- a/assets/llm.json +++ b/assets/llm.json @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a16272c3288983a9f2545ef13bf5c0182e81f44d72dedba11f0b3a633fffc7da -size 689 +oid sha256:bf62ca0a175b9c8804e37cf81ceb6e95d0c5dbbb2c33788a3d64f6bf9c84c400 +size 1075 diff --git a/assets/llm/compose.png b/assets/llm/compose.png new file mode 100644 index 0000000..bd4b873 --- /dev/null +++ b/assets/llm/compose.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f6b772b464b6dede45a55d9e171ee36883221fdee0f30025ef4be34b91bf7046 +size 5910 diff --git a/assets/llm/template.png b/assets/llm/template.png new file mode 100644 index 0000000..8bb84c8 --- /dev/null +++ b/assets/llm/template.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:431de0028bde67e540a6779b3493a0a6a154031de3dc44bf2fb56815d6aa99b5 +size 6666 diff --git a/lib/layout/components/animated_sidebar.dart b/lib/layout/components/animated_sidebar.dart index 709fbfa..afdbd67 100644 --- a/lib/layout/components/animated_sidebar.dart +++ b/lib/layout/components/animated_sidebar.dart @@ -80,22 +80,22 @@ class _AnimatedSidebarState extends ConsumerState children: [ SidebarItemWidget( item: SidebarItem( - icon: "assets/icons/dashboard.png", + icon: "assets/icons/AI.png", index: 0, + name: "AI Assistant", + inActiveIcon: "assets/icons/iAI.png")), + SidebarItemWidget( + item: SidebarItem( + icon: "assets/icons/dashboard.png", + index: 1, name: "Dashboard", inActiveIcon: "assets/icons/idashboard.png")), SidebarItemWidget( item: SidebarItem( icon: "assets/icons/toolbox.png", - index: 1, + index: 2, name: "Toolbox", inActiveIcon: "assets/icons/itoolbox.png")), - SidebarItemWidget( - item: SidebarItem( - icon: "assets/icons/AI.png", - index: 2, - name: "Langchain", - inActiveIcon: "assets/icons/iAI.png")) ], ), ), diff --git a/lib/layout/layout.dart b/lib/layout/layout.dart index fa8bf25..ad93936 100644 --- a/lib/layout/layout.dart +++ b/lib/layout/layout.dart @@ -1,7 +1,7 @@ import 'package:all_in_one/layout/components/animated_sidebar.dart'; import 'package:all_in_one/layout/notifiers/page_notifier.dart'; import 'package:all_in_one/layout/styles.dart'; -import 'package:all_in_one/llm/langchain/langchain_chat_screen.dart'; +import 'package:all_in_one/llm/ai_assistant_screen.dart'; import 'package:all_in_one/styles/app_style.dart'; import 'package:all_in_one/tool_entry/entry_screen.dart'; import 'package:all_in_one/workboard/workboard_screen.dart'; @@ -47,9 +47,9 @@ class _LayoutState extends ConsumerState with TickerProviderStateMixin { controller: ref.read(pageProvider.notifier).pageController, physics: const NeverScrollableScrollPhysics(), children: const [ + AIAssistantScreen(), WorkboardScreen(), EntryScreen(), - LangchainChatScreen() ], ), ), diff --git a/lib/llm/langchain/langchain_chat_screen.dart b/lib/llm/ai_assistant_screen.dart similarity index 75% rename from lib/llm/langchain/langchain_chat_screen.dart rename to lib/llm/ai_assistant_screen.dart index 787badd..d710ad3 100644 --- a/lib/llm/langchain/langchain_chat_screen.dart +++ b/lib/llm/ai_assistant_screen.dart @@ -1,4 +1,5 @@ import 'package:all_in_one/isar/llm_history.dart'; +import 'package:all_in_one/llm/editor/compose_screen.dart'; import 'package:all_in_one/llm/global/components/history_list.dart'; import 'package:all_in_one/llm/langchain/components/buttons.dart'; import 'package:all_in_one/llm/langchain/components/chat_ui.dart'; @@ -8,10 +9,10 @@ import 'package:all_in_one/llm/template_editor/template_editor.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'components/seq_chain_flow.dart'; +import 'langchain/components/seq_chain_flow.dart'; -class LangchainChatScreen extends ConsumerWidget { - const LangchainChatScreen({super.key}); +class AIAssistantScreen extends ConsumerWidget { + const AIAssistantScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { @@ -19,7 +20,13 @@ class LangchainChatScreen extends ConsumerWidget { body: PageView( physics: const NeverScrollableScrollPhysics(), controller: ref.read(toolProvider.notifier).controller, - children: const [ToolsScreen(), _UI(), FlowScreen(), TemplateEditor()], + children: const [ + ToolsScreen(), + _UI(), + FlowScreen(), + TemplateEditor(), + ComposeScreen() + ], ), ); } diff --git a/lib/llm/editor/compose_screen.dart b/lib/llm/editor/compose_screen.dart new file mode 100644 index 0000000..e4ea0dc --- /dev/null +++ b/lib/llm/editor/compose_screen.dart @@ -0,0 +1,60 @@ +// ignore: unused_import +import 'dart:convert'; + +import 'package:all_in_one/llm/editor/models/datasource.dart'; +import 'package:all_in_one/llm/langchain/notifiers/tool_notifier.dart'; +import 'package:appflowy_editor/appflowy_editor.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_expandable_fab/flutter_expandable_fab.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import 'editor.dart'; + +class ComposeScreen extends ConsumerStatefulWidget { + const ComposeScreen({super.key}); + + @override + ConsumerState createState() => _ComposeScreenState(); +} + +class _ComposeScreenState extends ConsumerState { + late EditorState _editorState; + late WidgetBuilder _widgetBuilder; + + @override + void initState() { + super.initState(); + + _widgetBuilder = (context) => Editor( + // jsonString: Future(() => _jsonString), + datasource: Datasource(type: DatasourceType.json, content: ""), + onEditorStateChange: (editorState) { + _editorState = editorState; + }, + showTemplateFeatures: false, + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + floatingActionButtonLocation: ExpandableFab.location, + floatingActionButton: ExpandableFab( + distance: 50, + type: ExpandableFabType.side, + children: [ + FloatingActionButton.small( + tooltip: "back", + heroTag: "", + onPressed: () { + ref.read(toolProvider.notifier).jumpTo(0); + }, + child: const Icon(Icons.chevron_left), + ), + ], + ), + extendBodyBehindAppBar: PlatformExtension.isDesktopOrWeb, + body: SafeArea(child: _widgetBuilder(context)), + ); + } +} diff --git a/lib/llm/template_editor/components/editor.dart b/lib/llm/editor/desktop_editor.dart similarity index 63% rename from lib/llm/template_editor/components/editor.dart rename to lib/llm/editor/desktop_editor.dart index aa5f3f8..6054d61 100644 --- a/lib/llm/template_editor/components/editor.dart +++ b/lib/llm/editor/desktop_editor.dart @@ -2,167 +2,25 @@ import 'package:all_in_one/llm/plugins/chat_db/sql_toolbar_item.dart'; import 'package:all_in_one/llm/plugins/chat_file/file_toolbar_item.dart'; import 'package:all_in_one/llm/plugins/chat_file/group.dart'; import 'package:all_in_one/llm/template_editor/components/show_ai_menu.dart'; -import 'package:all_in_one/llm/template_editor/models/datasource.dart'; import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:file_selector/file_selector.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:icons_plus/icons_plus.dart'; -import 'mark_as_template_item.dart'; - -class Editor extends StatefulWidget { - const Editor({ - super.key, - required this.datasource, - required this.onEditorStateChange, - this.editorStyle, - this.textDirection = TextDirection.ltr, - }); - - final Datasource datasource; - final EditorStyle? editorStyle; - final void Function(EditorState editorState) onEditorStateChange; - - final TextDirection textDirection; - - @override - State createState() => _EditorState(); -} - -class _EditorState extends State { - bool isInitialized = false; - - EditorState? editorState; - WordCountService? wordCountService; - - @override - void didUpdateWidget(covariant Editor oldWidget) { - if (oldWidget.datasource.data != widget.datasource.data) { - editorState = null; - isInitialized = false; - } - super.didUpdateWidget(oldWidget); - } - - int wordCount = 0; - int charCount = 0; - - int selectedWordCount = 0; - int selectedCharCount = 0; - - void registerWordCounter() { - wordCountService?.removeListener(onWordCountUpdate); - wordCountService?.dispose(); - - wordCountService = WordCountService(editorState: editorState!)..register(); - wordCountService!.addListener(onWordCountUpdate); - - WidgetsBinding.instance.addPostFrameCallback((_) { - onWordCountUpdate(); - }); - } - - void onWordCountUpdate() { - setState(() { - wordCount = wordCountService!.documentCounters.wordCount; - charCount = wordCountService!.documentCounters.charCount; - selectedWordCount = wordCountService!.selectionCounters.wordCount; - selectedCharCount = wordCountService!.selectionCounters.charCount; - }); - } - - @override - void dispose() { - if (mounted) { - try { - editorState?.dispose(); - } catch (_) {} - } - - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Stack( - children: [ - ColoredBox( - color: Colors.white, - child: Builder( - builder: (context) { - if (!isInitialized || editorState == null) { - isInitialized = true; - EditorState editorState = EditorState( - document: widget.datasource.toDocument(), - ); - - editorState.logConfiguration - ..handler = debugPrint - ..level = LogLevel.off; - - editorState.transactionStream.listen((event) { - if (event.$1 == TransactionTime.after) { - widget.onEditorStateChange(editorState); - } - }); - - widget.onEditorStateChange(editorState); - - this.editorState = editorState; - registerWordCounter(); - } - - return DesktopEditor( - editorState: editorState!, - textDirection: widget.textDirection, - ); - }, - ), - ), - Positioned( - bottom: 0, - right: 0, - child: Container( - padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 12), - decoration: BoxDecoration( - color: Colors.black.withOpacity(0.1), - borderRadius: BorderRadius.only( - topLeft: const Radius.circular(8), - bottomLeft: PlatformExtension.isMobile - ? const Radius.circular(8) - : Radius.zero, - ), - ), - child: Column( - children: [ - Text( - 'Word Count: $wordCount | Character Count: $charCount', - style: const TextStyle(fontSize: 11), - ), - if (!(editorState?.selection?.isCollapsed ?? true)) - Text( - '(In-selection) Word Count: $selectedWordCount | Character Count: $selectedCharCount', - style: const TextStyle(fontSize: 11), - ), - ], - ), - ), - ), - ], - ); - } -} +import '../template_editor/components/mark_as_template_item.dart'; class DesktopEditor extends StatefulWidget { const DesktopEditor({ super.key, required this.editorState, this.textDirection = TextDirection.ltr, + this.showTemplateFeatures = false, }); final EditorState editorState; final TextDirection textDirection; + final bool showTemplateFeatures; @override State createState() => _DesktopEditorState(); @@ -200,7 +58,7 @@ class _DesktopEditorState extends State { } late final customItem = SelectionMenuItem( - getName: () => "AI helper", + getName: () => "AI assistant", icon: (editorState, isSelected, style) => const Icon(Bootstrap.robot, size: 15), keywords: ['AI'], @@ -234,10 +92,10 @@ class _DesktopEditorState extends State { quoteItem, bulletedListItem, numberedListItem, - markAsTemplateItem, + if (widget.showTemplateFeatures) markAsTemplateItem, linkItem, - sqlItem, - fileChatItem, + if (widget.showTemplateFeatures) sqlItem, + if (widget.showTemplateFeatures) fileChatItem, buildTextColorItem(), buildHighlightColorItem(), ...textDirectionItems, diff --git a/lib/llm/editor/editor.dart b/lib/llm/editor/editor.dart new file mode 100644 index 0000000..af001b8 --- /dev/null +++ b/lib/llm/editor/editor.dart @@ -0,0 +1,152 @@ +import 'package:all_in_one/llm/editor/models/datasource.dart'; +import 'package:appflowy_editor/appflowy_editor.dart'; +import 'package:flutter/material.dart'; + +import 'desktop_editor.dart'; + +class Editor extends StatefulWidget { + const Editor( + {super.key, + required this.datasource, + required this.onEditorStateChange, + this.editorStyle, + this.textDirection = TextDirection.ltr, + required this.showTemplateFeatures}); + + final Datasource datasource; + final EditorStyle? editorStyle; + final void Function(EditorState editorState) onEditorStateChange; + + final TextDirection textDirection; + final bool showTemplateFeatures; + + @override + State createState() => _EditorState(); +} + +class _EditorState extends State { + bool isInitialized = false; + + EditorState? editorState; + WordCountService? wordCountService; + + @override + void didUpdateWidget(covariant Editor oldWidget) { + if (oldWidget.datasource.data != widget.datasource.data) { + editorState = null; + isInitialized = false; + } + super.didUpdateWidget(oldWidget); + } + + int wordCount = 0; + int charCount = 0; + + int selectedWordCount = 0; + int selectedCharCount = 0; + + void registerWordCounter() { + wordCountService?.removeListener(onWordCountUpdate); + wordCountService?.dispose(); + + wordCountService = WordCountService(editorState: editorState!)..register(); + wordCountService!.addListener(onWordCountUpdate); + + WidgetsBinding.instance.addPostFrameCallback((_) { + onWordCountUpdate(); + }); + } + + void onWordCountUpdate() { + setState(() { + wordCount = wordCountService!.documentCounters.wordCount; + charCount = wordCountService!.documentCounters.charCount; + selectedWordCount = wordCountService!.selectionCounters.wordCount; + selectedCharCount = wordCountService!.selectionCounters.charCount; + }); + } + + @override + void dispose() { + if (mounted) { + try { + editorState?.dispose(); + } catch (_) {} + } + + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Stack( + children: [ + ColoredBox( + color: Colors.white, + child: Builder( + builder: (context) { + if (!isInitialized || editorState == null) { + isInitialized = true; + EditorState editorState = EditorState( + document: widget.datasource.content == "" + ? Document.blank(withInitialText: true) + : widget.datasource.toDocument(), + ); + + editorState.logConfiguration + ..handler = debugPrint + ..level = LogLevel.off; + + editorState.transactionStream.listen((event) { + if (event.$1 == TransactionTime.after) { + widget.onEditorStateChange(editorState); + } + }); + + widget.onEditorStateChange(editorState); + + this.editorState = editorState; + registerWordCounter(); + } + + return DesktopEditor( + editorState: editorState!, + textDirection: widget.textDirection, + showTemplateFeatures: widget.showTemplateFeatures, + ); + }, + ), + ), + Positioned( + bottom: 0, + right: 0, + child: Container( + padding: const EdgeInsets.symmetric(vertical: 2, horizontal: 12), + decoration: BoxDecoration( + color: Colors.black.withOpacity(0.1), + borderRadius: BorderRadius.only( + topLeft: const Radius.circular(8), + bottomLeft: PlatformExtension.isMobile + ? const Radius.circular(8) + : Radius.zero, + ), + ), + child: Column( + children: [ + Text( + 'Word Count: $wordCount | Character Count: $charCount', + style: const TextStyle(fontSize: 11), + ), + if (!(editorState?.selection?.isCollapsed ?? true)) + Text( + '(In-selection) Word Count: $selectedWordCount | Character Count: $selectedCharCount', + style: const TextStyle(fontSize: 11), + ), + ], + ), + ), + ), + ], + ); + } +} diff --git a/lib/llm/template_editor/models/datasource.dart b/lib/llm/editor/models/datasource.dart similarity index 100% rename from lib/llm/template_editor/models/datasource.dart rename to lib/llm/editor/models/datasource.dart diff --git a/lib/llm/langchain/components/chat_ui.dart b/lib/llm/langchain/components/chat_ui.dart index a145387..4784206 100644 --- a/lib/llm/langchain/components/chat_ui.dart +++ b/lib/llm/langchain/components/chat_ui.dart @@ -129,7 +129,7 @@ class _ChatUIState extends ConsumerState { .addMessageBox(RequestMessageBox(content: s)); if (id == 0) { await ref.read(historyProvider(LLMType.openai).notifier).newHistory(s, - chatTag: model == null || model.toMessage().content == "normal" + chatTag: model == null || model.toMessage()!.content == "normal" ? "随便聊聊" : model.name); @@ -142,9 +142,9 @@ class _ChatUIState extends ConsumerState { .getMessages(config.historyLength, id); List history; - if (model != null && model.toMessage().content != "normal") { + if (model != null && model.toMessage()!.content != "normal") { history = [ - model.toMessage(), + model.toMessage()!, ...messages.map((e) => LLMMessage(uuid: "", content: e.content ?? "", type: e.roleType)) ]; diff --git a/lib/llm/langchain/components/tools_item.dart b/lib/llm/langchain/components/tools_item.dart index 59399cd..ab147ed 100644 --- a/lib/llm/langchain/components/tools_item.dart +++ b/lib/llm/langchain/components/tools_item.dart @@ -5,8 +5,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; class ToolsItem extends ConsumerStatefulWidget { - const ToolsItem({super.key, required this.toolModel}); + const ToolsItem({super.key, required this.toolModel, this.onTap}); final ToolModel toolModel; + final VoidCallback? onTap; @override ConsumerState createState() => _ToolsItemState(); @@ -17,8 +18,12 @@ class _ToolsItemState extends ConsumerState { Widget build(BuildContext context) { return GestureDetector( onTap: () { - ref.read(toolProvider.notifier).changeState(widget.toolModel); - ref.read(toolProvider.notifier).jumpTo(1); + if (widget.onTap != null) { + widget.onTap!(); + } else { + ref.read(toolProvider.notifier).changeState(widget.toolModel); + ref.read(toolProvider.notifier).jumpTo(1); + } }, child: MouseRegion( cursor: SystemMouseCursors.click, diff --git a/lib/llm/langchain/components/tools_screen.dart b/lib/llm/langchain/components/tools_screen.dart index 49c3e82..02160f0 100644 --- a/lib/llm/langchain/components/tools_screen.dart +++ b/lib/llm/langchain/components/tools_screen.dart @@ -5,9 +5,7 @@ import 'package:all_in_one/llm/langchain/notifiers/tool_notifier.dart'; import 'package:all_in_one/styles/app_style.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_expandable_fab/flutter_expandable_fab.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:icons_plus/icons_plus.dart'; import 'tools_item.dart'; @@ -23,6 +21,17 @@ class _ToolsScreenState extends ConsumerState { void initState() { super.initState(); future = loadData(); + controller.addListener(() { + if (controller.offset >= 200) { + setState(() { + showTitle = true; + }); + } else { + setState(() { + showTitle = false; + }); + } + }); } // ignore: prefer_typing_uninitialized_variables @@ -33,37 +42,42 @@ class _ToolsScreenState extends ConsumerState { textContent = await rootBundle.loadString('assets/llm.json'); } + final ScrollController controller = ScrollController(); + + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + + bool showTitle = false; + @override Widget build(BuildContext context) { return Scaffold( - floatingActionButtonLocation: ExpandableFab.location, - // floatingActionButton: FloatingActionButton( - // child: const Icon(Bootstrap.chat), - // onPressed: () { - // ref.read(toolProvider.notifier).jumpTo(2); - // }), - floatingActionButton: ExpandableFab( - distance: 50, - type: ExpandableFabType.side, - children: [ - FloatingActionButton.small( - tooltip: "flow", - heroTag: "", - onPressed: () { - ref.read(toolProvider.notifier).jumpTo(2); - }, - child: const Icon(Bootstrap.rainbow), - ), - FloatingActionButton.small( - tooltip: "template", - heroTag: null, - child: const Icon(Icons.masks), - onPressed: () { - ref.read(toolProvider.notifier).jumpTo(3); - }, - ), - ], - ), + // floatingActionButtonLocation: ExpandableFab.location, + // floatingActionButton: ExpandableFab( + // distance: 50, + // type: ExpandableFabType.side, + // children: [ + // FloatingActionButton.small( + // tooltip: "flow", + // heroTag: "", + // onPressed: () { + // ref.read(toolProvider.notifier).jumpTo(2); + // }, + // child: const Icon(Bootstrap.rainbow), + // ), + // FloatingActionButton.small( + // tooltip: "template", + // heroTag: null, + // child: const Icon(Icons.masks), + // onPressed: () { + // ref.read(toolProvider.notifier).jumpTo(3); + // }, + // ), + // ], + // ), body: Padding( padding: const EdgeInsets.all(10), child: FutureBuilder( @@ -71,53 +85,134 @@ class _ToolsScreenState extends ConsumerState { builder: (c, s) { if (s.connectionState == ConnectionState.done) { final Map jsonObj = json.decode(textContent); - return Column( - children: [ - Stack( - children: [ - Container( - width: double.infinity, - constraints: const BoxConstraints(maxHeight: 400), - child: Image.asset( - "assets/llm/banner.jpg", - fit: BoxFit.cover, + + return NestedScrollView( + controller: controller, + headerSliverBuilder: (ctx, _) { + return [ + SliverAppBar( + surfaceTintColor: Colors.transparent, + shadowColor: Colors.transparent, + backgroundColor: Colors.transparent, + foregroundColor: Colors.transparent, + expandedHeight: 400.0, + pinned: true, + flexibleSpace: FlexibleSpaceBar( + title: showTitle + ? const SizedBox( + height: 50, + child: Align( + alignment: Alignment.centerRight, + child: Text( + "😃 Have a nice day.", + style: TextStyle( + fontFamily: "xing", + fontSize: 30, + color: AppStyle.black), + ), + ), + ) + : null, + background: Stack( + children: [ + Container( + width: double.infinity, + constraints: + const BoxConstraints(maxHeight: 400), + child: Image.asset( + "assets/llm/banner.jpg", + fit: BoxFit.cover, + ), + ), + Positioned( + bottom: 40, + right: 20, + child: Transform.rotate( + angle: -3.14 / 10, + child: const Text( + "Let AI help you", + style: TextStyle( + fontFamily: "xing", + fontSize: 40, + color: AppStyle.orange), + ), + )) + ], + ), ), - ), - Positioned( - bottom: 40, - right: 20, - child: Transform.rotate( - angle: -3.14 / 10, - child: const Text( - "Let AI help you", - style: TextStyle( - fontFamily: "xing", - fontSize: 40, - color: AppStyle.orange), + ) + ]; + }, + body: _wrapper2( + SingleChildScrollView( + physics: const NeverScrollableScrollPhysics(), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (showTitle) + const SizedBox( + height: 60, + ), + const SizedBox( + width: double.infinity, + height: 35, + child: Text( + "AI Compose", + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold), + ), ), - )) - ], - ), - const SizedBox( - height: 10, - ), - Expanded( - child: Align( - alignment: Alignment.topLeft, - child: SingleChildScrollView( - child: Wrap( - runSpacing: 15, - spacing: 15, - children: jsonObj.entries - .map((e) => ToolsItem( + Wrap( + runSpacing: 15, + spacing: 15, + children: jsonObj.entries + .where((e) => e.value["type"] == "compose") + .map((e) { + return ToolsItem( + onTap: () { + if (e.key == "template") { + ref + .read(toolProvider.notifier) + .jumpTo(3); + } + if (e.key == "compose") { + ref + .read(toolProvider.notifier) + .jumpTo(4); + } + }, toolModel: ToolModel.fromJson(e.value), - )) - .toList(), + ); + }).toList(), + ), + const SizedBox( + height: 20, + ), + const SizedBox( + height: 35, + child: Text( + "AI Tools", + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold), + ), + ), + Wrap( + runSpacing: 15, + spacing: 15, + children: jsonObj.entries + .where((e) => e.value["type"] == "tool") + .map((e) => ToolsItem( + toolModel: + ToolModel.fromJson(e.value), + )) + .toList(), + ), + ], + ), ), - ), - )) - ], - ); + context)); } return const Center( child: CircularProgressIndicator(), @@ -126,4 +221,12 @@ class _ToolsScreenState extends ConsumerState { ), ); } + + Widget _wrapper2(Widget c, BuildContext context) { + return ScrollConfiguration( + behavior: ScrollConfiguration.of(context) + .copyWith(scrollbars: false, dragDevices: {}), + child: c, //嵌套你的SingleChildScrollView组件 + ); + } } diff --git a/lib/llm/langchain/models/tool_model.dart b/lib/llm/langchain/models/tool_model.dart index 6e39654..75d555a 100644 --- a/lib/llm/langchain/models/tool_model.dart +++ b/lib/llm/langchain/models/tool_model.dart @@ -4,18 +4,27 @@ class ToolModel { final String imgPath; final String systemPrompt; final String name; + final String type; ToolModel( - {required this.imgPath, required this.systemPrompt, required this.name}); + {required this.imgPath, + required this.systemPrompt, + required this.name, + required this.type}); factory ToolModel.fromJson(Map json) { return ToolModel( - imgPath: json['img_path'], - systemPrompt: json['system_prompt'], - name: json['name']); + imgPath: json['img_path'], + systemPrompt: json['system_prompt'], + name: json['name'], + type: json['type'], + ); } - LLMMessage toMessage() { + LLMMessage? toMessage() { + if (type != "tool") { + return null; + } return LLMMessage(uuid: "", content: systemPrompt, type: 1); } } diff --git a/lib/llm/template_editor/template_editor.dart b/lib/llm/template_editor/template_editor.dart index 2a8689c..2339acc 100644 --- a/lib/llm/template_editor/template_editor.dart +++ b/lib/llm/template_editor/template_editor.dart @@ -8,7 +8,7 @@ import 'package:all_in_one/llm/langchain/notifiers/tool_notifier.dart'; import 'package:all_in_one/llm/plugins/record/record_utils.dart'; import 'package:all_in_one/llm/template_editor/components/chain_flow.dart'; import 'package:all_in_one/llm/template_editor/extension.dart'; -import 'package:all_in_one/llm/template_editor/models/datasource.dart'; +import 'package:all_in_one/llm/editor/models/datasource.dart'; import 'package:all_in_one/llm/template_editor/notifiers/chain_flow_notifier.dart'; import 'package:all_in_one/llm/template_editor/notifiers/template_notifier.dart'; import 'package:all_in_one/src/rust/api/llm_api.dart'; @@ -18,7 +18,7 @@ import 'package:flutter_expandable_fab/flutter_expandable_fab.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:icons_plus/icons_plus.dart'; -import 'components/editor.dart'; +import '../editor/editor.dart'; import 'components/loading_dialog.dart'; import 'components/new_template_dialog.dart'; @@ -79,6 +79,7 @@ class _TemplateEditorState extends ConsumerState { onEditorStateChange: (editorState) { _editorState = editorState; }, + showTemplateFeatures: true, ); /// FIXME @@ -209,6 +210,7 @@ class _TemplateEditorState extends ConsumerState { onEditorStateChange: (editorState) { _editorState = editorState; }, + showTemplateFeatures: true, ); }, ); diff --git a/pubspec.yaml b/pubspec.yaml index 4dc4d33..b018e0f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,7 +2,7 @@ name: all_in_one description: "A new Flutter project." publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 0.0.8 +version: 0.0.8+1 environment: sdk: '>=3.3.0 <4.0.0' From d34f7630693aad6f2081efd55965e0026c0ce56c Mon Sep 17 00:00:00 2001 From: xiaoshuyui <528490652@qq.com> Date: Sun, 19 May 2024 20:13:29 +0800 Subject: [PATCH 2/2] Create build-arm64-linux.yml --- .github/workflows/build-arm64-linux.yml | 83 +++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 .github/workflows/build-arm64-linux.yml diff --git a/.github/workflows/build-arm64-linux.yml b/.github/workflows/build-arm64-linux.yml new file mode 100644 index 0000000..537cc65 --- /dev/null +++ b/.github/workflows/build-arm64-linux.yml @@ -0,0 +1,83 @@ +name: Build Linux App + +on: + push: + branches: + - release + +jobs: + qemu: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + lfs: true + + - name: Install Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: 3.22.0 + + - name: Cache pubspec + id: cache-pubspec + uses: actions/cache@v3 + with: + path: | + ${{ env.FLUTTER_HOME }}/.pub-cache + **/.flutter-plugins + **/.flutter-plugin-dependencies + **/.dart_tool/package_config.json + key: pubspec-${{ hashFiles('**/pubspec.lock') }} + restore-keys: | + pubspec- + + - name: Install Rust Toolchain + run: | + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + source $HOME/.cargo/env + rustup default stable + + - name: install dependencies + run: | + sudo wget -qO /etc/apt/trusted.gpg.d/dart_linux_signing_key.asc https://dl-ssl.google.com/linux/linux_signing_key.pub + sudo apt-get update + sudo apt-get install clang cmake git ninja-build pkg-config libgtk-3-dev liblzma-dev libstdc++-12-dev -y + chmod +x /home/runner/work/all_in_one/all_in_one/rust_builder/cargokit/run_build_tool.sh + + - name: Get dependencies + run: flutter pub get + + - name: Bump build number + run: | + flutter pub global activate cider + + - name: Build Linux app + run: flutter build linux --release -v + + - name: Set tag name + run: echo "tag_name=v$(cider version)" >> $GITHUB_ENV + + - name: List files in build directory + run: ls -la build/linux/x64/release/bundle/ + + # - name: Upload build artifacts + # uses: actions/upload-artifact@v2 + # with: + # name: linux-app + # path: build/linux/x64/release/bundle/ + + - name: Archive release + uses: thedoctor0/zip-release@0.7.6 + with: + type: 'zip' + filename: 'linux-arm64.zip' + directory: build/linux/x64/release/bundle/ + + - name: Publish release + uses: ncipollo/release-action@v1 + with: + allowUpdates: true + artifacts: build/linux/x64/release/bundle/linux-arm64.zip + generateReleaseNotes: true + tag: ${{ env.tag_name }} + token: ${{ secrets.RELEASE_TOKEN }}