Skip to content

Instantly share code, notes, and snippets.

@michalkejzlar
Last active February 12, 2017 21:23
Show Gist options
  • Save michalkejzlar/f840e32058e48f0929e02822c01a4787 to your computer and use it in GitHub Desktop.
Save michalkejzlar/f840e32058e48f0929e02822c01a4787 to your computer and use it in GitHub Desktop.
Example usage of API.ai Android SDK. This activity receives speech input from user, sends it to API.ai and reads returned response
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_speech"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:background="@color/colorPrimary">
<TextView android:id="@+id/welcomeTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="28sp"
android:textColor="@android:color/white"
android:fontFamily="sans-serif-light"
android:text="@string/welcome_message"/>
<TextView android:id="@+id/speechHelpTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/welcomeTextView"
android:textSize="18sp"
android:layout_marginTop="16dp"
android:textColor="@android:color/white"
android:fontFamily="sans-serif-light"
android:text="@string/welcome_message_desc"/>
<ImageButton
android:id="@+id/testButton"
android:layout_width="130dp"
android:layout_height="130dp"
android:layout_centerInParent="true"
android:background="@drawable/speech_button" <!-- Create big rounded button -->
android:foreground="?attr/selectableItemBackground"
android:src="@drawable/ic_microphone"/> <!-- Add mic icon -->
<Button android:id="@+id/skipButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:text="Skip"/>
</RelativeLayout>
import ai.api.AIListener;
import ai.api.android.AIConfiguration;
import ai.api.android.AIService;
import ai.api.model.AIError;
import ai.api.model.AIResponse;
import ai.api.model.Result;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.speech.tts.TextToSpeech;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageButton;
import android.widget.Toast;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import com.easycore.digestio.Config;
import com.easycore.digestio.R;
import com.facebook.rebound.Spring;
import com.facebook.rebound.SpringConfig;
import com.facebook.rebound.SpringListener;
import com.facebook.rebound.SpringSystem;
import com.google.gson.JsonElement;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Map;
public class SpeechActivity extends AppCompatActivity implements AIListener, SpringListener {
private AIService aiService;
private TextToSpeech tts;
private String parameters;
private Handler handler;
private Spring spring;
private static final double TENSION = 800;
private static final double DAMPER = 20; //friction
private boolean isListening = false;
@BindView(R.id.testButton) ImageButton testButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_speech);
ButterKnife.bind(this);
handler = new Handler(Looper.getMainLooper());
// ask for permission
final AIConfiguration config = new AIConfiguration(Config.CLIENT_ACCESS_TOKEN,
ai.api.AIConfiguration.SupportedLanguages.French,
AIConfiguration.RecognitionEngine.System);
aiService = AIService.getService(this, config);
aiService.setListener(this);
tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
@Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
tts.setLanguage(Locale.CANADA_FRENCH);
}
}
});
SpringSystem springSystem = SpringSystem.create();
spring = springSystem.createSpring();
spring.addListener(this);
SpringConfig springConfig = new SpringConfig(TENSION, DAMPER);
spring.setSpringConfig(springConfig);
if (savedInstanceState != null) {
isListening = savedInstanceState.getBoolean("isListening");
}
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onPause() {
super.onPause();
aiService.stopListening();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("isListening", isListening);
}
@Override
protected void onDestroy() {
super.onDestroy();
tts.shutdown();
}
@OnClick(R.id.testButton)
public void onButtonClicked() {
if (isListening) {
aiService.cancel();
} else {
aiService.startListening();
}
}
@OnClick(R.id.skipButton)
public void onSkipButtonClicked() {
MainActivity.startActivity(this, "");
}
private void processAIResponse(AIResponse response) {
final Result result = response.getResult();
final String fulfillment = result.getFulfillment().getSpeech();
if ("input.unknown".equals(result.getAction())
|| "input.welcome".equals(result.getAction())) {
tts.speak(fulfillment, TextToSpeech.QUEUE_FLUSH, null);
return;
}
ArrayList<String> values = new ArrayList<>();
// Get parameters
if (result.getParameters() != null && !result.getParameters().isEmpty()) {
for (final Map.Entry<String, JsonElement> entry : result.getParameters().entrySet()) {
String s = entry.getValue().toString();
if (s == null || s.isEmpty() || "[]".equals(s)) continue;
s = s.replaceAll("\"", "");
values.add(s);
}
}
if (values.isEmpty()) {
Toast.makeText(this, "Nothing found", Toast.LENGTH_LONG).show();
return;
}
final String query = result.getResolvedQuery();
final String action = result.getAction();
tts.speak(fulfillment, TextToSpeech.QUEUE_FLUSH, null);
StringBuilder builder = new StringBuilder();
for (int i = 0; i < values.size() - 1; i++) {
builder.append(values.get(i));
builder.append(",");
}
builder.append(values.get(values.size() - 1));
startAudio(builder.toString());
}
private void startAudio(final String speechResult) {
handler.postDelayed(new Runnable() {
@Override
public void run() {
MainActivity.startActivity(SpeechActivity.this, speechResult);
}
}, 1500); // random pause after French lady finish speaking
}
@Override
public void onResult(AIResponse response) {
processAIResponse(response);
}
@Override
public void onError(AIError error) {
}
@Override
public void onAudioLevel(float level) {
}
@Override
public void onListeningStarted() {
isListening = true;
spring.setEndValue(1f);
}
@Override
public void onListeningCanceled() {
isListening = false;
spring.setEndValue(0f);
}
@Override
public void onListeningFinished() {
isListening = false;
spring.setEndValue(0f);
}
@Override
public void onSpringUpdate(Spring spring) {
float value = (float) spring.getCurrentValue();
float scale = 1f - (value * 0.5f);
testButton.setScaleX(scale);
testButton.setScaleY(scale);
}
@Override
public void onSpringAtRest(Spring spring) {
}
@Override
public void onSpringActivate(Spring spring) {
}
@Override
public void onSpringEndStateChange(Spring spring) {
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment