diff --git a/lib/config.dart b/lib/config.dart new file mode 100644 index 0000000..79956bf --- /dev/null +++ b/lib/config.dart @@ -0,0 +1,6 @@ +const String model = 'assets/datasets/model.tflite'; +const String label = 'assets/datasets/label.txt'; +const String inputType = 'decodedWav'; +const int sampleRate = 16000; +const int recordingLength = 16000; +const int bufferSize = 2000; \ No newline at end of file diff --git a/lib/view/screens/content.dart b/lib/view/screens/content.dart index 9f8d6dc..dc66645 100644 --- a/lib/view/screens/content.dart +++ b/lib/view/screens/content.dart @@ -1,8 +1,14 @@ -import 'package:easy_learn/view/widgets/list_contents_box.dart'; -import 'package:easy_learn/view/widgets/score_board.dart'; +import 'dart:async'; +import 'dart:developer'; + +import 'package:tflite_audio/tflite_audio.dart'; import 'package:flutter/material.dart'; import 'package:easy_learn/view/widgets/custom_button.dart'; +import 'package:easy_learn/view/widgets/score_board.dart'; +import 'package:easy_learn/view/widgets/list_contents_box.dart'; +import 'package:easy_learn/config.dart' show model, label, inputType, sampleRate, recordingLength, bufferSize; + class Content extends StatefulWidget { const Content({Key? key, required this.category}) : super(key: key); @@ -14,64 +20,126 @@ class Content extends StatefulWidget { } class _ContentState extends State { + final isRecording = ValueNotifier(false); + Stream>? result; + + @override + void initState() { + super.initState(); + TfliteAudio.loadModel( + // numThreads: this.numThreads, + // isAsset: this.isAsset, + model: model, + label: label, + ); + } + + void getResult() { + result = TfliteAudio.startAudioRecognition( + inputType: inputType, + sampleRate: sampleRate, + recordingLength: recordingLength, + bufferSize: bufferSize, + ); + + result ?.listen( + (event) => log(event.toString()) + ).onDone(() => isRecording.value = false); + } + + String showResult(AsyncSnapshot snapshot, String key) => snapshot.hasData ? snapshot.data[key].toString() : 'null '; + @override Widget build(BuildContext context) { return Scaffold( - body: Container( - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage('assets/images/content_bg.png'), - fit: BoxFit.cover - ) - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + body: StreamBuilder>( + stream: result, + builder: (BuildContext context, AsyncSnapshot> snapshot) { + dynamic scoreBoard; + + switch (snapshot.connectionState) { + case ConnectionState.none: + scoreBoard = const ScoreBoard(score: "-",); + break; + case ConnectionState.waiting: + scoreBoard = const ScoreBoard(score: "-",); + break; + default: + scoreBoard = ScoreBoard(score: showResult(snapshot, 'recognitionResult'),); + } + return Container( + decoration: const BoxDecoration( + image: DecorationImage( + image: AssetImage('assets/images/content_bg.png'), + fit: BoxFit.cover + ) + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ - Container( - margin: const EdgeInsets.only(left: 10.0, bottom: 60.0), - child: CustomButton(name: 'close', size: 60.0, navigator: () { - Navigator.pop(context); - },) + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Container( + margin: const EdgeInsets.only(left: 10.0, bottom: 60.0), + child: CustomButton(name: 'close', size: 60.0, navigator: () { + Navigator.pop(context); + },) + ), + scoreBoard, + Container( + margin: const EdgeInsets.only(right: 10.0, bottom: 60.0), + child: CustomButton(name: 'sound', size: 60.0, navigator: () {},) + ), + ], ), - const ScoreBoard(), - Container( - margin: const EdgeInsets.only(right: 10.0, bottom: 60.0), - child: CustomButton(name: 'sound', size: 60.0, navigator: () {},) + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Container( + margin: const EdgeInsets.only(left: 5.0), + child: CustomButton(name: 'previous', size: 100.0, navigator: () {},) + ), + const SizedBox( + width: 180, + height: 180, + child: ListContentsBox( + imagePath: 'assets/images/list_contents_animals.png', + title: 'Animals' + ), + ), + Container( + margin: const EdgeInsets.only(right: 5.0), + child: CustomButton(name: 'next', size: 100.0, navigator: () {}) + ) + ], + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ValueListenableBuilder( + valueListenable: isRecording, + builder: (context, value, widget) { + if (value == false) { + return CustomButton(name: 'microphone', size: 190.0, navigator: () { + isRecording.value = true; + setState(() { + getResult(); + }); + }); + } else { + return CustomButton(name: 'microphone', size: 190.0, navigator: () { + TfliteAudio.stopAudioRecognition(); + }); + } + } + ) + ], ), ], ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Container( - margin: const EdgeInsets.only(left: 5.0), - child: CustomButton(name: 'previous', size: 100.0, navigator: () {},) - ), - const SizedBox( - width: 180, - height: 180, - child: ListContentsBox( - imagePath: 'assets/images/list_contents_animals.png', - title: 'Animals' - ), - ), - Container( - margin: const EdgeInsets.only(right: 5.0), - child: CustomButton(name: 'next', size: 100.0, navigator: () {}) - ) - ], - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - CustomButton(name: 'microphone', size: 190.0, navigator: () {},) - ], - ), - ], - ), + ); + } ), ); }