Skip to content

Commit bb81f93

Browse files
committed
multi-language support
1 parent d9c4717 commit bb81f93

File tree

3 files changed

+196
-87
lines changed

3 files changed

+196
-87
lines changed

java-ai/src/main/java/oracleai/aiholo/AIHoloController.java

Lines changed: 16 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,16 @@
3737
public class AIHoloController {
3838
private String theValue = "mirrorme";
3939
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
40-
private static final String API_URL = "http://129.x.x.x/v1/chat/completions?client=server";
40+
private static final String API_URL = "http://129.x.x.x/v1/chat/completions?client=server";
4141
private static final String AUTH_TOKEN = "Bearer asdf";
42+
private static final String DEFAULT_LANGUAGE_CODE = "Bearer asdf";
43+
private static final String DEFAULT_VOICE_NAME = "Bearer asdf";
4244

4345
@Autowired
4446
private DataSource dataSource;
4547

46-
private volatile long lastRequestTime = System.currentTimeMillis();
48+
private static final Object metahumanLock = new Object();
49+
private static boolean isRecentQuestionProcessed;
4750

4851
public AIHoloController() {
4952
System.out.println("startInactivityMonitor...");
@@ -52,18 +55,18 @@ public AIHoloController() {
5255

5356
private void startInactivityMonitor() {
5457
scheduler.scheduleAtFixedRate(() -> {
55-
System.out.println("about to say testing 1 2 3...");
56-
sendToAudio2Face("testing123-brazil.wav");
57-
// long currentTime = System.currentTimeMillis();
58-
// if (currentTime - lastRequestTime > TimeUnit.MINUTES.toMillis(2)) {
59-
// sendToAudio2Face("testing123-brazil.wav");
60-
// lastRequestTime = currentTime; // Reset timer to prevent repeated execution
61-
// }
62-
}, 1, 1, TimeUnit.MINUTES);
58+
if (isRecentQuestionProcessed) {
59+
System.out.println("isRecentQuestionProcessed true so skipping the timecheck/keepalive");
60+
isRecentQuestionProcessed = false;
61+
}
62+
String fileName = "currenttime.wav"; //testing123-brazil.wav
63+
TTSAndAudio2Face.processMetahuman(
64+
fileName, TimeInWords.getTimeInWords(true),
65+
DEFAULT_LANGUAGE_CODE, DEFAULT_VOICE_NAME);
66+
}, 1, 15, TimeUnit.MINUTES);
6367
}
6468

6569

66-
6770
@GetMapping("/set")
6871
public String setValue(@RequestParam("value") String value) {
6972
theValue = value;
@@ -94,7 +97,7 @@ public String getValue() {
9497
static String sql = """
9598
SELECT DBMS_CLOUD_AI.GENERATE(
9699
prompt => ?,
97-
profile_name => 'AIHOLO',
100+
profile_name => 'VIDEO_GAMES',
98101
action => ?
99102
) FROM dual
100103
""";
@@ -151,10 +154,7 @@ public String play(@RequestParam("question") String question,
151154
}
152155
String fileName = "output.wav";
153156
System.out.println("about to TTS and sendAudioToAudio2Face for answer: " + answer);
154-
TTS(fileName, answer, languagecode, voicename);
155-
TTS("hello-brazil.wav", "olá", languagecode, voicename);
156-
TTS("testing123-brazil.wav", "testando um, dois, três", languagecode, voicename);
157-
sendToAudio2Face(fileName);
157+
TTSAndAudio2Face.processMetahuman(fileName, answer, languagecode, voicename);
158158
return answer;
159159
}
160160

@@ -169,48 +169,6 @@ public String play(@RequestParam("question") String question,
169169

170170

171171

172-
private void sendToAudio2Face(String fileName) {
173-
RestTemplate restTemplate = new RestTemplate();
174-
String baseUrl = "http://localhost:8011/A2F/Player/";
175-
176-
String setRootPathUrl = baseUrl + "SetRootPath";
177-
Map<String, Object> rootPathPayload = new HashMap<>();
178-
rootPathPayload.put("a2f_player", "/World/audio2face/Player");
179-
rootPathPayload.put("dir_path", "C:/Users/opc/src/github.com/paulparkinson/oracle-ai-for-sustainable-dev/java-ai");
180-
sendPostRequest(restTemplate, setRootPathUrl, rootPathPayload);
181-
182-
String setTrackUrl = baseUrl + "SetTrack";
183-
Map<String, Object> trackPayload = new HashMap<>();
184-
trackPayload.put("a2f_player", "/World/audio2face/Player");
185-
trackPayload.put("file_name", fileName);
186-
trackPayload.put("time_range", new int[] { 0, -1 });
187-
sendPostRequest(restTemplate, setTrackUrl, trackPayload);
188-
189-
String playTrackUrl = baseUrl + "Play";
190-
Map<String, Object> playPayload = new HashMap<>();
191-
playPayload.put("a2f_player", "/World/audio2face/Player");
192-
sendPostRequest(restTemplate, playTrackUrl, playPayload);
193-
}
194-
195-
private void sendPostRequest(RestTemplate restTemplate, String url, Map<String, Object> payload) {
196-
HttpHeaders headers = new HttpHeaders();
197-
headers.setContentType(MediaType.APPLICATION_JSON);
198-
HttpEntity<Map<String, Object>> request = new HttpEntity<>(payload, headers);
199-
200-
ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);
201-
if (response.getStatusCode().is2xxSuccessful()) {
202-
System.out.println("Successfully sent request to: " + url);
203-
} else {
204-
System.err.println("Failed to send request to " + url + ". Response: " + response.getBody());
205-
}
206-
}
207-
208-
209-
210-
211-
212-
213-
214172
public String executeSandbox(String cummulativeResult) {
215173
System.out.println("isRag is true, using AI sandbox: " + cummulativeResult);
216174

@@ -255,35 +213,6 @@ public String executeSandbox(String cummulativeResult) {
255213
// `https://141.148.204.74:8444/aiholo/tts?textToConvert=${encodeURIComponent(textToConvert)}&languageCode=${encodeURIComponent(languageCode)}&ssmlGender=${encodeURIComponent(ssmlGender)}&voiceName=${encodeURIComponent(voiceName)}`;
256214

257215

258-
public void TTS(String fileName, String text, String languageCode, String voicename) throws Exception {
259-
try (TextToSpeechClient textToSpeechClient = TextToSpeechClient.create()) {
260-
System.out.println("in TTS languagecode:" + languageCode + " voicename:" + voicename + " text:" + text);
261-
SynthesisInput input = SynthesisInput.newBuilder().setText(
262-
// "最受欢迎的游戏是Pods Of Kon。").build();
263-
text).build();
264-
// "最も人気のあるビデオゲームは「Pods Of Kon」です。").build();
265-
VoiceSelectionParams voice =
266-
VoiceSelectionParams.newBuilder()
267-
.setLanguageCode(languageCode) //ja-JP, en-US, ...
268-
.setSsmlGender(SsmlVoiceGender.FEMALE) // NEUTRAL, MALE
269-
// .setName("pt-BR-Wavenet-D") // tts-pt-BRFEMALEpt-BR-Wavenet-D_Bem-vindo
270-
.setName(voicename) // "Kore" tts-pt-BRFEMALEpt-BR-Wavenet-D_Bem-vindo
271-
.build();
272-
273-
AudioConfig audioConfig =
274-
AudioConfig.newBuilder()
275-
.setAudioEncoding(AudioEncoding.LINEAR16) // wav
276-
// .setAudioEncoding(AudioEncoding.MP3)
277-
.build();
278-
SynthesizeSpeechResponse response =
279-
textToSpeechClient.synthesizeSpeech(input, voice, audioConfig);
280-
ByteString audioContents = response.getAudioContent();
281-
try (OutputStream out = new FileOutputStream(fileName)) {
282-
out.write(audioContents.toByteArray());
283-
System.out.println("Audio content written to file:" + fileName);
284-
}
285-
}
286-
}
287216

288217
// `https://host:port/aiholo/tts?textToConvert=${encodeURIComponent(textToConvert)}&languageCode=${encodeURIComponent(languageCode)}&ssmlGender=${encodeURIComponent(ssmlGender)}&voiceName=${encodeURIComponent(voiceName)}`;
289218
@GetMapping("/tts")
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package oracleai.aiholo;
2+
3+
import com.google.cloud.texttospeech.v1.*;
4+
import com.google.protobuf.ByteString;
5+
import org.springframework.http.HttpEntity;
6+
import org.springframework.http.HttpHeaders;
7+
import org.springframework.http.MediaType;
8+
import org.springframework.http.ResponseEntity;
9+
import org.springframework.web.client.RestTemplate;
10+
11+
import java.io.FileOutputStream;
12+
import java.io.OutputStream;
13+
import java.util.HashMap;
14+
import java.util.Map;
15+
import java.util.concurrent.ExecutorService;
16+
import java.util.concurrent.Executors;
17+
18+
public class TTSAndAudio2Face {
19+
private static final ExecutorService executor = Executors.newSingleThreadExecutor();
20+
21+
public static void processMetahuman(String fileName, String textToSay, String languageCode, String voiceName) {
22+
executor.submit(() -> {
23+
try {
24+
TTS(fileName, textToSay, languageCode, voiceName);
25+
sendToAudio2Face(fileName);
26+
} catch (Exception e) {
27+
System.out.println("processMetahuman exception during TTS:" + e);
28+
//TODO might be funny and helpful to do this, ie have the system gives its status and ask for help ...
29+
// sendToAudio2Face("uhoh-lookslikeIneedanewTTStoken.wav");
30+
sendToAudio2Face("uhoh-lookslikeIneedanewTTStoken.wav");
31+
}
32+
33+
});
34+
}
35+
36+
37+
public static void TTS(String fileName, String text, String languageCode, String voicename) throws Exception {
38+
try (TextToSpeechClient textToSpeechClient = TextToSpeechClient.create()) {
39+
System.out.println("in TTS languagecode:" + languageCode + " voicename:" + voicename + " text:" + text);
40+
SynthesisInput input = SynthesisInput.newBuilder().setText(text).build();
41+
// "最受欢迎的游戏是Pods Of Kon。").build();
42+
// "最も人気のあるビデオゲームは「Pods Of Kon」です。").build();
43+
VoiceSelectionParams voice =
44+
VoiceSelectionParams.newBuilder()
45+
.setLanguageCode(languageCode) //ja-JP, en-US, ...
46+
.setSsmlGender(SsmlVoiceGender.FEMALE) // NEUTRAL, MALE
47+
.setName(voicename) // "Kore" pt-BR-Wavenet-D
48+
.build();
49+
AudioConfig audioConfig =
50+
AudioConfig.newBuilder()
51+
.setAudioEncoding(AudioEncoding.LINEAR16) // wav AudioEncoding.MP3
52+
.build();
53+
SynthesizeSpeechResponse response =
54+
textToSpeechClient.synthesizeSpeech(input, voice, audioConfig);
55+
ByteString audioContents = response.getAudioContent();
56+
try (OutputStream out = new FileOutputStream(fileName)) {
57+
out.write(audioContents.toByteArray());
58+
System.out.println("Audio content written to file:" + fileName);
59+
}
60+
}
61+
}
62+
63+
64+
65+
66+
67+
private static void sendToAudio2Face(String fileName) {
68+
RestTemplate restTemplate = new RestTemplate();
69+
String baseUrl = "http://localhost:8011/A2F/Player/";
70+
71+
String setRootPathUrl = baseUrl + "SetRootPath";
72+
Map<String, Object> rootPathPayload = new HashMap<>();
73+
rootPathPayload.put("a2f_player", "/World/audio2face/Player");
74+
rootPathPayload.put("dir_path", "C:/Users/opc/src/github.com/paulparkinson/oracle-ai-for-sustainable-dev/java-ai");
75+
sendPostRequest(restTemplate, setRootPathUrl, rootPathPayload);
76+
77+
String setTrackUrl = baseUrl + "SetTrack";
78+
Map<String, Object> trackPayload = new HashMap<>();
79+
trackPayload.put("a2f_player", "/World/audio2face/Player");
80+
trackPayload.put("file_name", fileName);
81+
trackPayload.put("time_range", new int[] { 0, -1 });
82+
sendPostRequest(restTemplate, setTrackUrl, trackPayload);
83+
84+
String playTrackUrl = baseUrl + "Play";
85+
Map<String, Object> playPayload = new HashMap<>();
86+
playPayload.put("a2f_player", "/World/audio2face/Player");
87+
sendPostRequest(restTemplate, playTrackUrl, playPayload);
88+
}
89+
90+
private static void sendPostRequest(RestTemplate restTemplate, String url, Map<String, Object> payload) {
91+
HttpHeaders headers = new HttpHeaders();
92+
headers.setContentType(MediaType.APPLICATION_JSON);
93+
HttpEntity<Map<String, Object>> request = new HttpEntity<>(payload, headers);
94+
95+
ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);
96+
if (response.getStatusCode().is2xxSuccessful()) {
97+
System.out.println("Successfully sent request to: " + url);
98+
} else {
99+
System.err.println("Failed to send request to " + url + ". Response: " + response.getBody());
100+
}
101+
}
102+
103+
104+
105+
106+
107+
}
108+
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package oracleai.aiholo;
2+
3+
import java.time.*;
4+
import java.util.Map;
5+
6+
public class TimeInWords {
7+
8+
private static final Map<Integer, String> NUMBERS_EN = Map.ofEntries(
9+
Map.entry(0, "Twelve"), Map.entry(1, "One"), Map.entry(2, "Two"), Map.entry(3, "Three"),
10+
Map.entry(4, "Four"), Map.entry(5, "Five"), Map.entry(6, "Six"), Map.entry(7, "Seven"),
11+
Map.entry(8, "Eight"), Map.entry(9, "Nine"), Map.entry(10, "Ten"), Map.entry(11, "Eleven"),
12+
Map.entry(12, "Twelve"), Map.entry(13, "One"), Map.entry(14, "Two"), Map.entry(15, "Three"),
13+
Map.entry(16, "Four"), Map.entry(17, "Five"), Map.entry(18, "Six"), Map.entry(19, "Seven"),
14+
Map.entry(20, "Eight"), Map.entry(21, "Nine"), Map.entry(22, "Ten"), Map.entry(23, "Eleven")
15+
);
16+
17+
private static final Map<Integer, String> MINUTES_EN = Map.ofEntries(
18+
Map.entry(0, "o'clock"), Map.entry(15, "fifteen"), Map.entry(30, "thirty"), Map.entry(45, "forty-five")
19+
);
20+
21+
private static final Map<String, String> AM_PM_EN = Map.of("AM", "AM", "PM", "PM");
22+
23+
// Brazilian Portuguese mappings
24+
private static final Map<Integer, String> NUMBERS_PT = Map.ofEntries(
25+
Map.entry(0, "Doze"), Map.entry(1, "Uma"), Map.entry(2, "Duas"), Map.entry(3, "Três"),
26+
Map.entry(4, "Quatro"), Map.entry(5, "Cinco"), Map.entry(6, "Seis"), Map.entry(7, "Sete"),
27+
Map.entry(8, "Oito"), Map.entry(9, "Nove"), Map.entry(10, "Dez"), Map.entry(11, "Onze"),
28+
Map.entry(12, "Doze"), Map.entry(13, "Uma"), Map.entry(14, "Duas"), Map.entry(15, "Três"),
29+
Map.entry(16, "Quatro"), Map.entry(17, "Cinco"), Map.entry(18, "Seis"), Map.entry(19, "Sete"),
30+
Map.entry(20, "Oito"), Map.entry(21, "Nove"), Map.entry(22, "Dez"), Map.entry(23, "Onze")
31+
);
32+
33+
private static final Map<Integer, String> MINUTES_PT = Map.ofEntries(
34+
Map.entry(0, "em ponto"), Map.entry(15, "e quinze"), Map.entry(30, "e meia"), Map.entry(45, "menos quinze")
35+
);
36+
37+
private static final Map<String, String> AM_PM_PT = Map.of("AM", "da manhã", "PM", "da noite");
38+
39+
public static String getTimeInWords(boolean inPortuguese) {
40+
ZoneId brazilZone = ZoneId.of("America/Sao_Paulo");
41+
LocalTime now = LocalTime.now(brazilZone);
42+
43+
int hour = now.getHour() % 12;
44+
int minute = now.getMinute();
45+
boolean isAM = now.getHour() < 12;
46+
if (hour == 0) hour = 12;
47+
48+
if (inPortuguese) {
49+
return formatTime(NUMBERS_PT, MINUTES_PT, AM_PM_PT, hour, minute, isAM);
50+
} else {
51+
return formatTime(NUMBERS_EN, MINUTES_EN, AM_PM_EN, hour, minute, isAM);
52+
}
53+
}
54+
55+
private static String formatTime(Map<Integer, String> numbers, Map<Integer, String> minutes,
56+
Map<String, String> amPm, int hour, int minute, boolean isAM) {
57+
String hourWord = numbers.get(hour);
58+
String minuteWord = minutes.getOrDefault(minute, String.valueOf(minute));
59+
String amPmWord = isAM ? amPm.get("AM") : amPm.get("PM");
60+
61+
if (minute == 0) {
62+
return hourWord + " " + minuteWord + " " + amPmWord;
63+
} else {
64+
return hourWord + " " + minuteWord + " " + amPmWord;
65+
}
66+
}
67+
68+
public static void main(String[] args) {
69+
System.out.println("Current time in Brazil (English): " + getTimeInWords(false));
70+
System.out.println("Hora atual no Brasil (Português): " + getTimeInWords(true));
71+
}
72+
}

0 commit comments

Comments
 (0)