API pública.
Introdução
O Speaqr fornece serviços de tradução em tempo real através de uma API construída sobre o Socket.IO. Os clientes podem ligar-se, enviar dados de áudio e receber resultados processados, tais como transcrições, traduções e discurso sintetizado.A Speaqr foi concebida para conversações, em que a velocidade é crucial para proporcionar uma experiência de qualidade. Por este motivo, a API Speaqr segue a filosofia "session on socket".Uma vez autenticado, o consumidor mantém uma ligação aberta através de um socket até à desconexão, tratando a maioria das interações através de eventos, com algumas excepções.Para utilizar a API , é necessária uma chave de API válida. Para a obter, contacte-nos através do formulário de contratação.Url
O url para aceder à API é:https://public.speaqr.ai
Postman
Pode descarregar a coleção Postman e o ambiente para testar os métodos da API.Lembre-se de colocar a suachave de API
válida no ambiente.Descarregar a coleçãoDescarregar o ambienteErros
Os erros são sempre devolvidos num JSON com os seguintes campos:Campo | Explicação |
---|---|
code | O código de erro geral. |
error | O código de erro específico no âmbito do erro geral. |
description | A descrição textual do erro. |
Exemplo
{
"code": "bad_file",
"error": "language_not_detected",
"description": "The audio language could not be determined"
}
Métodos
A API tem vários métodos disponíveis. As suas utilizações e configurações são descritas em seguida.api/languages
Obtém a lista de idiomas suportados pelo SDK para transcrição, tradução e síntese de voz.Endpoint
GET https://public.speaqr.ai/api/languages
Cabeçalhos
Exemplo
const myHeaders = new Headers();
myHeaders.append("x-api-key", "xxxxxxx"); //Your valid api key
const requestOptions = {
method: "GET",
headers: myHeaders
};
fetch("https://public.speaqr.ai/api/languages", requestOptions)
.then((response) => response.text())
.then((result) => console.log(result))
.catch((error) => console.error(error));
import requests
headers = {
"x-api-key": "xxxxxxx" # Your valid api key
}
response = requests.get("https://public.speaqr.ai/api/languages", headers=headers)
if response.status_code == 200:
print("Languages available:", response.json())
else:
print("Error:", response.status_code, response.text)
import okhttp3.*;
public class Languages {
public static void main(String[] args) {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url("https://public.speaqr.ai/api/languages")
.header("x-api-key", "xxxxxxx") //Your valid api key
.get()
.build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful() && response.body() != null) {
System.out.println("Languages available: " + response.body().string());
} else {
System.out.println("Error: " + response.code());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Resposta
/api/voices
Obtém a lista de vozes disponíveis para a síntese de voz (TTS) numa língua. Opcionalmente, o resultado pode ser filtrado por género de voz, modo de resposta e/ou motor de voz.Desta forma, é possível descobrir se uma configuração de língua, género, modo de resposta e motor pode ser realizada, uma vez que não existem vozes para todas as combinações.Endpoint
GET https://public.speaqr.ai/api/voices
Cabeçalhos
Parâmetros
QUERY
Exemplo
const apiKey = 'xxxxxxx'; // Your valid API key
const params = new URLSearchParams({
language: 'en-gb',
mode: 'block',
voiceGender: 'M',
voiceEngine: 'neural',
voiceEngine: 'standard'
});
const requestOptions = {
method: 'GET',
headers: {
'x-api-key': apiKey
}
};
fetch(`https://public.speaqr.ai/api/voices?${params.toString()}`, requestOptions)
.then((response) => response.text())
.then((result) => console.log(result))
.catch((error) => console.error(error));
import requests
params = {
"language": "es-es",
"mode": "block",
"voiceEngine": ["neural", "standard"],
"voiceGender": "M"
}
headers = {
"x-api-key": "xxxxxxx" # Your valid API key
}
response = requests.get("https://public.speaqr.ai/api/voices", params=params, headers=headers)
if response.status_code == 200:
print("Voices available:", response.json())
else:
print("Error:", response.status_code, response.text)
import okhttp3.*;
public class ListAvailableVoices {
public static void main(String[] args) {
OkHttpClient client = new OkHttpClient();
HttpUrl url = HttpUrl.parse("https://public.speaqr.ai/api/voices").newBuilder()
.addQueryParameter("language", "en-gb")
.addQueryParameter("mode", "block")
.addQueryParameter("voiceGender", "M")
.addQueryParameter("voiceEngine", "neural")
.addQueryParameter("voiceEngine", "standard")
.build();
Request request = new Request.Builder()
.url(url)
.get()
.addHeader("x-api-key", "xxxxxxx") // Your valid API key
.build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful() && response.body() != null) {
System.out.println("Voices available: " + response.body().string());
} else {
System.out.println("Error: " + response.code() + " - " + response.message());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Resposta
batch/file
Processa um ficheiro áudio e executa a operação especificada nomodo
. O resultado dependerá do modo selecionado.Endpoint
POST https://public.speaqr.ai/api/batch/file
Cabeçalhos
Parâmetros
FORM DATA
Exemplo
const myHeaders = new Headers();
myHeaders.append("x-api-key", "xxxxxxx"); //Your valid api key
const wavFile = getWav();
const formData = new FormData();
formData.append("mode", "stt");
formData.append("file", wavFile, "dummy.wav");
const requestOptions = {
method: "POST",
headers: myHeaders,
body: formData,
};
fetch("https://public.speaqr.ai/api/batch/file", requestOptions)
.then((response) => response.text())
.then((result) => console.log("Response:", result))
.catch((error) => console.error("Error:", error));
//Function to generate a dummy wav
function getWav(){
const sampleRate = 16000;
const numChannels = 1;
const duration = 2;
const bitsPerSample = 16;
//We generate empty data (silence)
const numSamples = sampleRate * duration;
const buffer = new ArrayBuffer(numSamples * (bitsPerSample / 8));
const view = new DataView(buffer);
//We write the WAV header
writeString(view, 0, "RIFF"); // ChunkID
view.setUint32(4, 36 + buffer.byteLength, true); // ChunkSize
writeString(view, 8, "WAVE") // Format
writeString(view, 12, "fmt ") // Subchunk1ID
view.setUint32(16, 16, true); // Subchunk1Size
view.setUint16(20, 1, true); // AudioFormat (PCM)
view.setUint16(22, numChannels, true); // NumChannels
view.setUint32(24, sampleRate, true); // SampleRate
view.setUint32(28, sampleRate * numChannels * (bitsPerSample / 8), true); // ByteRate
view.setUint16(32, numChannels * (bitsPerSample / 8), true); // BlockAlign
view.setUint16(34, bitsPerSample, true); // BitsPerSample
writeString(view, 36, "data") // Subchunk2ID
view.setUint32(40, buffer.byteLength, true); // Subchunk2Size
//We create a valid Blob in WAV format
const wavBlob = new Blob([buffer], { type: "audio/wav" });
return new File([wavBlob], "dummy.wav", { type: "audio/wav" });
}
//Function to write text to WAV header
function writeString(view, offset, string) {
for (let i = 0; i < string.length; i++) {
view.setUint8(offset + i, string.charCodeAt(i));
}
}
import requests
import struct
# //Function to generate a dummy wav
def generate_wav():
sample_rate = 16000
num_channels = 1
duration = 2
bits_per_sample = 16
num_samples = sample_rate * duration
byte_rate = sample_rate * num_channels * (bits_per_sample // 8)
block_align = num_channels * (bits_per_sample // 8)
# Cabecera WAV
wav_header = struct.pack(
'<4sI4s4sIHHIIHH4sI',
b'RIFF', # ChunkID
36 + num_samples * block_align, # ChunkSize
b'WAVE', # Format
b'fmt ', # Subchunk1ID
16, # Subchunk1Size
1, # AudioFormat (PCM)
num_channels, # NumChannels
sample_rate, # SampleRate
byte_rate, # ByteRate
block_align, # BlockAlign
bits_per_sample, # BitsPerSample
b'data', # Subchunk2ID
num_samples * block_align # Subchunk2Size
)
# We generate empty data (silence)
audio_data = b'\x00' * (num_samples * block_align)
with open("dummy.wav", "wb") as f:
f.write(wav_header + audio_data)
return "dummy.wav"
wav_file = generate_wav()
files = {
"file": ("dummy.wav", open(wav_file, "rb"), "audio/wav")
}
data = {
"mode": "stt",
}
headers = {
"x-api-key": "xxxxxxx" # Your valid api key
}
response = requests.post("https://public.speaqr.ai/api/batch/file", headers=headers, files=files, data=data)
print("Response:", response.text)
import okhttp3.*;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class BatchFile {
public static void main(String[] args) {
String apiUrl = "https://public.speaqr.ai/api/batch/file";
String apiKey = "xxxxxxx"; //Your valid api key
// Generate dummy WAV file
String wavFilePath = "dummy.wav";
generateWavFile(wavFilePath);
// Send request to API
sendFileToApi(apiUrl, apiKey, wavFilePath);
}
// Function to generate a dummy WAV file
public static void generateWavFile(String filePath) {
int sampleRate = 16000;
int numChannels = 1;
int duration = 2;
int bitsPerSample = 16;
int numSamples = sampleRate * duration;
int byteRate = sampleRate * numChannels * (bitsPerSample / 8);
int blockAlign = numChannels * (bitsPerSample / 8);
int subchunk2Size = numSamples * blockAlign;
int chunkSize = 36 + subchunk2Size;
try (FileOutputStream fos = new FileOutputStream(filePath);
DataOutputStream dos = new DataOutputStream(fos)) {
// Write WAV header
dos.writeBytes("RIFF"); // ChunkID
dos.writeInt(Integer.reverseBytes(chunkSize)); // ChunkSize
dos.writeBytes("WAVE"); // Format
dos.writeBytes("fmt "); // Subchunk1ID
dos.writeInt(Integer.reverseBytes(16)); // Subchunk1Size
dos.writeShort(Short.reverseBytes((short) 1)); // AudioFormat (PCM)
dos.writeShort(Short.reverseBytes((short) numChannels)); // NumChannels
dos.writeInt(Integer.reverseBytes(sampleRate)); // SampleRate
dos.writeInt(Integer.reverseBytes(byteRate)); // ByteRate
dos.writeShort(Short.reverseBytes((short) blockAlign)); // BlockAlign
dos.writeShort(Short.reverseBytes((short) bitsPerSample)); // BitsPerSample
dos.writeBytes("data"); // Subchunk2ID
dos.writeInt(Integer.reverseBytes(subchunk2Size)); // Subchunk2Size
// Write silent audio data (zeros)
byte[] silence = new byte[subchunk2Size];
dos.write(silence);
System.out.println("WAV file generated: " + filePath);
} catch (IOException e) {
e.printStackTrace();
}
}
// Function to send file to API
public static void sendFileToApi(String apiUrl, String apiKey, String filePath) {
OkHttpClient client = new OkHttpClient();
// Create file request body
File file = new File(filePath);
RequestBody fileBody = RequestBody.create(file, MediaType.get("audio/wav"));
// Create multipart form-data request
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("mode", "stt")
.addFormDataPart("file", file.getName(), fileBody)
.build();
// Build HTTP request
Request request = new Request.Builder()
.url(apiUrl)
.post(requestBody)
.addHeader("x-api-key", apiKey)
.build();
// Execute request
try (Response response = client.newCall(request).execute()) {
String responseBody = (response.body() != null) ? response.body().string() : "No response body";
if (response.isSuccessful()) {
System.out.println("Response: " + responseBody);
} else {
System.out.println("Error: " + response.code() + " - " + response.message());
System.out.println("Response Body: " + responseBody); // Print JSON error response
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Resposta
A resposta JSON conterá apenas os campos do resultado especificado em mode
. O campo file.data
é um ArrayBuffer
em formato mp3.
Erros
Ligação de tomada
Compatibilidade
Para utilizar a API, é necessário desenvolver numa linguagem compatível com um cliente socket.io: Javascript, Java, C++, Swift, Dart, Python, .Net, Rust, Kotlin, PHP. https://socket.io/docs/v4Namespaces
As tomadas são organizadas por namespaces de acordo com a função a desempenhar, transcrição, tradução, síntese de fala ou o ciclo completo.A forma como são instanciados é independente do espaço de nomes a utilizar, embora cada um deles receba os seus próprios parâmetros.Exemplo
const namespace = 'translator';
const params = {
languageIdSource: 'en-gb',
languageIdTarget: 'fr-fr'
};
const Sockets = io("https://public.speaqr.ai/" + namespace, {
transports: ['websocket'],
upgrade: false,
auth: {token: "xxxxxxx"}, //Your valid api key
autoConnect: false,
reconnection: false,
query: params
});
Sockets.on('connect', () => console.log('connect!'));
Sockets.on('disconnect', reason => console.log('disconnect!', reason));
console.debug('Connecting to sockets...');
Sockets.connect();
setTimeout(() => Sockets.disconnect(), 5000);
import socketio
import threading
sio = socketio.Client()
api_key = "xxxxxxx"
params = {
"languageIdSource": "en-gb",
"languageIdTarget": "fr-fr"
}
query_string = "&".join(f"{k}={v}" for k, v in params.items())
@sio.on("connect", namespace="/translator")
def connect():
print("Connected to /translator")
@sio.on("disconnect", namespace="/translator")
def disconnect():
print("Disconnected from /translator")
@sio.on("connect_error", namespace="/translator")
def connect_error(data):
print("Connection error:", data)
sio.connect(
f"https://public.speaqr.ai/translator?{query_string}",
auth={"token": api_key},
transports=["websocket"],
namespaces=["/translator"]
)
print("Socket:", sio.connected)
print("Socket ID:", sio.sid)
print("Connected:", sio.connected)
print("Transport:", sio.transport())
threading.Timer(5, sio.disconnect).start()
sio.wait()
import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;
import java.util.HashMap;
import java.util.Map;
import java.net.URI;
import java.net.URISyntaxException;
public class Sockets_connect {
public static void main(String[] args) {
try {
// Define connection parameters
String params = "languageIdTarget=fr-fr&languageIdSource=en-gb";
String url = "https://public.speaqr.ai/translator?" + params;
// Configure WebSocket options
IO.Options options = new IO.Options();
options.transports = new String[]{"websocket"};
options.forceNew = true;
options.reconnection = false;
Map authData = new HashMap<>();
authData.put("token", "xxxxxxx");
options.auth = authData;
// Create socket instance
Socket socket = IO.socket(new URI(url), options);
// Event listeners
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("connect!");
}
});
socket.on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("disconnect! Reason: " + (args.length > 0 ? args[0] : "unknown"));
System.exit(0);
}
});
// Connecting
System.out.println("Connecting to sockets...");
socket.connect();
// Disconnect after 5 seconds
Thread.sleep(5000);
socket.disconnect();
} catch (URISyntaxException | InterruptedException e) {
e.printStackTrace();
}
}
}
Namespaces
Os espaços nominais suportados pela API Speaqr para a ligação de sockets são descritos a seguir.Transcrição
Transcreve o áudio que lhe é enviado.Url
https://public.speaqr.ai/stt
Parâmetros
Tradução
Traduz o texto que lhe é enviado de uma língua para outra.Url
https://public.speaqr.ai/translator
Parâmetros
Síntese de voz
Gera áudio a partir do texto que lhe é enviado.Url
https://public.speaqr.ai/tts
Parâmetros
Transcrição - tradução - syntexis
Transcreve o áudio que lhe é enviado, traduz-o e sintetiza um novo áudio com a tradução obtida.Url
https://public.speaqr.ai/sts
Parâmetros
Eventos recebidos
A seguir descrevem-se os eventos específicos dos sockets api.connected
Se este evento for recebido, a ligação foi bem sucedida. Recebe um objeto com os parâmetros que foram utilizados para a ligação.Resposta
start
Até este evento ser recebido, os sockets não estarão prontos para receber texto ou áudio, por isso, antes de enviar, é importante esperar por este evento. Pode receber uma resposta booleana ou, se invocou o streaming de áudio, o url para captar o áudio.Exemplo de "ligado" e "iniciar
const namespace = 'sts';
const params = {
languageIdTarget: 'fr-fr',
languageIdSource: 'en-gb',
sendAudio: JSON.stringify({
broadcastVia: 'chunk'
}),
receiveAudio: JSON.stringify({
obtainVia: 'chunk',
codec: 'mp3',
sampleRate: 16000
})
};
const Sockets = io("https://public.speaqr.ai/" + namespace, {
transports: ['websocket'],
upgrade: false,
auth: {token: "xxxxxxx"}, //Your valid api key
autoConnect: false,
reconnection: false,
query: params
});
Sockets.on('connect', () => {
console.log('connect!');
console.log('Waiting to be able to send data...');
});
Sockets.on('connected', (status) => {
console.log('Connection status', status);
});
Sockets.on('start', () => {
console.log('Speaqr is ready to receive data!');
setTimeout(() => Sockets.disconnect(), 5000);
});
Sockets.on('disconnect', reason => console.log('disconnect!', reason));
console.debug('Connecting to sockets...');
Sockets.connect();
import socketio
import urllib.parse
import os
api_key = "xxxxxxx"
params = {
"languageIdSource": "en-gb",
"languageIdTarget": "fr-fr",
"sendAudio": '{"broadcastVia": "chunk"}',
"receiveAudio": '{"obtainVia": "chunk", "codec": "mp3", "sampleRate": 16000}'
}
query_string = urllib.parse.urlencode(params)
sio = socketio.Client()
@sio.event(namespace="/sts")
def connect():
print("connect!")
print("Waiting to be able to send data...")
@sio.on("connected", namespace="/sts")
def on_connected(status):
print("Connection status:", status)
@sio.on("start", namespace="/sts")
def on_start(data):
print("Speaqr is ready to receive data.")
sio.sleep(5)
sio.disconnect()
@sio.event(namespace="/sts")
def disconnect(reason=None):
print("disconnect!", reason)
os._exit(0)
print("Connecting to Speaqr sockets...")
sio.connect(
f"https://public.speaqr.ai/sts?{query_string}",
auth={"token": api_key},
transports=["websocket"],
namespaces=["/sts"]
)
sio.wait()
import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
public class Sockets_evt_status_con {
public static void main(String[] args) {
try {
// Define connection parameters
String params = "languageIdTarget=fr-fr&languageIdSource=en-gb" +
"&sendAudio=" + encode("{\"broadcastVia\": \"chunk\"}") +
"&receiveAudio=" + encode("{\"obtainVia\": \"chunk\", \"codec\": \"mp3\", \"sampleRate\": 16000}");
String url = "https://public.speaqr.ai/sts?" + params;
// Configure WebSocket options
IO.Options options = new IO.Options();
options.transports = new String[]{"websocket"};
options.forceNew = true;
options.reconnection = false;
// Set authentication token
Map authData = new HashMap<>();
authData.put("token", "xxxxxxx"); // Your valid API key
options.auth = authData;
// Create socket instance
Socket socket = IO.socket(new URI(url), options);
// Event listeners
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("connect!");
System.out.println("Waiting to be able to send data...");
}
});
socket.on("connected", new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("Connection status: " + args[0]);
}
});
socket.on("start", new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("Speaqr is ready to receive data!");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
socket.disconnect();
}
});
socket.on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("disconnect! Reason: " + (args.length > 0 ? args[0] : "unknown"));
System.exit(0);
}
});
// Connecting
System.out.println("Connecting to sockets...");
socket.connect();
} catch (URISyntaxException e) {
e.printStackTrace();
System.exit(1);
}
}
// Helper method to encode JSON in query params
private static String encode(String value) {
return value.replace("{", "%7B").replace("}", "%7D")
.replace("\"", "%22").replace(":", "%3A")
.replace(",", "%2C").replace(" ", "%20");
}
}
result
Os campos do objeto que recebe dependerão do espaço de nomes utilizado. Abaixo está um objeto para o espaço de nomessts
que contém todos os campos possíveis.Resposta
endSynth
Este evento é recebido pelos namespacestts
e sts
. Ele é recebido quando a síntese de texto é concluída. Se receiveAudio.mode = 'block'
ele é recebido imediatamente após o evento result
. Se receiveAudio.mode = 'streaming'
ele é recebido imediatamente após o último evento result
.Resposta
error
Este evento recebe um objeto com diferentes descrições de erros que podem ocorrer, quer devido a erros de programação na instanciação dos modos de utilização, quer nos dados que estão a tentar ser processados. São enumerados os possíveis erros de execução.Erros
Transmissão de eventos
A seguir descrevem-se as transmissões para tratamento de dados suportadas pelas tomadas. As funções de envio recebem umack
com o estado do envio.text
Envia um texto para ser processado.Exemplo
const namespace = 'translator';
const params = {
languageIdSource: 'en-gb',
languageIdTarget: 'fr-fr'
};
const Sockets = io("https://public.speaqr.ai/" + namespace, {
transports: ['websocket'],
upgrade: false,
auth: {token: "xxxxxxx"}, //Your valid api key
autoConnect: false,
reconnection: false,
query: params
});
Sockets.on('connect', () => {
console.log('connect!');
console.log('Waiting to be able to send data...');
});
Sockets.on('error', (error) => {
console.log('error!', error);
});
Sockets.on('connected', (status) => {
console.log('Connection status', status);
});
Sockets.on('start', () => {
console.log('Speaqr is ready to receive data!');
console.log('I send text to translate...');
Sockets.emit('text', 'Hello word!. I want to translate it into French.', (ack) =>{
console.log('ack emit text', ack);
});
});
Sockets.on('result', (response) => {
console.log('response', response);
Sockets.disconnect();
});
Sockets.on('disconnect', reason => console.log('disconnect!', reason));
console.debug('Connecting to sockets...');
Sockets.connect();
import socketio
import urllib.parse
import os
api_key = "xxxxxxx"
params = {
"languageIdSource": "en-gb",
"languageIdTarget": "fr-fr"
}
query_string = urllib.parse.urlencode(params)
sio = socketio.Client()
@sio.event(namespace="/translator")
def connect():
print("connect!")
print("Waiting to be able to send data...")
@sio.on("error", namespace="/translator")
def on_error(error):
print("error!", error)
@sio.on("connected", namespace="/translator")
def on_connected(status):
print("Connection status", status)
@sio.on("start", namespace="/translator")
def on_start(data):
print("Speaqr is ready to receive data!")
print("I send text to translate...")
sio.emit("text", "Hello world! I want to translate it into French.", namespace="/translator", callback=on_ack)
@sio.on("result", namespace="/translator")
def on_result(response):
print("response", response)
sio.disconnect()
@sio.event(namespace="/translator")
def disconnect(reason=None):
print("disconnect!", reason)
os._exit(0)
def on_ack(ack):
print("ack emit text", ack)
print("Connecting to sockets...")
sio.connect(
f"https://public.speaqr.ai/translator?{query_string}",
auth={"token": api_key},
transports=["websocket"],
namespaces=["/translator"]
)
sio.wait()
import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;
import io.socket.client.Ack;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;
public class Sockets_emit_text {
public static void main(String[] args) {
try {
// Define connection parameters
String params = "languageIdSource=en-gb&languageIdTarget=fr-fr";
String url = "https://public.speaqr.ai/translator?" + params;
// Configure WebSocket options
IO.Options options = new IO.Options();
options.transports = new String[]{"websocket"};
options.forceNew = true;
options.reconnection = false;
// Set authentication token
Map authData = new HashMap<>();
authData.put("token", "xxxxxxx"); // Your valid API key
options.auth = authData;
// Create socket instance
Socket socket = IO.socket(new URI(url), options);
// Event listeners
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("connect!");
System.out.println("Waiting to be able to send data...");
}
});
socket.on("error", new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("error! " + (args.length > 0 ? args[0] : "unknown"));
}
});
socket.on("connected", new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("Connection status: " + (args.length > 0 ? args[0] : "unknown"));
}
});
socket.on("start", new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("Speaqr is ready to receive data!");
System.out.println("I send text to translate...");
// Emit text and handle acknowledgment
socket.emit("text", "Hello world! I want to translate it into French.", new Ack() {
@Override
public void call(Object... ackArgs) {
System.out.println("ack emit text: " + (ackArgs.length > 0 ? ackArgs[0] : "No ack received"));
}
});
}
});
socket.on("result", new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("response: " + (args.length > 0 ? args[0] : "unknown"));
socket.disconnect();
}
});
socket.on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("disconnect! Reason: " + (args.length > 0 ? args[0] : "unknown"));
System.exit(0);
}
});
// Connecting
System.out.println("Connecting to sockets...");
socket.connect();
} catch (URISyntaxException e) {
e.printStackTrace();
System.exit(1);
}
}
}
write_stream
Envia um fragmento de áudio para ser processado.Exemplo
No exemplo seguinte, o microfone do dispositivo é captado e a primeira frase ouvida é transcrita.
let mediaRecorder = null;
const namespace = 'stt';
const params = {
languageIdSource: 'en-gb',
sendAudio: JSON.stringify({
broadcastVia: 'chunk'
})
};
const Sockets = io("https://public.speaqr.ai/" + namespace, {
transports: ['websocket'],
upgrade: false,
auth: {token: "xxxxxxx"}, //Your valid api key
autoConnect: false,
reconnection: false,
query: params
});
Sockets.on('connect', () => {
console.log('connect!');
console.log('Waiting to be able to send data...');
});
Sockets.on('error', (error) => {
console.log('error!', error);
});
Sockets.on('connected', (status) => {
console.log('Connection status', status);
});
Sockets.on('start', () => {
console.log('Speaqr is ready to receive data. Speak now in English!!!!');
start();
});
Sockets.on('result', (response) => {
console.log('first response\n-----------------------\n\n');
console.log(response);
console.log('\n\n-----------------------\n\n');
console.log('We stopped listening!');
stop();
Sockets.disconnect();
});
Sockets.on('disconnect', reason => console.log('disconnect!', reason));
console.debug('Connecting to sockets...');
Sockets.connect();
// Start capturing and processing microphone audio
const start = async () => {
navigator.mediaDevices.getUserMedia({ audio: true })
.then(stream => {
mediaRecorder = new MediaRecorder(stream);
mediaRecorder.ondataavailable = ondataavailable;
mediaRecorder.start(500);
})
.catch(error => {
console.error("Error starting recording:", error);
});
}
// Here you receive each audio fragment in a Blob
const ondataavailable = (event) => {
if (event.data && event.data.size > 0) {
const audioChunk = event.data;
console.log('audio chunk', audioChunk);
Sockets.emit('write_stream', audioChunk, (ack) => {
if (!ack) console.error("Error write_stream", ack);
});
}
};
// Stop the process
const stop = async () => {
try {
//We stop the MediaRecorder
if (mediaRecorder){
mediaRecorder.stop();
mediaRecorder = null;
}
} catch (error) {
console.error("Error while stopping resources", error);
}
}
import socketio
import sounddevice as sd
import numpy as np
import urllib.parse
import signal
import sys
import threading
import time
SAMPLE_RATE = 16000
CHANNELS = 1
CHUNK_SIZE = 1024
api_key = "xxxxxxx"
params = {
"languageIdSource": "en-gb",
"sendAudio": '{"broadcastVia": "chunk", "codec": "linear16", "sampleRate": 16000}',
}
query_string = urllib.parse.urlencode(params)
sio = socketio.Client()
stream = None
should_exit = False
@sio.event(namespace="/stt")
def connect():
print("connect!")
@sio.on("connected", namespace="/stt")
def on_connected(status):
print("Connection status", status)
@sio.on("start", namespace="/stt")
def on_start(_):
print("Speaqr is ready to receive data. Speak now in English!")
start_recording()
@sio.on("result", namespace="/stt")
def on_result(response):
print("response:\n", response)
stop()
@sio.event(namespace="/stt")
def disconnect(reason=None):
print("disconnect!", reason)
global should_exit
should_exit = True
@sio.on("error", namespace="/stt")
def on_error(error):
print("error!", error)
def audio_callback(indata, frames, time, status):
if status:
print(status)
audio_data = indata.copy().astype(np.int16).tobytes()
sio.emit("write_stream", audio_data, namespace="/stt", callback=on_ack)
def on_ack(ok):
if not ok:
print("write_stream ack = False")
def start_recording():
global stream
stream = sd.InputStream(samplerate=SAMPLE_RATE, channels=CHANNELS, dtype='int16',
blocksize=CHUNK_SIZE, callback=audio_callback)
stream.start()
print("Recording... Press Ctrl+C to stop.")
def stop():
global stream, should_exit
if stream:
print("Stopping and closing stream...")
stream.stop()
stream.close()
stream = None
print("Disconnecting socket...")
sio.disconnect()
should_exit = True
def signal_handler(sig, frame):
print("Ctrl+C pressed. Exiting...")
stop()
signal.signal(signal.SIGINT, signal_handler)
print("Connecting to sockets...")
sio.connect(
f"https://public.speaqr.ai/stt?{query_string}",
auth={"token": api_key},
transports=["websocket"],
namespaces=["/stt"]
)
# Espera activa (se puede interrumpir con Ctrl+C en Windows)
while not should_exit:
time.sleep(0.2)
import io.socket.client.IO;
import io.socket.client.Socket;
import io.socket.emitter.Emitter;
import javax.sound.sampled.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class Sockets_emit_write_stream {
private static Socket socket;
private static boolean recording = false;
private static TargetDataLine microphone;
public static void main(String[] args) {
try {
// Define connection parameters
String params = "languageIdSource=en-gb" +
"&sendAudio=" + encode("{\"broadcastVia\": \"chunk\", \"codec\": \"linear16\", \"sampleRate\": 16000}");
String url = "https://public.speaqr.ai/stt?" + params;
// Configure WebSocket options
IO.Options options = new IO.Options();
options.transports = new String[]{"websocket"};
options.forceNew = true;
options.reconnection = false;
// Set authentication token
Map authData = new HashMap<>();
authData.put("token", "xxxxxxx"); // Your valid API key
options.auth = authData;
// Create socket instance
socket = IO.socket(new URI(url), options);
// Event listeners
socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("connect!");
System.out.println("Waiting to be able to send data...");
}
});
socket.on("error", new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("error! " + (args.length > 0 ? args[0] : "unknown"));
}
});
socket.on("connected", new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("Connection status: " + (args.length > 0 ? args[0] : "unknown"));
}
});
socket.on("start", new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("Speaqr is ready to receive data. Speak now in English!!!!");
startRecording();
}
});
socket.on("result", new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("first response\n-----------------------\n\n");
System.out.println(args.length > 0 ? args[0] : "unknown");
System.out.println("\n\n-----------------------\n\n");
System.out.println("We stopped listening!");
stopRecording();
socket.disconnect();
}
});
socket.on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {
@Override
public void call(Object... args) {
System.out.println("disconnect! Reason: " + (args.length > 0 ? args[0] : "unknown"));
System.exit(0);
}
});
// Connecting
System.out.println("Connecting to sockets...");
socket.connect();
} catch (URISyntaxException e) {
e.printStackTrace();
System.exit(1);
}
}
// Start capturing and processing microphone audio
private static void startRecording() {
recording = true;
new Thread(() -> {
try {
AudioFormat format = new AudioFormat(16000, 16, 1, true, false);
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
if (!AudioSystem.isLineSupported(info)) {
System.err.println("Microphone not supported");
return;
}
microphone = (TargetDataLine) AudioSystem.getLine(info);
microphone.open(format);
microphone.start();
byte[] buffer = new byte[1024];
ByteArrayOutputStream out = new ByteArrayOutputStream();
System.out.println("Recording...");
while (recording) {
int bytesRead = microphone.read(buffer, 0, buffer.length);
if (bytesRead > 0) {
// Print a small portion of the buffer for debugging
System.out.println("Captured audio data: " + Arrays.toString(Arrays.copyOf(buffer, 10)) + "...");
socket.emit("write_stream", buffer);
}
}
microphone.stop();
microphone.close();
out.close();
System.out.println("Recording stopped.");
} catch (LineUnavailableException | IOException e) {
e.printStackTrace();
}
}).start();
}
// Stop the process
private static void stopRecording() {
recording = false;
}
// Helper method to encode JSON in query params
private static String encode(String value) {
return value.replace("{", "%7B").replace("}", "%7D")
.replace("\"", "%22").replace(":", "%3A")
.replace(",", "%2C").replace(" ", "%20");
}
}
Este sítio Web utiliza cookies
Os cookies neste sítio Web são utilizados para personalizar o conteúdo e analisar o tráfego.
Pode encontrar os detalhes destes cookies na secção Política de Privacidade.