From 94820a300e39a17a3bc735b6fedf06a2b8e1fb15 Mon Sep 17 00:00:00 2001 From: JHubi1 Date: Sat, 1 Jun 2024 15:46:08 +0200 Subject: [PATCH] Added custom header option --- lib/l10n/app_en.arb | 12 ++++++++++- lib/main.dart | 9 +++++--- lib/screen_settings.dart | 32 ++++++++++++++++++++++++++-- lib/worker_setter.dart | 46 ++++++++++++++++++++++++++++++++-------- 4 files changed, 84 insertions(+), 15 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index fb79641..fec669f 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -130,7 +130,7 @@ "description": "Text displayed as description for new title input", "context": "Visible in the rename dialog" }, - "dialogEditMessageTitle": "Edit Message", + "dialogEditMessageTitle": "Edit message", "@dialogEditMessageTitle": { "description": "Title of the edit message dialog", "context": "Visible in the edit message dialog" @@ -181,6 +181,16 @@ } } }, + "settingsHostHeaderTitle": "Set host header", + "@settingsHostHeader": { + "description": "Text displayed as description for host header input", + "context": "Visible in the settings view" + }, + "settingsHostHeaderInvalid": "The entered text isn't a valid header JSON object", + "@settingsHostHeaderInvalid": { + "description": "Text displayed when the host header is invalid", + "context": "Visible in the settings view" + }, "settingsHostInvalidDetailed": "{type, select, url{The URL you entered is invalid. It isn't an a standardized URL format.} other{The host you entered is invalid. It cannot be reached. Please check the host and try again.}}", "@settingsHostInvalidDetailed": { "description": "Text displayed when the host is invalid", diff --git a/lib/main.dart b/lib/main.dart index 23edb4c..0911ace 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -674,8 +674,12 @@ class _MainAppState extends State { chatAllowed = false; String newId = const Uuid().v4(); - llama.OllamaClient client = - llama.OllamaClient(baseUrl: "$host/api"); + llama.OllamaClient client = llama.OllamaClient( + headers: + (jsonDecode(prefs!.getString("hostHeaders") ?? "{}") + as Map) + .cast(), + baseUrl: "$host/api"); try { if ((prefs!.getString("requestType") ?? "stream") == @@ -1242,7 +1246,6 @@ class _MainAppState extends State { title: AppLocalizations.of(context)! .dialogEnterNewTitle, value: oldTitle, - force: false, uuid: jsonDecode(item)["uuid"]); var tmp = (prefs!.getStringList("chats") ?? []); for (var i = 0; i < tmp.length; i++) { diff --git a/lib/screen_settings.dart b/lib/screen_settings.dart index 5cd31f4..151aecd 100644 --- a/lib/screen_settings.dart +++ b/lib/screen_settings.dart @@ -6,7 +6,7 @@ import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'main.dart'; -import 'package:intl/intl.dart'; +import 'package:ollama_app/worker_setter.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:dartx/dartx.dart'; @@ -16,6 +16,7 @@ import 'package:url_launcher/url_launcher.dart'; import 'package:restart_app/restart_app.dart'; import 'package:file_picker/file_picker.dart'; import 'package:pick_or_save/pick_or_save.dart'; +import 'package:intl/intl.dart'; class ScreenSettings extends StatefulWidget { const ScreenSettings({super.key}); @@ -49,7 +50,11 @@ class _ScreenSettingsState extends State { http.Response request; try { request = await http - .get(Uri.parse(tmpHost)) + .get( + Uri.parse(tmpHost), + headers: (jsonDecode(prefs!.getString("hostHeaders") ?? "{}") as Map) + .cast(), + ) .timeout(const Duration(seconds: 5), onTimeout: () { return http.Response("Error", 408); }); @@ -165,6 +170,29 @@ class _ScreenSettingsState extends State { decoration: InputDecoration( labelText: AppLocalizations.of(context)!.settingsHost, hintText: "http://localhost:11434", + prefixIcon: IconButton( + onPressed: () async { + HapticFeedback.selectionClick(); + String tmp = await prompt(context, + placeholder: + "{\"Authorization\": \"Bearer ...\"}", + title: AppLocalizations.of(context)! + .settingsHostHeaderTitle, + value: (prefs!.getString("hostHeaders") ?? + ""), validator: (content) async { + try { + var tmp = jsonDecode(content); + tmp as Map; + return true; + } catch (_) { + return false; + } + }, + validatorError: AppLocalizations.of(context)! + .settingsHostHeaderInvalid); + prefs!.setString("hostHeaders", tmp); + }, + icon: const Icon(Icons.add_rounded)), suffixIcon: useHost ? const SizedBox.shrink() : (hostLoading diff --git a/lib/worker_setter.dart b/lib/worker_setter.dart index 8fe3cfd..ed4d434 100644 --- a/lib/worker_setter.dart +++ b/lib/worker_setter.dart @@ -21,7 +21,12 @@ void setModel(BuildContext context, Function setState) { bool loaded = false; Function? setModalState; void load() async { - var list = await llama.OllamaClient(baseUrl: "$host/api").listModels(); + var list = await llama.OllamaClient( + headers: + (jsonDecode(prefs!.getString("hostHeaders") ?? "{}") as Map) + .cast(), + baseUrl: "$host/api") + .listModels(); for (var i = 0; i < list.models!.length; i++) { models.add(list.models![i].model!.split(":")[0]); modelsReal.add(list.models![i].model!); @@ -284,15 +289,18 @@ Future prompt(BuildContext context, {String description = "", String value = "", String title = "", - bool force = false, String? valueIfCanceled, TextInputType keyboard = TextInputType.text, Icon? prefixIcon, int maxLines = 1, - String? uuid}) async { + String? uuid, + Future Function(String content)? validator, + String? validatorError, + String? placeholder}) async { var returnText = (valueIfCanceled != null) ? valueIfCanceled : value; final TextEditingController controller = TextEditingController(text: value); bool loading = false; + String? error; await showModalBottomSheet( context: context, isScrollControlled: true, @@ -329,9 +337,25 @@ Future prompt(BuildContext context, maxLines: maxLines, decoration: InputDecoration( border: const OutlineInputBorder(), + hintText: placeholder, + errorText: error, suffixIcon: IconButton( - onPressed: () { + onPressed: () async { + if (validator != null) { + setLocalState(() { + error = null; + }); + bool valid = + await validator(controller.text); + if (!valid) { + setLocalState(() { + error = validatorError; + }); + return; + } + } returnText = controller.text; + // ignore: use_build_context_synchronously Navigator.of(context).pop(); }, icon: const Icon(Icons.save_rounded)), @@ -381,11 +405,15 @@ Future prompt(BuildContext context, return; } - final generated = - await llama.OllamaClient( - baseUrl: - "$host/api") - .generateCompletion( + final generated = await llama.OllamaClient( + headers: (jsonDecode(prefs! + .getString( + "hostHeaders") ?? + "{}") as Map) + .cast(), + baseUrl: "$host/api") + .generateCompletion( request: llama .GenerateCompletionRequest( model: model!,