Skip to content

Instantly share code, notes, and snippets.

@xiprox
Last active January 23, 2024 11:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xiprox/118fe3042e333fa2b022a7e09d4ebe5f to your computer and use it in GitHub Desktop.
Save xiprox/118fe3042e333fa2b022a7e09d4ebe5f to your computer and use it in GitHub Desktop.
OpenAI TTS chunked transfer streaming dart (not working on web)
import 'dart:convert';
import 'package:universal_io/io.dart';
import 'package:http/http.dart' as http;
import 'dart:typed_data';
const _kOpenAiApiKey = 'sk-QDU...';
abstract interface class OpenAiApi {
Future<Uint8List> textToSpeech(
String text, {
String? voice,
double? speed,
});
Future<Stream<List<int>>> textToSpeechStream(
String text, {
String? voice,
double? speed,
});
}
class OpenAiApiImpl implements OpenAiApi {
@override
Future<Uint8List> textToSpeech(
String text, {
String? voice,
double? speed,
}) async {
try {
final response = await http.post(
Uri.parse('https://api.openai.com/v1/audio/speech'),
headers: {
'Authorization': 'Bearer $_kOpenAiApiKey',
HttpHeaders.contentTypeHeader: 'application/json',
},
body: json.encode({
'model': 'tts-1',
'voice': voice ?? 'nova',
'input': text,
'speed': speed?.toString() ?? '1',
}),
);
if (response.statusCode != 200) {
throw Exception(
'Error generating speech: '
'${response.statusCode} - ${response.reasonPhrase} \n '
'${response.body}',
);
} else {
logger.i('Audio generated successfully');
return response.bodyBytes;
}
} catch (e, s) {
logger.e(e);
logger.e(s);
}
return Uint8List(0);
}
@override
Future<Stream<List<int>>> textToSpeechStream(
String text, {
String? voice,
double? speed,
}) async {
try {
final request = http.Request(
'POST',
Uri.parse('https://api.openai.com/v1/audio/speech'),
);
request.headers.addAll({
'Authorization': 'Bearer $_kOpenAiApiKey',
// HttpHeaders.transferEncodingHeader: 'chunked',
HttpHeaders.contentTypeHeader: 'application/json',
});
request.body = json.encode({
'model': 'tts-1',
'voice': voice ?? 'nova',
'input': text,
'speed': speed?.toString() ?? '1',
});
final streamedResponse = await request.send();
if (streamedResponse.statusCode != 200) {
final response = await http.Response.fromStream(streamedResponse);
throw Exception(
'Error generating speech: '
'${response.statusCode} - ${response.reasonPhrase} \n '
'${response.body}',
);
} else {
logger.i('Audio generated successfully');
return streamedResponse.stream.asBroadcastStream();
}
} catch (e, s) {
logger.e(e);
logger.e(s);
}
return const Stream.empty();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment