团子AI · 开放平台文档团子AI · 开放平台文档
主页
返回开放平台
主页
返回开放平台
  • 介绍
  • 价格与充值
  • 开始上手
  • 代码DEMO
  • 常见问题
  • 伴奏人声提取
  • 无损升降音调
  • 任意乐器分离
  • 混响回声移除
  • 有损音频修复
  • 团子轻函数

代码DEMO

团子提供必要的代码DEMO,包含数种语言的实现,方便开发者快速上手使用。

如何与团子通信

以下为如何与团子通信的代码DEMO。

该接口将返回你发送的请求体内容,来验证你的请求体、请求头和token是否正确。

该片段为最基本的和团子通信的写法,如需要其他的API请求,只需要替换请求地址、请求体和请求头,举一反三即可。

JavaScript
// 需要的依赖:axios(网络请求库), md5(MD5摘要算法实现库)
const axios = require('axios')
const md5 = require('md5')

// 替换为自己的appKey、secret
const appKey = '***' 
const secret = '***'

function buildToken(appKey, secret) {
	const timestamp = Date.now()
	return appKey + "$$" + timestamp + "$$" + md5(secret + timestamp)
}

const request = axios.post(
	'https://api.tuanziai.com/echo',
	{"test": "my-test-string"},
	{
		headers: {
			"token": buildToken(appKey, secret), 
            "Content-Type": "application/json"
		}
	}
)

request.then(response => {
	// 输出为:
	//Response: { code: 0, message: 'success', data: 'my-test-string' }
	console.log('Response:', response.data)
})
Java
// 需要的依赖:okhttp(网络请求库), commons-codec(MD5摘要算法实现库)
import org.apache.commons.codec.digest.DigestUtils;
import java.io.IOException;
import okhttp3.*;

public class DangoDemo {
    private static final String APP_KEY = "***";
    private static final String SECRET = "***";

	private static String buildToken(String appKey, String secret) {
		long timestamp = System.currentTimeMillis();
		return appKey + "$$" + timestamp + "$$" + DigestUtils.md5Hex(secret + timestamp);
	}

	public static void main(String[] args) throws IOException {
		OkHttpClient client = new OkHttpClient();

		// 构建请求体,这里直接拼写了一个JSON字符串,也可以使用其他JSON库来构建请求体
		String json = "{\"test\": \"my-test-string\"}";
		RequestBody body = RequestBody.create(json, MediaType.parse("application/json"));

		// 构建请求
		okhttp3.Request request = new Request.Builder()
				.url("https://api.tuanziai.com/echo")
				.header("token", buildToken(APP_KEY, SECRET))
				.header("Content-Type", "application/json")
				.post(body)
				.build();

		// 发送请求
		try (Response response = client.newCall(request).execute()) {
			// 输出为:
			// Response: {"code":0,"message":"success","data":"my-test-string"}
			System.out.println("Response: " + response.body().string());
		}

	}
}
Groovy
// 需要的依赖:spring-web(网络请求库,也可以用okHttp,参考java版本写法)
import groovy.json.JsonOutput
import groovy.transform.CompileStatic
import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders
import org.springframework.web.client.RestTemplate

@CompileStatic
class GDangoDemo {
	static String APP_KEY = "***"
	static String SECRET = "***"

	private static String buildToken(String appKey, String secret) {
		def timestamp = System.currentTimeMillis()
		return appKey + "\$\$" + timestamp + "\$\$" + (secret + timestamp).md5()
	}

	static void main(String[] args) {
		def headers = new HttpHeaders()
		headers.add("token", buildToken(APP_KEY, SECRET))
		headers.add("Content-Type", "application/json")

		def body = new RestTemplate().postForObject(
            "https://api.tuanziai.com/echo",
            new HttpEntity(JsonOutput.toJson(["test": "my-test-string"]), headers),
            String,
		)

		// 输出为:
		// Response: {"code":0,"message":"success","data":"my-test-string"}
		println("Response: " + body)

	}
}
Python
# 需要的依赖:requests
import requests
import hashlib
import time

# 替换为自己的appKey、secret
APP_KEY = '***'
SECRET = '***'

def build_token(app_key, secret):
    timestamp = int(time.time() * 1000)  # 毫秒级时间戳
    sign_str = secret + str(timestamp)
    md5_sign = hashlib.md5(sign_str.encode()).hexdigest()
    return f"{app_key}$${timestamp}$${md5_sign}"

# 发送POST请求
response = requests.post(
    url='https://api.tuanziai.com/echo',
    json={"test": "my-test-string"},
    headers={"token": build_token(APP_KEY, SECRET), "Content-Type": "application/json"}
)

# 输出为:
# Response: {'code': 0, 'message': 'success', 'data': 'my-test-string'}
print('Response:', response.json())

创建通道并上传歌曲

这里给出创建上传通道、上传歌曲文件到阿里云OSS、并开始处理歌曲的代码DEMO,以伴奏人声提取功能为例。

额外需要注意的是,这里只做了最精简的封装,并没有考虑网络请求的重试、异常处理、以及一些边界情况,请开发者根据自己的实际情况进行完善。

JavaScript
// 需要的依赖:axios(网络请求库), md5(MD5摘要算法实现库),fs(Node环境下的文件系统模块,如果浏览器环境需要file对象代替)
const axios = require('axios')
const md5 = require('md5')
const fs = require('fs')

const appKey = '**'
const secret = '**'

function buildToken(appKey, secret) {
	const timestamp = Date.now()
	return appKey + '$$' + timestamp + '$$' + md5(secret + timestamp)
}

// 简单的封装一个请求函数,方便后续调用
function postToDango(url, body) {
	return axios.post(url, body, {
		headers: {
			'token': buildToken(appKey, secret),
			'Content-Type': 'application/json'
		}
	})
}

async function uploadToDango(filePath) {
	// 第一步:创建上传通道
	const {url, form, channel} = (await postToDango('https://api.tuanziai.com/vocal-remover/upload/channel', {
		"uploadVersion": 2,
		"style": 29,
		"filename": "test.mp3",
		"config": {
			"separateBackingVocals": false
		}
	})).data.data

	// 第二步:使用返回的url和form字段上传文件到OSS
	// 当前代码为Node环境,如果是浏览器环境,可以使用file对象和FormData来上传。
	await axios.postForm(
		url, //无需关心上传到哪里,直接使用团子返回的url字段 
        {
            ...form, // 无需关心团子提供的form都有什么键值,直接“一股脑”将form字段展开作为请求体的一部分
            file: fs.createReadStream(filePath) //在form的最后添加一个file字段,值为要上传的文件
	    }
	)

	// 第三步:通知团子上传完成,并获取musicId
	const musicId = (await postToDango(`https://api.tuanziai.com/vocal-remover/upload/${channel}/result`)).data.data

	return musicId
}

uploadToDango('d:\\test\\real.wav').then(musicId => {
	// 输出为:
	// 上传成功,音乐ID: f81be254ec5242d29be254ec52c2d2e2
	// 之后就可以使用这个音乐ID去请求处理结果了,具体接口文档请参考开放平台文档
	console.log('上传成功,音乐ID:', musicId)
})
Java
// 需要的依赖:okhttp(网络请求库), commons-codec(MD5摘要算法实现库),fastjson(JSON解析库)
import org.apache.commons.codec.digest.DigestUtils;

import java.io.File;
import java.io.IOException;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import okhttp3.*;

public class DangoDemo {
	private static final String APP_KEY = "**";
	private static final String SECRET = "**";
	private static final OkHttpClient client = new OkHttpClient();

	private static String buildToken() {
		long ts = System.currentTimeMillis();
		return APP_KEY + "$$" + ts + "$$" + DigestUtils.md5Hex(SECRET + ts);
	}

	// 通用请求方法:url, body(可为null), 是否返回JSON对象
	private static JSONObject postToDango(String url, Object body) throws IOException {
		Request.Builder builder = new Request.Builder().url(url).header("token", buildToken());

		if(body == null) {
			body = "";
		} else {
			body = JSON.toJSONString(body);
		}

		builder.post(RequestBody.create((String)body, MediaType.parse("application/json")));

		try (Response resp = client.newCall(builder.build()).execute()) {
			return JSONObject.parseObject(resp.body().string());
		}
	}

	public static String uploadToDango(String filePath) throws IOException {
		// 1. 创建通道
		JSONObject req = new JSONObject();
		req.put("uploadVersion", 2);
		req.put("style", 29);
		req.put("filename", "test.mp3");
		req.put("config", new JSONObject().put("separateBackingVocals", false));

		JSONObject createUploadChannelResultBody = postToDango("https://api.tuanziai.com/vocal-remover/upload/channel", req);
		createUploadChannelResultBody = createUploadChannelResultBody.getJSONObject("data");

		JSONObject form = createUploadChannelResultBody.getJSONObject("form");
		String url = createUploadChannelResultBody.getString("url");
		String channel = createUploadChannelResultBody.getString("channel");

		// 2. 上传文件
		MultipartBody.Builder formBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);

		form.entrySet().forEach(entry -> {
			formBuilder.addFormDataPart(entry.getKey(), entry.getValue().toString());
		});

		formBuilder.addFormDataPart("file", new File(filePath).getName(), RequestBody.create(new File(filePath), MediaType.parse("application/octet-stream")));

		client.newCall(new Request.Builder().url(url).post(formBuilder.build()).build()).execute();

		// 3. 获取结果(返回纯字符串)
		JSONObject getChannelResultBody = postToDango("https://api.tuanziai.com/vocal-remover/upload/" + channel + "/result", null);
		String musicId = getChannelResultBody.getString("data");

		return musicId;
	}

	public static void main(String[] args) throws IOException {
		String musicId = uploadToDango("d:\\test\\real.wav");
		// 输出为:
		// 上传成功,音乐ID: f81be254ec5242d29be254ec52c2d2e2
		// 之后就可以使用这个音乐ID去请求处理结果了,具体接口文档请参考开放平台文档
		System.out.println("上传成功,音乐ID: " + musicId);
	}
}
Groovy
// 需要的依赖:spring-web(网络请求库,也可以用okHttp,参考java版本写法)
import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import groovy.transform.CompileStatic
import org.springframework.core.io.FileSystemResource
import org.springframework.http.HttpEntity
import org.springframework.http.HttpHeaders
import org.springframework.util.LinkedMultiValueMap
import org.springframework.web.client.RestTemplate

@CompileStatic
class GDangoDemo2 {
	static String APP_KEY = "***"
	static String SECRET = "***"

	private static String buildToken(String appKey, String secret) {
		def timestamp = System.currentTimeMillis()
		return appKey + "\$\$" + timestamp + "\$\$" + (secret + timestamp).md5()
	}

	private static Map postToDango(String url, Map body = null) {
		def headers = new HttpHeaders()
		headers.add("token", buildToken(APP_KEY, SECRET))
		headers.add("Content-Type", "application/json")

		def entity = new HttpEntity(JsonOutput.toJson(body ?: []), headers)
		def response = new RestTemplate().postForObject(url, entity, String)

		return new JsonSlurper().parseText(response as String) as Map
	}

	static String uploadToDango(String filePath)  {
		// 1. 创建通道
		def channelResponse = postToDango("https://api.tuanziai.com/vocal-remover/upload/channel", [
	        "uploadVersion": 2,
			"style": 29,
			"filename": "test.mp3",
			"config": [
		        "separateBackingVocals": false
			]
		]).data as Map

		// 2. 上传文件
		def uploadOSSBody = new LinkedMultiValueMap()

		for(def entry : (channelResponse.form as Map).entrySet())
			uploadOSSBody.add(entry.key, entry.value)

		uploadOSSBody.add("file", new FileSystemResource(filePath))
		
		new RestTemplate().postForObject(channelResponse.url as String, new HttpEntity(uploadOSSBody, new HttpHeaders()), String)

		// 3. 获取结果(返回纯字符串)
		String musicId = postToDango("https://api.tuanziai.com/vocal-remover/upload/${channelResponse.channel}/result").data as String
		return musicId
	}

	static void main(String[] args) {
		def musicId = uploadToDango("d:\\test\\real.wav")
		// 输出为:
		// 上传成功,音乐ID: f81be254ec5242d29be254ec52c2d2e2
		// 之后就可以使用这个音乐ID去请求处理结果了,具体接口文档请参考开放平台文档
		println("上传成功,音乐ID: " + musicId)
	}
}
Python
# 需要的依赖:requests
import requests
import hashlib
import time
import os

APP_KEY = '***'
SECRET = '***'

def compute_token(app_key, secret):
    timestamp = int(time.time() * 1000)
    return f"{app_key}$${timestamp}$${hashlib.md5((secret + str(timestamp)).encode()).hexdigest()}"

def post_to_dango(url, body=None):
    headers = {
        'token': compute_token(APP_KEY, SECRET),
        'Content-Type': 'application/json'
    }

    resp = requests.post(url, json=body, headers=headers)
    resp.raise_for_status()

    data = resp.json()['data']
    return data

def upload_to_dango(file_path):
    # 第一步:创建上传通道
    channel_data = post_to_dango('https://api.tuanziai.com/vocal-remover/upload/channel', {
        "uploadVersion": 2,
        "style": 29,
        "filename": os.path.basename(file_path),  # 使用实际文件名
        "config": {
            "separateBackingVocals": False
        }
    })

    url = channel_data['url']
    form = channel_data['form']
    channel = channel_data['channel']

    # 第二步:使用返回的url和form字段上传文件到OSS
    with open(file_path, 'rb') as f:
        upload_resp = requests.post(url, data=form, files={'file': (os.path.basename(file_path), f, 'audio/wav')})
        upload_resp.raise_for_status()

    # 第三步:通知团子上传完成,等待处理结果
    music_id = post_to_dango(f'https://api.tuanziai.com/vocal-remover/upload/{channel}/result')
    return music_id


if __name__ == '__main__':
    music_id = upload_to_dango('d:\\test\\real.wav')
    # 输出为:
    # 上传成功,音乐ID: f81be254ec5242d29be254ec52c2d2e2
    print('上传成功,音乐ID:', music_id)
Prev
开始上手
Next
常见问题