Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature addtion #632 #636

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,20 @@ void main() async {
await Babylon.init();

MaidProperties props = await MaidProperties.last;
final settingsService = AppSettingsService();
await settingsService.init();

runApp(
MaidApp(
props: props
)
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => AppPreferences()),
ChangeNotifierProvider(create: (_) => CharacterProvider()),
ChangeNotifierProvider(create: (_) => ModelProvider()),
],
child: const MaidApp(
props: props
),
),
);
}

Expand Down
42 changes: 42 additions & 0 deletions lib/providers/app_preferences.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import 'package:shared_preferences/shared_preferences.dart';

class AppPreferences extends ChangeNotifier {
final AppSettingsService _settingsService = AppSettingsService();

// Load saved settings on initialization
Future<void> loadSavedSettings() async {
final selectedModel = _settingsService.getSelectedModel();
final modelParameters = _settingsService.getModelParameters();
final selectedCharacter = _settingsService.getSelectedCharacter();
final characterSettings = _settingsService.getCharacterSettings();

if (selectedModel != null) {
// Apply saved model selection
currentModel = selectedModel;
}

if (modelParameters != null) {
// Apply saved model parameters
applyModelParameters(modelParameters);
}

// ... apply other settings as needed ...

notifyListeners();
}

// Save settings when they change
Future<void> updateModelSelection(String modelId) async {
await _settingsService.saveSelectedModel(modelId);
currentModel = modelId;
notifyListeners();
}

Future<void> updateModelParameters(Map<String, dynamic> parameters) async {
await _settingsService.saveModelParameters(parameters);
// Apply parameters
notifyListeners();
}

// ... other methods ...
}
118 changes: 118 additions & 0 deletions lib/services/app_settings_service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';

class AppSettingsService {
static const String _selectedCharacterKey = 'selected_character';
static const String _selectedModelKey = 'selected_model';
static const String _modelParametersKey = 'model_parameters';
static const String _characterSettingsKey = 'character_settings';

// Singleton instance
static final AppSettingsService _instance = AppSettingsService._internal();
factory AppSettingsService() => _instance;
AppSettingsService._internal();

late SharedPreferences _prefs;

Future<void> init() async {
_prefs = await SharedPreferences.getInstance();
}

// Save methods
Future<void> saveSelectedCharacter(String characterId) async {
await _prefs.setString(_selectedCharacterKey, characterId);
}

Future<void> saveSelectedModel(String modelId) async {
await _prefs.setString(_selectedModelKey, modelId);
}

Future<void> saveModelParameters(Map<String, dynamic> parameters) async {
await _prefs.setString(_modelParametersKey, jsonEncode(parameters));
}

Future<void> saveCharacterSettings(Map<String, dynamic> settings) async {
await _prefs.setString(_characterSettingsKey, jsonEncode(settings));
}

// Load methods
String? getSelectedCharacter() {
return _prefs.getString(_selectedCharacterKey);
}

String? getSelectedModel() {
return _prefs.getString(_selectedModelKey);
}

Map<String, dynamic>? getModelParameters() {
final String? data = _prefs.getString(_modelParametersKey);
if (data == null) return null;
return jsonDecode(data) as Map<String, dynamic>;
}

Map<String, dynamic>? getCharacterSettings() {
final String? data = _prefs.getString(_characterSettingsKey);
if (data == null) return null;
return jsonDecode(data) as Map<String, dynamic>;
}

// Clear methods
Future<void> clearAllSettings() async {
await _prefs.clear();
}

// Model-specific keys
static const String _modelTemperatureKey = 'model_temperature';
static const String _modelMaxTokensKey = 'model_max_tokens';
static const String _modelTopPKey = 'model_top_p';
static const String _modelTopKKey = 'model_top_k';
static const String _modelContextLengthKey = 'model_context_length';

Future<void> saveModelSettings({
required String modelId,
required double temperature,
required int maxTokens,
required double topP,
required int topK,
required int contextLength,
}) async {
await _prefs.setString(_selectedModelKey, modelId);
await _prefs.setDouble(_modelTemperatureKey, temperature);
await _prefs.setInt(_modelMaxTokensKey, maxTokens);
await _prefs.setDouble(_modelTopPKey, topP);
await _prefs.setInt(_modelTopKKey, topK);
await _prefs.setInt(_modelContextLengthKey, contextLength);
}

ModelSettings? getModelSettings() {
final modelId = _prefs.getString(_selectedModelKey);
if (modelId == null) return null;

return ModelSettings(
modelId: modelId,
temperature: _prefs.getDouble(_modelTemperatureKey) ?? 0.7,
maxTokens: _prefs.getInt(_modelMaxTokensKey) ?? 2048,
topP: _prefs.getDouble(_modelTopPKey) ?? 0.9,
topK: _prefs.getInt(_modelTopKKey) ?? 40,
contextLength: _prefs.getInt(_modelContextLengthKey) ?? 4096,
);
}
}

class ModelSettings {
final String modelId;
final double temperature;
final int maxTokens;
final double topP;
final int topK;
final int contextLength;

ModelSettings({
required this.modelId,
required this.temperature,
required this.maxTokens,
required this.topP,
required this.topK,
required this.contextLength,
});
}
117 changes: 85 additions & 32 deletions lib/ui/mobile/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,46 +12,99 @@ import 'package:maid/ui/mobile/pages/model_settings/ollama_page.dart';
import 'package:maid/ui/mobile/pages/model_settings/open_ai_page.dart';
import 'package:maid/ui/mobile/pages/settings_page.dart';
import 'package:provider/provider.dart';
import 'package:your_app/services/app_settings_service.dart';
import 'package:your_app/models/model_provider.dart';
import 'package:your_app/models/character_provider.dart';

/// The [MobileApp] class represents the main application widget for the mobile platforms.
/// It is a stateless widget that builds the user interface based on the consumed [AppPreferences].
class MobileApp extends StatelessWidget {
/// It is a stateful widget that builds the user interface based on the consumed [AppPreferences].
class MobileApp extends StatefulWidget {
const MobileApp({super.key});

@override
Widget build(BuildContext context) {
return Consumer<AppPreferences>(
builder: appBuilder
);
State<MobileApp> createState() => _MobileAppState();
}

class _MobileAppState extends State<MobileApp> {
final AppSettingsService _settings = AppSettingsService();
bool _isLoading = true;

@override
void initState() {
super.initState();
_loadAllSettings();
}

/// Builds the root widget for the Maid mobile app.
///
/// This function takes in the [context], [appPreferences], and [child] parameters
/// and returns a [MaterialApp] widget that serves as the root of the app.
/// The [MaterialApp] widget is configured with various properties such as the app title,
/// theme, initial route, and route mappings.
/// The [home] property is set to [MobileHomePage], which serves as the default landing page.
Widget appBuilder(BuildContext context, AppPreferences appPreferences, Widget? child) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Maid',
theme: Themes.lightTheme(),
darkTheme: Themes.darkTheme(),
themeMode: appPreferences.themeMode,
initialRoute: '/',
routes: {
'/character': (context) => const CharacterCustomizationPage(),
'/characters': (context) => const CharacterBrowserPage(),
'/llamacpp': (context) => const LlamaCppPage(),
'/ollama': (context) => const OllamaPage(),
'/openai': (context) => const OpenAiPage(),
'/mistralai': (context) => const MistralAiPage(),
'/gemini': (context) => const GoogleGeminiPage(),
'/settings': (context) => const SettingsPage(),
'/about': (context) => const AboutPage(),
Future<void> _loadAllSettings() async {
try {
// Load model settings
final modelSettings = _settings.getModelSettings();
final characterId = _settings.getSelectedCharacter();

if (mounted) {
// Apply model settings
if (modelSettings != null) {
final modelProvider = context.read<ModelProvider>();
await modelProvider.setModel(modelSettings.modelId);
modelProvider.updateParameters(
temperature: modelSettings.temperature,
maxTokens: modelSettings.maxTokens,
topP: modelSettings.topP,
topK: modelSettings.topK,
contextLength: modelSettings.contextLength,
);
}

// Apply character settings
if (characterId != null) {
await context.read<CharacterProvider>().selectCharacter(characterId);
}
}
} catch (e) {
debugPrint('Error loading settings: $e');
} finally {
if (mounted) {
setState(() => _isLoading = false);
}
}
}

@override
Widget build(BuildContext context) {
return Consumer<AppPreferences>(
builder: (context, appPreferences, child) {
if (_isLoading) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
),
);
}

return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Maid',
theme: Themes.lightTheme(),
darkTheme: Themes.darkTheme(),
themeMode: appPreferences.themeMode,
initialRoute: '/',
routes: {
'/character': (context) => const CharacterCustomizationPage(),
'/characters': (context) => const CharacterBrowserPage(),
'/llamacpp': (context) => const LlamaCppPage(),
'/ollama': (context) => const OllamaPage(),
'/openai': (context) => const OpenAiPage(),
'/mistralai': (context) => const MistralAiPage(),
'/gemini': (context) => const GoogleGeminiPage(),
'/settings': (context) => const SettingsPage(),
'/about': (context) => const AboutPage(),
},
home: const MobileHomePage()
);
},
home: const MobileHomePage()
);
}
}
32 changes: 32 additions & 0 deletions lib/ui/shared/screens/home_screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:your_app/ui/shared/widgets/settings_drawer.dart';
import 'package:your_app/ui/shared/screens/chat_view.dart';

class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
final modelProvider = context.watch<ModelProvider>();
final characterProvider = context.watch<CharacterProvider>();

return Scaffold(
appBar: AppBar(
title: Text(characterProvider.selectedCharacter?.name ?? 'Maid'),
actions: [
// Model indicator
Padding(
padding: const EdgeInsets.all(8.0),
child: Chip(
label: Text(modelProvider.currentModel?.name ?? 'No Model'),
avatar: const Icon(Icons.memory),
),
),
],
),
body: const ChatView(),
drawer: SettingsDrawer(),
);
}
}
Loading