Skip to content

Commit

Permalink
[Voice] Allow hli list
Browse files Browse the repository at this point in the history
Signed-off-by: Miguel Álvarez Díez <miguelwork92@gmail.com>
  • Loading branch information
GiviMAD committed Apr 10, 2022
1 parent 90f6a95 commit b2fd89d
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package org.openhab.core.io.rest.voice.internal;

import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -55,6 +56,8 @@
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsApplicationSelect;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsName;
import org.osgi.service.jaxrs.whiteboard.propertytypes.JaxrsResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
Expand Down Expand Up @@ -86,6 +89,7 @@ public class VoiceResource implements RESTResource {
/** The URI path to this resource */
public static final String PATH_VOICE = "voice";

private final Logger logger = LoggerFactory.getLogger(VoiceResource.class);
private final LocaleService localeService;
private final AudioManager audioManager;
private final VoiceManager voiceManager;
Expand Down Expand Up @@ -121,15 +125,15 @@ public Response getInterpreters(
@ApiResponse(responseCode = "404", description = "Interpreter not found") })
public Response getInterpreter(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @Parameter(description = "language") @Nullable String language,
@PathParam("id") @Parameter(description = "interpreter id") String id) {
@PathParam("id") @Parameter(description = "comma separated list of interpreter ids") String id) {
final Locale locale = localeService.getLocale(language);
HumanLanguageInterpreter hli = voiceManager.getHLI(id);
Collection<HumanLanguageInterpreter> hli = voiceManager.getHLIByIds(id);
if (hli == null) {
return JSONResponse.createErrorResponse(Status.NOT_FOUND, "No interpreter found");
}

HumanLanguageInterpreterDTO dto = HLIMapper.map(hli, locale);
return Response.ok(dto).build();
return Response
.ok(hli.stream().map(interpreter -> HLIMapper.map(interpreter, locale)).collect(Collectors.toList()))
.build();
}

@POST
Expand All @@ -144,17 +148,32 @@ public Response interpret(
@Parameter(description = "text to interpret", required = true) String text,
@PathParam("id") @Parameter(description = "interpreter id") String id) {
final Locale locale = localeService.getLocale(language);
HumanLanguageInterpreter hli = voiceManager.getHLI(id);
Collection<HumanLanguageInterpreter> hli = voiceManager.getHLIByIds(id);
if (hli == null) {
return JSONResponse.createErrorResponse(Status.NOT_FOUND, "No interpreter found");
}

try {
hli.interpret(locale, text);
return Response.ok(null, MediaType.TEXT_PLAIN).build();
} catch (InterpretationException e) {
return JSONResponse.createErrorResponse(Status.BAD_REQUEST, e.getMessage());
String answer = null;
String error = null;
for (var interpreter : hli) {
try {
answer = interpreter.interpret(locale, text);
logger.debug("Interpretation result: {}", answer);
error = null;
break;
} catch (InterpretationException e) {
logger.debug("Interpretation exception: {}", e.getMessage());
var msg = e.getMessage();
if (msg != null) {
error = msg;
}
}
}
if (answer != null) {
return Response.ok(answer, MediaType.TEXT_PLAIN).build();
} else if (error != null) {
return JSONResponse.createErrorResponse(Status.BAD_REQUEST, error);
}
return Response.ok("", MediaType.TEXT_PLAIN).build();
}

@POST
Expand All @@ -168,17 +187,32 @@ public Response interpret(
@HeaderParam(HttpHeaders.ACCEPT_LANGUAGE) @Parameter(description = "language") @Nullable String language,
@Parameter(description = "text to interpret", required = true) String text) {
final Locale locale = localeService.getLocale(language);
HumanLanguageInterpreter hli = voiceManager.getHLI();
Collection<HumanLanguageInterpreter> hli = voiceManager.getDefaultHLIs();
if (hli == null) {
return JSONResponse.createErrorResponse(Status.NOT_FOUND, "No interpreter found");
}

try {
hli.interpret(locale, text);
return Response.ok(null, MediaType.TEXT_PLAIN).build();
} catch (InterpretationException e) {
return JSONResponse.createErrorResponse(Status.BAD_REQUEST, e.getMessage());
String answer = null;
String error = null;
for (var interpreter : hli) {
try {
answer = interpreter.interpret(locale, text);
error = null;
logger.debug("Interpretation result: {}", answer);
break;
} catch (InterpretationException e) {
logger.debug("Interpretation exception: {}", e.getMessage());
var msg = e.getMessage();
if (msg != null) {
error = msg;
}
}
}
if (answer != null) {
return Response.ok(answer, MediaType.TEXT_PLAIN).build();
} else if (error != null) {
return JSONResponse.createErrorResponse(Status.BAD_REQUEST, error);
}
return Response.ok("", MediaType.TEXT_PLAIN).build();
}

@GET
Expand Down Expand Up @@ -264,9 +298,9 @@ public Response startDialog(
return JSONResponse.createErrorResponse(Status.NOT_FOUND, "Text-to-Speech not found");
}
}
HumanLanguageInterpreter hli = null;
Collection<HumanLanguageInterpreter> hli = null;
if (hliId != null) {
hli = voiceManager.getHLI(hliId);
hli = voiceManager.getHLIByIds(hliId);
if (hli == null) {
return JSONResponse.createErrorResponse(Status.NOT_FOUND, "Interpreter not found");
}
Expand Down Expand Up @@ -349,9 +383,9 @@ public Response listenAndAnswer(
return JSONResponse.createErrorResponse(Status.NOT_FOUND, "Text-to-Speech not found");
}
}
HumanLanguageInterpreter hli = null;
Collection<HumanLanguageInterpreter> hli = null;
if (hliId != null) {
hli = voiceManager.getHLI(hliId);
hli = voiceManager.getHLIByIds(hliId);
if (hli == null) {
return JSONResponse.createErrorResponse(Status.NOT_FOUND, "Interpreter not found");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package org.openhab.core.model.script.actions;

import java.util.Collection;
import java.util.Locale;
import java.util.Objects;

Expand Down Expand Up @@ -157,7 +158,7 @@ public static String interpret(@ParamDoc(name = "text") Object text) {
* In case of interpretation error, the error message is played using the default audio sink.
*
* @param text The text to interpret
* @param interpreter The Human Language Interpreter to be used
* @param interpreter Comma separated list of human language text interpreters to use or null to use the default services
*/
@ActionDoc(text = "interprets a given text by a given human language interpreter", returns = "human language response")
public static String interpret(@ParamDoc(name = "text") Object text,
Expand All @@ -180,7 +181,7 @@ public static String interpret(@ParamDoc(name = "text") Object text,
* If sink parameter is null, the error message is simply not played.
*
* @param text The text to interpret
* @param interpreter The Human Language Interpreter to be used
* @param interpreter Comma separated list of human language text interpreters to use or null to use the default services
* @param sink The name of audio sink to be used to play the error message
*/
@ActionDoc(text = "interprets a given text by a given human language interpreter", returns = "human language response")
Expand Down Expand Up @@ -218,10 +219,10 @@ public static void startDialog(@ParamDoc(name = "source") @Nullable String sourc
* @param ks the keyword spotting service to use or null to use the default service
* @param stt the speech-to-text service to use or null to use the default service
* @param tts the text-to-speech service to use or null to use the default service
* @param interpreter the human language text interpreter to use or null to use the default service
* @param interpreter comma separated list of human language text interpreters to use or null to use the default services
* @param source the name of audio source to use or null to use the default source
* @param sink the name of audio sink to use or null to use the default sink
* @param Locale the locale to use or null to use the default locale
* @param locale the locale to use or null to use the default locale
* @param keyword the keyword to use during keyword spotting or null to use the default keyword
* @param listeningItem the item to switch ON while listening to a question
*/
Expand Down Expand Up @@ -265,10 +266,10 @@ public static void startDialog(@ParamDoc(name = "keyword spotting service") @Nul
return;
}
}
HumanLanguageInterpreter hliService = null;
Collection<HumanLanguageInterpreter> hliServices = null;
if (interpreter != null) {
hliService = VoiceActionService.voiceManager.getHLI(interpreter);
if (hliService == null) {
hliServices = VoiceActionService.voiceManager.getHLIByIds(interpreter);
if (hliServices == null) {
logger.warn("Failed starting dialog processing: interpreter '{}' not found", interpreter);
return;
}
Expand All @@ -292,7 +293,7 @@ public static void startDialog(@ParamDoc(name = "keyword spotting service") @Nul
}

try {
VoiceActionService.voiceManager.startDialog(ksService, sttService, ttsService, hliService, audioSource,
VoiceActionService.voiceManager.startDialog(ksService, sttService, ttsService, hliServices, audioSource,
audioSink, loc, keyword, listeningItem);
} catch (IllegalStateException e) {
logger.warn("Failed starting dialog processing: {}", e.getMessage());
Expand Down Expand Up @@ -339,10 +340,10 @@ public static void listenAndAnswer(@ParamDoc(name = "source") @Nullable String s
*
* @param stt the speech-to-text service to use or null to use the default service
* @param tts the text-to-speech service to use or null to use the default service
* @param interpreter the human language text interpreter to use or null to use the default service
* @param interpreter comma separated list of human language text interpreters to use or null to use the default services
* @param source the name of audio source to use or null to use the default source
* @param sink the name of audio sink to use or null to use the default sink
* @param Locale the locale to use or null to use the default locale
* @param locale the locale to use or null to use the default locale
* @param listeningItem the item to switch ON while listening to a question
*/
@ActionDoc(text = "executes a simple dialog sequence without keyword spotting for a given audio source")
Expand Down Expand Up @@ -376,10 +377,10 @@ public static void listenAndAnswer(@ParamDoc(name = "speech-to-text service") @N
return;
}
}
HumanLanguageInterpreter hliService = null;
Collection<HumanLanguageInterpreter> hliServices = null;
if (interpreter != null) {
hliService = VoiceActionService.voiceManager.getHLI(interpreter);
if (hliService == null) {
hliServices = VoiceActionService.voiceManager.getHLIByIds(interpreter);
if (hliServices == null) {
logger.warn("Failed executing simple dialog: interpreter '{}' not found", interpreter);
return;
}
Expand All @@ -403,7 +404,7 @@ public static void listenAndAnswer(@ParamDoc(name = "speech-to-text service") @N
}

try {
VoiceActionService.voiceManager.listenAndAnswer(sttService, ttsService, hliService, audioSource, audioSink,
VoiceActionService.voiceManager.listenAndAnswer(sttService, ttsService, hliServices, audioSource, audioSink,
loc, listeningItem);
} catch (IllegalStateException e) {
logger.warn("Failed executing simple dialog: {}", e.getMessage());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ public interface VoiceManager {
* Interprets the passed string using a particular HLI service and the default locale.
*
* @param text The text to interpret
* @param hliId The id of the HLI service to use or null
* @param hliId Comma separated list of HLI service ids to use or null
* @throws InterpretationException
* @return a human language response
*/
Expand Down Expand Up @@ -144,17 +144,17 @@ public interface VoiceManager {
* @param ks the keyword spotting service to use or null to use the default service
* @param stt the speech-to-text service to use or null to use the default service
* @param tts the text-to-speech service to use or null to use the default service
* @param hli the human language text interpreter to use or null to use the default service
* @param hli collection of human language text interpreters to use or null to use the default services
* @param source the audio source to use or null to use the default source
* @param sink the audio sink to use or null to use the default sink
* @param Locale the locale to use or null to use the default locale
* @param locale the locale to use or null to use the default locale
* @param keyword the keyword to use during keyword spotting or null to use the default keyword
* @param listeningItem the item to switch ON while listening to a question
* @throws IllegalStateException if required services are not all available or the provided locale is not supported
* by all these services or a dialog is already started for this audio source
*/
void startDialog(@Nullable KSService ks, @Nullable STTService stt, @Nullable TTSService tts,
@Nullable HumanLanguageInterpreter hli, @Nullable AudioSource source, @Nullable AudioSink sink,
@Nullable Collection<HumanLanguageInterpreter> hli, @Nullable AudioSource source, @Nullable AudioSink sink,
@Nullable Locale locale, @Nullable String keyword, @Nullable String listeningItem)
throws IllegalStateException;

Expand Down Expand Up @@ -187,17 +187,17 @@ void startDialog(@Nullable KSService ks, @Nullable STTService stt, @Nullable TTS
*
* @param stt the speech-to-text service to use or null to use the default service
* @param tts the text-to-speech service to use or null to use the default service
* @param hli the human language text interpreter to use or null to use the default service
* @param hli collection of human language text interpreters to use or null to use the default services
* @param source the audio source to use or null to use the default source
* @param sink the audio sink to use or null to use the default sink
* @param locale the locale to use or null to use the default locale
* @param listeningItem the item to switch ON while listening to a question
* @throws IllegalStateException if required services are not all available or the provided locale is not supported
* by all these services or a dialog is already started for this audio source
*/
void listenAndAnswer(@Nullable STTService stt, @Nullable TTSService tts, @Nullable HumanLanguageInterpreter hli,
@Nullable AudioSource source, @Nullable AudioSink sink, @Nullable Locale locale,
@Nullable String listeningItem) throws IllegalStateException;
void listenAndAnswer(@Nullable STTService stt, @Nullable TTSService tts,
@Nullable Collection<HumanLanguageInterpreter> hli, @Nullable AudioSource source, @Nullable AudioSink sink,
@Nullable Locale locale, @Nullable String listeningItem) throws IllegalStateException;

/**
* Retrieves a TTS service.
Expand Down Expand Up @@ -280,6 +280,29 @@ void listenAndAnswer(@Nullable STTService stt, @Nullable TTSService tts, @Nullab
*/
Collection<KSService> getKSs();

/**
* Retrieves a HumanLanguageInterpreter collection.
* If no services are available returns null.
*
* @param idList Comma separated list of HLI service ids to use or null
* @return a Collection<HumanLanguageInterpreter> or null, if no services are available or if some defaults are
* configured, but no
* according services are found
*/
@Nullable
Collection<HumanLanguageInterpreter> getHLIByIds(String idList);

/**
* Retrieves a HumanLanguageInterpreter collection.
* If a default names are configured and the services are available, those are returned. Otherwise, the first
* available service is returned.
*
* @return a Collection<HumanLanguageInterpreter> or null, if no services are available or if some defaults are
* configured, but no according services are found.
*/
@Nullable
Collection<HumanLanguageInterpreter> getDefaultHLIs();

/**
* Retrieves a HumanLanguageInterpreter.
* If a default name is configured and the service available, this is returned. Otherwise, the first available
Expand Down
Loading

0 comments on commit b2fd89d

Please sign in to comment.