Skip to content

Commit ce66a01

Browse files
feat: voiceclone implement comprehensive voice cloning service with full API support (#38)
Co-authored-by: tomsun28 <tomsun28@outlook.com>
1 parent 6430107 commit ce66a01

18 files changed

Lines changed: 789 additions & 1 deletion

core/src/main/java/ai/z/openapi/AbstractAiClient.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
import ai.z.openapi.service.videos.VideosServiceImpl;
2424
import ai.z.openapi.service.assistant.AssistantService;
2525
import ai.z.openapi.service.assistant.AssistantServiceImpl;
26+
import ai.z.openapi.service.voiceclone.VoiceCloneService;
27+
import ai.z.openapi.service.voiceclone.VoiceCloneServiceImpl;
2628
import ai.z.openapi.core.config.ZaiConfig;
2729
import ai.z.openapi.core.model.BiFlowableClientResponse;
2830
import ai.z.openapi.core.model.ClientRequest;
@@ -98,6 +100,9 @@ public abstract class AbstractAiClient extends AbstractClientBaseService {
98100
/** Assistant service for AI assistant functionality */
99101
private AssistantService assistantService;
100102

103+
/** Voice clone service for voice cloning operations */
104+
private VoiceCloneService voiceCloneService;
105+
101106
/**
102107
* Constructs a new AbstractAiClient with the specified configuration.
103108
* @param config the configuration object containing API keys, timeouts, and other
@@ -238,6 +243,18 @@ public synchronized AssistantService assistants() {
238243
return assistantService;
239244
}
240245

246+
/**
247+
* Returns the voice clone service for voice cloning operations. This service handles
248+
* voice cloning creation, deletion, and listing functionality.
249+
* @return the VoiceCloneService instance (lazily initialized)
250+
*/
251+
public synchronized VoiceCloneService voiceClone() {
252+
if (voiceCloneService == null) {
253+
this.voiceCloneService = new VoiceCloneServiceImpl(this);
254+
}
255+
return voiceCloneService;
256+
}
257+
241258
// ==================== Utility Methods ====================
242259

243260
/**
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package ai.z.openapi.api.voiceclone;
2+
3+
import ai.z.openapi.service.voiceclone.VoiceCloneRequest;
4+
import ai.z.openapi.service.voiceclone.VoiceCloneResult;
5+
import ai.z.openapi.service.voiceclone.VoiceDeleteRequest;
6+
import ai.z.openapi.service.voiceclone.VoiceDeleteResult;
7+
import ai.z.openapi.service.voiceclone.VoiceListResult;
8+
import io.reactivex.rxjava3.core.Single;
9+
import retrofit2.http.Body;
10+
import retrofit2.http.GET;
11+
import retrofit2.http.Header;
12+
import retrofit2.http.POST;
13+
import retrofit2.http.Query;
14+
15+
/**
16+
* Voice Clone API for voice cloning and management operations. Provides endpoints for
17+
* creating voice clones from audio samples, deleting existing voice clones, and listing
18+
* available voice clones.
19+
*/
20+
public interface VoiceCloneApi {
21+
22+
/**
23+
* Creates a new voice clone from provided audio sample and parameters. Uses advanced
24+
* neural voice cloning technology to generate a custom voice model that can
25+
* synthesize speech matching the characteristics of the provided sample.
26+
* @param request voice clone creation parameters including voice name, sample text,
27+
* target text, and audio file reference
28+
* @return voice clone creation result with voice ID and preview file information
29+
*/
30+
@POST("voice/clone")
31+
Single<VoiceCloneResult> cloneVoice(@Body VoiceCloneRequest request);
32+
33+
/**
34+
* Deletes an existing voice clone by voice ID. Permanently removes the voice model
35+
* and associated data from the system. This operation cannot be undone.
36+
* @param request voice deletion parameters containing the voice ID to delete
37+
* @return voice deletion result with confirmation and deletion timestamp
38+
*/
39+
@POST("voice/delete")
40+
Single<VoiceDeleteResult> deleteVoice(@Body VoiceDeleteRequest request);
41+
42+
/**
43+
* Retrieves a list of available voice clones with optional filtering. Returns
44+
* metadata and details for voice clones including voice IDs, names, types, download
45+
* URLs, and creation timestamps.
46+
* @param voiceType optional voice type filter
47+
* @param voiceName optional voice name filter
48+
* @return list of voice clone data with comprehensive metadata
49+
*/
50+
@GET("voice/list")
51+
Single<VoiceListResult> listVoices(@Query("voiceType") String voiceType, @Query("voiceName") String voiceName);
52+
53+
/**
54+
* Retrieves a list of available voice clones with optional filtering and Request-Id
55+
* header. Returns metadata and details for voice clones including voice IDs, names,
56+
* types, download URLs, and creation timestamps.
57+
* @param voiceType optional voice type filter
58+
* @param voiceName optional voice name filter
59+
* @param requestId unique request identifier for tracking and monitoring
60+
* @return list of voice clone data with comprehensive metadata
61+
*/
62+
@GET("voice/list")
63+
Single<VoiceListResult> listVoices(@Query("voiceType") String voiceType, @Query("voiceName") String voiceName,
64+
@Header("Request-Id") String requestId);
65+
66+
}

core/src/main/java/ai/z/openapi/service/file/UploadFilePurpose.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
public enum UploadFilePurpose {
44

5-
BATCH("batch"), FILE_EXTRACT("file-extract"), CODE_INTERPRETER("code-interpreter"), AGENT("agent");
5+
BATCH("batch"), FILE_EXTRACT("file-extract"), CODE_INTERPRETER("code-interpreter"), AGENT("agent"),
6+
VOICE_CLONE_INPUT("voice-clone-input");
67

78
private final String value;
89

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package ai.z.openapi.service.voiceclone;
2+
3+
import ai.z.openapi.core.model.ClientRequest;
4+
import ai.z.openapi.service.CommonRequest;
5+
import com.fasterxml.jackson.annotation.JsonProperty;
6+
import lombok.Data;
7+
import lombok.EqualsAndHashCode;
8+
9+
/**
10+
* Request parameters for voice cloning API. This class contains all the necessary
11+
* parameters for voice cloning operations, including voice name, sample audio text,
12+
* target preview text, and audio file information.
13+
*/
14+
@EqualsAndHashCode(callSuper = true)
15+
@Data
16+
public class VoiceCloneRequest extends CommonRequest implements ClientRequest<VoiceCloneRequest> {
17+
18+
/** Voice name */
19+
@JsonProperty("voice_name")
20+
private String voiceName;
21+
22+
/** Text content corresponding to the sample audio */
23+
@JsonProperty("voice_text_input")
24+
private String voiceTextInput;
25+
26+
/** Target text for preview audio */
27+
@JsonProperty("voice_text_output")
28+
private String voiceTextOutput;
29+
30+
/** File ID of the audio file */
31+
@JsonProperty("file_id")
32+
private String fileId;
33+
34+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package ai.z.openapi.service.voiceclone;
2+
3+
import ai.z.openapi.core.model.ClientResponse;
4+
import ai.z.openapi.service.batches.BatchPage;
5+
import ai.z.openapi.service.model.ChatError;
6+
import com.fasterxml.jackson.annotation.JsonProperty;
7+
import lombok.AllArgsConstructor;
8+
import lombok.Builder;
9+
import lombok.Data;
10+
import lombok.NoArgsConstructor;
11+
12+
import java.io.Serializable;
13+
14+
/**
15+
* Response wrapper for voice cloning API operations. This class contains the standard
16+
* response structure including status code, message, success flag, result data, and error
17+
* information.
18+
*/
19+
@Data
20+
@Builder
21+
@NoArgsConstructor
22+
@AllArgsConstructor
23+
public class VoiceCloneResponse implements ClientResponse<VoiceCloneResult> {
24+
25+
private int code;
26+
27+
private String msg;
28+
29+
private boolean success;
30+
31+
private VoiceCloneResult data;
32+
33+
private ChatError error;
34+
35+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package ai.z.openapi.service.voiceclone;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Data;
7+
import lombok.NoArgsConstructor;
8+
9+
/**
10+
* Result data for voice cloning operations. This class contains the voice cloning result
11+
* information including voice ID, audio file ID, and file purpose.
12+
*/
13+
@Data
14+
@Builder
15+
@AllArgsConstructor
16+
@NoArgsConstructor
17+
public class VoiceCloneResult {
18+
19+
/** Voice ID */
20+
@JsonProperty("voice_id")
21+
private String voiceId;
22+
23+
/** Audio preview file ID */
24+
@JsonProperty("file_id")
25+
private String fileId;
26+
27+
/** File purpose */
28+
@JsonProperty("file_purpose")
29+
private String filePurpose;
30+
31+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package ai.z.openapi.service.voiceclone;
2+
3+
/**
4+
* Voice clone service interface for voice cloning operations. This service provides
5+
* methods for creating, deleting, and listing voice clones.
6+
*/
7+
public interface VoiceCloneService {
8+
9+
/**
10+
* Creates a new voice clone based on the provided audio sample and parameters.
11+
* @param request the voice clone creation request containing voice name, sample audio
12+
* text, target text, and audio file information
13+
* @return VoiceCloneResponse containing the voice clone result and metadata
14+
*/
15+
VoiceCloneResponse cloneVoice(VoiceCloneRequest request);
16+
17+
/**
18+
* Deletes an existing voice clone by voice ID.
19+
* @param request the voice deletion request containing the voice ID to delete
20+
* @return VoiceDeleteResponse containing the deletion result and timestamp
21+
*/
22+
VoiceDeleteResponse deleteVoice(VoiceDeleteRequest request);
23+
24+
/**
25+
* Retrieves a list of available voice clones with optional filtering.
26+
* @param request the voice list request containing optional voice type and name
27+
* filters
28+
* @return VoiceListResponse containing the filtered list of voice data
29+
*/
30+
VoiceListResponse listVoice(VoiceListRequest request);
31+
32+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package ai.z.openapi.service.voiceclone;
2+
3+
import ai.z.openapi.AbstractAiClient;
4+
import ai.z.openapi.api.voiceclone.VoiceCloneApi;
5+
import ai.z.openapi.service.deserialize.MessageDeserializeFactory;
6+
import ai.z.openapi.utils.RequestSupplier;
7+
import com.fasterxml.jackson.databind.ObjectMapper;
8+
import lombok.extern.slf4j.Slf4j;
9+
10+
/**
11+
* Voice clone service implementation for voice cloning operations. This service provides
12+
* methods for creating, deleting, and listing voice clones using the VoiceClone API
13+
* endpoints.
14+
*/
15+
public class VoiceCloneServiceImpl implements VoiceCloneService {
16+
17+
protected static final ObjectMapper mapper = MessageDeserializeFactory.defaultObjectMapper();
18+
19+
private final AbstractAiClient zAiClient;
20+
21+
private final VoiceCloneApi voiceCloneApi;
22+
23+
public VoiceCloneServiceImpl(AbstractAiClient zAiClient) {
24+
this.zAiClient = zAiClient;
25+
this.voiceCloneApi = zAiClient.retrofit().create(VoiceCloneApi.class);
26+
}
27+
28+
@Override
29+
public VoiceCloneResponse cloneVoice(VoiceCloneRequest request) {
30+
validateCreateVoiceParams(request);
31+
RequestSupplier<VoiceCloneRequest, VoiceCloneResult> supplier = voiceCloneApi::cloneVoice;
32+
return this.zAiClient.executeRequest(request, supplier, VoiceCloneResponse.class);
33+
}
34+
35+
@Override
36+
public VoiceDeleteResponse deleteVoice(VoiceDeleteRequest request) {
37+
validateDeleteVoiceParams(request);
38+
RequestSupplier<VoiceDeleteRequest, VoiceDeleteResult> supplier = voiceCloneApi::deleteVoice;
39+
return this.zAiClient.executeRequest(request, supplier, VoiceDeleteResponse.class);
40+
}
41+
42+
@Override
43+
public VoiceListResponse listVoice(VoiceListRequest request) {
44+
RequestSupplier<VoiceListRequest, VoiceListResult> supplier = (params) -> {
45+
String voiceType = params != null ? params.getVoiceType() : null;
46+
String voiceName = params != null ? params.getVoiceName() : null;
47+
String requestId = params != null ? params.getRequestId() : "";
48+
49+
return voiceCloneApi.listVoices(voiceType, voiceName, requestId);
50+
};
51+
return this.zAiClient.executeRequest(request, supplier, VoiceListResponse.class);
52+
}
53+
54+
private void validateCreateVoiceParams(VoiceCloneRequest request) {
55+
if (request == null) {
56+
throw new IllegalArgumentException("request cannot be null");
57+
}
58+
if (request.getVoiceName() == null || request.getVoiceName().trim().isEmpty()) {
59+
throw new IllegalArgumentException("voice name cannot be null or empty");
60+
}
61+
if (request.getVoiceTextInput() == null || request.getVoiceTextInput().trim().isEmpty()) {
62+
throw new IllegalArgumentException("voice text input cannot be null or empty");
63+
}
64+
if (request.getFileId() == null || request.getFileId().trim().isEmpty()) {
65+
throw new IllegalArgumentException("file ID cannot be null or empty");
66+
}
67+
}
68+
69+
private void validateDeleteVoiceParams(VoiceDeleteRequest request) {
70+
if (request == null) {
71+
throw new IllegalArgumentException("request cannot be null");
72+
}
73+
if (request.getVoiceId() == null || request.getVoiceId().trim().isEmpty()) {
74+
throw new IllegalArgumentException("voice ID cannot be null or empty");
75+
}
76+
}
77+
78+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package ai.z.openapi.service.voiceclone;
2+
3+
import com.fasterxml.jackson.annotation.JsonFormat;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
5+
import lombok.Data;
6+
7+
import java.util.Date;
8+
9+
/**
10+
* Voice data entity containing voice information. This class contains voice details
11+
* including voice ID, name, type, download URL, and creation time.
12+
*/
13+
@Data
14+
public class VoiceData {
15+
16+
@JsonProperty("voice_id")
17+
private String voiceId;
18+
19+
@JsonProperty("voice_name")
20+
private String voiceName;
21+
22+
@JsonProperty("voice_type")
23+
private String voiceType;
24+
25+
@JsonProperty("download_url")
26+
private String downloadUrl;
27+
28+
@JsonProperty("create_time")
29+
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
30+
private Date createTime;
31+
32+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package ai.z.openapi.service.voiceclone;
2+
3+
import ai.z.openapi.core.model.ClientRequest;
4+
import ai.z.openapi.service.CommonRequest;
5+
import com.fasterxml.jackson.annotation.JsonProperty;
6+
import lombok.Data;
7+
import lombok.EqualsAndHashCode;
8+
9+
/**
10+
* Request parameters for voice deletion API. This class contains the necessary parameters
11+
* for deleting a voice, specifically the voice ID.
12+
*/
13+
@EqualsAndHashCode(callSuper = true)
14+
@Data
15+
public class VoiceDeleteRequest extends CommonRequest implements ClientRequest<VoiceDeleteRequest> {
16+
17+
@JsonProperty("voice_id")
18+
private String voiceId;
19+
20+
}

0 commit comments

Comments
 (0)