1
0
forked from GitHub/gf-core

visualization for topics in the Android app

This commit is contained in:
krasimir
2015-11-28 23:15:58 +00:00
parent 06043c06c7
commit fffab87469
7 changed files with 233 additions and 124 deletions

View File

@@ -25,7 +25,14 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="AlternativesActivity"></activity>
<activity android:name="AlternativesActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="gf-translator"/>
</intent-filter>
</activity>
<activity android:name="HelpActivity"></activity>
<activity android:name="SemanticGraphActivity"
android:launchMode="singleTop">

View File

@@ -11,6 +11,7 @@
<string name="help">Help</string>
<string name="global_preferences_key">org.grammaticalframework.ui.android.GLOBAL_PREFERENCES</string>
<string name="authority_key">authority_key</string>
<string name="source_key">source_key</string>
<string name="target_key">target_key</string>
<string name="alternatives_key">alternatives_key</string>

View File

@@ -1,6 +1,6 @@
package org.grammaticalframework.ui.android;
import java.util.List;
import java.util.*;
import android.app.Activity;
import android.app.ListActivity;
@@ -17,6 +17,7 @@ import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.util.Log;
import org.grammaticalframework.pgf.*;
import org.grammaticalframework.ui.android.LanguageSelector.OnLanguageSelectedListener;
@@ -26,7 +27,8 @@ public class AlternativesActivity extends ListActivity {
private Translator mTranslator;
private LanguageSelector mShowLanguageView;
private View mProgressBarView = null;
private AlternativesAdapter mAdapter = null;
/** Called when the activity is first created. */
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -55,7 +57,8 @@ public class AlternativesActivity extends ListActivity {
@Override
protected void onPostExecute(Void result) {
updateTranslations();
mAdapter.notifyDataSetChanged();
expandedView = null;
hideProgressBar();
}
}.execute();
@@ -63,11 +66,20 @@ public class AlternativesActivity extends ListActivity {
});
TextView descrView = (TextView) findViewById(R.id.lexical_desc);
descrView.setText(getIntent().getExtras().getString("source"));
String authority = getIntent().getData().getAuthority();
String source = getIntent().getData().getQueryParameter("source");
List analyses = new ArrayList();
for (String an : getIntent().getData().getQueryParameters("alternative")) {
analyses.add(Expr.readExpr(an));
}
descrView.setText(source);
mAdapter = new AlternativesAdapter(this, authority, analyses);
setListAdapter(mAdapter);
expandedView = null;
mProgressBarView = findViewById(R.id.progressBarView);
updateTranslations();
}
@Override
@@ -86,15 +98,6 @@ public class AlternativesActivity extends ListActivity {
}
private View expandedView;
private void updateTranslations() {
@SuppressWarnings("unchecked")
List<Object> list = (List<Object>)
getIntent().getExtras().getSerializable("analyses");
setListAdapter(new AlternativesAdapter(this, list));
expandedView = null;
}
private void collapse() {
if (expandedView == null)
@@ -113,7 +116,7 @@ public class AlternativesActivity extends ListActivity {
expandedView = null;
}
private void expand(View view, String lemma) {
private void expandWord(View view, Expr lemma) {
String html = mTranslator.getInflectionTable(lemma);
if (html == null)
return;
@@ -136,7 +139,7 @@ public class AlternativesActivity extends ListActivity {
expandedView = view;
}
private void expandExpr(View view, ExprProb ep) {
private void expandSentence(View view, Expr expr) {
ImageView arrow = (ImageView) view.findViewById(R.id.arrow);
arrow.setImageResource(R.drawable.close_arrow);
@@ -150,7 +153,7 @@ public class AlternativesActivity extends ListActivity {
((RelativeLayout) view).addView(parseView, params);
}
Object[] brackets = mTranslator.bracketedLinearize(ep.getExpr());
Object[] brackets = mTranslator.bracketedLinearize(expr);
if (brackets[0] instanceof Bracket) {
Bracket b = (Bracket) brackets[0];
if (b.children[0].equals("*") ||
@@ -174,20 +177,23 @@ public class AlternativesActivity extends ListActivity {
params.addRule(RelativeLayout.BELOW, R.id.desc_details);
((RelativeLayout) view).addView(textView, params);
}
textView.setText(ep.getExpr().toString());
textView.setText(expr.toString());
expandedView = view;
}
private class AlternativesAdapter extends ArrayAdapter<Object> {
public AlternativesAdapter(Context context, List<Object> data) {
private class AlternativesAdapter extends ArrayAdapter<Expr> {
private String mAuthority;
public AlternativesAdapter(Context context, String authority, List<Expr> data) {
super(context, android.R.layout.simple_list_item_1, data);
mAuthority = authority;
}
public View getView(int position, View convertView, ViewGroup parent) {
Object item = getItem(position);
final Expr expr = getItem(position);
if (item instanceof MorphoAnalysis) {
if (mAuthority.equals(Translator.WORDS)) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater)
getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
@@ -197,9 +203,7 @@ public class AlternativesActivity extends ListActivity {
TextView descView = (TextView)
convertView.findViewById(R.id.lexical_desc);
final String lemma = ((MorphoAnalysis) item).getLemma();
String phrase = mTranslator.generateLexiconEntry(lemma);
String phrase = mTranslator.generateLexiconEntry(expr);
descView.setText(phrase);
convertView.setOnClickListener(new OnClickListener() {
@@ -208,16 +212,14 @@ public class AlternativesActivity extends ListActivity {
if (expandedView == view)
collapse();
else if (expandedView == null)
expand(view, lemma);
expandWord(view, expr);
else {
collapse();
expand(view, lemma);
expandWord(view, expr);
}
}
});
} else if (item instanceof ExprProb) {
final ExprProb ep = (ExprProb) item;
} else if (mAuthority.equals(Translator.SENTENCES)) {
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater)
getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
@@ -233,7 +235,7 @@ public class AlternativesActivity extends ListActivity {
TextView descView = (TextView)
convertView.findViewById(R.id.alternative_desc);
String phrase = mTranslator.linearize(ep.getExpr());
String phrase = mTranslator.linearize(expr);
// parse by words, marked by %, darkest red color
if (phrase.charAt(0) == '%') {
@@ -270,10 +272,10 @@ public class AlternativesActivity extends ListActivity {
if (expandedView == view)
collapse();
else if (expandedView == null)
expandExpr(view, ep);
expandSentence(view, expr);
else {
collapse();
expandExpr(view, ep);
expandSentence(view, expr);
}
}
});

View File

@@ -1,7 +1,7 @@
package org.grammaticalframework.ui.android;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.*;
import android.content.Context;
import android.os.Bundle;
@@ -17,6 +17,8 @@ import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import org.grammaticalframework.pgf.Expr;
public class ConversationView extends ScrollView {
private LayoutInflater mInflater;
@@ -105,7 +107,7 @@ public class ConversationView extends ScrollView {
}
@SuppressWarnings("deprecation")
public CharSequence addSecondPersonUtterance(final CharSequence source, CharSequence target, final Object alternatives) {
public CharSequence addSecondPersonUtterance(String authority, CharSequence source, CharSequence target, List<Expr> alternatives) {
TextView view;
if (mLastUtterance != null && mLastUtterance.getTag() != null)
view = (TextView) mLastUtterance.getTag();
@@ -124,6 +126,7 @@ public class ConversationView extends ScrollView {
mLastUtterance.setTag(view);
}
view.setTag(R.string.authority_key, authority);
view.setTag(R.string.source_key, source);
view.setTag(R.string.target_key, target);
view.setTag(R.string.alternatives_key, alternatives);
@@ -176,9 +179,10 @@ public class ConversationView extends ScrollView {
mAlternativesListener = new OnClickListener() {
@Override
public void onClick(View v) {
String authority = v.getTag(R.string.authority_key).toString();
String source = v.getTag(R.string.source_key).toString();
Object alternatives = v.getTag(R.string.alternatives_key);
listener.onAlternativesSelected(source, alternatives);
List<Expr> alternatives = (List<Expr>) v.getTag(R.string.alternatives_key);
listener.onAlternativesSelected(authority, source, alternatives);
}
};
}
@@ -186,12 +190,13 @@ public class ConversationView extends ScrollView {
public void setSpeechInputListener(ASR.Listener listener) {
mSpeechListener = listener;
}
public interface OnAlternativesListener {
public void onAlternativesSelected(CharSequence word, Object lexicon);
public void onAlternativesSelected(CharSequence authority, CharSequence word, List<Expr> althernatives);
}
public void saveConversation(Bundle state) {
ArrayList<String> authorities = new ArrayList<String>();
ArrayList<String> firstPersonUtterances = new ArrayList<String>();
ArrayList<String> secondPersonUtterances = new ArrayList<String>();
ArrayList<Object> translationAlternatives = new ArrayList<Object>();
@@ -200,31 +205,36 @@ public class ConversationView extends ScrollView {
for (int i = 0; i < childCount; i++) {
View child = mContent.getChildAt(i);
if (child.getClass() == TextView.class) {
authorities.add(child.getTag(R.string.authority_key).toString());
firstPersonUtterances.add(child.getTag(R.string.source_key).toString());
secondPersonUtterances.add(child.getTag(R.string.target_key).toString());
translationAlternatives.add(child.getTag(R.string.alternatives_key));
}
}
state.putStringArrayList("authorities", authorities);
state.putStringArrayList("first_person_uterances", firstPersonUtterances);
state.putStringArrayList("second_person_uterances", secondPersonUtterances);
state.putSerializable("translation_alternatives",(Serializable) translationAlternatives);
}
public void restoreConversation(Bundle state) {
ArrayList<String> authorities = state.getStringArrayList("authorities");
ArrayList<String> firstPersonUtterances = state.getStringArrayList("first_person_uterances");
ArrayList<String> secondPersonUtterances = state.getStringArrayList("second_person_uterances");
ArrayList<Object> translationAlternatives= (ArrayList<Object>) state.getSerializable("translation_alternatives");
ArrayList<List<Expr>> translationAlternatives= (ArrayList<List<Expr>>) state.getSerializable("translation_alternatives");
int i = 0;
while (i < firstPersonUtterances.size() &&
while (i < authorities.size() &&
i < firstPersonUtterances.size() &&
i < Math.min(secondPersonUtterances.size(), translationAlternatives.size())) {
String text = firstPersonUtterances.get(i);
addFirstPersonUtterance(text, false);
String authority = authorities.get(i);
String translation = secondPersonUtterances.get(i);
Object alternatives = translationAlternatives.get(i);
addSecondPersonUtterance(text, translation, alternatives);
List<Expr> alternatives = translationAlternatives.get(i);
addSecondPersonUtterance(authority, text, translation, alternatives);
i++;
}

View File

@@ -1,9 +1,7 @@
package org.grammaticalframework.ui.android;
import java.io.Serializable;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.io.*;
import java.util.*;
import android.app.Activity;
import android.content.Intent;
@@ -11,6 +9,7 @@ import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.speech.SpeechRecognizer;
import android.net.Uri;
import android.util.Log;
import android.util.Pair;
import android.view.Menu;
@@ -25,8 +24,7 @@ import android.widget.ImageView;
import org.grammaticalframework.ui.android.ASR.State;
import org.grammaticalframework.ui.android.LanguageSelector.OnLanguageSelectedListener;
import org.grammaticalframework.ui.android.ConversationView.OnAlternativesListener;
import org.grammaticalframework.pgf.ExprProb;
import org.grammaticalframework.pgf.MorphoAnalysis;
import org.grammaticalframework.pgf.*;
public class MainActivity extends Activity {
@@ -89,10 +87,16 @@ public class MainActivity extends Activity {
mConversationView.setOnAlternativesListener(new OnAlternativesListener() {
@Override
public void onAlternativesSelected(CharSequence input, Object lexicon) {
Intent myIntent = new Intent(MainActivity.this, AlternativesActivity.class);
myIntent.putExtra("source", input);
myIntent.putExtra("analyses", (Serializable) lexicon);
public void onAlternativesSelected(CharSequence authority, CharSequence input, List<Expr> alternatives) {
Uri.Builder builder = new Uri.Builder();
builder.scheme("gf-translator");
builder.authority(authority.toString());
builder.appendQueryParameter("source", input.toString());
for (Expr e : alternatives) {
builder.appendQueryParameter("alternative", e.toString());
}
Intent myIntent = new Intent(Intent.ACTION_VIEW, builder.build());
MainActivity.this.startActivity(myIntent);
}
});
@@ -187,10 +191,16 @@ public class MainActivity extends Activity {
editor.commit();
return true;
case R.id.help:
case R.id.semantic_graph: {
Intent myIntent = new Intent(MainActivity.this, SemanticGraphActivity.class);
MainActivity.this.startActivity(myIntent);
return true;
}
case R.id.help: {
Intent myIntent = new Intent(MainActivity.this, HelpActivity.class);
MainActivity.this.startActivity(myIntent);
return true;
}
default:
return super.onOptionsItemSelected(item);
}
@@ -278,11 +288,16 @@ public class MainActivity extends Activity {
protected void onPostExecute(Pair<String,List<ExprProb>> res) {
String text = res.first;
List<ExprProb> transl = res.second;
Object alts = null;
List<Expr> alts = null;
String authority = null;
// filter out duplicates
int i = 0;
if (list.size() > 0) {
alts = new ArrayList(list.size());
authority = Translator.WORDS;
while (i < list.size()) {
MorphoAnalysis an = list.get(i);
boolean found = false;
@@ -293,14 +308,16 @@ public class MainActivity extends Activity {
}
}
if (found)
list.remove(i);
else {
i++;
if (!found) {
alts.add(Expr.readExpr(an.getLemma()));
}
i++;
}
alts = list;
} else {
alts = new ArrayList(transl.size());
authority = Translator.SENTENCES;
Set<String> strings = new HashSet<String>();
while (i < transl.size()) {
String s = mTranslator.linearize(transl.get(i).getExpr());
@@ -309,20 +326,18 @@ public class MainActivity extends Activity {
s = s.substring(2);
}
if (strings.contains(s))
transl.remove(i);
else {
if (!strings.contains(s)) {
strings.add(s);
i++;
alts.add(transl.get(i).getExpr());
}
}
alts = transl;
}
i++;
}
}
if (DBG) Log.d(TAG, "Speaking: " + res.first);
CharSequence text2 =
mConversationView.addSecondPersonUtterance(input, text, alts);
mConversationView.addSecondPersonUtterance(authority, input, text, alts);
text2 = text2.toString().replace('[',' ').replace(']',' ').replaceAll("_","").trim();
mTts.speak(getTargetLanguageCode(), text2.toString());

View File

@@ -11,6 +11,7 @@ public class SemanticGraphManager implements Closeable {
private SG mDB;
public static final String GLOSSES_FILE_NAME = "glosses.txt";
public static final String TOPICS_FILE_NAME = "topics.txt";
public static final String DATABASE_FILE_NAME = "semantics.db";
public SemanticGraphManager(Context context) {
@@ -44,9 +45,14 @@ public class SemanticGraphManager implements Closeable {
if (exists)
return;
loadFile(GLOSSES_FILE_NAME);
loadFile(TOPICS_FILE_NAME);
}
private void loadFile(String assetName) throws IOException {
BufferedReader br = new BufferedReader(
new InputStreamReader(
mContext.getAssets().open(GLOSSES_FILE_NAME)));
mContext.getAssets().open(assetName)));
try {
mDB.beginTrans();
@@ -67,7 +73,7 @@ public class SemanticGraphManager implements Closeable {
} finally {
br.close();
}
}
}
public void close() {
if (mDB != null) {
@@ -75,40 +81,9 @@ public class SemanticGraphManager implements Closeable {
mDB = null;
}
}
public Expr getDefinition(Expr lemma, boolean withExample) {
Expr gloss = null;
Expr example = null;
try {
createDatabaseFromAssets();
{
TripleResult res = mDB.queryTriple(lemma, Expr.readExpr("gloss"), null);
if (res.hasNext()) {
gloss = res.getObject();
}
res.close();
}
if (withExample) {
TripleResult res = mDB.queryTriple(lemma, Expr.readExpr("example"), null);
if (res.hasNext()) {
example = res.getObject();
}
res.close();
}
} catch (IOException e) {
// nothing
} catch (SGError e) {
// nothing
}
if (gloss == null)
return null;
else if (example == null)
return new Expr("MkDefinition", gloss);
else
return new Expr("MkDefinitionEx", gloss, example);
public TripleResult queryTriple(Expr subj, Expr pred, Expr obj) throws IOException {
createDatabaseFromAssets();
return mDB.queryTriple(subj, pred, obj);
}
}

View File

@@ -5,10 +5,12 @@ import android.content.SharedPreferences;
import android.content.pm.PackageManager.NameNotFoundException;
import android.util.Log;
import android.util.Pair;
import android.net.Uri;
import android.view.inputmethod.CompletionInfo;
import android.database.sqlite.SQLiteDatabase;
import android.database.Cursor;
import org.grammaticalframework.sg.*;
import org.grammaticalframework.pgf.*;
import java.io.*;
import java.util.*;
@@ -54,6 +56,9 @@ public class Translator {
private static final String SOURCE_LANG_KEY = "source_lang";
private static final String TARGET_LANG_KEY = "target_lang";
public static final String WORDS = "words";
public static final String SENTENCES = "sentences";
private static final int NUM_ALT_TRANSLATIONS = 10;
private SharedPreferences mSharedPref;
@@ -345,48 +350,142 @@ public class Translator {
return targetLang.bracketedLinearize(expr);
}
public String generateLexiconEntry(String lemma) {
public String generateLexiconEntry(Expr lemma) {
Concr sourceLang = getSourceConcr();
Concr targetLang = getTargetConcr();
String cat = getGrammar().getFunctionType(lemma).getCategory();
String fun = lemma.toString();
String cat = getGrammar().getFunctionType(fun).getCategory();
Expr e1 = Expr.readExpr(lemma);
Expr e2 = Expr.readExpr("MkTag (Inflection"+cat+" "+lemma+")");
Expr e2 = Expr.readExpr("MkTag (Inflection"+cat+" "+fun+")");
if (targetLang.hasLinearization("Inflection"+cat)) {
if (targetLang.hasLinearization(lemma))
return sourceLang.linearize(e1) + " - " + targetLang.linearize(e2) + ". " + targetLang.linearize(e1);
if (targetLang.hasLinearization(fun))
return sourceLang.linearize(lemma) + " - " + targetLang.linearize(e2) + ". " + targetLang.linearize(lemma);
else
return sourceLang.linearize(e1) + " " + targetLang.linearize(e2)+".";
return sourceLang.linearize(lemma) + " " + targetLang.linearize(e2)+".";
} else {
if (targetLang.hasLinearization(lemma))
return sourceLang.linearize(e1) + " - " + targetLang.linearize(e1);
if (targetLang.hasLinearization(fun))
return sourceLang.linearize(lemma) + " - " + targetLang.linearize(lemma);
else
return sourceLang.linearize(e1);
return sourceLang.linearize(lemma);
}
}
public String getInflectionTable(String lemma) {
private static final Expr gloss_pred = Expr.readExpr("gloss");
private static final Expr topic_pred = Expr.readExpr("topic");
private static final Expr example_pred = Expr.readExpr("example");
public Expr getDefinition(Expr lemma, boolean withExample) {
Expr gloss = null;
Expr example = null;
Map<String,Uri.Builder> topics = new TreeMap<String,Uri.Builder>();
try {
TripleResult res = mSGManager.queryTriple(lemma, null, null);
while (res.hasNext()) {
if (res.getPredicate().equals(gloss_pred))
gloss = res.getObject();
else if (res.getPredicate().equals(topic_pred))
updateWordsMap(res.getObject(), topics);
else if (res.getPredicate().equals(example_pred))
example = res.getObject();
}
res.close();
} catch (IOException e) {
// nothing
} catch (SGError e) {
// nothing
}
Expr topic = null;
if (topics.size() > 0) {
StringBuilder builder = new StringBuilder();
builder.append('(');
buildWordsHtml(topics, builder);
builder.append(')');
topic = new Expr(builder.toString());
}
if (gloss == null)
return topic;
else {
if (topic == null)
topic = new Expr("");
if (withExample && example != null)
return new Expr("MkDefinitionEx", topic, gloss, example);
else
return new Expr("MkDefinition", topic, gloss);
}
}
private void updateWordsMap(Expr expr, Map<String,Uri.Builder> map) {
String word = getTargetConcr().linearize(expr);
Uri.Builder builder = map.get(word);
if (builder == null) {
builder = new Uri.Builder();
builder.scheme("gf-translator");
builder.authority(WORDS);
builder.appendQueryParameter("source", word);
map.put(word,builder);
}
builder.appendQueryParameter("alternative", expr.toString());
}
private void buildWordsHtml(Map<String,Uri.Builder> map, StringBuilder sbuilder) {
boolean first = true;
for (Map.Entry<String,Uri.Builder> entry : map.entrySet()) {
if (first)
first = false;
else
sbuilder.append(", ");
sbuilder.append("<a href=\""+entry.getValue().build()+"\">"+entry.getKey()+"</a>");
}
}
private Expr getTopicWords(Expr lemma) {
StringBuilder sbuilder = new StringBuilder();
try {
TripleResult res = mSGManager.queryTriple(null, topic_pred, lemma);
Map<String,Uri.Builder> map = new TreeMap<String,Uri.Builder>();
while (res.hasNext()) {
updateWordsMap(res.getSubject(), map);
}
res.close();
StringBuilder builder = new StringBuilder();
buildWordsHtml(map, builder);
return new Expr(builder.toString());
} catch (IOException e) {
// nothing
} catch (SGError e) {
// nothing
}
return null;
}
public String getInflectionTable(Expr lemma) {
boolean withExample =
(getSourceLanguage().getLangCode().equals("en-US") ||
getTargetLanguage().getLangCode().equals("en-US"));
Expr def =
mSGManager.getDefinition(Expr.readExpr(lemma), withExample);
getDefinition(lemma, withExample);
String fun = lemma.toString();
Concr targetLang = getTargetConcr();
String cat = getGrammar().getFunctionType(lemma).getCategory();
String cat = getGrammar().getFunctionType(fun).getCategory();
if (targetLang.hasLinearization(lemma) &&
if (targetLang.hasLinearization(fun) &&
targetLang.hasLinearization("Inflection"+cat)) {
if (def == null)
def = Expr.readExpr("NoDefinition");
Expr e = new Expr("MkDocument",
def,
Expr.readExpr("Inflection"+cat+" "+lemma),
Expr.readExpr("\"\""));
new Expr("Inflection"+cat,lemma),
getTopicWords(lemma));
String html =
"<html><head><meta charset=\"UTF-8\"/></head><body>" +
"<html><head><meta charset=\"UTF-8\"/><style>a {color: gray;}</style></head><body>" +
targetLang.linearize(e) +
"</body>";
return html;