mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-04-20 22:13:48 +00:00
- Introduced translation functionality in chat screen, allowing users to translate messages before sending. - Added MessageTranslationButton to the input bar for enabling/disabling translation. - Implemented translation service to handle incoming and outgoing text translations using llama models. - Enhanced message storage to include original and translated text, language codes, and translation status. - Created UI components for displaying translated messages and managing translation options. - Added translation model management, including downloading and storing models locally. - Updated app settings to manage translation preferences and model selections.
136 lines
4.4 KiB
Dart
136 lines
4.4 KiB
Dart
enum MessageTranslationStatus { none, pending, completed, failed, skipped }
|
|
|
|
extension MessageTranslationStatusValue on MessageTranslationStatus {
|
|
String get value {
|
|
switch (this) {
|
|
case MessageTranslationStatus.pending:
|
|
return 'pending';
|
|
case MessageTranslationStatus.completed:
|
|
return 'completed';
|
|
case MessageTranslationStatus.failed:
|
|
return 'failed';
|
|
case MessageTranslationStatus.skipped:
|
|
return 'skipped';
|
|
case MessageTranslationStatus.none:
|
|
return 'none';
|
|
}
|
|
}
|
|
}
|
|
|
|
MessageTranslationStatus parseMessageTranslationStatus(dynamic value) {
|
|
if (value is! String) {
|
|
return MessageTranslationStatus.none;
|
|
}
|
|
for (final status in MessageTranslationStatus.values) {
|
|
if (status.value == value) {
|
|
return status;
|
|
}
|
|
}
|
|
return MessageTranslationStatus.none;
|
|
}
|
|
|
|
class TranslationModelRecord {
|
|
final String id;
|
|
final String name;
|
|
final String sourceUrl;
|
|
final String localPath;
|
|
final DateTime downloadedAt;
|
|
final int fileSizeBytes;
|
|
|
|
const TranslationModelRecord({
|
|
required this.id,
|
|
required this.name,
|
|
required this.sourceUrl,
|
|
required this.localPath,
|
|
required this.downloadedAt,
|
|
required this.fileSizeBytes,
|
|
});
|
|
|
|
Map<String, dynamic> toJson() {
|
|
return {
|
|
'id': id,
|
|
'name': name,
|
|
'source_url': sourceUrl,
|
|
'local_path': localPath,
|
|
'downloaded_at': downloadedAt.millisecondsSinceEpoch,
|
|
'file_size_bytes': fileSizeBytes,
|
|
};
|
|
}
|
|
|
|
factory TranslationModelRecord.fromJson(Map<String, dynamic> json) {
|
|
return TranslationModelRecord(
|
|
id: json['id'] as String? ?? '',
|
|
name: json['name'] as String? ?? '',
|
|
sourceUrl: json['source_url'] as String? ?? '',
|
|
localPath: json['local_path'] as String? ?? '',
|
|
downloadedAt: DateTime.fromMillisecondsSinceEpoch(
|
|
json['downloaded_at'] as int? ?? 0,
|
|
),
|
|
fileSizeBytes: json['file_size_bytes'] as int? ?? 0,
|
|
);
|
|
}
|
|
}
|
|
|
|
String translationModelFriendlyName(TranslationModelRecord model) {
|
|
switch (model.id) {
|
|
case 'hy-mt1.5-1.8b-q4_k_m':
|
|
return 'Tencent HY-MT 1.5 1.8B Q4_K_M';
|
|
case 'hy-mt1.5-1.8b-q6_k':
|
|
return 'Tencent HY-MT 1.5 1.8B Q6_K';
|
|
default:
|
|
final trimmed = model.name.trim();
|
|
if (trimmed.endsWith('.gguf')) {
|
|
return trimmed.substring(0, trimmed.length - 5);
|
|
}
|
|
return trimmed.isEmpty ? model.id : trimmed;
|
|
}
|
|
}
|
|
|
|
class TranslationLanguageOption {
|
|
final String code;
|
|
final String label;
|
|
|
|
const TranslationLanguageOption({required this.code, required this.label});
|
|
}
|
|
|
|
const List<TranslationLanguageOption> supportedTranslationLanguages = [
|
|
TranslationLanguageOption(code: 'bg', label: 'Bulgarian'),
|
|
TranslationLanguageOption(code: 'de', label: 'German'),
|
|
TranslationLanguageOption(code: 'en', label: 'English'),
|
|
TranslationLanguageOption(code: 'es', label: 'Spanish'),
|
|
TranslationLanguageOption(code: 'fr', label: 'French'),
|
|
TranslationLanguageOption(code: 'hu', label: 'Hungarian'),
|
|
TranslationLanguageOption(code: 'it', label: 'Italian'),
|
|
TranslationLanguageOption(code: 'ja', label: 'Japanese'),
|
|
TranslationLanguageOption(code: 'ko', label: 'Korean'),
|
|
TranslationLanguageOption(code: 'nl', label: 'Dutch'),
|
|
TranslationLanguageOption(code: 'pl', label: 'Polish'),
|
|
TranslationLanguageOption(code: 'pt', label: 'Portuguese'),
|
|
TranslationLanguageOption(code: 'ru', label: 'Russian'),
|
|
TranslationLanguageOption(code: 'sk', label: 'Slovak'),
|
|
TranslationLanguageOption(code: 'sl', label: 'Slovenian'),
|
|
TranslationLanguageOption(code: 'sv', label: 'Swedish'),
|
|
TranslationLanguageOption(code: 'uk', label: 'Ukrainian'),
|
|
TranslationLanguageOption(code: 'zh', label: 'Chinese'),
|
|
];
|
|
|
|
final List<TranslationModelRecord> translationPresetModels = [
|
|
TranslationModelRecord(
|
|
id: 'hy-mt1.5-1.8b-q4_k_m',
|
|
name: 'HY-MT1.5-1.8B-Q4_K_M.gguf',
|
|
sourceUrl:
|
|
'https://huggingface.co/tencent/HY-MT1.5-1.8B-GGUF/resolve/main/HY-MT1.5-1.8B-Q4_K_M.gguf?download=true',
|
|
localPath: '',
|
|
downloadedAt: DateTime.fromMillisecondsSinceEpoch(0),
|
|
fileSizeBytes: 0,
|
|
),
|
|
TranslationModelRecord(
|
|
id: 'hy-mt1.5-1.8b-q6_k',
|
|
name: 'HY-MT1.5-1.8B-Q6_K.gguf',
|
|
sourceUrl:
|
|
'https://huggingface.co/tencent/HY-MT1.5-1.8B-GGUF/resolve/main/HY-MT1.5-1.8B-Q6_K.gguf?download=true',
|
|
localPath: '',
|
|
downloadedAt: DateTime.fromMillisecondsSinceEpoch(0),
|
|
fileSizeBytes: 0,
|
|
),
|
|
];
|