diff --git a/CODEOWNERS b/CODEOWNERS
index 0526f553154..71e75f22779 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -465,6 +465,7 @@
/bundles/org.openhab.voice.mactts/ @kaikreuzer
/bundles/org.openhab.voice.marytts/ @kaikreuzer
/bundles/org.openhab.voice.mimictts/ @dalgwen
+/bundles/org.openhab.voice.openaitts/ @Artur-Fedjukevits
/bundles/org.openhab.voice.picotts/ @FlorianSW
/bundles/org.openhab.voice.pipertts/ @GiviMAD
/bundles/org.openhab.voice.pollytts/ @openhab/add-ons-maintainers
diff --git a/bom/openhab-addons/pom.xml b/bom/openhab-addons/pom.xml
index 170f8ce163d..ea798c3d2c6 100644
--- a/bom/openhab-addons/pom.xml
+++ b/bom/openhab-addons/pom.xml
@@ -2301,6 +2301,11 @@
org.openhab.voice.mimictts
${project.version}
+
+ org.openhab.addons.bundles
+ org.openhab.voice.openaitts
+ ${project.version}
+
org.openhab.addons.bundles
org.openhab.voice.picotts
diff --git a/bundles/org.openhab.voice.openaitts/NOTICE b/bundles/org.openhab.voice.openaitts/NOTICE
new file mode 100644
index 00000000000..4205fa32370
--- /dev/null
+++ b/bundles/org.openhab.voice.openaitts/NOTICE
@@ -0,0 +1,14 @@
+This content is produced and maintained by the openHAB project.
+
+* Project home: https://www.openhab.org
+
+== Declared Project Licenses
+
+This program and the accompanying materials are made available under the terms
+of the Eclipse Public License 2.0 which is available at
+https://www.eclipse.org/legal/epl-2.0/.
+
+== Source Code
+
+https://github.com/openhab/openhab-addons
+
diff --git a/bundles/org.openhab.voice.openaitts/README.md b/bundles/org.openhab.voice.openaitts/README.md
new file mode 100644
index 00000000000..4793ad9b7da
--- /dev/null
+++ b/bundles/org.openhab.voice.openaitts/README.md
@@ -0,0 +1,23 @@
+# OpenAI Text-to-Speech
+
+The OpenAI TTS (Text-to-Speech) add-on for openHAB allows you to integrate OpenAI's Text-to-Speech capabilities into your openHAB system.
+The advantage of this service over others is that one selected voice can speak different languages.
+This is useful, for example, in conjunction with ChatGPT binding, which will help in learning foreign languages.
+You can find the price for this service here - https://openai.com/api/pricing/
+
+## Configuration
+
+To configure the OpenAI TTS, **Settings / Other Services - OpenAI Text-to-Speech** and set:
+
+* **apiKey** - The API key to be used for the requests.
+* **apiUrl** - The server API where to reach the AI TTS service.
+* **model** - The ID of the model to use for TTS.
+
+### Default Text-to-Speech and Voice Configuration
+
+You can setup your preferred default Text-to-Speech and default voice in the UI:
+
+* Go to **Settings**.
+* Edit **System Services - Voice**.
+* Set **OpenAI TTS Service** as **Default Text-to-Speech**.
+* Choose your preferred **Default Voice** for your setup.
diff --git a/bundles/org.openhab.voice.openaitts/pom.xml b/bundles/org.openhab.voice.openaitts/pom.xml
new file mode 100644
index 00000000000..46b4723b676
--- /dev/null
+++ b/bundles/org.openhab.voice.openaitts/pom.xml
@@ -0,0 +1,16 @@
+
+
+
+ 4.0.0
+
+
+ org.openhab.addons.bundles
+ org.openhab.addons.reactor.bundles
+ 5.0.0-SNAPSHOT
+
+
+ org.openhab.voice.openaitts
+
+ openHAB Add-ons :: Bundles :: Voice :: OpenAI Text-to-Speech
+
diff --git a/bundles/org.openhab.voice.openaitts/src/main/feature/feature.xml b/bundles/org.openhab.voice.openaitts/src/main/feature/feature.xml
new file mode 100644
index 00000000000..917ab777c38
--- /dev/null
+++ b/bundles/org.openhab.voice.openaitts/src/main/feature/feature.xml
@@ -0,0 +1,9 @@
+
+
+ mvn:org.openhab.core.features.karaf/org.openhab.core.features.karaf.openhab-core/${ohc.version}/xml/features
+
+
+ openhab-runtime-base
+ mvn:org.openhab.addons.bundles/org.openhab.voice.openaitts/${project.version}
+
+
diff --git a/bundles/org.openhab.voice.openaitts/src/main/java/org/openhab/voice/openaitts/internal/OpenAITTSConfiguration.java b/bundles/org.openhab.voice.openaitts/src/main/java/org/openhab/voice/openaitts/internal/OpenAITTSConfiguration.java
new file mode 100644
index 00000000000..d560a52d35c
--- /dev/null
+++ b/bundles/org.openhab.voice.openaitts/src/main/java/org/openhab/voice/openaitts/internal/OpenAITTSConfiguration.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2010-2024 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.voice.openaitts.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * @author Artur Fedjukevits - Initial contribution
+ */
+@NonNullByDefault
+public class OpenAITTSConfiguration {
+
+ public String apiKey = "";
+ public String apiUrl = "https://api.openai.com/v1/audio/speech";
+ public String model = "tts-1";
+ public String speed = "1";
+}
diff --git a/bundles/org.openhab.voice.openaitts/src/main/java/org/openhab/voice/openaitts/internal/OpenAITTSConstants.java b/bundles/org.openhab.voice.openaitts/src/main/java/org/openhab/voice/openaitts/internal/OpenAITTSConstants.java
new file mode 100644
index 00000000000..32a9fc7310a
--- /dev/null
+++ b/bundles/org.openhab.voice.openaitts/src/main/java/org/openhab/voice/openaitts/internal/OpenAITTSConstants.java
@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2010-2024 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.voice.openaitts.internal;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+
+/**
+ * @author Artur Fedjukevits - Initial contribution
+ */
+@NonNullByDefault
+public class OpenAITTSConstants {
+
+ public static final String TTS_SERVICE_ID = "openaitts";
+ public static final String TTS_SERVICE_PID = "org.openhab.voice.openaitts";
+}
diff --git a/bundles/org.openhab.voice.openaitts/src/main/java/org/openhab/voice/openaitts/internal/OpenAITTSService.java b/bundles/org.openhab.voice.openaitts/src/main/java/org/openhab/voice/openaitts/internal/OpenAITTSService.java
new file mode 100644
index 00000000000..3e6b0cae2c8
--- /dev/null
+++ b/bundles/org.openhab.voice.openaitts/src/main/java/org/openhab/voice/openaitts/internal/OpenAITTSService.java
@@ -0,0 +1,148 @@
+/**
+ * Copyright (c) 2010-2024 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.voice.openaitts.internal;
+
+import static org.openhab.voice.openaitts.internal.OpenAITTSConstants.*;
+
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.client.api.ContentResponse;
+import org.eclipse.jetty.client.util.StringContentProvider;
+import org.eclipse.jetty.http.HttpMethod;
+import org.eclipse.jetty.http.HttpStatus;
+import org.openhab.core.audio.AudioFormat;
+import org.openhab.core.audio.AudioStream;
+import org.openhab.core.audio.ByteArrayAudioStream;
+import org.openhab.core.config.core.ConfigurableService;
+import org.openhab.core.config.core.Configuration;
+import org.openhab.core.io.net.http.HttpClientFactory;
+import org.openhab.core.voice.AbstractCachedTTSService;
+import org.openhab.core.voice.TTSCache;
+import org.openhab.core.voice.TTSException;
+import org.openhab.core.voice.TTSService;
+import org.openhab.core.voice.Voice;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Modified;
+import org.osgi.service.component.annotations.Reference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+
+/**
+ * @author Artur Fedjukevits - Initial contribution
+ * API documentation: https://platform.openai.com/docs/guides/text-to-speech
+ */
+@Component(configurationPid = TTS_SERVICE_PID, property = Constants.SERVICE_PID + "="
+ + TTS_SERVICE_PID, service = TTSService.class)
+@ConfigurableService(category = "voice", label = "OpenAI TTS Service", description_uri = "voice:" + TTS_SERVICE_ID)
+
+@NonNullByDefault
+public class OpenAITTSService extends AbstractCachedTTSService {
+
+ private static final int REQUEST_TIMEOUT_MS = 10_000;
+ private final Logger logger = LoggerFactory.getLogger(OpenAITTSService.class);
+ private OpenAITTSConfiguration config = new OpenAITTSConfiguration();
+ private final HttpClient httpClient;
+ private final Gson gson = new Gson();
+ private static final Set VOICES = Stream.of("nova", "alloy", "echo", "fable", "onyx", "shimmer")
+ .map(OpenAITTSVoice::new).collect(Collectors.toSet());
+
+ @Activate
+ public OpenAITTSService(@Reference HttpClientFactory httpClientFactory, @Reference TTSCache ttsCache,
+ Map config) {
+ super(ttsCache);
+ this.httpClient = httpClientFactory.getCommonHttpClient();
+ }
+
+ @Activate
+ protected void activate(Map config) {
+ this.config = new Configuration(config).as(OpenAITTSConfiguration.class);
+ }
+
+ @Modified
+ protected void modified(Map config) {
+ this.config = new Configuration(config).as(OpenAITTSConfiguration.class);
+ }
+
+ @Override
+ public Set getSupportedFormats() {
+ return Set.of(new AudioFormat(AudioFormat.CONTAINER_NONE, AudioFormat.CODEC_MP3, null, 16, 64000, 44100L));
+ }
+
+ @Override
+ public String getId() {
+ return TTS_SERVICE_ID;
+ }
+
+ @Override
+ public String getLabel(@Nullable Locale locale) {
+ return "OpenAI TTS Service";
+ }
+
+ @Override
+ public Set getAvailableVoices() {
+ return VOICES;
+ }
+
+ /**
+ * Synthesizes the given text to audio data using the OpenAI API
+ *
+ * @param text The text to synthesize
+ * @param voice The voice to use
+ * @param requestedFormat The requested audio format
+ * @return The synthesized audio data
+ * @throws TTSException If the synthesis fails
+ */
+ @Override
+ public AudioStream synthesizeForCache(String text, Voice voice, AudioFormat requestedFormat) throws TTSException {
+ JsonObject content = new JsonObject();
+ content.addProperty("model", config.model);
+ content.addProperty("input", text);
+ content.addProperty("voice", voice.getLabel().toLowerCase());
+ content.addProperty("speed", config.speed);
+
+ String queryJson = gson.toJson(content);
+
+ try {
+ ContentResponse response = httpClient.newRequest(config.apiUrl).method(HttpMethod.POST)
+ .timeout(REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS)
+ .header("Authorization", "Bearer " + config.apiKey).header("Content-Type", "application/json")
+ .content(new StringContentProvider(queryJson)).send();
+
+ if (response.getStatus() == HttpStatus.OK_200) {
+ return new ByteArrayAudioStream(response.getContent(), requestedFormat);
+ } else {
+ logger.error("Request resulted in HTTP {} with message: {}", response.getStatus(),
+ response.getReason());
+ throw new TTSException("Failed to generate audio data");
+ }
+ } catch (InterruptedException | TimeoutException | ExecutionException e) {
+ logger.error("Request to OpenAI failed: {}", e.getMessage(), e);
+ throw new TTSException("Failed to generate audio data");
+ }
+ }
+}
diff --git a/bundles/org.openhab.voice.openaitts/src/main/java/org/openhab/voice/openaitts/internal/OpenAITTSVoice.java b/bundles/org.openhab.voice.openaitts/src/main/java/org/openhab/voice/openaitts/internal/OpenAITTSVoice.java
new file mode 100644
index 00000000000..f5f155b036a
--- /dev/null
+++ b/bundles/org.openhab.voice.openaitts/src/main/java/org/openhab/voice/openaitts/internal/OpenAITTSVoice.java
@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2010-2024 Contributors to the openHAB project
+ *
+ * See the NOTICE file(s) distributed with this work for additional
+ * information.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ */
+package org.openhab.voice.openaitts.internal;
+
+import java.util.Locale;
+
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.openhab.core.voice.Voice;
+
+/**
+ * @author Artur Fedjukevits - Initial contribution
+ */
+@NonNullByDefault
+public class OpenAITTSVoice implements Voice {
+
+ private final String label;
+
+ public OpenAITTSVoice(String label) {
+ this.label = label;
+ }
+
+ /**
+ * The unique identifier of the voice, used for internal purposes
+ *
+ * @return The unique identifier of the voice
+ */
+ @Override
+ public String getUID() {
+ return "openaitts:" + label;
+ }
+
+ /**
+ * The voice label, used for GUI's or VUI's
+ *
+ * @return The voice label
+ */
+ @Override
+ public String getLabel() {
+ return Character.toUpperCase(label.charAt(0)) + label.substring(1);
+ }
+
+ /**
+ * The locale of the voice
+ *
+ * @return The locale of the voice
+ */
+ @Override
+ public Locale getLocale() {
+ return Locale.ENGLISH;
+ }
+}
diff --git a/bundles/org.openhab.voice.openaitts/src/main/resources/OH-INF/addon/addon.xml b/bundles/org.openhab.voice.openaitts/src/main/resources/OH-INF/addon/addon.xml
new file mode 100644
index 00000000000..a3934d428a2
--- /dev/null
+++ b/bundles/org.openhab.voice.openaitts/src/main/resources/OH-INF/addon/addon.xml
@@ -0,0 +1,15 @@
+
+
+
+ voice
+ OpenAI Text-to-Speech
+ OpenAI TTS Service provides text-to-speech capabilities for openHAB.
+ cloud
+
+ org.openhab.voice.openaitts
+
+
+
+
diff --git a/bundles/org.openhab.voice.openaitts/src/main/resources/OH-INF/config/config.xml b/bundles/org.openhab.voice.openaitts/src/main/resources/OH-INF/config/config.xml
new file mode 100644
index 00000000000..581fd450e0e
--- /dev/null
+++ b/bundles/org.openhab.voice.openaitts/src/main/resources/OH-INF/config/config.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+ Authentication for connecting to OpenAI API.
+
+
+
+ Configure Text to Speech.
+
+
+
+ true
+ OpenAI API key.
+ password
+
+
+
+ true
+ TTS host API URL.
+ https://api.openai.com/v1/audio/speech
+
+
+
+ true
+ ID of the model to use.
+
+
+
+
+ false
+ tts-1
+
+
+
+ The speed of the generated audio. Select a value from 0.25 to 4.0.
+ 1.0
+
+
+
+
diff --git a/bundles/org.openhab.voice.openaitts/src/main/resources/OH-INF/i18n/openaitts.properties b/bundles/org.openhab.voice.openaitts/src/main/resources/OH-INF/i18n/openaitts.properties
new file mode 100644
index 00000000000..a66ca6fff71
--- /dev/null
+++ b/bundles/org.openhab.voice.openaitts/src/main/resources/OH-INF/i18n/openaitts.properties
@@ -0,0 +1,17 @@
+# add-on
+
+addon.openaitts.name = OpenAI Text-to-Speech
+addon.openaitts.description = OpenAI TTS Service provides text-to-speech capabilities for openHAB.
+
+voice.config.openaitts.apiKey.label = API Key
+voice.config.openaitts.apiKey.description = OpenAI API key.
+voice.config.openaitts.apiUrl.label = API URL
+voice.config.openaitts.apiUrl.description = TTS host API URL.
+voice.config.openaitts.group.authentication.label = Authentication
+voice.config.openaitts.group.authentication.description = Authentication for connecting to OpenAI API.
+voice.config.openaitts.group.tts.label = TTS Configuration
+voice.config.openaitts.group.tts.description = Configure Text to Speech.
+voice.config.openaitts.model.label = Model
+voice.config.openaitts.model.description = ID of the model to use.
+voice.config.openaitts.speed.label = Speed
+voice.config.openaitts.speed.description = The speed of the generated audio. Select a value from 0.25 to 4.0.
diff --git a/bundles/pom.xml b/bundles/pom.xml
index 68102f6c939..f3ae1218ef6 100644
--- a/bundles/pom.xml
+++ b/bundles/pom.xml
@@ -483,6 +483,7 @@
org.openhab.voice.mactts
org.openhab.voice.marytts
org.openhab.voice.mimictts
+ org.openhab.voice.openaitts
org.openhab.voice.picotts
org.openhab.voice.pipertts
org.openhab.voice.pollytts