ajax-cat 1.0.0 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -1
- data/Gemfile.lock +4 -3
- data/README.rdoc +1 -1
- data/VERSION +1 -1
- data/ajax-cat.gemspec +10 -5
- data/ajax-cat_old.ini.json +15 -0
- data/lib/ajax-cat.rb +5 -0
- data/lib/ajax-cat/ajax_cat_server.rb +39 -16
- data/lib/ajax-cat/pairs.rb +3 -1
- data/lib/ajax-cat/public/AjaxCatList.coffee +11 -3
- data/lib/ajax-cat/public/AjaxCatTranslation.coffee +36 -12
- data/lib/ajax-cat/public/Suggestions.coffee +12 -3
- data/lib/ajax-cat/public/TranslationTable.coffee +20 -1
- data/lib/ajax-cat/public/Utils.coffee +16 -0
- data/lib/ajax-cat/public/ajax-cat.js +111 -16
- data/lib/ajax-cat/public/cookie.js +72 -0
- data/lib/ajax-cat/public/index.html +1 -1
- data/lib/ajax-cat/public/translation.html +13 -7
- data/lib/ajax-cat/request/suggestion.rb +12 -2
- data/lib/ajax-cat/views/admin.erb +65 -16
- data/lib/ajax-cat/views/experiment.erb +62 -7
- data/test/unit/test_suggestion_request.rb +18 -6
- metadata +39 -26
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -25,8 +25,8 @@ GEM
|
|
25
25
|
git (>= 1.2.5)
|
26
26
|
rake
|
27
27
|
rdoc
|
28
|
-
json (1.
|
29
|
-
multi_json (1.3.
|
28
|
+
json (1.7.3)
|
29
|
+
multi_json (1.3.6)
|
30
30
|
rack (1.4.1)
|
31
31
|
rack-protection (1.2.0)
|
32
32
|
rack
|
@@ -55,7 +55,8 @@ PLATFORMS
|
|
55
55
|
ruby
|
56
56
|
|
57
57
|
DEPENDENCIES
|
58
|
-
activerecord
|
58
|
+
activerecord (>= 3.2.3)
|
59
|
+
activesupport (>= 3.2.3)
|
59
60
|
bundler (~> 1.0.0)
|
60
61
|
colorize (~> 0.5.8)
|
61
62
|
curb (~> 0.8.0)
|
data/README.rdoc
CHANGED
@@ -5,7 +5,7 @@ Ajax-cat is a web server for computer-aided translation build around Moses SMT s
|
|
5
5
|
== Installation
|
6
6
|
* Requirements: Moses, Ruby (version at least 1.9), SQLite
|
7
7
|
* Then simply <code>gem install ajax-cat</code>
|
8
|
-
* Generate sample ini file with <code>ajax-cat
|
8
|
+
* Generate sample ini file with <code>ajax-cat example</code>
|
9
9
|
* Change path in moses in your <code>ajax-cat.ini.json</code> file
|
10
10
|
* Run server with <code>ajax-cat start</code>
|
11
11
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.0.1
|
data/ajax-cat.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "ajax-cat"
|
8
|
-
s.version = "
|
8
|
+
s.version = "2.0.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Ondrej Odchazel"]
|
12
|
-
s.date = "2012-
|
12
|
+
s.date = "2012-08-22"
|
13
13
|
s.description = "computer-aided translation backed by machine translation"
|
14
14
|
s.email = "odchazel@gmail.com"
|
15
15
|
s.executables = ["ajax-cat"]
|
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
|
|
26
26
|
"Rakefile",
|
27
27
|
"VERSION",
|
28
28
|
"ajax-cat.gemspec",
|
29
|
+
"ajax-cat_old.ini.json",
|
29
30
|
"bin/ajax-cat",
|
30
31
|
"lib/.DS_Store",
|
31
32
|
"lib/ajax-cat.rb",
|
@@ -43,6 +44,7 @@ Gem::Specification.new do |s|
|
|
43
44
|
"lib/ajax-cat/public/ajax-cat.js",
|
44
45
|
"lib/ajax-cat/public/bootstrap.css",
|
45
46
|
"lib/ajax-cat/public/bootstrap.js",
|
47
|
+
"lib/ajax-cat/public/cookie.js",
|
46
48
|
"lib/ajax-cat/public/index.html",
|
47
49
|
"lib/ajax-cat/public/index.js",
|
48
50
|
"lib/ajax-cat/public/jquery.js",
|
@@ -89,7 +91,8 @@ Gem::Specification.new do |s|
|
|
89
91
|
s.add_runtime_dependency(%q<thin>, ["~> 1.3.1"])
|
90
92
|
s.add_runtime_dependency(%q<thor>, ["~> 0.15.2"])
|
91
93
|
s.add_runtime_dependency(%q<sqlite3>, ["~> 1.3.3"])
|
92
|
-
s.add_runtime_dependency(%q<activerecord>, [">=
|
94
|
+
s.add_runtime_dependency(%q<activerecord>, [">= 3.2.3"])
|
95
|
+
s.add_runtime_dependency(%q<activesupport>, [">= 3.2.3"])
|
93
96
|
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
94
97
|
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
95
98
|
s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
|
@@ -101,7 +104,8 @@ Gem::Specification.new do |s|
|
|
101
104
|
s.add_dependency(%q<thin>, ["~> 1.3.1"])
|
102
105
|
s.add_dependency(%q<thor>, ["~> 0.15.2"])
|
103
106
|
s.add_dependency(%q<sqlite3>, ["~> 1.3.3"])
|
104
|
-
s.add_dependency(%q<activerecord>, [">=
|
107
|
+
s.add_dependency(%q<activerecord>, [">= 3.2.3"])
|
108
|
+
s.add_dependency(%q<activesupport>, [">= 3.2.3"])
|
105
109
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
106
110
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
107
111
|
s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
|
@@ -114,7 +118,8 @@ Gem::Specification.new do |s|
|
|
114
118
|
s.add_dependency(%q<thin>, ["~> 1.3.1"])
|
115
119
|
s.add_dependency(%q<thor>, ["~> 0.15.2"])
|
116
120
|
s.add_dependency(%q<sqlite3>, ["~> 1.3.3"])
|
117
|
-
s.add_dependency(%q<activerecord>, [">=
|
121
|
+
s.add_dependency(%q<activerecord>, [">= 3.2.3"])
|
122
|
+
s.add_dependency(%q<activesupport>, [">= 3.2.3"])
|
118
123
|
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
119
124
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
120
125
|
s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
|
@@ -0,0 +1,15 @@
|
|
1
|
+
{
|
2
|
+
"port": 8585,
|
3
|
+
"pairs": [
|
4
|
+
{
|
5
|
+
"name": "de-en",
|
6
|
+
"moses_path": "moses",
|
7
|
+
"moses_ini_path": "/Users/ondrejodchazel/projects/ajax-cat/ajax-cat-new/lib/../test/fixtures/moses.ini"
|
8
|
+
},
|
9
|
+
{
|
10
|
+
"name": "en-cs",
|
11
|
+
"moses_path": "moses",
|
12
|
+
"moses_ini_path": "/Users/ondrejodchazel/projects/ajax-cat/models/en-cs/moses.ini"
|
13
|
+
}
|
14
|
+
]
|
15
|
+
}
|
data/lib/ajax-cat.rb
CHANGED
@@ -43,11 +43,29 @@ module AjaxCat
|
|
43
43
|
end
|
44
44
|
|
45
45
|
post '/admin/add_task' do
|
46
|
-
Task.new(pair: params[:pair],
|
46
|
+
task = Task.new(pair: params[:pair], name: params[:name])
|
47
|
+
task.save
|
48
|
+
params[:users].to_i.times do |i|
|
49
|
+
puts "USER #{i}"
|
50
|
+
options = []
|
51
|
+
params[:sentences].length.times do |j|
|
52
|
+
if j % 2 == i % 2
|
53
|
+
type = 'a'
|
54
|
+
else
|
55
|
+
type = 'b'
|
56
|
+
end
|
57
|
+
sentence_options = {}
|
58
|
+
sentence_options["type"] = type
|
59
|
+
sentence_options["suggestion"] = (params["suggestion-#{type}"] == "on")
|
60
|
+
options.push(sentence_options)
|
61
|
+
end
|
62
|
+
Log.new(task_id: task.id, options: options.to_json, sentences: params[:sentences].to_json).save
|
63
|
+
end
|
47
64
|
redirect '/admin'
|
48
65
|
end
|
49
66
|
|
50
67
|
post '/admin/remove_task' do
|
68
|
+
Log.where(task_id: params[:id]).delete_all
|
51
69
|
Task.find(params[:id]).destroy
|
52
70
|
redirect '/admin'
|
53
71
|
end
|
@@ -58,28 +76,33 @@ module AjaxCat
|
|
58
76
|
|
59
77
|
tasks = Task.where(pair: pair)
|
60
78
|
tasks = tasks.map {|el| el.id}
|
61
|
-
completed = Log.where(email: email)
|
62
|
-
completed = completed.map {|el| el.task_id}
|
63
79
|
|
64
|
-
|
80
|
+
free_task_ids = Log.where(email: nil).map {|el| el.task_id}
|
65
81
|
|
66
|
-
|
82
|
+
completed = Log.where(email: email)
|
83
|
+
completed = completed.map {|el| el.task_id}
|
67
84
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
85
|
+
pool = (tasks | free_task_ids) - completed
|
86
|
+
|
87
|
+
puts email
|
88
|
+
puts "t: #{tasks.inspect}, f: #{free_task_ids.inspect}, c: #{completed.inspect}, p: #{pool.inspect}"
|
89
|
+
|
90
|
+
@task = Log.where(task_id: pool.first).first
|
91
|
+
@task.email = email
|
92
|
+
@task.save
|
93
|
+
ret = {
|
94
|
+
task_id: @task.id,
|
95
|
+
pair: @task.task.pair,
|
96
|
+
sentences: @task.sentences,
|
97
|
+
options: @task.options,
|
98
|
+
email: email
|
99
|
+
}.to_json
|
100
|
+
ret
|
75
101
|
end
|
76
102
|
|
77
103
|
post '/admin/save_experiment' do
|
104
|
+
@log = Log.find(params[:log_id])
|
78
105
|
data = JSON.parse(params[:log])
|
79
|
-
@task = Task.find(data["task_id"])
|
80
|
-
@log = Log.new()
|
81
|
-
@log.task_id = @task.id
|
82
|
-
@log.email = data["email"]
|
83
106
|
@log.time = Time.now
|
84
107
|
@log.log = data.to_json
|
85
108
|
@log.save
|
data/lib/ajax-cat/pairs.rb
CHANGED
@@ -14,7 +14,7 @@ module AjaxCat
|
|
14
14
|
create table tasks (
|
15
15
|
id integer primary key,
|
16
16
|
pair varchar (30),
|
17
|
-
|
17
|
+
name varchar (30)
|
18
18
|
)
|
19
19
|
SQL
|
20
20
|
)
|
@@ -25,6 +25,8 @@ module AjaxCat
|
|
25
25
|
task_id integer,
|
26
26
|
email varchar (60),
|
27
27
|
time current_timestamp,
|
28
|
+
sentences text,
|
29
|
+
options text,
|
28
30
|
log text
|
29
31
|
)
|
30
32
|
SQL
|
@@ -28,19 +28,22 @@ class AjaxCatList
|
|
28
28
|
unless filter.test(email)
|
29
29
|
alert "Write your email, please."
|
30
30
|
return
|
31
|
+
$.cookie("email", email)
|
31
32
|
$.ajax "/admin/get_experiment"
|
32
33
|
data:
|
33
34
|
email: email
|
34
35
|
pair: pair
|
35
36
|
success: (data) =>
|
36
37
|
data = JSON.parse(data)
|
37
|
-
id = @add_translation(data.
|
38
|
+
id = @add_translation(JSON.parse(data.sentences), "EXPERIMENT ##{data.task_id}, #{data.email}", data.pair, data.task_id, data.email, data)
|
39
|
+
#return
|
38
40
|
window.location = "/translation.html##{id}"
|
39
41
|
error: =>
|
40
42
|
alert "Could not find experiment for you."
|
41
43
|
|
42
44
|
new_experiment_translation: =>
|
43
45
|
$("#new-experiment-pair").html("")
|
46
|
+
$("#new-experiment-email").val($.cookie("email"))
|
44
47
|
$.ajax "/api/info"
|
45
48
|
success: (data) =>
|
46
49
|
data = JSON.parse(data)
|
@@ -93,7 +96,7 @@ class AjaxCatList
|
|
93
96
|
$('#new-translation-modal').modal('hide')
|
94
97
|
@show_translations()
|
95
98
|
|
96
|
-
add_translation: (text, name, pair, task_id = false, email = false) =>
|
99
|
+
add_translation: (text, name, pair, task_id = false, email = false, experiment_data) =>
|
97
100
|
if localStorage['ac-data']
|
98
101
|
docs = JSON.parse(localStorage['ac-data'])
|
99
102
|
else
|
@@ -104,7 +107,12 @@ class AjaxCatList
|
|
104
107
|
doc.pair = pair
|
105
108
|
doc.email = email
|
106
109
|
doc.task_id = task_id
|
107
|
-
|
110
|
+
#is experiment
|
111
|
+
if jQuery.isArray(text)
|
112
|
+
doc.source = text
|
113
|
+
doc.options = JSON.parse(experiment_data.options)
|
114
|
+
else
|
115
|
+
doc.source = Utils.split_source(text)
|
108
116
|
doc.target = new Array(doc.source.length)
|
109
117
|
docs.push(doc.id)
|
110
118
|
localStorage.setItem('ac-data', JSON.stringify(docs))
|
@@ -1,6 +1,8 @@
|
|
1
1
|
class AjaxCatTranslation
|
2
2
|
|
3
3
|
cur_position: false
|
4
|
+
experiment: false
|
5
|
+
param_suggestion: true
|
4
6
|
|
5
7
|
constructor: ->
|
6
8
|
@now = Date.now()
|
@@ -46,22 +48,34 @@ class AjaxCatTranslation
|
|
46
48
|
$("#time").html(t)
|
47
49
|
setTimeout(@time, 10)
|
48
50
|
|
51
|
+
change_experiment_sentence: =>
|
52
|
+
if @cur_position + 1 < @doc.source.length
|
53
|
+
@change_position(@cur_position + 1)
|
54
|
+
else
|
55
|
+
$("#send-experiment").hide()
|
56
|
+
$.ajax "/admin/save_experiment"
|
57
|
+
data:
|
58
|
+
"log_id": @doc.task_id
|
59
|
+
log: JSON.stringify(@doc)
|
60
|
+
type: "post"
|
61
|
+
success: =>
|
62
|
+
alert "Experiment saved."
|
63
|
+
window.location = "/"
|
64
|
+
error: =>
|
65
|
+
alert "Could not save experiment."
|
66
|
+
|
67
|
+
|
49
68
|
prepare_test: =>
|
50
69
|
AjaxCatList.delete_document(@hash)
|
70
|
+
@experiment = true
|
51
71
|
$("#save").hide()
|
72
|
+
$("#experiment-settings").show()
|
73
|
+
$("#top-translations").hide()
|
74
|
+
$("#bottom-translations").hide()
|
52
75
|
$("#send-experiment").show()
|
53
76
|
$("#send-experiment").click(
|
54
77
|
=>
|
55
|
-
|
56
|
-
$.ajax "/admin/save_experiment"
|
57
|
-
data:
|
58
|
-
log: JSON.stringify(@doc)
|
59
|
-
type: "post"
|
60
|
-
success: =>
|
61
|
-
alert "Experiment saved."
|
62
|
-
window.location = "/"
|
63
|
-
error: =>
|
64
|
-
alert "Could not save experiment."
|
78
|
+
@change_experiment_sentence()
|
65
79
|
)
|
66
80
|
@doc.log = []
|
67
81
|
@time()
|
@@ -76,7 +90,9 @@ class AjaxCatTranslation
|
|
76
90
|
)
|
77
91
|
new_log.type = type if type
|
78
92
|
new_log.param = param if param
|
79
|
-
@doc.log
|
93
|
+
if @doc.log[@cur_position] == undefined
|
94
|
+
@doc.log[@cur_position] = []
|
95
|
+
@doc.log[@cur_position].push(new_log)
|
80
96
|
$("#log").append(JSON.stringify(new_log) + "<br>")
|
81
97
|
|
82
98
|
|
@@ -151,13 +167,14 @@ class AjaxCatTranslation
|
|
151
167
|
|
152
168
|
|
153
169
|
load_translation_table: (sentence) =>
|
170
|
+
@table_request.abort() if @table_request
|
154
171
|
sentence = Utils.tokenize(sentence)
|
155
172
|
if sentence.match(/^[\ \t]*$/)
|
156
173
|
$("#translation-table-container").html("")
|
157
174
|
@suggestions.clear()
|
158
175
|
return
|
159
176
|
$("#translation-table-container").text("")
|
160
|
-
$.ajax "/api/table"
|
177
|
+
@table_request = $.ajax "/api/table"
|
161
178
|
data:
|
162
179
|
pair: @pair
|
163
180
|
q: sentence
|
@@ -169,6 +186,13 @@ class AjaxCatTranslation
|
|
169
186
|
#alert "failed to load translation table"
|
170
187
|
|
171
188
|
change_position: (position) =>
|
189
|
+
if @experiment
|
190
|
+
return if not ((position == 0 and @cur_position == false) or (@cur_position + 1 == position))
|
191
|
+
@param_suggestion = @doc.options[position].suggestion
|
192
|
+
$("#suggestion-panel-is-on").text(@param_suggestion)
|
193
|
+
$("#translated-status").text("translating sentence #{position + 1} out of #{@doc.source.length}")
|
194
|
+
$("#send-experiment").text("Finish experiment") if (position + 1) == @doc.source.length
|
195
|
+
@suggestions.clear()
|
172
196
|
@save_target() if @cur_position != false
|
173
197
|
$("#source-top").children().slice(0,position).show()
|
174
198
|
$("#source-top").children().slice(position,@length).hide()
|
@@ -23,17 +23,19 @@ class Suggestions
|
|
23
23
|
)
|
24
24
|
|
25
25
|
clear: =>
|
26
|
+
@suggestion_request.abort() if @suggestion_request
|
26
27
|
$(".ac-suggestion").text("")
|
27
28
|
$(".ac-suggestion").removeClass('suggestion-enabled')
|
28
29
|
$(".ac-suggestion").removeClass('suggestion-active')
|
29
30
|
|
30
31
|
load_suggestions: =>
|
31
32
|
@clear()
|
33
|
+
return unless @translation.param_suggestion
|
32
34
|
sentence = $("#source-sentence").text()
|
33
35
|
sentence = Utils.tokenize(sentence)
|
34
36
|
translated = Utils.tokenize($("#source-target").text())
|
35
37
|
covered = @translation.table.covered_vector()
|
36
|
-
$.ajax "/api/suggestion"
|
38
|
+
@suggestion_request = $.ajax "/api/suggestion"
|
37
39
|
data:
|
38
40
|
pair: @translation.pair
|
39
41
|
q: Utils.tokenize(sentence)
|
@@ -48,8 +50,13 @@ class Suggestions
|
|
48
50
|
take_suggestion: =>
|
49
51
|
return if (@get_position() == false)
|
50
52
|
text = $(".suggestion-active span").text()
|
53
|
+
|
54
|
+
from = $(".suggestion-active").data('from')
|
55
|
+
to = $(".suggestion-active").data('to')
|
51
56
|
@translation.add_words(text)
|
52
|
-
|
57
|
+
#alert "#{from}-#{to}"
|
58
|
+
@translation.table.mark_interval(from, to)
|
59
|
+
#@translation.table.mark_words(text)
|
53
60
|
|
54
61
|
|
55
62
|
process_suggestions: (data) =>
|
@@ -57,7 +64,9 @@ class Suggestions
|
|
57
64
|
for suggestion in data.suggestions
|
58
65
|
translation = $("#target-sentence").val()
|
59
66
|
el = $(".ac-suggestion").slice(i, (i + 1))
|
60
|
-
el.html("#{translation} <span>#{suggestion}</span>")
|
67
|
+
el.html("#{translation} <span>#{suggestion.text}</span>")
|
68
|
+
el.data('from', suggestion.from)
|
69
|
+
el.data('to', suggestion.to)
|
61
70
|
el.addClass('suggestion-enabled')
|
62
71
|
i += 1
|
63
72
|
|
@@ -63,7 +63,26 @@ class TranslationTable
|
|
63
63
|
return true if $("th.ac-source").slice(position, (position + 1)).hasClass('ac-selected')
|
64
64
|
return false
|
65
65
|
|
66
|
-
|
66
|
+
#use edit distance to mark written words
|
67
|
+
mark_words: (word) =>
|
68
|
+
word = Utils.trim word
|
69
|
+
best_result = 10000
|
70
|
+
best_element = null
|
71
|
+
maximal_acceptable_distance = 1
|
72
|
+
maximal_acceptable_distance = 0 if word.length < 5
|
73
|
+
maximal_acceptable_distance = 2 if word.length > 10
|
74
|
+
for el in $(".ac-word div")
|
75
|
+
element_text = Utils.trim($(el).text())
|
76
|
+
result = Utils.edit_distance(word, element_text)
|
77
|
+
if result < best_result
|
78
|
+
best_result = result
|
79
|
+
best_element = $(el)
|
80
|
+
if best_element != null and best_result <= maximal_acceptable_distance
|
81
|
+
@mark_interval(best_element.data('position-from'), best_element.data('position-to'))
|
82
|
+
|
83
|
+
#when more words, there should be fix on server side giving most likely continuation
|
84
|
+
mark_words_OLD: (words) =>
|
85
|
+
console.log "MARKING WORDS: #{words}"
|
67
86
|
words = "#{words} "
|
68
87
|
for el in $(".ac-word div")
|
69
88
|
el_text = Utils.trim $(el).text()
|