From d6ff18a7695f2e0172c7063c2067816d0a819d39 Mon Sep 17 00:00:00 2001 From: poka Date: Sun, 8 Jan 2023 23:27:07 +0100 Subject: [PATCH] improve env token management --- .gitignore | 3 + lib/global.dart | 4 + lib/load_env.dart | 22 ++ lib/riverpods/openai.dart | 41 +++- lib/screens/home.dart | 209 ++++++++++-------- ...s_sliders.dart => parameters_sliders.dart} | 0 pubspec.lock | 7 + pubspec.yaml | 6 +- scripts/publish.sh | 7 +- 9 files changed, 193 insertions(+), 106 deletions(-) create mode 100644 lib/load_env.dart rename lib/widgets/{paramters_sliders.dart => parameters_sliders.dart} (100%) diff --git a/.gitignore b/.gitignore index 24476c5..780aa72 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,6 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release + +# ignore .env +.env diff --git a/lib/global.dart b/lib/global.dart index 77c3224..fb1af72 100644 --- a/lib/global.dart +++ b/lib/global.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:logger/logger.dart'; // Colors const Color orangeC = Color(0xffd07316); @@ -8,3 +9,6 @@ const Color backgroundColor = Color(0xFFF5F5F5); late double screenWidth; late double screenHight; + +// Logger +final log = Logger(); diff --git a/lib/load_env.dart b/lib/load_env.dart new file mode 100644 index 0000000..c8502b5 --- /dev/null +++ b/lib/load_env.dart @@ -0,0 +1,22 @@ +import 'package:flutter/services.dart'; + +Future> loadEnv({String assetsFileName = '.env'}) async { + Map environment = {}; + try { + final lines = await rootBundle.loadString(assetsFileName); + for (String line in lines.split('\n')) { + line = line.trim(); + if (line.contains('=') //Set Key Value Pairs on lines separated by = + && + !line.startsWith(RegExp(r'=|#'))) { + //No need to add empty keys and remove comments + List contents = line.split('='); + environment[contents[0]] = contents.sublist(1).join('='); + } + } + } catch (e) { + return {'': ''}; + } + + return environment; +} diff --git a/lib/riverpods/openai.dart b/lib/riverpods/openai.dart index 12a5b4d..5ef256f 100644 --- a/lib/riverpods/openai.dart +++ b/lib/riverpods/openai.dart @@ -1,24 +1,49 @@ +import 'package:bogui/global.dart'; +import 'package:bogui/load_env.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:openai_gpt3_api/completion.dart'; import 'package:openai_gpt3_api/openai_gpt3_api.dart'; -class OpenAI extends GPT3 { - OpenAI() : super(String.fromEnvironment('OPENAPI_SECRET_KEY')); +class OpenAI { + // final openaiSecret; + late GPT3 gpt; + // final prompt = TextEditingController(); final prompt = StateProvider((ref) => TextEditingController()); final isLoading = StateProvider((ref) => false); final temperature = StateProvider((ref) => 0.7); + Future init() async { + final env = await loadEnv(); + String openaiSecretFile = ''; + if (env.containsKey('OPENAPI_SECRET_KEY')) { + openaiSecretFile = env['OPENAPI_SECRET_KEY']!; + } + const openaiSecretEnv = String.fromEnvironment('OPENAPI_SECRET_KEY'); + gpt = GPT3(kDebugMode ? openaiSecretFile : openaiSecretEnv); + } + Future completionEasy(WidgetRef ref) async { if (ref.read(isLoading) || ref.read(prompt).text.length < 2) return ''; ref.read(isLoading.notifier).state = true; - final anwser = await OpenAI().completion(ref.read(prompt).text, - maxTokens: 250, - engine: Engine.davinci3, - temperature: ref.read(temperature), - echo: false, - stream: false); + late CompletionApiResult anwser; + try { + anwser = await gpt.completion(ref.read(prompt).text, + maxTokens: 250, + engine: Engine.davinci3, + temperature: ref.read(temperature), + echo: false, + stream: false); + } catch (e) { + log.d(e); + ref.read(prompt).text += + "\nJe n'ai pas la bonne clé API secret pour OpenAI, connard."; + ref.read(isLoading.notifier).state = false; + return "\nJe n'ai pas la bonne clé API secret pour OpenAI, connard."; + } String anwserString = ''; for (final choice in anwser.choices) { diff --git a/lib/screens/home.dart b/lib/screens/home.dart index 00ebf4a..6bf2555 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -1,9 +1,11 @@ import 'package:bogui/global.dart'; import 'package:bogui/riverpods/openai.dart'; -import 'package:bogui/widgets/paramters_sliders.dart'; +import 'package:bogui/widgets/parameters_sliders.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +// import 'package:flutter/gestures.dart'; +// import 'dart:math'; class Bogui extends ConsumerStatefulWidget { const Bogui({super.key, required this.title}); @@ -21,6 +23,7 @@ class _BoguiState extends ConsumerState { @override void initState() { gpt = OpenAI(); + gpt.init(); super.initState(); } @@ -31,6 +34,7 @@ class _BoguiState extends ConsumerState { @override Widget build(BuildContext context) { + final scrollController = ScrollController(); screenWidth = MediaQuery.of(context).size.width; // screenHight = MediaQuery.of(context).size.height; return Scaffold( @@ -40,102 +44,121 @@ class _BoguiState extends ConsumerState { body: Center( child: SizedBox( width: screenWidth, - child: SingleChildScrollView( - child: Row(mainAxisAlignment: MainAxisAlignment.center, children: [ - const Spacer(flex: 3), - Column(children: [ - const SizedBox(height: 40), - Container( - constraints: const BoxConstraints(minWidth: 300), - width: screenWidth - 600, - child: CallbackShortcuts( - bindings: { - LogicalKeySet(LogicalKeyboardKey.control, - LogicalKeyboardKey.enter): - (() => _handleValidation()), - }, - child: TextField( - focusNode: promptFocus, - controller: ref.read(gpt.prompt), - autofocus: true, - textInputAction: TextInputAction.search, - // minLines: 3, - maxLines: null, - keyboardType: TextInputType.multiline, - cursorColor: orangeC, - style: TextStyle(color: Colors.grey[400], fontSize: 16), - decoration: InputDecoration( - hintText: "Qu'ils aillent tous se faire enculer", - filled: true, - // fillColor: Colors.white, - prefixIconConstraints: const BoxConstraints( - minHeight: 32, - ), - prefixIcon: const Padding( - padding: EdgeInsets.symmetric(horizontal: 17), - child: Icon( - Icons.fireplace_rounded, - color: orangeC, - size: 30, - )), - border: OutlineInputBorder( - borderSide: - BorderSide(color: Colors.grey[500]!, width: 2), - borderRadius: BorderRadius.circular(8)), - focusedBorder: OutlineInputBorder( - borderSide: - BorderSide(color: Colors.grey[500]!, width: 2.5), - borderRadius: BorderRadius.circular(8), - ), - contentPadding: const EdgeInsets.all(20), - ), - onSubmitted: (value) => promptFocus.requestFocus(), - ), - ), - ), - const SizedBox(height: 40), - SizedBox( - width: 250, - height: 50, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - foregroundColor: Colors.white, elevation: 4, - backgroundColor: orangeC, // foreground - ), - onPressed: ref.watch(gpt.prompt).text.length > 100000000000 - ? null - : () { - _handleValidation(); - }, - child: ref.watch(gpt.isLoading) - ? SizedBox( - height: 18, - width: 18, - child: CircularProgressIndicator( - color: Colors.grey[800], - strokeWidth: 4, - ), - ) - : const Text( - 'Valider', - style: TextStyle( - fontSize: 21, fontWeight: FontWeight.w500), + child: Listener( + onPointerSignal: (_) { + // if (_ is PointerScrollEvent) { + // scrollController.jumpTo( + // max( + // min( + // scrollController.position.maxScrollExtent, + // scrollController.offset + _.scrollDelta.dx, + // ), + // scrollController.position.minScrollExtent, + // ), + // ); + // } + }, + child: SingleChildScrollView( + controller: scrollController, + child: + Row(mainAxisAlignment: MainAxisAlignment.center, children: [ + const Spacer(flex: 3), + Column(children: [ + const SizedBox(height: 40), + Container( + constraints: const BoxConstraints(minWidth: 300), + width: screenWidth - 600, + child: CallbackShortcuts( + bindings: { + LogicalKeySet(LogicalKeyboardKey.control, + LogicalKeyboardKey.enter): + (() => _handleValidation()), + }, + child: TextField( + scrollPhysics: const NeverScrollableScrollPhysics(), + focusNode: promptFocus, + controller: ref.read(gpt.prompt), + autofocus: true, + textInputAction: TextInputAction.search, + // minLines: 3, + maxLines: null, + keyboardType: TextInputType.multiline, + cursorColor: orangeC, + style: TextStyle(color: Colors.grey[400], fontSize: 16), + decoration: InputDecoration( + hintText: "Qu'ils aillent tous se faire enculer", + filled: true, + // fillColor: Colors.white, + prefixIconConstraints: const BoxConstraints( + minHeight: 32, ), + prefixIcon: const Padding( + padding: EdgeInsets.symmetric(horizontal: 17), + child: Icon( + Icons.fireplace_rounded, + color: orangeC, + size: 30, + )), + border: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.grey[500]!, width: 2), + borderRadius: BorderRadius.circular(8)), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: Colors.grey[500]!, width: 2.5), + borderRadius: BorderRadius.circular(8), + ), + contentPadding: const EdgeInsets.all(20), + ), + onSubmitted: (value) => promptFocus.requestFocus(), + ), + ), ), + const SizedBox(height: 40), + SizedBox( + width: 250, + height: 50, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + foregroundColor: Colors.white, elevation: 4, + backgroundColor: orangeC, // foreground + ), + onPressed: + ref.watch(gpt.prompt).text.length > 100000000000 + ? null + : () { + _handleValidation(); + }, + child: ref.watch(gpt.isLoading) + ? SizedBox( + height: 18, + width: 18, + child: CircularProgressIndicator( + color: Colors.grey[800], + strokeWidth: 4, + ), + ) + : const Text( + 'Valider', + style: TextStyle( + fontSize: 21, fontWeight: FontWeight.w500), + ), + ), + ), + const SizedBox(height: 40), + ]), + const Spacer(), + Column( + children: [ + CustomSlider( + parameter: gpt.temperature, + nameParameter: 'Température', + ), + ], ), - const SizedBox(height: 40), + const Spacer(), ]), - const Spacer(), - Column( - children: [ - CustomSlider( - parameter: gpt.temperature, - nameParameter: 'Température', - ), - ], - ), - const Spacer(), - ]), + ), ), ), ), diff --git a/lib/widgets/paramters_sliders.dart b/lib/widgets/parameters_sliders.dart similarity index 100% rename from lib/widgets/paramters_sliders.dart rename to lib/widgets/parameters_sliders.dart diff --git a/pubspec.lock b/pubspec.lock index ec0b7a0..7faf026 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -109,6 +109,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.1" + logger: + dependency: "direct main" + description: + name: logger + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" matcher: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index ef9344a..a4fd291 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -20,6 +20,7 @@ dependencies: ref: main flutter_hooks: ^0.18.0 flutter_riverpod: ^2.1.3 + logger: ^1.1.0 dev_dependencies: flutter_test: @@ -32,9 +33,8 @@ flutter: uses-material-design: true # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg + assets: + - .env # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware diff --git a/scripts/publish.sh b/scripts/publish.sh index 9f0a33b..85a2544 100755 --- a/scripts/publish.sh +++ b/scripts/publish.sh @@ -2,14 +2,17 @@ set -e +OPENAI_SECRET_KEY=$1 +[[ ! $OPENAI_SECRET_KEY ]] && echo "Please pass a valid OpenAI token API key" && exit 1 + flutter clean && flutter pub get if [[ $1 == "html" ]]; then - rm -rf /home/poka/dev/bogui/build/web && flutter build web --web-renderer html + rm -rf /home/poka/dev/bogui/build/web && flutter build web --web-renderer html --dart-define=OPENAPI_SECRET_KEY=${OPENAI_SECRET_KEY} ssh -p 10322 poka@p2p.legal 'rm -rf /home/poka/bogui-html && mkdir /home/poka/bogui-html' rs /home/poka/dev/bogui/build/web poka@p2p.legal:/home/poka/bogui-html/ 10322 else - rm -rf /home/poka/dev/bogui/build/web && flutter build web --web-renderer canvaskit + rm -rf /home/poka/dev/bogui/build/web && flutter build web --web-renderer canvaskit --dart-define=OPENAPI_SECRET_KEY=${OPENAI_SECRET_KEY} ssh -p 10322 poka@p2p.legal 'rm -rf /home/poka/bogui-web && mkdir /home/poka/bogui-web' rs /home/poka/dev/bogui/build/web poka@p2p.legal:/home/poka/bogui/ 10322 fi