123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447 |
- #import "SpeechPlugin.h"
- #import <iflyMSC/iflyMSC.h>
- #import "M4aToPcmHelper.h"
- #import "Mp4ToPcmHelper.h"
- #import "Results/ISEResult.h"
- #import "Results/ISEResultXmlParser.h"
- #import "Results/ISEResultTools.h"
- #import "aiengine.h"
- #import <TAISDK/TAISDK.h>
- #import <TAISDK/TAIOralEvaluation.h>
- @interface SpeechPlugin () <IFlySpeechEvaluatorDelegate, ISEResultXmlParserDelegate,TAIOralEvaluationDelegate>
- @property (nonatomic, strong) IFlySpeechEvaluator *iFlySpeechEvaluator;
- @property (nonatomic, strong) NSNumber *index;
- @property struct aiengine * engine;
- @property (strong, nonatomic) TAIOralEvaluation *oralEvaluation;
- @property (nonatomic) BOOL xunFeiOneVoice;
- @end
- @implementation SpeechPlugin
- + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
- _channel = [FlutterMethodChannel
- methodChannelWithName:@"speech_plugin"
- binaryMessenger:[registrar messenger]];
- SpeechPlugin* instance = [[SpeechPlugin alloc] init];
- [registrar addMethodCallDelegate:instance channel: _channel];
- }
- - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
- if ([@"getPlatformVersion" isEqualToString:call.method]) {
- result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
- } else if ([@"initSpeechSdk" isEqualToString:call.method]) {
- [self iflyInit];
- self.oralEvaluation=[[TAIOralEvaluation alloc]init];
- self.oralEvaluation.delegate=self;
- result(nil);
- } else if ([@"evaluatorByAudio" isEqualToString:call.method]) {
- NSNumber* index = call.arguments[@"index"];
- NSString* recordPath = call.arguments[@"recordPath"];
- NSString* text = call.arguments[@"en"];
- NSString* pathEvaluatorDecode = call.arguments[@"pathEvaluatorDecode"];
- NSString* videoId = call.arguments[@"videoId"];
- NSNumber* evaluatorType = call.arguments[@"evaluatorType"];
- NSNumber* sdkType = call.arguments[@"sdkType"];
-
- [self evaluateVoice:index andPath:recordPath andText:text andIsVideo:false pathEvaluatorDecode:pathEvaluatorDecode videoId:videoId evaluatorType:evaluatorType sdkType:sdkType];
- } else if ([@"evaluatorByMp4" isEqualToString:call.method]) {
- NSNumber* index = call.arguments[@"index"];
- NSString* recordPath = call.arguments[@"recordPath"];
- NSString* text = call.arguments[@"en"];
- NSString* pathEvaluatorDecode = call.arguments[@"pathEvaluatorDecode"];
- NSString* videoId = call.arguments[@"videoId"];
- NSNumber* evaluatorType = call.arguments[@"evaluatorType"];
- NSNumber* sdkType = call.arguments[@"sdkType"];
-
- [self evaluateVoice:index andPath:recordPath andText:text andIsVideo:true
- pathEvaluatorDecode:pathEvaluatorDecode videoId:videoId evaluatorType:evaluatorType sdkType:sdkType];
- } else {
- result(FlutterMethodNotImplemented);
- }
- }
- #pragma mark - Bridge Actions
- - (void)iflyInit {
- [IFlySpeechUtility createUtility:@"appid=5db7af6b"];
- self.iFlySpeechEvaluator = [IFlySpeechEvaluator sharedInstance];
- self.iFlySpeechEvaluator.delegate = self;
- [self configEvaluator];
- }
- - (void)chivosInit:(NSString *)en
- {
- char cfg[4096];
- char version[512] = {0};
- char record_id[64] = {0};
- char param[4096];
- NSString* user_id = @"ios_user";
-
- /*获取当前SDK版本号*/
- aiengine_opt(NULL, AIENGINE_OPT_GET_VERSION, version, sizeof(version));
- NSLog(@"version: %s\n",version);
-
- /*获取证书路径*/
- NSString * provision = [[NSBundle mainBundle] pathForResource:@"aiengine" ofType:@"provision"];
- /*引擎初始化传参设置*/
- NSMutableDictionary *jsonDic = [[NSMutableDictionary alloc] initWithCapacity:10];
- /*授权参数*/
- [jsonDic setValue:@"157775873600002d" forKey:@"appKey"];
- [jsonDic setValue:@"a6c766845f9a83974aed16f103e60621" forKey:@"secretKey"];
- [jsonDic setValue:provision forKey:@"provision"];
- /*日志传参*/
- NSMutableDictionary *logDic = [[NSMutableDictionary alloc] init];
- NSString *logFileName = @"log.txt";
- [logDic setValue:[NSNumber numberWithInt:0] forKey:@"enable"];
- [logDic setValue:logFileName forKey:@"output"];
- /*服务链接参数*/
- NSMutableDictionary *cloudDic = [[NSMutableDictionary alloc] init];
- NSString *serverPath = @"wss://cloud.chivox.com:443";
- [cloudDic setValue:[NSNumber numberWithInt:1] forKey:@"enable"];
- [cloudDic setValue:serverPath forKey:@"server"];
- [cloudDic setValue:[NSNumber numberWithInt:60] forKey:@"serverTimeout"];
- /*初始化传参设置*/
- [jsonDic setValue:logDic forKey:@"prof"];
- [jsonDic setValue:cloudDic forKey:@"cloud"];
- NSString *jsonString;
- jsonString = [self dicToString:jsonDic];
- /*cfg赋值:string转char*/
- strcpy(cfg, [jsonString UTF8String]);
- NSLog(@"cfg: %s\n",cfg);
- /*评分引擎初始化*/
- _engine = aiengine_new(cfg);
- NSLog(@"engine: %p\n", _engine);
- /*引擎启用param传参设置*/
- NSMutableDictionary *paramDic = [[NSMutableDictionary alloc] initWithCapacity:10];
- /*在线离线参数配置(cloud/native)*/
- [paramDic setValue:@"cloud" forKey:@"coreProvideType"];
- /*音量实时返回参数设置(0关/1开)*/
- [paramDic setValue:[NSNumber numberWithInt:0] forKey:@"soundIntensityEnable"];
- /*appUser传参*/
- NSMutableDictionary *appDic = [[NSMutableDictionary alloc] init];
- [appDic setValue:user_id forKey:@"userId"];
- /*audio音频数据传参*/
- NSMutableDictionary *audioDic = [[NSMutableDictionary alloc] init];
- [audioDic setValue:@"m4a" forKey:@"audioType"];//音频编码格式
- [audioDic setValue:[NSNumber numberWithInt:16000] forKey:@"sampleRate"];//音频采样率
- [audioDic setValue:[NSNumber numberWithInt:1] forKey:@"channel"];//单声道设置
- [audioDic setValue:[NSNumber numberWithInt:2] forKey:@"sampleBytes"];//采样字节数(1-单字节-8位,2-双字节-16位)
- /*内核request传参*/
- NSMutableDictionary *requestDic = [[NSMutableDictionary alloc] init];
- //内核类型设置cn.word.raw/cn.sent.raw/cn.pred.raw
- [requestDic setValue:@"en.sent.score" forKey:@"coreType"];
- [requestDic setValue:en forKey:@"refText"];//评测文本
- [requestDic setValue:[NSNumber numberWithInt:100] forKey:@"rank"];//总分分制
- [requestDic setValue:[NSNumber numberWithInt:1] forKey:@"attachAudioUrl"];
- [requestDic setValue:[NSNumber numberWithInt:1] forKey:@"precision"];//段落评分精度设置(0.5/1)
-
- [paramDic setValue:appDic forKey:@"app"];
- [paramDic setValue:audioDic forKey:@"audio"];
- [paramDic setValue:requestDic forKey:@"request"];
-
- NSString *paramString;
- paramString = [self dicToString:paramDic];
- /*cfg赋值:string转char*/
- strcpy(param, [paramString UTF8String]);
- int rv = 0;
- rv = aiengine_start(_engine,param,record_id,(aiengine_callback)_aiengine_callback, (__bridge const void *)(self));
- if (rv) {
- NSLog(@"aiengine_start() failed: %d\n", rv);
- return;
- }
- }
- /*字典转为String*/
- - (NSString *)dicToString: (NSMutableDictionary *) jsonDictionary{
- NSError *error;
- NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonDictionary options:0 error:&error];
- NSString *jsString;
- if (!jsonData) {
- NSLog(@"sorry you get an error:%@",error);
- } else {
- jsString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
- }
- NSLog(@"引擎初始化传参#####:%@",jsString);
- return jsString;
- }
- - (void) configEvaluator {
- [self.iFlySpeechEvaluator setParameter:@"" forKey:[IFlySpeechConstant PARAMS]];
- [self.iFlySpeechEvaluator setParameter:@"read_sentence" forKey:[IFlySpeechConstant ISE_CATEGORY]];
- [self.iFlySpeechEvaluator setParameter:@"en_us" forKey:[IFlySpeechConstant LANGUAGE]];
- [self.iFlySpeechEvaluator setParameter:@"5000" forKey:[IFlySpeechConstant VAD_BOS]];
- [self.iFlySpeechEvaluator setParameter:@"1800" forKey:[IFlySpeechConstant VAD_EOS]];
- [self.iFlySpeechEvaluator setParameter:@"-1" forKey:[IFlySpeechConstant SPEECH_TIMEOUT]];
- [self.iFlySpeechEvaluator setParameter:@"complete" forKey:[IFlySpeechConstant ISE_RESULT_LEVEL]];
- [self.iFlySpeechEvaluator setParameter:@"16000" forKey:[IFlySpeechConstant SAMPLE_RATE]];
- [self.iFlySpeechEvaluator setParameter:@"xml" forKey:[IFlySpeechConstant ISE_RESULT_TYPE]];
- [self.iFlySpeechEvaluator setParameter:@"0" forKey:@"plev"];
- [self.iFlySpeechEvaluator setParameter:@"-1" forKey:@"audio_source"];
- }
- - (void) evaluateVoice: (NSNumber*)index andPath:(NSString*)path andText:(NSString*)text andIsVideo:(BOOL) isVideo pathEvaluatorDecode:(NSString*)pathEvaluatorDecode videoId:(NSString*)videoId evaluatorType:(NSNumber*)evaluatorType sdkType:(NSNumber*)sdkType
- {
- self.index = index;
- if (sdkType.intValue == 0) {
- //调用讯飞解析
- self.xunFeiOneVoice = true;
- [self.iFlySpeechEvaluator setParameter:evaluatorType.stringValue forKey:@"plev"];
- if(isVideo) {
- [Mp4ToPcmHelper Mp4ToPcmWithUrl:[[NSURL alloc] initFileURLWithPath:path] completion:^(NSData *data) {
- if(data == nil) {
- [_channel invokeMethod:@"evaluatorResult" arguments: [NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]];
- return;
- }
- NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
- NSMutableData *buffer= [NSMutableData dataWithData:[text dataUsingEncoding:encoding]];
- [self.iFlySpeechEvaluator startListening:buffer params:nil];
- [self.iFlySpeechEvaluator writeAudio:data];
- [self.iFlySpeechEvaluator stopListening];
- }];
- } else {
- NSData *voiceData = [M4aToPcmHelper M4aToPcmWithUrl:[[NSURL alloc] initFileURLWithPath:path]];
- if(voiceData == nil) {
- [_channel invokeMethod:@"evaluatorResult" arguments: [NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]];
- return;
- }
- NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
- NSMutableData *buffer= [NSMutableData dataWithData:[text dataUsingEncoding:encoding]];
- [self.iFlySpeechEvaluator startListening:buffer params:nil];
- [self.iFlySpeechEvaluator writeAudio:voiceData];
- [self.iFlySpeechEvaluator stopListening];
- }
- }else if(sdkType.intValue == 1){
- //调用池声解析
- [self chivosInit:text];
-
- int bytes = 0;
- char buf[1024]={0};
- FILE *file = NULL;
- const char * audiopath = [path UTF8String];
- file = fopen(audiopath, "rb");//待评分音频地址
- if(!file)
- {
- printf("read file error!\n");
- return;
- }
- // fseek(file, 44, SEEK_SET); //wav音频文件需要跳过头文件信息,其它音频格式不需要
- while ((bytes = (int)fread(buf, 1, 1024, file)))
- {
- aiengine_feed(_engine, buf, bytes);
- }
- aiengine_stop(_engine);
- }else {
- //调用腾讯解析
- TAIOralEvaluationParam *param =[[TAIOralEvaluationParam alloc]init];
- param.sessionId = [[NSUUID UUID]UUIDString];
- param.appId =@"1301049120";
- param.workMode = TAIOralEvaluationWorkMode_Once;
- param.evalMode = TAIOralEvaluationEvalMode_Sentence;
- param.storageMode = TAIOralEvaluationStorageMode_Disable;
- param.serverType = TAIOralEvaluationServerType_English;
- param.scoreCoeff = 1.0;
- param.fileType = TAIOralEvaluationFileType_Wav;
- param.refText = text;
- param.secretId = @"AKIDUf0EEzc8NMpPmu4Po1zhXBZicKp5G7xZ";
- param.secretKey = @"WnsjKaqtgDVbV9cMtABwVptarwpWyBAt";
- TAIOralEvaluationData *data = [[TAIOralEvaluationData alloc] init];
- data.seqId = 1;
- data.bEnd = YES;
- data.audio = [NSData dataWithContentsOfFile:path];
- [self.oralEvaluation oralEvaluation:param data:data callback:^(TAIError *error) {
- //接口调用结果返回
- if(error){
- NSLog(@"调用腾讯失败:code:%ld , msg:%@",(long)error.code ,error.desc);
- }else{
- NSLog(@"调用腾讯成功");
- }
- }];
-
- }
- }
- #pragma mark - iFly delegate
- // 评测结果回调
- - (void)onResults:(NSData *)results isLast:(BOOL)isLast {
- BOOL isSuccess = false;
- if (isLast) {
- if(results) {
- const char* chResult = [results bytes];
- NSString* strResults = nil;
- NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
- strResults = [[NSString alloc] initWithBytes:chResult length:[results length] encoding:encoding];
- if(strResults != nil) {
- ISEResultXmlParser *parser = [ISEResultXmlParser alloc];
- [parser setDelegate:self];
- [parser parserXml:strResults];
- isSuccess = YES;
- }
- }
- }
- if(isSuccess == NO){
- self.xunFeiOneVoice = false;
- [_channel invokeMethod:@"evaluatorResult" arguments: [NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]];
- }
- }
- - (void)onCompleted:(IFlySpeechError *)errorCode {
- if (errorCode.errorCode != 0 || self.xunFeiOneVoice == true) {
- self.xunFeiOneVoice = false;
- [_channel invokeMethod:@"evaluatorResult" arguments: [NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]];
- }
- }
- - (void)onCancel {
- NSLog(@"取消录音");
- }
- - (void)onBeginOfSpeech {
- NSLog(@"开始录音");
- }
- - (void)onEndOfSpeech {
- NSLog(@"停止录音");
- }
- - (void)onVolumeChanged:(int)volume buffer:(NSData *)buffer {
- NSLog(@"音量改变");
- }
- #pragma mark - ISEResultXmlParser delegate
- -(void)onISEResultXmlParser:(NSXMLParser *)parser Error:(NSError*)error {
- if (error.code != 0) {
- [_channel invokeMethod:@"evaluatorResult" arguments: [NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]];
- }
- }
- -(void)onISEResultXmlParserResult:(ISEResult*)result {
- if (result.is_rejected) {
- self.xunFeiOneVoice = false;
- [_channel invokeMethod:@"evaluatorResult" arguments: [NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]];
- } else {
- NSMutableDictionary *dic = [NSMutableDictionary dictionary];
- [dic setValue:self.index forKey:@"index"];
- [dic setValue:@(result.total_score) forKey:@"score"];
- [dic setValue:@(result.accuracy_score) forKey:@"accuracy_score"];
- [dic setValue:@(result.fluency_score) forKey:@"fluency_score"];
- [dic setValue:@(result.integrity_score) forKey:@"integrity_score"];
- NSString* words = [ISEResultTools formatDetailsForLanguageEN: result.sentences];
- [dic setValue:words forKey:@"words"];
- self.xunFeiOneVoice = false;
- [_channel invokeMethod:@"evaluatorResult" arguments: dic];
- }
- }
- #pragma mark - chisheng回掉
- /*评分引擎回调方法*/
- int _aiengine_callback(const void *usrdata, const char *id, int type, const void *message, int size)
- {
- if (type == AIENGINE_MESSAGE_TYPE_JSON) {
- [(__bridge SpeechPlugin *)usrdata performSelectorOnMainThread:@selector(onChiResult:) withObject:[[NSString alloc] initWithUTF8String:(char *)message] waitUntilDone:NO];
- }
-
- return 0;
- }
- //返回的内容
- -(void) onChiResult:(NSString *) result{
- if(result == nil){
- [_channel invokeMethod:@"evaluatorResult" arguments: [NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]];
- return;
- }
- NSLog(@"返回的结果:%@",result);
- NSData *jsonData = [result dataUsingEncoding:NSUTF8StringEncoding];
- NSError *err = nil;
- NSMutableDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&err];
- if(err) {
- NSLog(@"json解析失败:%@",err);
- [_channel invokeMethod:@"evaluatorResult" arguments: [NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]];
- return ;
- }
- NSNumber *score = dic[@"result"][@"overall"];
- NSNumber *integrity = dic[@"result"][@"integrity"];
- NSNumber *accuracy = dic[@"result"][@"accuracy"];
- NSNumber *fluency = dic[@"result"][@"fluency"][@"overall"];
- NSArray<NSDictionary *>* worksList = dic[@"result"][@"details"];
-
- NSMutableDictionary *dict = [NSMutableDictionary dictionary];
- dict[@"index"] = self.index;
- dict[@"score"] = @(score.doubleValue/20);
- dict[@"accuracy_score"] = @(accuracy.doubleValue/20);
- dict[@"fluency_score"] = @(fluency.doubleValue/20);
- dict[@"integrity_score"] = @(integrity.doubleValue/20);
- NSMutableArray<NSDictionary *> * works =[NSMutableArray array];
-
- for (NSDictionary* work in worksList) {
- NSMutableDictionary *workDict = [NSMutableDictionary dictionary];
- workDict[@"score"] = work[@"score"];
- workDict[@"content"] = work[@"char"];
- [works addObject:workDict];
- }
- NSData *data = [NSJSONSerialization dataWithJSONObject:works options:NSJSONWritingPrettyPrinted error:nil];
- NSString *jsonStr = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
- [dict setValue:jsonStr forKey:@"words"];
-
- [_channel invokeMethod:@"evaluatorResult" arguments: dict];
- if (_engine) {
- aiengine_delete(_engine);
- _engine = NULL;
- }
- }
- #pragma mark - 腾讯会掉
- - (void)oralEvaluation:(TAIOralEvaluation *)oralEvaluation onEvaluateData:(TAIOralEvaluationData *)data result:(TAIOralEvaluationRet *)result error:(TAIError *)error {
- //数据和结果回调(只有data.bEnd为YES,result有效)
- if (data.bEnd) {
- float pronFluency = result.pronFluency *5;
- float pronAccuracy = result.pronAccuracy;
- if(pronAccuracy == -1){
- pronAccuracy = 0;
- }else {
- pronAccuracy = pronAccuracy/20;
- }
- float pronCompletion = result.pronCompletion * 5;
-
- float totalScore = (pronFluency + pronAccuracy + pronCompletion)/ 3;
-
- NSMutableArray* workList =[NSMutableArray array];
-
- for (TAIOralEvaluationWord* work in result.words) {
- NSMutableDictionary *dic =[NSMutableDictionary dictionary];
- float score = work.pronAccuracy;
- if(score == -1.0){
- score = 0;
-
- }else{
- score = score/20;
-
- }
- dic[@"score"]= [NSNumber numberWithFloat:score];
- dic[@"content"] = work.word;
- [workList addObject:dic];
- }
- NSMutableDictionary *dict = [NSMutableDictionary dictionary];
- [dict setValue:self.index forKey:@"index"];
- [dict setValue:@(totalScore) forKey:@"score"];
- [dict setValue:@(pronAccuracy) forKey:@"accuracy_score"];
- [dict setValue:@(pronFluency) forKey:@"fluency_score"];
- [dict setValue:@(pronCompletion) forKey:@"integrity_score"];
- NSData *data = [NSJSONSerialization dataWithJSONObject:workList options:NSJSONWritingPrettyPrinted error:nil];
- NSString *jsonStr = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
- [dict setValue:workList forKey:@"words"];
- [_channel invokeMethod:@"evaluatorResult" arguments: dict];
- }else{
- [_channel invokeMethod:@"evaluatorResult" arguments: [NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]];
- }
- }
- @end
|