Skip to content

Commit

Permalink
Create Market page for downloading models and update DB SQL schema
Browse files Browse the repository at this point in the history
  • Loading branch information
WilliamKarolDiCioccio committed Sep 30, 2024
1 parent bd1cb43 commit 92b83aa
Show file tree
Hide file tree
Showing 16 changed files with 819 additions and 168 deletions.
42 changes: 21 additions & 21 deletions app/assets/l10n/intl_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,10 @@
"dashboardAboutButton": "About",
"dashboardChatButton": "Chat",
"dashboardHomeButton": "Home",
"dashboardModelsButton": "Models",
"dashboardInventoryButton": "Inventory",
"dashboardMarketButton": "Market",
"dashboardSessionsButton": "Sessions",
"dashboardSettingsButton": "Settings",
"dashboardTuningButton": "Tuning",
"devicePluggedInSnackBar": "Device plugged in. Power delivery increased.",
"deviceUnpluggedSnackBar": "Device unplugged. Power delivery reduced.",
"dialogAttachButton": "Attach",
Expand Down Expand Up @@ -124,6 +124,24 @@
"folderCreatedSnackBar": "Folder created",
"frequencyPenalty": "Frequency Penalty",
"importModelDialogTitle": "Import model",
"inventoryPageCreateButton": "Create",
"inventoryPageDeleteButton": "Delete model",
"inventoryPageDeleteDialogText": "This will delete {modelName}. Do you confirm?",
"@inventoryPageDeleteDialogText": {
"placeholders": {
"modelName": {
"type": "String"
}
}
},
"inventoryPageDeleteDialogTitle": "Delete model",
"inventoryPageDetailsButton": "View model details",
"inventoryPageImportButton": "Import",
"inventoryPagePullButton": "Pull",
"inventoryPagePushButton": "Push",
"inventoryPageRefreshButton": "Refresh",
"inventoryPageSettingsButton": "Open model settings",
"inventoryPageTitle": "Inventory",
"keepAlive": "Keep Alive",
"licenseButton": "License",
"listFiltersSortByLabel": "Sort by",
Expand Down Expand Up @@ -231,24 +249,6 @@
}
}
},
"modelsPageCreateButton": "Create",
"modelsPageDeleteButton": "Delete model",
"modelsPageDeleteDialogText": "This will delete {modelName}. Do you confirm?",
"@modelsPageDeleteDialogText": {
"placeholders": {
"modelName": {
"type": "String"
}
}
},
"modelsPageDeleteDialogTitle": "Delete model",
"modelsPageDetailsButton": "View model details",
"modelsPageImportButton": "Import",
"modelsPagePullButton": "Pull",
"modelsPagePushButton": "Push",
"modelsPageRefreshButton": "Refresh",
"modelsPageSettingsButton": "Open model settings",
"modelsPageTitle": "Models management",
"modifiedAtTextShared": "Modified at: {modifiedAt}",
"moreOptionsButton": "More options",
"noModelsAvailableSnackBar": "No models available",
Expand Down Expand Up @@ -301,7 +301,7 @@
}
}
},
"pullModelDialogGuideText": "Please type the name of the model to pull:",
"pullModelDialogGuideText": "Please type the release of the model to pull:",
"pullModelDialogModelNameHint": "Type model name...",
"pullModelDialogModelNameLabel": "Model name",
"pullModelDialogTitle": "Pull model",
Expand Down
84 changes: 84 additions & 0 deletions app/lib/backend/private/storage/ollama_models.dart
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,90 @@ class OllamaModelsDB {
return result.map((row) => row).toList();
}

// Get models filtered by name and/or capabilities
List<Map<String, dynamic>> getModelsFiltered({
String? name,
List<String>? capabilities,
double? minSize,
double? maxSize,
}) {
if (_db == null) {
throw Exception("Database not initialized");
}

// Start query with a join between models and releases
String query = '''
SELECT m.*
FROM models m
JOIN releases r ON m.id = r.model_id
WHERE 1=1
''';

final List<Object?> queryParams = [];

// Filter by model name
if (name != null && name.isNotEmpty) {
query += ' AND m.name LIKE ?';
queryParams.add('%$name%');
}

// Filter by capabilities
if (capabilities != null && capabilities.isNotEmpty) {
int capabilitiesMask = 0;

const int visionMask = 1 << 0;
const int toolsMask = 1 << 1;
const int embeddingMask = 1 << 2;
const int codeMask = 1 << 3;

for (String capability in capabilities) {
if (capability == 'vision') {
capabilitiesMask |= visionMask;
} else if (capability == 'tools') {
capabilitiesMask |= toolsMask;
} else if (capability == 'embedding') {
capabilitiesMask |= embeddingMask;
} else if (capability == 'code') {
capabilitiesMask |= codeMask;
}
}

query += ' AND (m.capabilities & ?) = ?';
queryParams.add(capabilitiesMask);
queryParams.add(capabilitiesMask);
}

// Filter by minSize and maxSize of the release
if (minSize != null) {
query += ' AND r.size >= ?';
queryParams.add(minSize);
}

if (maxSize != null) {
query += ' AND r.size <= ?';
queryParams.add(maxSize);
}

// Execute the query and return the result
final result = _db!.select(query, queryParams);

return result.map((row) => row).toList();
}

// Get model releases by model name
List<Map<String, dynamic>> getModelReleases(String name) {
if (_db == null) {
throw Exception("Database not initialized");
}

final result = _db!.select(
'SELECT * FROM releases WHERE model_id = (SELECT id FROM models WHERE name = ?)',
[name],
);

return result.map((row) => row).toList();
}

// Check if a specific model exists in the database by its name
bool isModelInDatabase(String name) {
if (_db == null) {
Expand Down
70 changes: 20 additions & 50 deletions app/lib/frontend/dialogs/create_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,8 @@ class CreateModelDialog extends StatefulWidget {
class _CreateModelDialogState extends State<CreateModelDialog> {
final TextEditingController _nameEditingController = TextEditingController();
final TextEditingController _fileEditingController = TextEditingController();
final TextEditingController _modelSelectionController =
TextEditingController();
final List<DropdownMenuEntry> _modelsMenuEntries = [];
String? _selectedModel;
final List<DropdownMenuItem<String>> _modelsMenuEntries = [];
bool _isCreating = false;
int _stepsCount = 0;
double _progressValue = 0.0;
Expand All @@ -29,21 +28,20 @@ class _CreateModelDialogState extends State<CreateModelDialog> {
void initState() {
super.initState();

for (final model in context.read<OllamaAPIProvider>().models) {
final shortName = model.name.length > 20
? '${model.name.substring(0, 20)}...'
: model.name;

_modelsMenuEntries
.add(DropdownMenuEntry(value: model.name, label: shortName));
}
_modelsMenuEntries.addAll(
context.read<OllamaAPIProvider>().models.map((model) {
return DropdownMenuItem<String>(
value: model.name,
child: Text(model.name),
);
}).toList(),
);
}

@override
void dispose() {
_nameEditingController.dispose();
_fileEditingController.dispose();
_modelSelectionController.dispose();
super.dispose();
}

Expand All @@ -65,21 +63,9 @@ class _CreateModelDialogState extends State<CreateModelDialog> {
void _createModel() async {
setState(() => _isCreating = true);

final splitIndex = _modelSelectionController.text.indexOf(':');
String modelBaseName;

if (splitIndex != -1) {
modelBaseName = _modelSelectionController.text.substring(
0,
splitIndex,
);
} else {
modelBaseName = _modelSelectionController.text;
}

final stream = context.read<OllamaAPIProvider>().create(
_nameEditingController.text.toLowerCase(),
"FROM $modelBaseName\nSYSTEM ${_fileEditingController.text}",
"FROM $_selectedModel\nSYSTEM ${_fileEditingController.text}",
);

await for (final data in stream) {
Expand Down Expand Up @@ -115,31 +101,15 @@ class _CreateModelDialogState extends State<CreateModelDialog> {
AppLocalizations.of(context).createModelDialogGuideText1,
),
const Gap(8.0),
DropdownMenu(
menuHeight: 128,
menuStyle: MenuStyle(
elevation: WidgetStateProperty.all(
8.0,
),
shape: WidgetStateProperty.all(
const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(16.0)),
),
),
),
controller: _modelSelectionController,
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(
borderSide: BorderSide.none,
),
floatingLabelBehavior: FloatingLabelBehavior.never,
),
enableFilter: true,
enableSearch: true,
hintText: AppLocalizations.of(context)
.createModelDialogModelSelectorHint,
dropdownMenuEntries: _modelsMenuEntries,
onSelected: null,
DropdownButton(
value: _selectedModel,
onChanged: (String? value) {
setState(() {
_selectedModel = value;
});
},
items: _modelsMenuEntries,
isExpanded: true,
),
const SizedBox(height: 16.0),
Text(
Expand Down
2 changes: 1 addition & 1 deletion app/lib/frontend/dialogs/import_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ class _ImportModelDialogState extends State<ImportModelDialog> {
TextButton(
onPressed: () => _importModel(),
child: Text(
AppLocalizations.of(context).modelsPageImportButton,
AppLocalizations.of(context).inventoryPageImportButton,
),
),
],
Expand Down
3 changes: 2 additions & 1 deletion app/lib/frontend/dialogs/model_details.dart
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ class ModelDetailsDialog extends StatelessWidget {
),
SelectableText(
AppLocalizations.of(context).modelDetailsParametersSizeText(
model.details.parameterSize),
model.details.parameterSize,
),
),
SelectableText(
AppLocalizations.of(context).modelDetailsQuantizationLevelText(
Expand Down
Loading

0 comments on commit 92b83aa

Please sign in to comment.