From 34a13250f3b878a13e56d5dd5d0eda45d4e884c5 Mon Sep 17 00:00:00 2001 From: Almas Baim Date: Tue, 26 Mar 2024 08:57:02 +0000 Subject: [PATCH] refactor: load fxgl-intelligence locally, keep consistent package structure --- .../com/almasb/fxgl/intelligence/WebAPI.java | 24 +++++- .../almasb/fxgl/intelligence/WebAPIService.kt | 2 + .../{ => intelligence}/gesturerecog/Hand.kt | 2 +- .../gesturerecog/HandLandmark.kt | 2 +- .../gesturerecog/HandTrackingService.kt | 2 +- .../intelligence/tts/TextToSpeechService.kt | 1 - .../almasb/fxgl/intelligence/rpc-common.js | 20 +++++ .../almasb/fxgl/intelligence/tts/index.html | 24 ++++++ .../almasb/fxgl/intelligence/tts/script.js | 82 +++++++++++++++++++ .../java/sandbox/net/HandTrackingSample.java | 2 +- 10 files changed, 155 insertions(+), 6 deletions(-) rename fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/{ => intelligence}/gesturerecog/Hand.kt (92%) rename fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/{ => intelligence}/gesturerecog/HandLandmark.kt (93%) rename fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/{ => intelligence}/gesturerecog/HandTrackingService.kt (98%) create mode 100644 fxgl-intelligence/src/main/resources/com/almasb/fxgl/intelligence/rpc-common.js create mode 100644 fxgl-intelligence/src/main/resources/com/almasb/fxgl/intelligence/tts/index.html create mode 100644 fxgl-intelligence/src/main/resources/com/almasb/fxgl/intelligence/tts/script.js diff --git a/fxgl-intelligence/src/main/java/com/almasb/fxgl/intelligence/WebAPI.java b/fxgl-intelligence/src/main/java/com/almasb/fxgl/intelligence/WebAPI.java index 65f37b967..435703701 100644 --- a/fxgl-intelligence/src/main/java/com/almasb/fxgl/intelligence/WebAPI.java +++ b/fxgl-intelligence/src/main/java/com/almasb/fxgl/intelligence/WebAPI.java @@ -6,6 +6,8 @@ package com.almasb.fxgl.intelligence; +import com.almasb.fxgl.logging.Logger; + /** * Stores constants related to web-api projects. * Changes to these values must be synchronized with the web-api project (https://github.com/AlmasB/web-api). @@ -14,11 +16,31 @@ */ public final class WebAPI { - public static final String TEXT_TO_SPEECH_API = "https://almasb.github.io/web-api/text-to-speech-v1/"; + private static final Logger log = Logger.get(WebAPI.class); + + public static final String TEXT_TO_SPEECH_API = getURL("tts/index.html"); public static final String SPEECH_RECOGNITION_API = "https://almasb.github.io/web-api/speech-recog-v1/"; public static final String GESTURE_RECOGNITION_API = "https://almasb.github.io/web-api/gesture-recog-v1/"; public static final int TEXT_TO_SPEECH_PORT = 55550; public static final int SPEECH_RECOGNITION_PORT = 55555; public static final int GESTURE_RECOGNITION_PORT = 55560; + + static { + log.debug("TTS API: " + TEXT_TO_SPEECH_API + ":" + TEXT_TO_SPEECH_PORT); + } + + private static String getURL(String relativeURL) { + try { + var url = WebAPI.class.getResource(relativeURL).toExternalForm(); + + if (url != null) + return url; + + } catch (Exception e) { + log.warning("Failed to get url: " + relativeURL, e); + } + + return "DUMMY_URL"; + } } diff --git a/fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/intelligence/WebAPIService.kt b/fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/intelligence/WebAPIService.kt index e75e3905e..f0aa66575 100644 --- a/fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/intelligence/WebAPIService.kt +++ b/fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/intelligence/WebAPIService.kt @@ -85,6 +85,8 @@ abstract class WebAPIService(server: LocalWebSocketServer, private val apiURL: S driverSuppliers.forEach { supplier -> try { + log.debug("WebDriver opening: $url") + val driver = supplier() driver.get(url) return driver diff --git a/fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/gesturerecog/Hand.kt b/fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/intelligence/gesturerecog/Hand.kt similarity index 92% rename from fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/gesturerecog/Hand.kt rename to fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/intelligence/gesturerecog/Hand.kt index 643396b25..e2bfbd8d6 100644 --- a/fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/gesturerecog/Hand.kt +++ b/fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/intelligence/gesturerecog/Hand.kt @@ -4,7 +4,7 @@ * See LICENSE for details. */ -package com.almasb.fxgl.gesturerecog +package com.almasb.fxgl.intelligence.gesturerecog import javafx.geometry.Point3D diff --git a/fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/gesturerecog/HandLandmark.kt b/fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/intelligence/gesturerecog/HandLandmark.kt similarity index 93% rename from fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/gesturerecog/HandLandmark.kt rename to fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/intelligence/gesturerecog/HandLandmark.kt index 2050eda8a..a92f3654a 100644 --- a/fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/gesturerecog/HandLandmark.kt +++ b/fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/intelligence/gesturerecog/HandLandmark.kt @@ -4,7 +4,7 @@ * See LICENSE for details. */ -package com.almasb.fxgl.gesturerecog +package com.almasb.fxgl.intelligence.gesturerecog /** * The ordinal of each item matches the format defined at: diff --git a/fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/gesturerecog/HandTrackingService.kt b/fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/intelligence/gesturerecog/HandTrackingService.kt similarity index 98% rename from fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/gesturerecog/HandTrackingService.kt rename to fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/intelligence/gesturerecog/HandTrackingService.kt index 4ae576623..3dc235a36 100644 --- a/fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/gesturerecog/HandTrackingService.kt +++ b/fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/intelligence/gesturerecog/HandTrackingService.kt @@ -4,7 +4,7 @@ * See LICENSE for details. */ -package com.almasb.fxgl.gesturerecog +package com.almasb.fxgl.intelligence.gesturerecog import com.almasb.fxgl.core.EngineService import com.almasb.fxgl.core.concurrent.Async diff --git a/fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/intelligence/tts/TextToSpeechService.kt b/fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/intelligence/tts/TextToSpeechService.kt index 5d6bd21de..cffc1c68a 100644 --- a/fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/intelligence/tts/TextToSpeechService.kt +++ b/fxgl-intelligence/src/main/kotlin/com/almasb/fxgl/intelligence/tts/TextToSpeechService.kt @@ -6,7 +6,6 @@ package com.almasb.fxgl.intelligence.tts -import com.almasb.fxgl.core.concurrent.Async import com.almasb.fxgl.intelligence.WebAPI import com.almasb.fxgl.intelligence.WebAPIService import com.almasb.fxgl.logging.Logger diff --git a/fxgl-intelligence/src/main/resources/com/almasb/fxgl/intelligence/rpc-common.js b/fxgl-intelligence/src/main/resources/com/almasb/fxgl/intelligence/rpc-common.js new file mode 100644 index 000000000..e5ac93f33 --- /dev/null +++ b/fxgl-intelligence/src/main/resources/com/almasb/fxgl/intelligence/rpc-common.js @@ -0,0 +1,20 @@ +const SEPARATOR = "*,,*"; +const FUNCTION_CALL_TAG = "F_CALL:"; +const FUNCTION_RETURN_TAG = "F_RETURN:"; + +function rpcRun(funcName, ...args) { + let argsString = ""; + + for (const arg of args) { + argsString += arg + SEPARATOR; + } + + let message = `${FUNCTION_CALL_TAG}${funcName}${SEPARATOR}${argsString}`; + + socket.send(message); +} + +function rpcReturn(funcName) { + // TODO: unique id? + //socket.send(`${FUNCTION_RETURN_TAG}${funcName}.F_RESULT:${names}`); +} \ No newline at end of file diff --git a/fxgl-intelligence/src/main/resources/com/almasb/fxgl/intelligence/tts/index.html b/fxgl-intelligence/src/main/resources/com/almasb/fxgl/intelligence/tts/index.html new file mode 100644 index 000000000..b2ec0232a --- /dev/null +++ b/fxgl-intelligence/src/main/resources/com/almasb/fxgl/intelligence/tts/index.html @@ -0,0 +1,24 @@ + + + + + + + Text-to-speech + + + +

Text-to-speech service

+ +
+ + +
+ +
+
+ + + + + \ No newline at end of file diff --git a/fxgl-intelligence/src/main/resources/com/almasb/fxgl/intelligence/tts/script.js b/fxgl-intelligence/src/main/resources/com/almasb/fxgl/intelligence/tts/script.js new file mode 100644 index 000000000..e8b92d17b --- /dev/null +++ b/fxgl-intelligence/src/main/resources/com/almasb/fxgl/intelligence/tts/script.js @@ -0,0 +1,82 @@ +const synth = window.speechSynthesis; +let voices = []; +let selectedVoice = null; + +const inputForm = document.querySelector("form"); +const inputTxt = document.querySelector(".txt"); + +const socket = new WebSocket('ws://localhost:55550'); + +socket.addEventListener('open', function (event) { + voices = synth.getVoices(); + + if (voices.length == 0) { + // voices are loaded async + window.speechSynthesis.onvoiceschanged = function() { + voices = synth.getVoices(); + initVoices(); + }; + } else { + initVoices(); + } +}); + +socket.addEventListener('message', function (event) { + let message = event.data; + + if (message.startsWith(FUNCTION_CALL_TAG)) { + let func = message.substring(FUNCTION_CALL_TAG.length); + let tokens = func.split('*,,*'); + let funcName = tokens[0]; + + if (funcName === "speak") { + // TODO: check length? + let voiceName = tokens[1]; + let voiceText = tokens[2]; + + for (let i = 0; i < voices.length; i++) { + if (voices[i].name === voiceName) { + selectedVoice = voices[i]; + break; + } + } + + speak(voiceText); + } + } +}); + +function initVoices() { + let names = voices.map((v) => v.name); + + rpcRun("initVoices", names); +} + +function speak(text) { + if (synth.speaking || text === "") + return; + + const speech = new SpeechSynthesisUtterance(text); + + speech.onerror = function (event) { + // TODO: + //socket.send(`Speech synthesis error: ${event.error}`); + }; + + if (selectedVoice !== null) { + speech.voice = selectedVoice; + } + + speech.pitch = 1.0; + speech.rate = 1.0; + + synth.speak(speech); +} + +inputForm.onsubmit = function (event) { + event.preventDefault(); + + speak(inputTxt.value); + + inputTxt.blur(); +}; \ No newline at end of file diff --git a/fxgl-samples/src/main/java/sandbox/net/HandTrackingSample.java b/fxgl-samples/src/main/java/sandbox/net/HandTrackingSample.java index 60eb09989..d71806c68 100644 --- a/fxgl-samples/src/main/java/sandbox/net/HandTrackingSample.java +++ b/fxgl-samples/src/main/java/sandbox/net/HandTrackingSample.java @@ -9,7 +9,7 @@ import com.almasb.fxgl.app.GameApplication; import com.almasb.fxgl.app.GameSettings; import com.almasb.fxgl.core.math.Vec2; -import com.almasb.fxgl.gesturerecog.HandTrackingService; +import com.almasb.fxgl.intelligence.gesturerecog.HandTrackingService; import javafx.geometry.Point2D; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext;