ajax-cat 1.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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()
|