dolphinai_soe_flutter_sdk 1.3.1 copy "dolphinai_soe_flutter_sdk: ^1.3.1" to clipboard
dolphinai_soe_flutter_sdk: ^1.3.1 copied to clipboard

Flutter plugin for dolphinAI.

example/lib/main.dart

import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:logger/logger.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:smart_speech_sdk/smart_speech_sdk.dart';
import 'package:smart_speech_sdk_example/permission_dialog.dart';
import 'package:flutter/services.dart';
import 'custom_text.dart';


/// 客户需要填入从商务得到的appId和appSecret
const appId = "";
const appSecret = "";

class GlobalEngine{
  static const TAG = "system.out";
  static SmartSpeechSdk? _speechEvalSdkPlugin;
  static final logger  = Logger();
  static void loggerd(String msg){
    logger.d(TAG,msg);
  }

  static void loggere(String msg){
    logger.e(TAG,msg);
  }

  static void loggeri(String msg){
    logger.i(TAG,msg);
  }

  static void loggerw(String msg){
    logger.w(TAG,msg);
  }

  static void loggerv(String msg){
    logger.v(TAG,msg);
  }

  static Map getEnData(){
    return {
      "phoneme":"ih",
      "word":"market",
      "sentence":"It's a nice day.",
      "chapter":"We all know that the earth is our home. But today there is more and more pollution and the environment is becoming worse and worse. The river in our city is polluted seriously. The air pollution is serious too. We can see a lot of rubbish wherever we go. To live happily, we should do something to protect our environment. I think we should protect the river from pollution. It's good for us to walk or ride bikes to school instead of taking a car. We'd better save water and paper. We can't throw the rubbish everywhere.",
    };
  }

  static Map getZhData(){
    return {
      "phoneme":"jin1 tian1 tian1 qi4 bu4 cuo4.",
      "word":"天道",
      "sentence":"道可顿悟,行须渐修.",
      "chapter":"第一境界, 昨夜西风凋碧树,独上高楼 望尽天涯路。第二境界,衣带渐宽终不悔,为伊消得人憔悴。第三境界,众里寻他千百度,蓦然回首,那人却在灯火阑珊处。",
    };
  }
}


void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {

  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: HomePage(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('智言语音评测'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children:  [
                HomeButton('英文音标', "phoneme","en"),
                const SizedBox(width: 24.0),
                HomeButton('英文单词', "word","en"),
              ],
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                HomeButton('英文句子', "sentence","en"),
                const SizedBox(width: 24.0),
                HomeButton('英文段落', "chapter","en"),
              ],
            ),

            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                HomeButton('中文拼音', "phoneme","zh"),
                const SizedBox(width: 24.0),
                HomeButton('中文字词', "word","zh"),
              ],
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                HomeButton('中文句子', "sentence","zh"),
                const SizedBox(width: 24.0),
                HomeButton('中文段落', "chapter","zh"),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

class HomeButton extends StatelessWidget {
  final String buttonText;
  final String coreType;
  final String langType;

  HomeButton(this.buttonText,this.coreType, this.langType);

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () {
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (context) => SpeechPage(buttonText: buttonText, coreType: coreType,langType: langType,),
          ),
        );
      },
      child: Text(buttonText),
    );
  }
}


class SpeechPage extends StatefulWidget {

  final String buttonText;
  final String coreType;
  final String langType;

  const SpeechPage({super.key,required this.buttonText,required this.coreType,required this.langType});

  @override
  State<SpeechPage> createState() => _SpeechPageState();
}

class _SpeechPageState extends State<SpeechPage> {

  final TextEditingController _selectionController =  TextEditingController();
  bool editStatus = true;
  String speechText = "good morning";
  String tempEditContent = "";
  String resultData = "{}";
  String overall = "";
  bool isShowResult = false;
  bool isIniited = false;
  bool isSpeeching = false;
  double volume = 0;

  @override
  void initState() {
    super.initState();
    createEngine();
    speechText = (widget.langType == "zh")? GlobalEngine.getZhData()[widget.coreType]:GlobalEngine.getEnData()[widget.coreType];
    _selectionController.text = speechText;
    _selectionController.addListener(() {
      GlobalEngine.loggerd(_selectionController.text);
      tempEditContent = _selectionController.text;
    });
  }


  void _doResult(String result, bool online) {
    setState(() {
      isShowResult = false;
      Map obj = jsonDecode(result);
      num o = obj["overall"];
      String audioUrl = obj["audioUrl"];
      GlobalEngine.loggere("=====audioUrl:$audioUrl");
      overall = o.toStringAsFixed(2);
      resultData = const JsonEncoder.withIndent(' ').convert(obj);
    });
  }

  @override
  void dispose() {
    super.dispose();
    engineDelete();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        backgroundColor: const Color(0xfefefefe),
        resizeToAvoidBottomInset: false,
        appBar: AppBar(
          leading: IconButton(onPressed: ()=>{
            Navigator.of(context).pop("返回")
          }, icon: const Icon(Icons.arrow_back_ios)),
          title: Text(widget.buttonText),
        ),
        body: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          mainAxisAlignment: MainAxisAlignment.start,
          children: [
            Container(
              alignment: Alignment.topCenter,
              width: MediaQuery.of(context).size.width,
              height: 250,
              decoration: BoxDecoration(
                  border: Border.all(color: Colors.blue),
                  color: const Color(0xffffffff)
              ),
              child: _speechContentTextWidget(),
            ),
            Container(
              margin: const EdgeInsets.only(left: 20,right: 20,bottom: 8,top: 20), //容器外补白
              child:  Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  ElevatedButton(
                    child: const Text("开始评测"),
                    onPressed: () {
                      startRecorder(context);
                    },
                  ),
                  ElevatedButton(
                    child: const Text("结束评测"),
                    onPressed: () {
                      stopRecorder();
                    },
                  ),
                  ElevatedButton(
                    child: const Text("取消评测"),
                    onPressed: () {
                      engineCancel();
                    },
                  ),
                ],
              ),
            ),
            Expanded(
              flex: 1,
              child: Container(
                padding: const EdgeInsets.all(8),
                alignment: Alignment.topLeft,
                width: MediaQuery.of(context).size.width,
                color: const Color(0xff555555),
                child: SingleChildScrollView(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children:  [
                      CustomText("音量:$volume",16, color: Colors.white,),
                      CustomText("总分: $overall", 16,color: Colors.white,),
                      const SizedBox(height: 12,),
                      GestureDetector(
                        child: const Text("点击查看完整结果(长按JSON可复制)",
                          style: TextStyle(
                              color: Colors.white,
                              fontSize: 18.0,
                              height: 1.2,
                              fontFamily: "Courier",
                              decoration:TextDecoration.underline,
                              decorationStyle: TextDecorationStyle.dashed
                          ),
                        ),
                        onTap: (){
                          setState(() {
                            isShowResult = !isShowResult;
                          });
                        },
                      ),
                      const SizedBox(height: 12,),
                      _resultDetails()
                    ],
                  ),
                )
              ),
            )
          ],
        ),
      ),
    );
  }



  Widget _resultDetails() {
    if(isShowResult){
      return GestureDetector(
        child: CustomText(resultData, 16,color: Colors.white,),
        onLongPress: () async {
          await Clipboard.setData(ClipboardData(text: resultData));
          Fluttertoast.showToast(msg: "文本已复制");
        },
      );
    }else {
      return Container();
    }
  }

  Widget _speechContentTextWidget() {
    if(editStatus){
      return _getStableContentText();
    }else {
      return _getEditContentText();
    }
  }

  /// 编辑状态下的 评测 widget
  Widget _getStableContentText() {
    return  Container(
      padding: const EdgeInsets.all(4),
      alignment: Alignment.center,
      width: MediaQuery.of(context).size.width,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          Expanded(
            flex: 1,
            child: Text(speechText,
              style: const TextStyle(
                fontSize: 14,
              ),
            ),),

          const SizedBox(
            width: 10,
          ),
          GestureDetector(
            child:Row(
              children: [
                SizedBox(
                  width: 20,
                  height: 20,
                  child: Image.asset("lib/assets/images/ic_edit.png"),
                ),
                const SizedBox(width: 4,),
                const Text("edit",
                    style:TextStyle(
                      fontSize: 16.0,
                    )
                ),
              ],
            ),
            onTap: () {
              if(isSpeeching){
                Fluttertoast.showToast(msg: "评测时不能编辑文本,请先完成评测任务");
                return;
              }
              setState(() {
                tempEditContent = speechText;
                editStatus = false;
              });
            },
          )
        ],
      ),
    );
  }

  /// 编辑状态下的 评测 widget
  Widget _getEditContentText() {
    return  Container(
      padding: const EdgeInsets.all(4),
      alignment: Alignment.center,
      width: MediaQuery.of(context).size.width,
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children:  [
           Expanded(
            flex: 1,
            child: TextField(
              autofocus: true,
              controller: _selectionController,
              maxLines: 10,
              decoration: const InputDecoration(
                border: OutlineInputBorder(),
              ),
            ),
          ),
          const SizedBox(
            width: 10,
          ),
          ElevatedButton(
            child: const Text("保存"),
            onPressed: () {
              setState(() {
                editStatus = true;
                if(tempEditContent.isNotEmpty){
                  speechText = tempEditContent;
                }
              });
            },
          ),
        ],
      ),
    );
  }


  Future<void> createEngine() async {
    Map cfg = {
      "appId": appId,
      "appSecret": appSecret,
      "sampleRate":"16000",
      //
      //  None,  不支持
      //  OralOnLine, 配置在线
      //  OralOffLine, 配置离线
      //  OralTypeMixed;  配置混合模式,有网络时使用在线,无网络或者网络不好时,使用离线
      //
      "en": InitSettingOnline.OralTypeMixed.name,   //英文语种初使化配置,如果没有可以设置为None
      "zh": InitSettingOnline.OralTypeMixed.name,   //中文语种初使化配置,如果没有可以设置为None
      "userId":"111",  //用户的uid ,配置后可通过用户uid
      "serverUrl":"",  //服务器域名,通常不用设置
      "i18n":I18n.ZH.name,  // 国际化提示,默认提示中文
    };

    GlobalEngine.loggerd("=========cfg::::${jsonEncode(cfg)}");
    GlobalEngine._speechEvalSdkPlugin = SmartSpeechSdk();
    GlobalEngine._speechEvalSdkPlugin?.create(jsonEncode(cfg),RecordScoreCallBack(engineInitState: (String code,String msg){
      GlobalEngine.loggere("engineInitState=========:::code:$code===msg:$msg");
      if(code == "00000"){
        isIniited = true;
        //创建引擎成功
        Fluttertoast.showToast(msg: "引擎初使化成功");
      } else {
        // 创建引擎失败
      }
    },onWsStart: (String taskId){
      //在线评测ws建立成功时回调
      GlobalEngine?.loggeri("onWsStart=====taskId:$taskId");
    },onStartRecording: (){
      isSpeeching = true;
      //录音开始回调,不会等ws连接成功
      GlobalEngine?.loggeri("onStartRecording=================");
    },onStopSending: (){
      //录音停止时回调
      GlobalEngine?.loggeri("onStopSending=====");
    },onGetVolume: (double volume){
      setState(() {
        this.volume = volume;
      });
      //实时返回音量信息回调
      GlobalEngine?.loggeri("onGetVolume=====volume:$volume");
    },onSaveAudioFile: (String localPath){
      // 设置 setSaveAudio(true) 时,此方法会回调
      GlobalEngine?.loggeri("onSaveAudioFile=====localPath:$localPath");
    },onWarning: (String taskId,String code,String msg){
      //提醒、警告信息,根据自己业务端需求进行处理
      GlobalEngine?.loggerw("onWarning=====taskId:$taskId==code:$code==msg:$msg");
    },onError: (String taskId,String code,String msg){
      ////评测错误回调
      setState(() {
        volume = 0;
        isSpeeching = false;
      });
      GlobalEngine?.loggere("onError=====taskId:$taskId==code:$code==msg:$msg");
      Fluttertoast.showToast(msg: msg);
    },onRealtimeResult: (String result){
      //realtime设置为true时,中/英文 sentence、chapter、freedom 题型,以及中文 poem、recite 题型 ,
      //会实时返回评测数据
      GlobalEngine?.loggeri("onRealtimeResult=====result:$result");
    },onResult: (String result,bool online){
      setState(() {
        volume = 0;
        isSpeeching = false;
      });
      //评测返回结果回调,online=true为在线返回的结果,false是离线返回的结果
      GlobalEngine?.loggeri("onResult====online:$online=result:$result");
      _doResult(result,online);
    }));
  }

  ///开始录音评测
  void startRecorder(BuildContext context) {
    startBefore(context, () => {
      engineStart()
    }, (always) => {
      Navigator.of(context).pop()
    });
  }

  void engineStart(){
    if(!isIniited){
      Fluttertoast.showToast(msg: "引擎未初使化,请稍候再试~");
      return;
    }
    if(!editStatus){
      Fluttertoast.showToast(msg: "编辑状态时不能调用评测,请先保存!");
      return;
    }
    setState(() {
      isShowResult = false;
      resultData = "{}";
      overall = "";
    });
    if(speechText.isNotEmpty){
      Fluttertoast.showToast(msg: "开始录音");
      GlobalEngine._speechEvalSdkPlugin?.setAudioUrl(true);
      GlobalEngine._speechEvalSdkPlugin?.setSaveAudio(true);
      GlobalEngine._speechEvalSdkPlugin?.setLangType(widget.langType == "en"? LangType.enUS: LangType.zhHans);
      GlobalEngine._speechEvalSdkPlugin?.setOnline(false);
      GlobalEngine._speechEvalSdkPlugin?.setUserId("10002");
      GlobalEngine._speechEvalSdkPlugin?.setConnectTimeout(30);
      GlobalEngine._speechEvalSdkPlugin?.setResponseTimeout(40);
      GlobalEngine._speechEvalSdkPlugin?.setConnti(0);
      GlobalEngine._speechEvalSdkPlugin?.setLooseness(4);
      GlobalEngine._speechEvalSdkPlugin?.setMaxPrefixSilence(0);
      GlobalEngine._speechEvalSdkPlugin?.setMaxSuffixSilence(0);
      GlobalEngine._speechEvalSdkPlugin?.setMini(0);
      GlobalEngine._speechEvalSdkPlugin?.setScale(100);
      GlobalEngine._speechEvalSdkPlugin?.setRealtime(false);
      GlobalEngine._speechEvalSdkPlugin?.setRatio(1.0);
      GlobalEngine._speechEvalSdkPlugin?.setClientData("1111");

      Map paramsJson ={
        "mode": widget.coreType,
        "refText":speechText
      };
      GlobalEngine.loggerd("paramsjson:$paramsJson");
      GlobalEngine._speechEvalSdkPlugin?.setParamsJson(jsonEncode(paramsJson));
      GlobalEngine._speechEvalSdkPlugin?.startRecorder();
    }
  }

  ///停止录音
  void stopRecorder() {
    if(!isIniited){
      Fluttertoast.showToast(msg: "引擎未初使化,请稍候再试~");
      return;
    }
    if(!editStatus){
      Fluttertoast.showToast(msg: "编辑状态时不能调用评测,请先保存!");
      return;
    }
    Fluttertoast.showToast(msg: "结束录音");
    GlobalEngine._speechEvalSdkPlugin?.stop();
  }

  ///取消录音
  void engineCancel() {
    if(!isIniited){
      Fluttertoast.showToast(msg: "引擎未初使化,请稍候再试~");
      return;
    }
    if(!editStatus){
      Fluttertoast.showToast(msg: "编辑状态时不能调用评测,请先保存!");
      return;
    }
    Fluttertoast.showToast(msg: "取消录音");
    GlobalEngine._speechEvalSdkPlugin?.cancel();
  }


  void engineDelete(){
    GlobalEngine._speechEvalSdkPlugin?.destroy();
  }

  void startBefore(BuildContext context,Function() granted, Function(bool always) errorFunc,{Function(bool show)? showP}) {
    showRecordPermissionDialog(context, denied: () {
      errorFunc(false);
    }, permanentlyDenied: () {
      //iOS不会走该回调
      if (Platform.isIOS) {
        errorFunc(false);
      }
      if (Platform.isAndroid) {
        openAppSettings();
      }
    }, granted: () {
      granted();
    }, showPerDialog:(show){
      if(showP!=null) {
        showP(show);
      }
    });
  }
}
0
likes
0
points
21
downloads

Publisher

unverified uploader

Weekly Downloads

Flutter plugin for dolphinAI.

Homepage

License

unknown (license)

Dependencies

flutter, flutter_web_plugins, plugin_platform_interface

More

Packages that depend on dolphinai_soe_flutter_sdk