请先查看接入必读了解具体接入方式,再参考此文档完成接入。
DeepChorus
为用户提供副歌检测能力,自动分析获取音乐的段落结构,发现音乐的副歌高潮部分,可用于音乐视频高光剪辑等场景。
payload
字段为将请求参数序列化后的json文本data
字段为将音频二进制文件按照base64格式编码(标准base64,RFC 4648)的文本注意项 | 说明 | |
---|---|---|
功能 | 限制说明 |
|
输入 | 音频格式支持 | wav、pcm、mp3、aac等常见格式 |
音频编码建议 | 采样率大于等于16kHz,否则将进行自动转码,可能带来效果损失和更多耗时处理 | |
音频时长限制 | 小于等于10分钟;建议大于15s,否则返回全曲高潮 | |
音频大小限制 | 小于等于100MB | |
输出 | 结果格式 | json字符串格式,详情请参考响应格式 |
参考详细说明功能调用-通用协议
payload
配置参数为json字符串格式
字段 | 描述 | 类型 | 是否必传 | 默认值 |
---|---|---|---|---|
url | 服务请求数据的url,若data字段为空,则使用该url下载音频数据。详见功能调用-通用协议-payload.url | string | 否 | - |
audio_info | 音频参数,便于服务节省音频解码耗时 | object | 否 | - |
audio_info.format | 音频编码格式,wav/mp3/aac | string | 否 | - |
audio_info.sample_rate | 音频采样率 | number | 否 | - |
audio_info.channel | 音频通道数 | number | 否 | - |
HTTP响应Content-Type: application/json
字段 | 描述 | 类型 |
---|---|---|
task_id | 请求任务id,用于链路追踪、问题排查 | string |
namespace | 服务接口命名空间,比如DeepChorus | string |
data | 请求响应二进制数据,标准base64编码 | string |
payload | 请求响应文本信息,json字符串格式 | string |
status_code | 状态码 | number |
status_text | 状态信息 | string |
响应结果payload为json字符串格式,json内容格式如下:
payload包含三个对象字段:"thumbnail" (高潮)、"chorus_segments"(副歌)、"raw_segments"(原始段落)。每个对象存的是一个list,结构包含以下字段:
interval: 段落的起点、终点秒数
start_prob: 起点的概率分数
end_prob: 终点的概率分数
chorus_prob: 整段落的副歌概率分数
duration: 段落的长度秒数
res_duration: 起点到整曲结束剩的余长度秒数
字段 | 描述 | 类型 |
---|---|---|
thumbnail | 置信度最大的一段高潮 | array |
thumbnail.interval | 段落的起点、终点秒数 | array |
thumbnail.start_prob | 起点的概率分数 | number |
thumbnail.end_prob | 终点的概率分数 | number |
thumbnail.chorus_prob | 整段落的副歌概率分数 | number |
thumbnail.duration | 段落的长度秒数 | number |
thumbnail.res_duration | 起点到整曲结束剩的余长度秒数 | number |
chorus_segments | 副歌 | array |
chorus_segments.* | 子结构的字段同thumbnail | - |
raw_segments | 原始段落 | array |
raw_segments.* | 子结构的字段同thumbnail | - |
响应结果payload示例:
{ "frame_sec": 0.192, "thumbnail": [ { "start_prob": 0.099719256, "end_prob": 0.04581437, "duration": 37.248, "interval": [ 212.73601, 249.98401 ], "res_duration": 57.024002, "chorus_prob": 0.86254287 } ], "chorus_segments": [ { "start_prob": 0.09299248, "end_prob": 0.02493893, "duration": 35.712, "interval": [ 54.528, 90.24 ], "res_duration": 215.232, "chorus_prob": 0.83274376 }, { "start_prob": 0.074075386, "end_prob": 0.037723586, "duration": 48.768, "interval": [ 117.888, 166.656 ], "res_duration": 151.872, "chorus_prob": 0.82471144 }, { "start_prob": 0.099719256, "end_prob": 0.04581437, "duration": 37.248, "interval": [ 212.73601, 249.98401 ], "res_duration": 57.024002, "chorus_prob": 0.86254287 } ], "raw_segments": [ { "start_prob": 0.055697553, "end_prob": 0.09299248, "duration": 0, "interval": [ 39.744, 54.528 ], "res_duration": 0, "chorus_prob": 0.31311455 }, ... { "start_prob": 0.049528554, "end_prob": 0.042224556, "duration": 0, "interval": [ 268.41602, 269.568 ], "res_duration": 0, "chorus_prob": 0.10143171 } ] }
调用方式为:POST /api/v1/invoke
// Code sample: // use http client to invoke SAMI HTTP Service package main import ( "bytes" "encoding/base64" "encoding/json" "fmt" "io/ioutil" "log" "net/http" "time" ) type InvokeResponse struct { StatusCode int32 `form:"status_code,required" json:"status_code,required" query:"status_code,required"` StatusText string `form:"status_text,required" json:"status_text,required" query:"status_text,required"` TaskId string `form:"task_id,required" json:"task_id,required" query:"task_id,required"` Namespace string `form:"namespace,required" json:"namespace,required" query:"namespace,required"` Payload *string `form:"payload,omitempty" json:"payload,omitempty" query:"payload,omitempty"` Data []byte `form:"data,omitempty" json:"data,omitempty" query:"data,omitempty"` State *string `form:"state,omitempty" json:"state,omitempty" query:"state,omitempty"` } const ( domain = "https://sami.bytedance.com" // auth token appkey = "your_appkey" // SAMI method version = "v4" namespace = "DeepChorus" // dump output dataOutputFile = "output.wav" payloadOutputFile = "output.json" isDump = true ) func main() { // Get token token := "your_token" // Construct HTTP request // 1. Read local audio file // 2. Set HTTP json body // 3. Do HTTP POST request audioPath := "/path/to/audio" content, err := ioutil.ReadFile(audioPath) if err != nil { log.Fatalf("failed to read file: %v", err) } data := base64.StdEncoding.EncodeToString(content) body := fmt.Sprintf(`{"data": "%v"}`, data) urlPath := fmt.Sprintf( "%v/api/v1/invoke?version=%v&token=%v&appkey=%v&namespace=%v", domain, version, token, appkey, namespace, ) log.Printf("invoke request: %v", urlPath) // HTTP POST request start := time.Now() resp, err := http.Post(urlPath, "application/json", bytes.NewBuffer([]byte(body))) if err != nil { panic(err) } defer resp.Body.Close() // Parse HTTP response ret, err := ioutil.ReadAll(resp.Body) if err != nil || resp.StatusCode != http.StatusOK { panic(string(ret)) } log.Printf("http invoke: cost=%vms, response: %v", time.Since(start).Milliseconds(), string(ret)) // parse SAMI response samiResp := InvokeResponse{} payloadStr := "" if err = json.Unmarshal(ret, &samiResp); err != nil { log.Println("parse response failed", string(ret), err) panic(err) } if samiResp.Payload != nil { payloadStr = *samiResp.Payload } log.Printf("response task_id=%v, payload=%v, data=[%d]byte", samiResp.TaskId, payloadStr, len(samiResp.Data)) if isDump && samiResp.Payload != nil { _ = ioutil.WriteFile(payloadOutputFile, []byte(*samiResp.Payload), 0644) } if isDump && len(samiResp.Data) > 0 { _ = ioutil.WriteFile(dataOutputFile, samiResp.Data, 0644) } }