File size: 2,720 Bytes
811126d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import "dotenv/config";
import FormData from "form-data";
import axios from "axios";
import fs from "fs";

interface ICloneVoiceParams {
  description: string;
  name: string;
  fileUrls: string[];
  labels: Record<string, string>;
}

const handleStreamEnd = (stream: fs.ReadStream): Promise<void> => {
  return new Promise((resolve) => {
    if (!stream || stream?.closed) {
      resolve();
      return;
    }

    stream.once("end", () => {
      resolve();
    });
    stream.once("close", () => {
      resolve();
    });
  });
};

const cloneVoiceHandler = async (
  params: ICloneVoiceParams
): Promise<string> => {
  const { name, description, fileUrls = [], labels = {} } = params;
  const formData = new FormData();
  const streams: fs.ReadStream[] = [];

  console.log("Début du clonage de voix...");
  console.log("Fichiers à traiter:", fileUrls);

  for (let i = 0; i < fileUrls.length; i++) {
    try {
      const filePath = fileUrls[i];
      console.log(`Traitement du fichier ${filePath}...`);

      const fileStream = fs.createReadStream(filePath);
      streams.push(fileStream);

      formData.append("files", fileStream, {
        filename: "sample1.mp3",
        contentType: "audio/mpeg",
      });
    } catch (err) {
      console.error("Erreur lors du traitement du fichier:", err);
      throw err;
    }
  }

  formData.append("name", name);
  formData.append("description", description);

  if (typeof labels === "object" && labels) {
    formData.append("labels", JSON.stringify(labels));
  }

  try {
    const elevenlabsUrl = "https://api.elevenlabs.io/v1/voices/add";
    const elevenLabsApiKey = process.env.ELEVENLABS_API_KEY || "";
    console.log("Envoi de la requête à ElevenLabs...");

    const elevenLabsResponse = await axios.post(elevenlabsUrl, formData, {
      headers: {
        ...formData.getHeaders(),
        Accept: "application/json",
        "xi-api-key": elevenLabsApiKey,
      },
    });

    console.log("Réponse d'ElevenLabs:", elevenLabsResponse.data);
    return elevenLabsResponse.data?.voice_id || "";
  } catch (err) {
    console.error(
      "Erreur lors de l'appel à ElevenLabs:",
      err.response?.data || err
    );
    throw err;
  } finally {
    // Fermer tous les streams
    for (const stream of streams) {
      stream.destroy();
    }
  }
};

const params = {
  name: "test",
  description: "Voix française calme",
  fileUrls: [
    "./sample1.mp3", // Notez le ./ pour indiquer le dossier courant
  ],
  labels: {
    accent: "français",
    type: "calme",
  },
};

try {
  const voiceId = await cloneVoiceHandler(params);
  console.log("Voice ID obtenu:", voiceId);
} catch (error) {
  console.error("Erreur globale:", error);
}