SpeechPlugin.m 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. #import "SpeechPlugin.h"
  2. #import <iflyMSC/iflyMSC.h>
  3. #import "M4aToPcmHelper.h"
  4. #import "Mp4ToPcmHelper.h"
  5. #import "Results/ISEResult.h"
  6. #import "Results/ISEResultXmlParser.h"
  7. #import "Results/ISEResultTools.h"
  8. #import "aiengine.h"
  9. #import <TAISDK/TAISDK.h>
  10. #import <TAISDK/TAIOralEvaluation.h>
  11. @interface SpeechPlugin () <IFlySpeechEvaluatorDelegate, ISEResultXmlParserDelegate,TAIOralEvaluationDelegate>
  12. @property (nonatomic, strong) IFlySpeechEvaluator *iFlySpeechEvaluator;
  13. @property (nonatomic, strong) NSNumber *index;
  14. @property struct aiengine * engine;
  15. @property (strong, nonatomic) TAIOralEvaluation *oralEvaluation;
  16. @property (nonatomic) BOOL xunFeiOneVoice;
  17. @end
  18. @implementation SpeechPlugin
  19. + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
  20. _channel = [FlutterMethodChannel
  21. methodChannelWithName:@"speech_plugin"
  22. binaryMessenger:[registrar messenger]];
  23. // [IFlySetting setLogFile:LVL_ALL];
  24. SpeechPlugin* instance = [[SpeechPlugin alloc] init];
  25. [registrar addMethodCallDelegate:instance channel: _channel];
  26. }
  27. - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
  28. if ([@"getPlatformVersion" isEqualToString:call.method]) {
  29. result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
  30. } else if ([@"initSpeechSdk" isEqualToString:call.method]) {
  31. [self iflyInit];
  32. self.oralEvaluation=[[TAIOralEvaluation alloc]init];
  33. self.oralEvaluation.delegate=self;
  34. result(nil);
  35. } else if ([@"evaluatorByAudio" isEqualToString:call.method]) {
  36. NSNumber* index = call.arguments[@"index"];
  37. NSString* recordPath = call.arguments[@"recordPath"];
  38. NSString* text = call.arguments[@"en"];
  39. NSString* pathEvaluatorDecode = call.arguments[@"pathEvaluatorDecode"];
  40. NSString* videoId = call.arguments[@"videoId"];
  41. NSNumber* evaluatorType = call.arguments[@"evaluatorType"];
  42. NSNumber* sdkType = call.arguments[@"sdkType"];
  43. [self evaluateVoice:index andPath:recordPath andText:text andIsVideo:false pathEvaluatorDecode:pathEvaluatorDecode videoId:videoId evaluatorType:evaluatorType sdkType:sdkType];
  44. } else if ([@"evaluatorByMp4" isEqualToString:call.method]) {
  45. NSNumber* index = call.arguments[@"index"];
  46. NSString* recordPath = call.arguments[@"recordPath"];
  47. NSString* text = call.arguments[@"en"];
  48. NSString* pathEvaluatorDecode = call.arguments[@"pathEvaluatorDecode"];
  49. NSString* videoId = call.arguments[@"videoId"];
  50. NSNumber* evaluatorType = call.arguments[@"evaluatorType"];
  51. NSNumber* sdkType = call.arguments[@"sdkType"];
  52. [self evaluateVoice:index andPath:recordPath andText:text andIsVideo:true
  53. pathEvaluatorDecode:pathEvaluatorDecode videoId:videoId evaluatorType:evaluatorType sdkType:sdkType];
  54. } else {
  55. result(FlutterMethodNotImplemented);
  56. }
  57. }
  58. #pragma mark - Bridge Actions
  59. - (void)iflyInit {
  60. [IFlySpeechUtility createUtility:@"appid=5db7af6b"];
  61. self.iFlySpeechEvaluator = [IFlySpeechEvaluator sharedInstance];
  62. self.iFlySpeechEvaluator.delegate = self;
  63. [self configEvaluator];
  64. }
  65. - (void)chivosInit:(NSString *)en
  66. {
  67. char cfg[4096];
  68. char version[512] = {0};
  69. char record_id[64] = {0};
  70. char param[4096];
  71. NSString* user_id = @"ios_user";
  72. /*获取当前SDK版本号*/
  73. aiengine_opt(NULL, AIENGINE_OPT_GET_VERSION, version, sizeof(version));
  74. NSLog(@"version: %s\n",version);
  75. /*获取证书路径*/
  76. NSString * provision = [[NSBundle mainBundle] pathForResource:@"aiengine" ofType:@"provision"];
  77. /*引擎初始化传参设置*/
  78. NSMutableDictionary *jsonDic = [[NSMutableDictionary alloc] initWithCapacity:10];
  79. /*授权参数*/
  80. [jsonDic setValue:@"157775873600002d" forKey:@"appKey"];
  81. [jsonDic setValue:@"a6c766845f9a83974aed16f103e60621" forKey:@"secretKey"];
  82. [jsonDic setValue:provision forKey:@"provision"];
  83. /*日志传参*/
  84. NSMutableDictionary *logDic = [[NSMutableDictionary alloc] init];
  85. NSString *logFileName = @"log.txt";
  86. [logDic setValue:[NSNumber numberWithInt:0] forKey:@"enable"];
  87. [logDic setValue:logFileName forKey:@"output"];
  88. /*服务链接参数*/
  89. NSMutableDictionary *cloudDic = [[NSMutableDictionary alloc] init];
  90. NSString *serverPath = @"wss://cloud.chivox.com:443";
  91. [cloudDic setValue:[NSNumber numberWithInt:1] forKey:@"enable"];
  92. [cloudDic setValue:serverPath forKey:@"server"];
  93. [cloudDic setValue:[NSNumber numberWithInt:60] forKey:@"serverTimeout"];
  94. /*初始化传参设置*/
  95. [jsonDic setValue:logDic forKey:@"prof"];
  96. [jsonDic setValue:cloudDic forKey:@"cloud"];
  97. NSString *jsonString;
  98. jsonString = [self dicToString:jsonDic];
  99. /*cfg赋值:string转char*/
  100. strcpy(cfg, [jsonString UTF8String]);
  101. NSLog(@"cfg: %s\n",cfg);
  102. /*评分引擎初始化*/
  103. _engine = aiengine_new(cfg);
  104. NSLog(@"engine: %p\n", _engine);
  105. /*引擎启用param传参设置*/
  106. NSMutableDictionary *paramDic = [[NSMutableDictionary alloc] initWithCapacity:10];
  107. /*在线离线参数配置(cloud/native)*/
  108. [paramDic setValue:@"cloud" forKey:@"coreProvideType"];
  109. /*音量实时返回参数设置(0关/1开)*/
  110. [paramDic setValue:[NSNumber numberWithInt:0] forKey:@"soundIntensityEnable"];
  111. /*appUser传参*/
  112. NSMutableDictionary *appDic = [[NSMutableDictionary alloc] init];
  113. [appDic setValue:user_id forKey:@"userId"];
  114. /*audio音频数据传参*/
  115. NSMutableDictionary *audioDic = [[NSMutableDictionary alloc] init];
  116. [audioDic setValue:@"m4a" forKey:@"audioType"];//音频编码格式
  117. [audioDic setValue:[NSNumber numberWithInt:16000] forKey:@"sampleRate"];//音频采样率
  118. [audioDic setValue:[NSNumber numberWithInt:1] forKey:@"channel"];//单声道设置
  119. [audioDic setValue:[NSNumber numberWithInt:2] forKey:@"sampleBytes"];//采样字节数(1-单字节-8位,2-双字节-16位)
  120. /*内核request传参*/
  121. NSMutableDictionary *requestDic = [[NSMutableDictionary alloc] init];
  122. //内核类型设置cn.word.raw/cn.sent.raw/cn.pred.raw
  123. [requestDic setValue:@"en.sent.score" forKey:@"coreType"];
  124. [requestDic setValue:en forKey:@"refText"];//评测文本
  125. [requestDic setValue:[NSNumber numberWithInt:100] forKey:@"rank"];//总分分制
  126. [requestDic setValue:[NSNumber numberWithInt:1] forKey:@"attachAudioUrl"];
  127. [requestDic setValue:[NSNumber numberWithInt:1] forKey:@"precision"];//段落评分精度设置(0.5/1)
  128. [paramDic setValue:appDic forKey:@"app"];
  129. [paramDic setValue:audioDic forKey:@"audio"];
  130. [paramDic setValue:requestDic forKey:@"request"];
  131. NSString *paramString;
  132. paramString = [self dicToString:paramDic];
  133. /*cfg赋值:string转char*/
  134. strcpy(param, [paramString UTF8String]);
  135. int rv = 0;
  136. rv = aiengine_start(_engine,param,record_id,(aiengine_callback)_aiengine_callback, (__bridge const void *)(self));
  137. if (rv) {
  138. NSLog(@"aiengine_start() failed: %d\n", rv);
  139. return;
  140. }
  141. }
  142. /*字典转为String*/
  143. - (NSString *)dicToString: (NSMutableDictionary *) jsonDictionary{
  144. NSError *error;
  145. NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonDictionary options:0 error:&error];
  146. NSString *jsString;
  147. if (!jsonData) {
  148. NSLog(@"sorry you get an error:%@",error);
  149. } else {
  150. jsString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
  151. }
  152. NSLog(@"引擎初始化传参#####:%@",jsString);
  153. return jsString;
  154. }
  155. - (void)configEvaluator {
  156. [self.iFlySpeechEvaluator setParameter:@"" forKey:[IFlySpeechConstant PARAMS]];
  157. [self.iFlySpeechEvaluator setParameter:@"read_sentence" forKey:[IFlySpeechConstant ISE_CATEGORY]];
  158. [self.iFlySpeechEvaluator setParameter:@"en_us" forKey:[IFlySpeechConstant LANGUAGE]];
  159. [self.iFlySpeechEvaluator setParameter:@"5000" forKey:[IFlySpeechConstant VAD_BOS]];
  160. [self.iFlySpeechEvaluator setParameter:@"1800" forKey:[IFlySpeechConstant VAD_EOS]];
  161. [self.iFlySpeechEvaluator setParameter:@"-1" forKey:[IFlySpeechConstant SPEECH_TIMEOUT]];
  162. [self.iFlySpeechEvaluator setParameter:@"complete" forKey:[IFlySpeechConstant ISE_RESULT_LEVEL]];
  163. [self.iFlySpeechEvaluator setParameter:@"16000" forKey:[IFlySpeechConstant SAMPLE_RATE]];
  164. [self.iFlySpeechEvaluator setParameter:@"xml" forKey:[IFlySpeechConstant ISE_RESULT_TYPE]];
  165. [self.iFlySpeechEvaluator setParameter:@"0" forKey:@"plev"];
  166. [self.iFlySpeechEvaluator setParameter:@"-1" forKey:@"audio_source"];
  167. }
  168. - (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
  169. {
  170. self.index = index;
  171. if (sdkType.intValue == 0) {
  172. //调用讯飞解析
  173. self.xunFeiOneVoice = true;
  174. [self.iFlySpeechEvaluator setParameter:evaluatorType.stringValue forKey:@"plev"];
  175. if(isVideo) {
  176. [Mp4ToPcmHelper Mp4ToPcmWithUrl:[[NSURL alloc] initFileURLWithPath:path] completion:^(NSData *data) {
  177. if(data == nil) {
  178. [_channel invokeMethod:@"evaluatorResult" arguments: [NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]];
  179. return;
  180. }
  181. NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
  182. NSMutableData *buffer= [NSMutableData dataWithData:[text dataUsingEncoding:encoding]];
  183. [self.iFlySpeechEvaluator startListening:buffer params:nil];
  184. [self.iFlySpeechEvaluator writeAudio:data];
  185. [self.iFlySpeechEvaluator stopListening];
  186. }];
  187. } else {
  188. NSURL *voiceUrl = [M4aToPcmHelper M4aToPcmWithUrl:[[NSURL alloc] initFileURLWithPath:path]];
  189. if(voiceUrl == nil) {
  190. NSLog(@"voice url is nil");
  191. [_channel invokeMethod:@"evaluatorResult" arguments: [NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]];
  192. return;
  193. }
  194. NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
  195. NSMutableData *buffer= [NSMutableData dataWithData:[text dataUsingEncoding:encoding]];
  196. [self.iFlySpeechEvaluator startListening:buffer params:nil];
  197. dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  198. NSData *data = [[NSData alloc] initWithContentsOfURL:voiceUrl];
  199. dispatch_async(dispatch_get_main_queue(), ^{
  200. [self.iFlySpeechEvaluator writeAudio:data];
  201. [self.iFlySpeechEvaluator stopListening];
  202. });
  203. });
  204. }
  205. }else if(sdkType.intValue == 1){
  206. //调用池声解析
  207. [self chivosInit:text];
  208. int bytes = 0;
  209. char buf[1024]={0};
  210. FILE *file = NULL;
  211. const char * audiopath = [path UTF8String];
  212. file = fopen(audiopath, "rb");//待评分音频地址
  213. if(!file)
  214. {
  215. printf("read file error!\n");
  216. return;
  217. }
  218. // fseek(file, 44, SEEK_SET); //wav音频文件需要跳过头文件信息,其它音频格式不需要
  219. while ((bytes = (int)fread(buf, 1, 1024, file)))
  220. {
  221. aiengine_feed(_engine, buf, bytes);
  222. }
  223. aiengine_stop(_engine);
  224. }else {
  225. //调用腾讯解析
  226. TAIOralEvaluationParam *param =[[TAIOralEvaluationParam alloc]init];
  227. param.sessionId = [[NSUUID UUID]UUIDString];
  228. param.appId =@"1301049120";
  229. param.workMode = TAIOralEvaluationWorkMode_Once;
  230. param.evalMode = TAIOralEvaluationEvalMode_Sentence;
  231. param.storageMode = TAIOralEvaluationStorageMode_Disable;
  232. param.serverType = TAIOralEvaluationServerType_English;
  233. param.scoreCoeff = 1.0;
  234. param.fileType = TAIOralEvaluationFileType_Wav;
  235. param.refText = text;
  236. param.secretId = @"AKIDUf0EEzc8NMpPmu4Po1zhXBZicKp5G7xZ";
  237. param.secretKey = @"WnsjKaqtgDVbV9cMtABwVptarwpWyBAt";
  238. TAIOralEvaluationData *data = [[TAIOralEvaluationData alloc] init];
  239. data.seqId = 1;
  240. data.bEnd = YES;
  241. data.audio = [NSData dataWithContentsOfFile:path];
  242. [self.oralEvaluation oralEvaluation:param data:data callback:^(TAIError *error) {
  243. //接口调用结果返回
  244. if(error){
  245. NSLog(@"调用腾讯失败:code:%ld , msg:%@",(long)error.code ,error.desc);
  246. }else{
  247. NSLog(@"调用腾讯成功");
  248. }
  249. }];
  250. }
  251. }
  252. #pragma mark - iFly delegate
  253. // 评测结果回调
  254. - (void)onResults:(NSData *)results isLast:(BOOL)isLast {
  255. NSLog(@"onResults");
  256. BOOL isSuccess = false;
  257. if (isLast) {
  258. if(results) {
  259. const char* chResult = [results bytes];
  260. NSString* strResults = nil;
  261. NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000);
  262. strResults = [[NSString alloc] initWithBytes:chResult length:[results length] encoding:encoding];
  263. if(strResults != nil) {
  264. NSLog(@"onResults is success");
  265. ISEResultXmlParser *parser = [ISEResultXmlParser alloc];
  266. [parser setDelegate:self];
  267. [parser parserXml:strResults];
  268. isSuccess = YES;
  269. }
  270. }
  271. }
  272. if(isSuccess == NO){
  273. NSLog(@"onResults is not success");
  274. self.xunFeiOneVoice = false;
  275. [_channel invokeMethod:@"evaluatorResult" arguments: [NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]];
  276. }
  277. }
  278. - (void)onCompleted:(IFlySpeechError *)errorCode {
  279. NSLog(@"onCompleted");
  280. if (errorCode.errorCode != 0 || self.xunFeiOneVoice == true) {
  281. NSLog(@"onCompleted not error code");
  282. self.xunFeiOneVoice = false;
  283. [_channel invokeMethod:@"evaluatorResult" arguments: [NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]];
  284. }
  285. }
  286. - (void)onCancel {
  287. NSLog(@"取消录音");
  288. }
  289. - (void)onBeginOfSpeech {
  290. NSLog(@"开始录音");
  291. }
  292. - (void)onEndOfSpeech {
  293. NSLog(@"停止录音");
  294. }
  295. - (void)onVolumeChanged:(int)volume buffer:(NSData *)buffer {
  296. NSLog(@"音量改变");
  297. }
  298. #pragma mark - ISEResultXmlParser delegate
  299. -(void)onISEResultXmlParser:(NSXMLParser *)parser Error:(NSError*)error {
  300. NSLog(@"onISEResultXmlParser");
  301. if (error.code != 0) {
  302. [_channel invokeMethod:@"evaluatorResult" arguments: [NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]];
  303. }
  304. }
  305. -(void)onISEResultXmlParserResult:(ISEResult*)result {
  306. NSLog(@"onISEResultXmlParserResult");
  307. if (result.is_rejected) {
  308. NSLog(@"onISEResultXmlParserResult reject");
  309. self.xunFeiOneVoice = false;
  310. [_channel invokeMethod:@"evaluatorResult" arguments: [NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]];
  311. } else {
  312. NSLog(@"onISEResultXmlParserResult not reject");
  313. NSMutableDictionary *dic = [NSMutableDictionary dictionary];
  314. [dic setValue:self.index forKey:@"index"];
  315. [dic setValue:@(result.total_score) forKey:@"score"];
  316. [dic setValue:@(result.accuracy_score) forKey:@"accuracy_score"];
  317. [dic setValue:@(result.fluency_score) forKey:@"fluency_score"];
  318. [dic setValue:@(result.integrity_score) forKey:@"integrity_score"];
  319. NSString* words = [ISEResultTools formatDetailsForLanguageEN: result.sentences];
  320. [dic setValue:words forKey:@"words"];
  321. self.xunFeiOneVoice = false;
  322. [_channel invokeMethod:@"evaluatorResult" arguments: dic];
  323. }
  324. }
  325. #pragma mark - chisheng回掉
  326. /*评分引擎回调方法*/
  327. int _aiengine_callback(const void *usrdata, const char *id, int type, const void *message, int size)
  328. {
  329. if (type == AIENGINE_MESSAGE_TYPE_JSON) {
  330. [(__bridge SpeechPlugin *)usrdata performSelectorOnMainThread:@selector(onChiResult:) withObject:[[NSString alloc] initWithUTF8String:(char *)message] waitUntilDone:NO];
  331. }
  332. return 0;
  333. }
  334. //返回的内容
  335. -(void) onChiResult:(NSString *) result{
  336. if(result == nil){
  337. [_channel invokeMethod:@"evaluatorResult" arguments: [NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]];
  338. return;
  339. }
  340. NSLog(@"返回的结果:%@",result);
  341. NSData *jsonData = [result dataUsingEncoding:NSUTF8StringEncoding];
  342. NSError *err = nil;
  343. NSMutableDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&err];
  344. if(err) {
  345. NSLog(@"json解析失败:%@",err);
  346. [_channel invokeMethod:@"evaluatorResult" arguments: [NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]];
  347. return ;
  348. }
  349. NSNumber *score = dic[@"result"][@"overall"];
  350. NSNumber *integrity = dic[@"result"][@"integrity"];
  351. NSNumber *accuracy = dic[@"result"][@"accuracy"];
  352. NSNumber *fluency = dic[@"result"][@"fluency"][@"overall"];
  353. NSArray<NSDictionary *>* worksList = dic[@"result"][@"details"];
  354. NSMutableDictionary *dict = [NSMutableDictionary dictionary];
  355. dict[@"index"] = self.index;
  356. dict[@"score"] = @(score.doubleValue/20);
  357. dict[@"accuracy_score"] = @(accuracy.doubleValue/20);
  358. dict[@"fluency_score"] = @(fluency.doubleValue/20);
  359. dict[@"integrity_score"] = @(integrity.doubleValue/20);
  360. NSMutableArray<NSDictionary *> * works =[NSMutableArray array];
  361. for (NSDictionary* work in worksList) {
  362. NSMutableDictionary *workDict = [NSMutableDictionary dictionary];
  363. workDict[@"score"] = work[@"score"];
  364. workDict[@"content"] = work[@"char"];
  365. [works addObject:workDict];
  366. }
  367. NSData *data = [NSJSONSerialization dataWithJSONObject:works options:NSJSONWritingPrettyPrinted error:nil];
  368. NSString *jsonStr = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
  369. [dict setValue:jsonStr forKey:@"words"];
  370. [_channel invokeMethod:@"evaluatorResult" arguments: dict];
  371. if (_engine) {
  372. aiengine_delete(_engine);
  373. _engine = NULL;
  374. }
  375. }
  376. #pragma mark - 腾讯会掉
  377. - (void)oralEvaluation:(TAIOralEvaluation *)oralEvaluation onEvaluateData:(TAIOralEvaluationData *)data result:(TAIOralEvaluationRet *)result error:(TAIError *)error {
  378. //数据和结果回调(只有data.bEnd为YES,result有效)
  379. if (data.bEnd) {
  380. float pronFluency = result.pronFluency *5;
  381. float pronAccuracy = result.pronAccuracy;
  382. if(pronAccuracy == -1){
  383. pronAccuracy = 0;
  384. }else {
  385. pronAccuracy = pronAccuracy/20;
  386. }
  387. float pronCompletion = result.pronCompletion * 5;
  388. float totalScore = (pronFluency + pronAccuracy + pronCompletion)/ 3;
  389. NSMutableArray* workList =[NSMutableArray array];
  390. for (TAIOralEvaluationWord* work in result.words) {
  391. NSMutableDictionary *dic =[NSMutableDictionary dictionary];
  392. float score = work.pronAccuracy;
  393. if(score == -1.0){
  394. score = 0;
  395. }else{
  396. score = score/20;
  397. }
  398. dic[@"score"]= [NSNumber numberWithFloat:score];
  399. dic[@"content"] = work.word;
  400. [workList addObject:dic];
  401. }
  402. NSMutableDictionary *dict = [NSMutableDictionary dictionary];
  403. [dict setValue:self.index forKey:@"index"];
  404. [dict setValue:@(totalScore) forKey:@"score"];
  405. [dict setValue:@(pronAccuracy) forKey:@"accuracy_score"];
  406. [dict setValue:@(pronFluency) forKey:@"fluency_score"];
  407. [dict setValue:@(pronCompletion) forKey:@"integrity_score"];
  408. NSData *data = [NSJSONSerialization dataWithJSONObject:workList options:NSJSONWritingPrettyPrinted error:nil];
  409. NSString *jsonStr = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
  410. [dict setValue:workList forKey:@"words"];
  411. [_channel invokeMethod:@"evaluatorResult" arguments: dict];
  412. }else{
  413. [_channel invokeMethod:@"evaluatorResult" arguments: [NSDictionary dictionaryWithObjectsAndKeys: self.index, @"index", [NSNull null], @"score", nil]];
  414. }
  415. }
  416. @end