whisper_flutter_new 1.0.1 whisper_flutter_new: ^1.0.1 copied to clipboard
Use whisper.cpp models implementation for Android and iOS
/*
* Copyright (c) 田梓萱[小草林] 2021-2024.
* All Rights Reserved.
* All codes are protected by China's regulations on the protection of computer software, and infringement must be investigated.
* 版权所有 (c) 田梓萱[小草林] 2021-2024.
* 所有代码均受中国《计算机软件保护条例》保护,侵权必究.
*/
import "dart:io";
import "package:flutter/material.dart";
import "package:flutter/services.dart";
import "package:flutter_riverpod/flutter_riverpod.dart";
import "package:path_provider/path_provider.dart";
import "package:test_whisper/providers.dart";
import "package:test_whisper/record_page.dart";
import "package:test_whisper/whisper_controller.dart";
import "package:test_whisper/whisper_result.dart";
import "package:whisper_flutter_new/whisper_flutter_new.dart";
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return ProviderScope(
child: MaterialApp(
title: "Whisper for Flutter",
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: Theme.of(context).colorScheme.primary),
useMaterial3: true,
),
home: const MyHomePage(),
),
);
}
}
class MyHomePage extends ConsumerWidget {
const MyHomePage({
super.key,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final WhisperModel model = ref.watch(modelProvider);
final String lang = ref.watch(langProvider);
final bool translate = ref.watch(translateProvider);
final bool withSegments = ref.watch(withSegmentsProvider);
final bool splitWords = ref.watch(splitWordsProvider);
final WhisperController controller = ref.watch(
whisperControllerProvider.notifier,
);
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text(
"Whisper flutter demo",
),
),
body: SafeArea(
minimum: const EdgeInsets.all(20),
child: SingleChildScrollView(child: Consumer(
builder: (context, ref, _) {
final AsyncValue<TranscribeResult?> transcriptionAsync = ref.watch(
whisperControllerProvider,
);
return transcriptionAsync.maybeWhen(
skipLoadingOnRefresh: true,
skipLoadingOnReload: true,
data: (TranscribeResult? transcriptionResult) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
const Text("Model :"),
DropdownButton(
isExpanded: true,
value: model,
items: WhisperModel.values
.map(
(WhisperModel model) => DropdownMenuItem(
value: model,
child: Text(model.modelName),
),
)
.toList(),
onChanged: (WhisperModel? model) {
if (model != null) {
ref.read(modelProvider.notifier).state = model;
}
},
),
const SizedBox(height: 20),
const Text("Lang :"),
DropdownButton(
isExpanded: true,
value: lang,
items: ["auto", "zh", "en"]
.map(
(String lang) => DropdownMenuItem(
value: lang,
child: Text(lang),
),
)
.toList(),
onChanged: (String? lang) {
if (lang != null) {
ref.read(langProvider.notifier).state = lang;
}
},
),
const SizedBox(height: 20),
const Text("Translate result :"),
DropdownButton(
isExpanded: true,
value: translate,
items: const [
DropdownMenuItem(
value: false,
child: Text("No"),
),
DropdownMenuItem(
value: true,
child: Text("Yes"),
),
],
onChanged: (bool? translate) {
if (translate != null) {
ref.read(translateProvider.notifier).state =
translate;
}
},
),
const Text("With segments :"),
DropdownButton(
isExpanded: true,
value: withSegments,
items: const [
DropdownMenuItem(
value: false,
child: Text("No"),
),
DropdownMenuItem(
value: true,
child: Text("Yes"),
),
],
onChanged: (bool? withSegments) {
if (withSegments != null) {
ref.read(withSegmentsProvider.notifier).state =
withSegments;
}
},
),
const Text("Split word :"),
DropdownButton(
isExpanded: true,
value: splitWords,
items: const [
DropdownMenuItem(
value: false,
child: Text("No"),
),
DropdownMenuItem(
value: true,
child: Text("Yes"),
),
],
onChanged: (bool? splitWords) {
if (splitWords != null) {
ref.read(splitWordsProvider.notifier).state =
splitWords;
}
},
),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
ElevatedButton(
onPressed: () async {
final Directory documentDirectory =
await getApplicationDocumentsDirectory();
final ByteData documentBytes =
await rootBundle.load(
"assets/jfk.wav",
);
final String jfkPath =
"${documentDirectory.path}/jfk.wav";
await File(jfkPath).writeAsBytes(
documentBytes.buffer.asUint8List(),
);
await controller.transcribe(jfkPath);
},
child: const Text("jfk.wav"),
),
const SizedBox(width: 20),
ElevatedButton(
onPressed: () async {
final String? recordFilePath =
await RecordPage.openRecordPage(
context,
);
if (recordFilePath != null) {
await controller.transcribe(recordFilePath);
}
},
child: const Text("record"),
),
],
),
if (transcriptionResult != null) ...[
const SizedBox(height: 20),
Text(
transcriptionResult.transcription.text,
),
const SizedBox(height: 20),
Text(
transcriptionResult.time.toString(),
),
if (transcriptionResult.transcription.segments !=
null) ...[
const SizedBox(height: 25),
Expanded(
child: ListView.separated(
itemCount: transcriptionResult
.transcription.segments!.length,
itemBuilder: (context, index) {
final WhisperTranscribeSegment segment =
transcriptionResult
.transcription.segments![index];
final Duration fromTs = segment.fromTs;
final Duration toTs = segment.toTs;
final String text = segment.text;
return Text(
"[$fromTs - $toTs] $text",
);
},
separatorBuilder: (context, index) {
return const Divider();
},
),
),
const SizedBox(height: 30),
],
],
],
);
},
orElse: () {
return const Center(
child: CircularProgressIndicator(),
);
},
);
},
)),
),
);
}
}