# 原生整段评测 上传音频与评测参数,返回总分,维度分与逐字逐句详情。 来源:https://open.shengzhiai.com/sdk/v2/api/evaluate/ `POST https://open.shengzhiai.com/api/v1/evaluate` ## 请求示例 cURL: ```bash # 原生整段评测。被签名参数只有 config 段的 JSON 原文 CONFIG='{"coreType":"sentence","referenceText":"今天天气很好","language":"zh-CN"}' TS=$(date +%s) NONCE=$(openssl rand -hex 16) SIGN=$(printf 'config=%s' "$CONFIG" | openssl dgst -sha256 -hmac "$YUGU_SECRET_KEY" -binary | base64) curl -sS https://open.shengzhiai.com/api/v1/evaluate \ -H "X-App-Key: $YUGU_APP_KEY" \ -H "X-Timestamp: $TS" \ -H "X-Nonce: $NONCE" \ -H "X-Signature: $SIGN" \ -H "Idempotency-Key: $(openssl rand -hex 16)" \ -F "audio=@audio.wav" \ -F "config=$CONFIG;type=application/json" ``` Java: ```java try (YuguClient client = YuguClient.builder() .apiKey(System.getenv("YUGU_APP_KEY"), System.getenv("YUGU_SECRET_KEY")) .build()) { EvalResult r = client.evaluate(Path.of("audio.wav"), new EvaluateConfig(EvaluateConfig.CORE_SENTENCE, "今天天气很好", "zh-CN")); System.out.println("总分 " + r.getOverall()); System.out.println("发音 " + r.getDims().getPronunciation()); System.out.println("流利度 " + r.getDims().getFluency()); System.out.println("完整度 " + r.getDims().getIntegrity()); r.getWords().forEach(w -> System.out.println(w.getWord() + " " + w.getScores().getOverall())); } catch (YuguException e) { System.err.println(e.getCategory() + " " + e.getCode() + " " + e.getRawMessage()); } ``` 安卓: ```kotlin thread { val result = client.evaluate( EvaluateConfig(CoreType.SENTENCE, "今天天气很好", Language.ZH_CN), File(filesDir, "sample.wav"), ) Log.i("yugu", "总分 ${result.overall},发音 ${result.dimensions.pronunciation}") } ``` iOS: ```swift client.evaluate(audio: .file(wavURL), config: config) { outcome in switch outcome { case .success(let result): print(result.overall ?? 0) case .failure(let error): print(error.category, error.code, error.message) } } ``` 网页: ```js const audio = await readFile(process.argv[2] || 'hello.wav'); const result = await client.evaluate(audio, { coreType: 'sentence', referenceText: '今天天气很好', language: 'zh-CN', }); console.log('总分', result.overall, '各维度', result.dims); ``` 小程序: ```js async onRecordStop() { const recording = await recorder.stop(); const result = await client.evaluate({ coreType: 'sentence', referenceText: '今天天气很好', language: 'zh-CN', audio: recording, }); console.log('总分', result.overall, '发音', result.dims.pronunciation, '流利', result.dims.fluency); }, ``` ## 返回示例 ```json { "recordId": "eval_a31712f40cbf", "eof": 1, "result": { "paragraphs": [], "kernel_version": "1.0.0", "resource_version": "1.0.0", "overall": 88.9, "pronunciation": 100, "tone": 83, "fluency": 96, "rhythm": 78, "integrity": 100, "speed": 225, "rear_tone": "fall", "duration": "1.920", "numeric_duration": 1.92, "warning": [], "words": [ { "word": "今", "pinyin": "jin", "rawpinyin": "jin1", "symbolpinyin": "jīn", "charType": 0, "readType": 0, "tone": "tone1", "scores": { "overall": 78, "pronunciation": 78, "tone": 100, "overall_pron": 78, "prominence": 0 }, "span": { "start": 15, "end": 31 }, "pause": { "type": 0, "duration": 0 }, "phonemes": [ { "phoneme": "J", "phone": "j", "category": 0, "pronunciation": 78, "tone_index": "0", "span": { "start": 15, "end": 23 } }, { "phoneme": "IN", "phone": "in", "category": 1, "pronunciation": 78, "tone_index": "1", "span": { "start": 23, "end": 31 } } ], "normalized_syllables": [ { "syllables": "今", "pinyin": "jin", "tone": "tone1", "tone_sandhi": "tone1", "phoneme_span": [ 0, 1 ] } ], "word_parts": [ { "part": "今", "charType": 0, "beginIndex": 0, "endIndex": 0 } ], "phonics": [], "linkable": false, "syllables": [], "evidence": { "scored": false, "rms_db": -32.7, "rel_db": -0.5, "dur_ms": 160, "dur_ratio": 0.8, "sfgop": 0.625 }, "readStatus": "correct", "read_status": "correct" }, { "word": "天", "pinyin": "tian", "rawpinyin": "tian1", "symbolpinyin": "tiān", "charType": 0, "readType": 0, "tone": "tone1", "scores": { "overall": 95, "pronunciation": 95, "tone": 100, "overall_pron": 95, "prominence": 0 }, "span": { "start": 31, "end": 57 }, "pause": { "type": 0, "duration": 0 }, "phonemes": [ { "phoneme": "T", "phone": "t", "category": 0, "pronunciation": 95, "tone_index": "0", "span": { "start": 31, "end": 43 } }, { "phoneme": "IAN", "phone": "ian", "category": 1, "pronunciation": 95, "tone_index": "1", "span": { "start": 43, "end": 55 } } ], "normalized_syllables": [ { "syllables": "天", "pinyin": "tian", "tone": "tone1", "tone_sandhi": "tone1", "phoneme_span": [ 0, 1 ] } ], "word_parts": [ { "part": "天", "charType": 0, "beginIndex": 0, "endIndex": 0 } ], "phonics": [], "linkable": false, "syllables": [], "evidence": { "scored": false, "rms_db": -31.8, "rel_db": 0.5, "dur_ms": 240, "dur_ratio": 1.2, "sfgop": 0.917 }, "readStatus": "correct", "read_status": "correct" }, { "word": "天", "pinyin": "tian", "rawpinyin": "tian1", "symbolpinyin": "tiān", "charType": 0, "readType": 0, "tone": "tone1", "scores": { "overall": 85, "pronunciation": 85, "tone": 100, "overall_pron": 85, "prominence": 0 }, "span": { "start": 57, "end": 71 }, "pause": { "type": 0, "duration": 0 }, "phonemes": [ { "phoneme": "T", "phone": "t", "category": 0, "pronunciation": 85, "tone_index": "0", "span": { "start": 57, "end": 64 } }, { "phoneme": "IAN", "phone": "ian", "category": 1, "pronunciation": 85, "tone_index": "1", "span": { "start": 64, "end": 71 } } ], "normalized_syllables": [ { "syllables": "天", "pinyin": "tian", "tone": "tone1", "tone_sandhi": "tone1", "phoneme_span": [ 0, 1 ] } ], "word_parts": [ { "part": "天", "charType": 0, "beginIndex": 0, "endIndex": 0 } ], "phonics": [], "linkable": false, "syllables": [], "evidence": { "scored": false, "rms_db": -34, "rel_db": -1.7, "dur_ms": 140, "dur_ratio": 0.7, "sfgop": 0.75 }, "readStatus": "correct", "read_status": "correct" } ], "sentences": [ { "sentence": "今天天气很好", "index": 0, "scores": { "overall": 89, "pronunciation": 100, "fluency": 96, "integrity": 100 }, "details": [ { "word": "今", "pinyin": "jin", "rawpinyin": "jin1", "symbolpinyin": "jīn", "charType": 0, "readType": 0, "tone": "tone1", "scores": { "overall": 78, "pronunciation": 78, "tone": 100, "overall_pron": 78, "prominence": 0 }, "span": { "start": 15, "end": 31 }, "pause": { "type": 0, "duration": 0 }, "phonemes": [ { "phoneme": "J", "phone": "j", "category": 0, "pronunciation": 78, "tone_index": "0", "span": { "start": 15, "end": 23 } }, { "phoneme": "IN", "phone": "in", "category": 1, "pronunciation": 78, "tone_index": "1", "span": { "start": 23, "end": 31 } } ], "normalized_syllables": [ { "syllables": "今", "pinyin": "jin", "tone": "tone1", "tone_sandhi": "tone1", "phoneme_span": [ 0, 1 ] } ], "word_parts": [ { "part": "今", "charType": 0, "beginIndex": 0, "endIndex": 0 } ], "phonics": [], "linkable": false, "syllables": [] }, { "word": "天", "pinyin": "tian", "rawpinyin": "tian1", "symbolpinyin": "tiān", "charType": 0, "readType": 0, "tone": "tone1", "scores": { "overall": 95, "pronunciation": 95, "tone": 100, "overall_pron": 95, "prominence": 0 }, "span": { "start": 31, "end": 57 }, "pause": { "type": 0, "duration": 0 }, "phonemes": [ { "phoneme": "T", "phone": "t", "category": 0, "pronunciation": 95, "tone_index": "0", "span": { "start": 31, "end": 43 } }, { "phoneme": "IAN", "phone": "ian", "category": 1, "pronunciation": 95, "tone_index": "1", "span": { "start": 43, "end": 55 } } ], "normalized_syllables": [ { "syllables": "天", "pinyin": "tian", "tone": "tone1", "tone_sandhi": "tone1", "phoneme_span": [ 0, 1 ] } ], "word_parts": [ { "part": "天", "charType": 0, "beginIndex": 0, "endIndex": 0 } ], "phonics": [], "linkable": false, "syllables": [] }, { "word": "天", "pinyin": "tian", "rawpinyin": "tian1", "symbolpinyin": "tiān", "charType": 0, "readType": 0, "tone": "tone1", "scores": { "overall": 85, "pronunciation": 85, "tone": 100, "overall_pron": 85, "prominence": 0 }, "span": { "start": 57, "end": 71 }, "pause": { "type": 0, "duration": 0 }, "phonemes": [ { "phoneme": "T", "phone": "t", "category": 0, "pronunciation": 85, "tone_index": "0", "span": { "start": 57, "end": 64 } }, { "phoneme": "IAN", "phone": "ian", "category": 1, "pronunciation": 85, "tone_index": "1", "span": { "start": 64, "end": 71 } } ], "normalized_syllables": [ { "syllables": "天", "pinyin": "tian", "tone": "tone1", "tone_sandhi": "tone1", "phoneme_span": [ 0, 1 ] } ], "word_parts": [ { "part": "天", "charType": 0, "beginIndex": 0, "endIndex": 0 } ], "phonics": [], "linkable": false, "syllables": [] } ] } ], "compositeReport": { "compositeScore": 88.9, "integrityScore": 100, "accuracyScore": 100, "toneVoiceScore": 83, "nasalsScore": 98, "pronunciationScore": 100, "phonemeScore": 100, "fluencyScore": 96, "fluentScore": 96, "readSpeedScore": 85, "readSpeed": 225, "skillScore": 78, "stopConnScore": 85, "stressScore": 32, "intonationScore": 100, "emotionScore": 76, "literalTotal": 89, "toneScore": 100, "completenessScore": 100, "skillSuggest": "重音变化不够明显,关键词应当适度强调(音高提升 / 时长延长 / 加强气流)。", "emotionSuggest": "第三声(上声)调值偏低。练习时走 214 曲线,先降再升。推荐练习『你好/美好/小狗』等词。", "initialScore": 83.5, "finalScore": 83.5 }, "yuguScores": { "overall": 88.9, "integrity": 100, "accuracy": { "overall": 100, "tone": 100, "nasal": 98, "phoneme": 100, "initial": 83.5, "final": 83.5 }, "fluency": { "overall": 96, "speed_score": 85, "naturalness": 100 }, "reading_skill": { "overall": 78, "pause": 85, "stress": 32, "intonation": 100 }, "prosody": 78, "emotion": 76, "tone": 83, "rear_tone": "fall", "speed": 225, "duration_s": 1.92 }, "initialScore": 83.5, "finalScore": 83.5, "nasalsScore": 98, "nasals": 98, "accuracy": 100, "reading_skill": 78, "emotion": 76 }, "report": { "dimensionSuggestions": { "integrity": [], "accuracy": [], "fluency": [], "reading_skill": [ "重音变化不够明显,关键词应当适度强调(音高提升 / 时长延长 / 加强气流)。", "先标出停连位置、句子重音和语调走向,再按标记朗读并回听节奏是否清楚。" ], "emotion": [ "第三声(上声)调值偏低。练习时走 214 曲线,先降再升。推荐练习『你好/美好/小狗』等词。", "先判断语句的情绪基调,选定符合语义的表达方式朗读;录音回听情感是否与内容一致。" ] }, "dimensionScores": { "accuracy": 100, "fluency": 96, "integrity": 100, "reading_skill": 78, "affect": 76, "speechRate": 85, "readSpeedRaw": 225 }, "dimensionEvidence": { "accuracy": [ { "word": "很", "type": "pitchLow", "detail": "声调 1 分(低于 60)" } ], "fluency": [], "integrity": [], "affect": [], "speechRate": [] }, "rubricVersion": "v20260707b", "scores": { "compositeScore": 88.9 }, "dimensions": { "accuracy": "声调:整句调型判定 100 分;其中“很”(字级调型 1 分)的调型与标准读音有偏差,需对照标准音重点纠正,其余字词调型整体稳定。", "reading_skill": "停连、重音、语调和节奏基本可控,细节仍可加强。", "emotion": "情感表达基本到位,语气起伏与文本内容大体匹配,变化幅度还可以更明显。" } }, "standardAudio": {}, "asrText": {}, "warnings": [] } ``` ## 错误示例 ```json { "code": 2003, "message": "签名验证失败", "timestamp": 1791447692272 } ``` ## 请求头 | 请求头 | 类型 | 必填 | 说明 | |---|---|---|---| | `X-App-Key` | string | 否 | appKey,签名鉴权时必填,token 鉴权时不带 | | `X-Timestamp` | string | 否 | 签名鉴权时必填,当前 Unix 时间戳,单位为秒,与服务端相差不超过 300 秒 | | `X-Nonce` | string | 否 | 随机串,服务端 300 秒内去重防重放,建议每次都带 | | `X-Signature` | string | 否 | 签名鉴权时必填,被签名参数为 `config` 段的 JSON 原文,规则见[签名与鉴权](https://open.shengzhiai.com/sdk/v2/api/authentication/) | | `Authorization` | string | 否 | token 鉴权时必填,`Bearer `,代替以上四个请求头 | | `Idempotency-Key` | string | 否 | 幂等键,1 到 200 个可见 ASCII 字符,也认 `X-Idempotency-Key` | ## 请求体 `POST /api/v1/evaluate`,`Content-Type: multipart/form-data`。 | 段 | 类型 | 说明 | |---|---|---| | `audio` | 文件 | wav,mp3,m4a,webm,ogg 等常见格式,建议 16 kHz,16 位,单声道 | | `image` | 文件,可选 | 只在 coreType 为 open,taskType 为 picture 的看图说话时上传 | | `config` | 文本段,`Content-Type: application/json` | 评测配置,字段见下表。缺少 `application/json` 类型时服务端回 415 | | 字段 | 类型 | 必填 | 取值与默认 | |---|---|---|---| | `coreType` | string | 是 | `word`,`sentence`,`passage`,`connected`,`open`,`alpha`,`pinyin` | | `referenceText` | string | 是 | 参考文本,open 时为题目,最长 1000 字 | | `language` | string | 否 | `en-US` 默认,`en-GB`,`zh-CN`。中文评测要显式传 `zh-CN` | | `includeReport` | bool | 否 | 生成 AI 报告,`report` 另含整体点评 `summary` 与改进建议 `suggestions`,默认 false | | `includeStandardAudio` | bool | 否 | 返回标准示范音地址,默认 false | | `includeAsrText` | bool | 否 | 返回识别文本,默认 false | | `slack` | double | 否 | 松紧度,取值 -1 到 1,默认 0 | | `scale` | int | 否 | 分制,取值 1 到 100,默认 100 | | `precision` | double | 否 | 精度,取值大于 0 到 1,默认 1 | | `agegroup` | int | 否 | 1 学前,2 小学,3 中学及以上,默认 3 | | `toneWeight` | double | 否 | 保留参数,取值 0 到 1,不改变总分 | | `refPinyin` | string | 否 | 拼音,多音字与 pinyin 题使用,例如 `chong2 qing4` | | `phonemeOutput` | bool | 否 | 音素级输出 | | `taskType` | string | 否 | open 题型:`picture`,`situational`,`free` | | `paragraphNeedWordScore` | int | 否 | passage 是否返回逐字详分,1 或 0 | ## 返回 成功时直接返回结果对象,不包信封: ```json { "recordId": "eval_xxx", "eof": 1, "result": {"overall": 85, "pronunciation": 88, "tone": 78, "fluency": 90, "rhythm": 82, "integrity": 100, "speed": 135, "rear_tone": "fall", "duration": "4.10", "warning": [], "words": [{"word": "北", "pinyin": "bei", "tone": "tone3", "scores": {"overall": 100, "pronunciation": 100, "tone": 100}, "span": {"start": 120, "end": 280}, "phonemes": [{"phoneme": "B", "pronunciation": 100, "span": {"start": 120, "end": 150}}]}], "sentences": [{"sentence": "北京你好", "index": 0, "scores": {"overall": 85}}]}, "report": {"summary": "...", "dimensions": {}, "suggestions": ["..."]}, "asrText": {"text": "北京你好", "alignment": [{"char": "北", "read_status": "correct"}]}, "standardAudio": {"url": "/audio/standard/xxx.wav", "format": "wav", "duration": "3.50"}, "warnings": [1002] } ``` 时间单位为 10 毫秒。字段 `read_status` 取值 correct,mispronounced,skipped,inserted。各评测模式的取分字段见[评测结果字段](https://open.shengzhiai.com/sdk/v2/api/results/),报告结构化字段沿用 [`1.x` 契约](https://open.shengzhiai.com/sdk/CONTRACT.md)第 7 节,含 `dimensionScores`,`dimensionEvidence`,`asrArbitration`,`rubricBackfilled`,开放题另有 `warning`,`openTaskAudit`,`rubricVersion`。 | 响应头 | 类型 | 必填 | 说明 | |---|---|---|---| | `Idempotency-Replayed` | string | 否 | 值为 `true` 表示这是同一幂等键首次结果的重放,不再计费 | ## 状态码 | 状态 | 错误码 | 原因 | |---|---|---| | 200 | 无 | 评测完成,返回结果对象 | | 400 | 40001,1004,1005,1012,1013,1310,2012 | 参数校验失败,例如音频短于 1 秒,pinyin 题缺 `refPinyin`。用户或账户被禁用,锁定,冻结,余额不足,API Key 配额超限同样回 400 | | 401 | 40100,2001 到 2011 | 未认证,签名错误,token 或 API Key 无效 | | 403 | 40300 | 无权限,例如 API Key 未授权该 coreType | | 409 | 40901,40902,40903 | 同一幂等键处理中,额度不足,幂等键用于不同请求 | | 415 | 无 | `config` 段缺少 `Content-Type: application/json` | | 429 | 42900,42901,42902,42903,3001 到 3003 | 限流,并发超限,试用层 AI 报告或沙箱当日次数用尽,带 `Retry-After` | | 500 | 50000 | 服务器内部错误,可重试 | | 502 | 50200 | 上游评测服务暂不可用,可重试 |