Bug fixes, small improvements, updated marketing assets
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 63 KiB |
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 149 KiB |
Before Width: | Height: | Size: 137 KiB After Width: | Height: | Size: 123 KiB |
Before Width: | Height: | Size: 257 KiB After Width: | Height: | Size: 238 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 118 KiB |
|
@ -1,73 +1,3 @@
|
||||||
{
|
{
|
||||||
"@@locale": "de",
|
"@@locale": "de"
|
||||||
"appTitle": "Ollama",
|
|
||||||
"@appTitle": {
|
|
||||||
"description": "Title of the application",
|
|
||||||
"context": "Visible in the side bar"
|
|
||||||
},
|
|
||||||
"optionSettings": "Einstellungen",
|
|
||||||
"@optionSettings": {
|
|
||||||
"description": "Text displayed for settings option",
|
|
||||||
"context": "Visible in the side bar"
|
|
||||||
},
|
|
||||||
"optionNewChat": "Neuer Chat",
|
|
||||||
"@optionNewChat": {
|
|
||||||
"description": "Text displayed for new chat option",
|
|
||||||
"context": "Visible in the side bar"
|
|
||||||
},
|
|
||||||
"takeImage": "Bild Aufnehmen",
|
|
||||||
"@takeImage": {
|
|
||||||
"description": "Text displayed for take image button",
|
|
||||||
"context": "Visible in attachment menu"
|
|
||||||
},
|
|
||||||
"uploadImage": "Bild Hochladen",
|
|
||||||
"@uploadImage": {
|
|
||||||
"description": "Text displayed for image upload button",
|
|
||||||
"context": "Visible in attachment menu"
|
|
||||||
},
|
|
||||||
"messageInputPlaceholder": "Nachricht",
|
|
||||||
"@messageInputPlaceholder": {
|
|
||||||
"description": "Placeholder text for message input",
|
|
||||||
"context": "Visible in the chat view"
|
|
||||||
},
|
|
||||||
"noModelSelected": "Kein Modell ausgewählt",
|
|
||||||
"@noModelSelected": {
|
|
||||||
"description": "Text displayed when no model is selected",
|
|
||||||
"context": "Visible in the chat view"
|
|
||||||
},
|
|
||||||
"hostDialogTitle": "Host Festlegen",
|
|
||||||
"@hostDialogTitle": {
|
|
||||||
"description": "Title of the host dialog",
|
|
||||||
"context": "Visible in the host dialog"
|
|
||||||
},
|
|
||||||
"hostDialogDescription": "Gebe den Host des Ollama-Servers ein. Dies wird validiert und kann später in den Einstellungen geändert werden.",
|
|
||||||
"@hostDialogDescription": {
|
|
||||||
"description": "Description of the host dialog",
|
|
||||||
"context": "Visible in the host dialog"
|
|
||||||
},
|
|
||||||
"hostDialogErrorInvalidHost": "Der Host konnte nicht validiert werden, bitte versuche es erneut. Entweder ist er nicht erreichbar oder es handelt sich nicht um eine gültige Ollama-Serverinstanz.",
|
|
||||||
"@hostDialogErrorInvalidHost": {
|
|
||||||
"description": "Error message displayed when the host is invalid",
|
|
||||||
"context": "Visible in the host dialog"
|
|
||||||
},
|
|
||||||
"hostDialogErrorInvalidUrl": "Die URL ist ungültig. Versuche, sie erneut zu überprüfen.",
|
|
||||||
"@hostDialogErrorInvalidUrl": {
|
|
||||||
"description": "Error message displayed when the URL is invalid",
|
|
||||||
"context": "Visible in the host dialog"
|
|
||||||
},
|
|
||||||
"hostDialogSave": "Host Speichern",
|
|
||||||
"@hostDialogSave": {
|
|
||||||
"description": "Text displayed for save host button, should be capitalized",
|
|
||||||
"context": "Visible in the host dialog"
|
|
||||||
},
|
|
||||||
"noSelectedModel": "<selektor>",
|
|
||||||
"@noSelectedModel": {
|
|
||||||
"description": "Text displayed when no model is selected",
|
|
||||||
"context": "Visible in the chat view, opens the model dialog when clicked"
|
|
||||||
},
|
|
||||||
"modelDialogAddModel": "Modell hinzufügen",
|
|
||||||
"@modelDialogAddModel": {
|
|
||||||
"description": "Text displayed for add model button",
|
|
||||||
"context": "Visible in the model dialog"
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -69,5 +69,10 @@
|
||||||
"@modelDialogAddModel": {
|
"@modelDialogAddModel": {
|
||||||
"description": "Text displayed for add model button",
|
"description": "Text displayed for add model button",
|
||||||
"context": "Visible in the model dialog"
|
"context": "Visible in the model dialog"
|
||||||
|
},
|
||||||
|
"modelDialogAddSteps": "To add a new model, visit ollama.com on your computer, look for a model you like, copy the command and paste it in a new terminal window. Wait for the download to complete, this can take a while. Once it is complete, reopen this selector and you'll find your newly added model.",
|
||||||
|
"@modelDialogAddSteps": {
|
||||||
|
"description": "Steps to add a new model",
|
||||||
|
"context": "Visible in the model dialog"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -391,7 +391,7 @@ class _MainAppState extends State<MainApp> {
|
||||||
.selectionClick();
|
.selectionClick();
|
||||||
},
|
},
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
Icons.file_copy_rounded),
|
Icons.photo_camera_rounded),
|
||||||
label: Text(AppLocalizations.of(
|
label: Text(AppLocalizations.of(
|
||||||
context)!
|
context)!
|
||||||
.takeImage))),
|
.takeImage))),
|
||||||
|
|
|
@ -8,7 +8,7 @@ import 'package:http/http.dart' as http;
|
||||||
import 'package:dartx/dartx.dart';
|
import 'package:dartx/dartx.dart';
|
||||||
import 'package:ollama_dart/ollama_dart.dart' as llama;
|
import 'package:ollama_dart/ollama_dart.dart' as llama;
|
||||||
|
|
||||||
void setHost(BuildContext context, [String host = ""]) {
|
void setHost(BuildContext context) {
|
||||||
bool loading = false;
|
bool loading = false;
|
||||||
bool invalidHost = false;
|
bool invalidHost = false;
|
||||||
bool invalidUrl = false;
|
bool invalidUrl = false;
|
||||||
|
@ -93,7 +93,7 @@ void setHost(BuildContext context, [String host = ""]) {
|
||||||
messages = [];
|
messages = [];
|
||||||
setState(() {});
|
setState(() {});
|
||||||
host = tmpHost;
|
host = tmpHost;
|
||||||
prefs?.setString("host", host);
|
prefs?.setString("host", host!);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child:
|
child:
|
||||||
|
@ -105,6 +105,7 @@ void setModel(BuildContext context, Function setState) {
|
||||||
List<String> models = [];
|
List<String> models = [];
|
||||||
List<bool> modal = [];
|
List<bool> modal = [];
|
||||||
int usedIndex = -1;
|
int usedIndex = -1;
|
||||||
|
int addIndex = -1;
|
||||||
bool loaded = false;
|
bool loaded = false;
|
||||||
Function? setModalState;
|
Function? setModalState;
|
||||||
void load() async {
|
void load() async {
|
||||||
|
@ -113,6 +114,10 @@ void setModel(BuildContext context, Function setState) {
|
||||||
models.add(list.models![i].model!.split(":")[0]);
|
models.add(list.models![i].model!.split(":")[0]);
|
||||||
modal.add((list.models![i].details!.families ?? []).contains("clip"));
|
modal.add((list.models![i].details!.families ?? []).contains("clip"));
|
||||||
}
|
}
|
||||||
|
addIndex = models.length;
|
||||||
|
// ignore: use_build_context_synchronously
|
||||||
|
models.add(AppLocalizations.of(context)!.modelDialogAddModel);
|
||||||
|
modal.add(false);
|
||||||
for (var i = 0; i < models.length; i++) {
|
for (var i = 0; i < models.length; i++) {
|
||||||
if (models[i] == model) {
|
if (models[i] == model) {
|
||||||
usedIndex = i;
|
usedIndex = i;
|
||||||
|
@ -147,55 +152,53 @@ void setModel(BuildContext context, Function setState) {
|
||||||
prefs?.setBool("multimodal", multimodal);
|
prefs?.setBool("multimodal", multimodal);
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
child: SizedBox(
|
child: Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
|
padding: const EdgeInsets.only(left: 16, right: 16, top: 16),
|
||||||
child: (!loaded)
|
child: (!loaded)
|
||||||
? const Padding(
|
? const LinearProgressIndicator()
|
||||||
padding: EdgeInsets.all(16),
|
|
||||||
child: LinearProgressIndicator())
|
|
||||||
: Column(mainAxisSize: MainAxisSize.min, children: [
|
: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||||
Padding(
|
Container(
|
||||||
padding: const EdgeInsets.only(
|
width: double.infinity,
|
||||||
left: 16, right: 16, top: 16),
|
constraints: BoxConstraints(
|
||||||
child: SizedBox(
|
maxHeight:
|
||||||
width: double.infinity,
|
MediaQuery.of(context).size.height * 0.4),
|
||||||
child: OutlinedButton.icon(
|
child: SingleChildScrollView(
|
||||||
onPressed: () {},
|
scrollDirection: Axis.vertical,
|
||||||
label: Text(AppLocalizations.of(context)!
|
child: Wrap(
|
||||||
.modelDialogAddModel),
|
spacing: 5.0,
|
||||||
icon: const Icon(Icons.add_rounded)))),
|
alignment: WrapAlignment.center,
|
||||||
const Divider(),
|
children: List<Widget>.generate(
|
||||||
Padding(
|
models.length,
|
||||||
padding:
|
(int index) {
|
||||||
const EdgeInsets.only(left: 16, right: 16),
|
return ChoiceChip(
|
||||||
child: Container(
|
label: Text(models[index]),
|
||||||
width: double.infinity,
|
selected: usedIndex == index,
|
||||||
constraints: BoxConstraints(
|
avatar: (addIndex == index)
|
||||||
maxHeight:
|
? const Icon(Icons.add_rounded)
|
||||||
MediaQuery.of(context).size.height *
|
: ((recommendedModels
|
||||||
0.4),
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
scrollDirection: Axis.vertical,
|
|
||||||
child: Wrap(
|
|
||||||
spacing: 5.0,
|
|
||||||
alignment: WrapAlignment.center,
|
|
||||||
children: List<Widget>.generate(
|
|
||||||
models.length,
|
|
||||||
(int index) {
|
|
||||||
return ChoiceChip(
|
|
||||||
label: Text(models[index]),
|
|
||||||
selected: usedIndex == index,
|
|
||||||
avatar: (recommendedModels
|
|
||||||
.contains(models[index]))
|
.contains(models[index]))
|
||||||
? const Icon(
|
? const Icon(
|
||||||
Icons.star_rounded)
|
Icons.star_rounded)
|
||||||
: ((modal[index])
|
: ((modal[index])
|
||||||
? const Icon(Icons
|
? const Icon(Icons
|
||||||
.collections_rounded)
|
.collections_rounded)
|
||||||
: null),
|
: null)),
|
||||||
checkmarkColor: (usedIndex ==
|
checkmarkColor: (usedIndex == index)
|
||||||
index)
|
? ((MediaQuery.of(context)
|
||||||
? ((MediaQuery.of(context)
|
.platformBrightness ==
|
||||||
|
Brightness.light)
|
||||||
|
? (theme ?? ThemeData())
|
||||||
|
.colorScheme
|
||||||
|
.secondary
|
||||||
|
: (themeDark ??
|
||||||
|
ThemeData.dark())
|
||||||
|
.colorScheme
|
||||||
|
.secondary)
|
||||||
|
: null,
|
||||||
|
labelStyle: (usedIndex == index)
|
||||||
|
? TextStyle(
|
||||||
|
color: (MediaQuery.of(context)
|
||||||
.platformBrightness ==
|
.platformBrightness ==
|
||||||
Brightness.light)
|
Brightness.light)
|
||||||
? (theme ?? ThemeData())
|
? (theme ?? ThemeData())
|
||||||
|
@ -205,45 +208,44 @@ void setModel(BuildContext context, Function setState) {
|
||||||
ThemeData.dark())
|
ThemeData.dark())
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.secondary)
|
.secondary)
|
||||||
: null,
|
: null,
|
||||||
labelStyle: (usedIndex == index)
|
selectedColor: (MediaQuery.of(context)
|
||||||
? TextStyle(
|
.platformBrightness ==
|
||||||
color: (MediaQuery.of(
|
Brightness.light)
|
||||||
context)
|
? (theme ?? ThemeData())
|
||||||
.platformBrightness ==
|
.colorScheme
|
||||||
Brightness.light)
|
.primary
|
||||||
? (theme ??
|
: (themeDark ?? ThemeData.dark())
|
||||||
ThemeData())
|
.colorScheme
|
||||||
.colorScheme
|
.primary,
|
||||||
.secondary
|
onSelected: (bool selected) {
|
||||||
: (themeDark ??
|
if (addIndex == index) {
|
||||||
ThemeData
|
Navigator.of(context).pop();
|
||||||
.dark())
|
showModalBottomSheet(
|
||||||
.colorScheme
|
context: context,
|
||||||
.secondary)
|
builder: (context) {
|
||||||
: null,
|
return Padding(
|
||||||
selectedColor: (MediaQuery.of(
|
padding:
|
||||||
context)
|
const EdgeInsets
|
||||||
.platformBrightness ==
|
.only(
|
||||||
Brightness.light)
|
left: 16,
|
||||||
? (theme ?? ThemeData())
|
right: 16,
|
||||||
.colorScheme
|
top: 16),
|
||||||
.primary
|
child: Text(
|
||||||
: (themeDark ??
|
AppLocalizations.of(
|
||||||
ThemeData.dark())
|
context)!
|
||||||
.colorScheme
|
.modelDialogAddSteps));
|
||||||
.primary,
|
});
|
||||||
onSelected: (bool selected) {
|
}
|
||||||
if (!chatAllowed) return;
|
if (!chatAllowed) return;
|
||||||
setLocalState(() {
|
setLocalState(() {
|
||||||
usedIndex =
|
usedIndex = selected ? index : -1;
|
||||||
selected ? index : -1;
|
});
|
||||||
});
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
).toList(),
|
);
|
||||||
))))
|
},
|
||||||
|
).toList(),
|
||||||
|
)))
|
||||||
])));
|
])));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|