/* * Copyright (C) 2007 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.voicedialer; import android.content.Intent; import android.util.Log; import java.io.File; import java.io.FileFilter; import java.util.Arrays; import java.util.HashSet; import java.util.Set; import java.util.Vector; /** * This class represents a person who may be called via the VoiceDialer app. * The person has a name and a list of phones (home, mobile, work). */ public class VoiceDialerTester { private static final String TAG = "VoiceDialerTester"; private final WavFile[] mWavFiles; private final File[] mWavDirs; // these indicate the current test private int mWavFile = -1; // -1 so it will step to 0 on first iteration private static class WavFile { final public File mFile; public int mRank; public int mTotal; public String mMessage; public WavFile(File file) { mFile = file; } } /** * Sweep directory of directories, listing all WAV files. */ public VoiceDialerTester(File dir) { if (false) { Log.d(TAG, "VoiceDialerTester " + dir); } // keep a list of directories visited Vector<File> wavDirs = new Vector<File>(); wavDirs.add(dir); // scan the directory tree Vector<File> wavFiles = new Vector<File>(); for (int i = 0; i < wavDirs.size(); i++) { File d = wavDirs.get(i); for (File f : d.listFiles()) { if (f.isFile() && f.getName().endsWith(".wav")) { wavFiles.add(f); } else if (f.isDirectory()) { wavDirs.add(f); } } } // produce a sorted list of WavFiles File[] fa = wavFiles.toArray(new File[wavFiles.size()]); Arrays.sort(fa); mWavFiles = new WavFile[fa.length]; for (int i = 0; i < mWavFiles.length; i++) { mWavFiles[i] = new WavFile(fa[i]); } // produce a sorted list of directories mWavDirs = wavDirs.toArray(new File[wavDirs.size()]); Arrays.sort(mWavDirs); } public File getWavFile() { return mWavFiles[mWavFile].mFile; } /** * Called by VoiceDialerActivity when a recognizer error occurs. */ public void onRecognitionError(String msg) { WavFile wf = mWavFiles[mWavFile]; wf.mRank = -1; wf.mTotal = -1; wf.mMessage = msg; } /** * Called by VoiceDialerActivity when a recognizer failure occurs. * @param msg Message to display. */ public void onRecognitionFailure(String msg) { WavFile wf = mWavFiles[mWavFile]; wf.mRank = 0; wf.mTotal = 0; wf.mMessage = msg; } /** * Called by VoiceDialerActivity when the recognizer succeeds. * @param intents Array of Intents corresponding to recognized sentences. */ public void onRecognitionSuccess(Intent[] intents) { WavFile wf = mWavFiles[mWavFile]; wf.mTotal = intents.length; String utter = wf.mFile.getName().toLowerCase().replace('_', ' '); utter = utter.substring(0, utter.indexOf('.')).trim(); for (int i = 0; i < intents.length; i++) { String sentence = intents[i].getStringExtra(RecognizerEngine.SENTENCE_EXTRA). toLowerCase().trim(); // note the first in case there are no matches if (i == 0) { wf.mMessage = sentence; if (intents.length > 1) wf.mMessage += ", etc"; } // is this a match if (utter.equals(sentence)) { wf.mRank = i + 1; wf.mMessage = null; break; } } } /** * Called to step to the next WAV file in the test set. * @return true if successful, false if no more test files. */ public boolean stepToNextTest() { mWavFile++; return mWavFile < mWavFiles.length; } private static final String REPORT_FMT = "%6s %6s %6s %6s %6s %6s %6s %s"; private static final String REPORT_HDR = String.format(REPORT_FMT, "1/1", "1/N", "M/N", "0/N", "Fail", "Error", "Total", ""); /** * Called when the test is complete to dump a summary. */ public void report() { // report for each file Log.d(TAG, "List of all utterances tested"); for (WavFile wf : mWavFiles) { Log.d(TAG, wf.mRank + "/" + wf.mTotal + " " + wf.mFile + (wf.mMessage != null ? " " + wf.mMessage : "")); } // summary reports by file name reportSummaryForEachFileName(); // summary reports by directory name reportSummaryForEachDir(); // summary report for all files Log.d(TAG, "Summary of all utterances"); Log.d(TAG, REPORT_HDR); reportSummary("Total", null); } private void reportSummaryForEachFileName() { Set<String> set = new HashSet<String>(); for (WavFile wf : mWavFiles) { set.add(wf.mFile.getName()); } String[] names = set.toArray(new String[set.size()]); Arrays.sort(names); Log.d(TAG, "Summary of utternaces by filename"); Log.d(TAG, REPORT_HDR); for (final String fn : names) { reportSummary(fn, new FileFilter() { public boolean accept(File file) { return fn.equals(file.getName()); } }); } } private void reportSummaryForEachDir() { Set<String> set = new HashSet<String>(); for (WavFile wf : mWavFiles) { set.add(wf.mFile.getParent()); } String[] names = set.toArray(new String[set.size()]); Arrays.sort(names); Log.d(TAG, "Summary of utterances by directory"); Log.d(TAG, REPORT_HDR); for (File dir : mWavDirs) { final String dn = dir.getPath(); final String dn2 = dn + "/"; reportSummary(dn, new FileFilter() { public boolean accept(File file) { return file.getPath().startsWith(dn2); } }); } } private void reportSummary(String label, FileFilter filter) { if (!false) return; // log cumulative stats int total = 0; int count11 = 0; int count1N = 0; int countMN = 0; int count0N = 0; int countFail = 0; int countErrors = 0; for (WavFile wf : mWavFiles) { if (filter == null || filter.accept(wf.mFile)) { total++; if (wf.mRank == 1 && wf.mTotal == 1) count11++; if (wf.mRank == 1 && wf.mTotal >= 1) count1N++; if (wf.mRank >= 1 && wf.mTotal >= 1) countMN++; if (wf.mRank == 0 && wf.mTotal >= 1) count0N++; if (wf.mRank == 0 && wf.mTotal == 0) countFail++; if (wf.mRank == -1 && wf.mTotal == -1) countErrors++; } } String line = String.format(REPORT_FMT, countString(count11, total), countString(count1N, total), countString(countMN, total), countString(count0N, total), countString(countFail, total), countString(countErrors, total), "" + total, label); Log.d(TAG, line); } private static String countString(int count, int total) { return total > 0 ? "" + (100 * count / total) + "%" : ""; } }