Skip to content

Commit

Permalink
Updated GSpeech API for better accuracy and code cleanup.
Browse files Browse the repository at this point in the history
  • Loading branch information
Skylion007 committed Jan 11, 2016
1 parent 5cb7291 commit ffa6951
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 93 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/bin
.classpath
.project
.settings
/target
104 changes: 52 additions & 52 deletions src/main/java/com/darkprograms/speech/recognizer/GSpeechDuplex.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.TargetDataLine;

import com.darkprograms.speech.util.ChunkedOutputStream;
import com.darkprograms.speech.util.StringUtil;

//TODO Add a better logging system to GSpeechDuplex
Expand Down Expand Up @@ -109,6 +108,8 @@ public void recognize(File flacFile, int sampleRate) throws IOException{
recognize(mapFileIn(flacFile), sampleRate);
}



/**
* Send a byte[] to the URL with a specified sampleRate.
* NOTE: The byte[] should contain no more than 15 seconds of audio.
Expand All @@ -119,7 +120,6 @@ public void recognize(File flacFile, int sampleRate) throws IOException{
public void recognize(byte[] data, int sampleRate){

if(data.length >= MAX_SIZE){//Temporary Chunking. Does not allow for Google to gather context.
System.out.println("Chunking the audio into smaller parts...");
byte[][] dataArray = chunkAudio(data);
for(byte[]array: dataArray){
recognize(array, sampleRate);
Expand Down Expand Up @@ -162,9 +162,10 @@ public void recognize(TargetDataLine tl, AudioFormat af) throws IOException, Lin
final String API_UP_URL = GOOGLE_DUPLEX_SPEECH_BASE +
"up?lang=" + language + "&lm=dictation&client=chromium&pair=" + PAIR +
"&key=" + API_KEY + "&continuous=true&interim=true"; //Tells Google to constantly monitor the stream;

//Opens downChannel
this.downChannel(API_DOWN_URL);

//Opens upChannel
this.upChannel(API_UP_URL, tl, af);
}
Expand All @@ -191,15 +192,16 @@ public void run() {
Scanner inStream = openHttpsConnection(url);
if(inStream == null){
//ERROR HAS OCCURED
System.out.println("Error has occured");
return;
}
while(inStream.hasNextLine()){
String response = inStream.nextLine();
String response;
while(inStream.hasNext() && (response = inStream.nextLine()) != null){
if(response.length()>17){//Prevents blank responses from Firing
GoogleResponse gr = new GoogleResponse();
parseResponse(response, gr);
fireResponseEvent(gr);
}

}
inStream.close();
System.out.println("Finished write on down stream...");
Expand Down Expand Up @@ -233,7 +235,7 @@ public void run() {
* @param af The AudioFormat to stream with.
* @throws LineUnavailableException If cannot open or stream the TargetDataLine.
*/
private void upChannel(String urlStr, TargetDataLine tl, AudioFormat af) throws LineUnavailableException{
private void upChannel(String urlStr, TargetDataLine tl, AudioFormat af) throws IOException, LineUnavailableException{
final String murl = urlStr;
final TargetDataLine mtl = tl;
final AudioFormat maf = af;
Expand All @@ -243,9 +245,8 @@ private void upChannel(String urlStr, TargetDataLine tl, AudioFormat af) throws
}
new Thread ("Upstream Thread") {
public void run() {
openHttpsPostConnection(murl, mtl, maf);
openHttpsPostConnection(murl, mtl, (int)maf.getSampleRate());
}

}.start();

}
Expand All @@ -258,8 +259,6 @@ public void run() {
private Scanner openHttpsConnection(String urlStr) {
int resCode = -1;
try {


URL url = new URL(urlStr);
URLConnection urlConn = url.openConnection();
if (!(urlConn instanceof HttpsURLConnection)) {
Expand All @@ -270,7 +269,6 @@ private Scanner openHttpsConnection(String urlStr) {
// TIMEOUT is required
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("GET");

httpConn.connect();
resCode = httpConn.getResponseCode();
if (resCode == HttpsURLConnection.HTTP_OK) {
Expand All @@ -293,49 +291,53 @@ private Scanner openHttpsConnection(String urlStr) {
* @param mtl The TargetDataLine you want to post data from. <b>Note should be open</b>
* @param maf The AudioFormat of the data you want to post
*/
private void openHttpsPostConnection(final String murl,
final TargetDataLine mtl, final AudioFormat maf) {
private void openHttpsPostConnection(String murl, TargetDataLine mtl, int sampleRate) {
URL url;
try {
url = new URL(murl);
URLConnection urlConn = url.openConnection();
if (!(urlConn instanceof HttpsURLConnection)) {
throw new IOException ("URL is not an Https URL");
}

HttpsURLConnection httpConn = (HttpsURLConnection)urlConn;
httpConn.setAllowUserInteraction(false);
httpConn.setInstanceFollowRedirects(true);
httpConn.setRequestMethod("POST");
httpConn.setDoOutput(true);
httpConn.setChunkedStreamingMode(0);
httpConn.setRequestProperty("Transfer-Encoding", "chunked");
httpConn.setRequestProperty("Content-Type", "audio/x-flac; rate=" + (int)maf.getSampleRate());
httpConn.setRequestProperty("Content-Type", "audio/x-flac; rate=" + sampleRate);
// also worked with ("Content-Type", "audio/amr; rate=8000");
httpConn.connect();

// this opens a connection, then sends POST & headers.
OutputStream out = httpConn.getOutputStream();
final OutputStream out = httpConn.getOutputStream();
//Note : if the audio is more than 15 seconds
// dont write it to UrlConnInputStream all in one block as this sample does.
// Rather, segment the byteArray and on intermittently, sleeping thread
// supply bytes to the urlConn Stream at a rate that approaches
// the bitrate ( =30K per sec. in this instance ).
System.out.println("Starting to write data to output...");
AudioInputStream ais = new AudioInputStream(mtl);
ChunkedOutputStream os = new ChunkedOutputStream(out);
AudioSystem.write(ais, FLACFileWriter.FLAC, os);
out.write(FINAL_CHUNK);
System.out.println("IO WRITE DONE");
out.close();
final AudioInputStream ais = new AudioInputStream(mtl);;
AudioSystem.write(ais, FLACFileWriter.FLAC, out);
//Output Stream is automatically closed
// do you need the trailer?
// NOW you can look at the status.
int resCode = httpConn.getResponseCode();

//Diagonostic Code.
/*int resCode = httpConn.getResponseCode();
if (resCode / 100 != 2) {
System.out.println("ERROR");
}
}catch(Exception ex){
Scanner scanner = new Scanner(httpConn.getInputStream());
while(scanner.hasNextLine()){
System.out.println("UPSTREAM READS:" + scanner.nextLine());
}
scanner.close();*/
System.out.println("Upstream Closed...");
}catch(IOException ex){
ex.printStackTrace();

}
}

Expand Down Expand Up @@ -369,34 +371,32 @@ private Scanner openHttpsPostConnection(String urlStr, byte[][] data, int sample
httpConn.setRequestProperty("Content-Type", "audio/x-flac; rate=" + sampleRate);
// also worked with ("Content-Type", "audio/amr; rate=8000");
httpConn.connect();

// this opens a connection, then sends POST & headers.
out = httpConn.getOutputStream();
//Note : if the audio is more than 15 seconds
// dont write it to UrlConnInputStream all in one block as this sample does.
// Rather, segment the byteArray and on intermittently, sleeping thread
// supply bytes to the urlConn Stream at a rate that approaches
// the bitrate ( =30K per sec. in this instance ).
System.out.println("Starting to write");
for(byte[] dataArray: mextrad){
out.write(dataArray); // one big block supplied instantly to the underlying chunker wont work for duration > 15 s.
try {
Thread.sleep(1000);//Delays the Audio so Google thinks its a mic.
} catch (InterruptedException e) {
e.printStackTrace();
}
}
out.write(FINAL_CHUNK);
System.out.println("IO WRITE DONE");
// do you need the trailer?
// NOW you can look at the status.
resCode = httpConn.getResponseCode();
if (resCode / 100 != 2) {
System.out.println("ERROR");
// this opens a connection, then sends POST & headers.
out = httpConn.getOutputStream();
//Note : if the audio is more than 15 seconds
// dont write it to UrlConnInputStream all in one block as this sample does.
// Rather, segment the byteArray and on intermittently, sleeping thread
// supply bytes to the urlConn Stream at a rate that approaches
// the bitrate ( =30K per sec. in this instance ).
System.out.println("Starting to write");
for(byte[] dataArray: mextrad){
out.write(dataArray); // one big block supplied instantly to the underlying chunker wont work for duration > 15 s.
try {
Thread.sleep(1000);//Delays the Audio so Google thinks its a mic.
} catch (InterruptedException e) {
e.printStackTrace();
}

}
out.write(FINAL_CHUNK);
System.out.println("IO WRITE DONE");
// do you need the trailer?
// NOW you can look at the status.
resCode = httpConn.getResponseCode();
if (resCode / 100 != 2) {
System.out.println("ERROR");
}
if (resCode == HttpsURLConnection.HTTP_OK) {
return new Scanner(httpConn.getInputStream());
return new Scanner(httpConn.getInputStream(), "UTF-8");
}
else{
System.out.println("HELP: " + resCode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import java.nio.charset.Charset;

import org.json.*;
import com.darkprograms.speech.util.StringUtil;

/***************************************************************
* Class that submits FLAC audio and retrieves recognized text
Expand Down Expand Up @@ -124,12 +123,6 @@ public String toString(){
private boolean profanityFilter = true;
private String language = null;
private String apikey = null;

/**
* Constructor
*/
private Recognizer() {
}

/**
* Constructor
Expand Down
33 changes: 11 additions & 22 deletions src/main/java/com/darkprograms/speech/synthesiser/Synthesiser.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ public class Synthesiser {
/**
* Constructor
*/
@Deprecated
public Synthesiser() {
languageCode = "auto";
}
Expand Down Expand Up @@ -96,16 +95,14 @@ public InputStream getMP3Data(String synthText) throws IOException{
String languageCode = this.languageCode;//Ensures retention of language settings if set to auto

if(languageCode == null || languageCode.equals("") || languageCode.equalsIgnoreCase("auto")){
try{
languageCode = detectLanguage(synthText);//Detects language
if(languageCode == null){
languageCode = "en-us";//Reverts to Default Language if it can't detect it.
//Throw an error message here eventually
}
}
catch(Exception ex){
ex.printStackTrace();
languageCode = detectLanguage(synthText);//Detects language
/* NOTE: Detect language relies on an entirely seperate endpoint.
* If the GoogleTranslate API stops working, do not use the auto parameter
* and switch to something else or a best guess.
*/
if(languageCode == null){
languageCode = "en-us";//Reverts to Default Language if it can't detect it.
//Throw an error message here eventually
}
}

Expand Down Expand Up @@ -137,7 +134,8 @@ public InputStream getMP3Data(String synthText) throws IOException{
URLConnection urlConn = url.openConnection(); //Open connection

//Adding header for user agent is required
urlConn.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) Gecko/20100101 Firefox/4.0");
urlConn.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:2.0) "
+ "Gecko/20100101 Firefox/4.0");

return urlConn.getInputStream();
}
Expand Down Expand Up @@ -201,7 +199,8 @@ private List<String> parseString(String input, List<String> fragments){
fragments.add(input.substring(0,100));//In case you sent gibberish to Google.
return parseString(input.substring(100), fragments);
}else{
fragments.add(input.substring(0,lastWord));//Otherwise, adds the last word to the list for recursion.
fragments.add(input.substring(0,lastWord));
//Otherwise, adds the last word to the list for recursion.
return parseString(input.substring(lastWord), fragments);
}
}
Expand Down Expand Up @@ -269,15 +268,5 @@ public InputStream call() throws IOException{
return getMP3Data(synthText);
}
}

public static void main(String[] args){
Synthesiser synth = new Synthesiser("en-US");
try {
synth.getMP3Data("Hello, this is a test");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
Expand Down Expand Up @@ -217,16 +215,9 @@ private static boolean containsLettersOnly(String text){
* This function generates the b parameter for translation acting as the seed for the hashing algorithm.
*/
private static int generateB() {
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy", Locale.US);

Date start;
Date now;
try {
start = sdf.parse("01/01/1970");
now = new Date();
} catch (ParseException e) {
return 402890;
}
Date start = new Date(0L); //Unix Epoch
Date now = new Date();

long diff = now.getTime() - start.getTime();
long hours = diff / (60 * 60 * 1000) % 24;
long days = diff / (24 * 60 * 60 * 1000);
Expand Down

2 comments on commit ffa6951

@halberthj
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how to run no main class found in netbeans ?

@Skylion007
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no main class period. You have to add it to another library and call the function per the API specification.

Please sign in to comment.