aac-metrics 0.1.8 → 0.2.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.
- checksums.yaml +4 -4
- data/lib/aac-metrics/loader.rb +13 -2
- data/lib/aac-metrics/metrics.rb +86 -27
- data/sets/common_words.en.json +1426 -1424
- data/sets/fringe.en.json +12 -129
- data/sets/l84f-e9fafa55d4.common.en.analysis +27620 -27480
- data/sets/l84f-e9fafa55d4.common.en.obfset +14784 -4752
- data/sets/l84ns-2f9h2f9.en.obfset +82466 -0
- data/sets/wp108-c428d7f2dc.en.analysis +16243 -15551
- data/sets/wp108-c428d7f2dc.en.obfset +7906 -2634
- data/sets/wp20-163743e671.obfset +266 -78
- data/sets/wp42-f67dc6f4a9.obfset +3767 -1549
- data/sets/wp60-ce5120b0d2.obfset +5694 -2385
- data/sets/wp80-dad3aeda5e.common.en.analysis +15423 -14787
- data/sets/wp80-dad3aeda5e.common.en.obfset +8049 -2846
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bddb8e430a21868a5b26312fb5924f36b914446dc212d849330462768fd9b233
|
4
|
+
data.tar.gz: c5ddd0e2b835678f0dabf8743099b29d462612d94a4aa4dd261e1cb7337eaa02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 876e09d6be2b2e2b7579c11bb06367296ee7fbba627db0f8d421b4e60d2b7042d9a41433f9b1af10c78a6fc8ac84077170224e059a5a5ba30db6b217cab56936
|
7
|
+
data.tar.gz: 5072598db0226690da77985e4e1ed760b24f0d0edc2bc99a5961e59d7f8e8bfa549073f4d0b223559ba48d7d2348556041d8b513944e5427c9c158db3b467f6c
|
data/lib/aac-metrics/loader.rb
CHANGED
@@ -20,6 +20,7 @@ module AACMetrics::Loader
|
|
20
20
|
}
|
21
21
|
if button['load_board'] && button['load_board']['id']
|
22
22
|
new_button['load_board'] = {'id' => button['load_board']['id']}
|
23
|
+
new_button['load_board']['add_to_sentence'] = true if button['load_board']['add_to_sentence']
|
23
24
|
end
|
24
25
|
new_board['buttons'].push(new_button)
|
25
26
|
end
|
@@ -177,6 +178,7 @@ module AACMetrics::Loader
|
|
177
178
|
else
|
178
179
|
puts "Link found with no access #{btn['load_board'].to_json}"
|
179
180
|
end
|
181
|
+
new_btn['load_board']['add_to_sentence'] = true if new_btn['load_board'] && btn['load_board']['add_to_sentence']
|
180
182
|
elsif btn['action']
|
181
183
|
# TODO: track keyboard actions and don't
|
182
184
|
# treat action buttons for metrics
|
@@ -391,9 +393,18 @@ module AACMetrics::Loader
|
|
391
393
|
end
|
392
394
|
end
|
393
395
|
all_words.uniq!
|
394
|
-
@@
|
396
|
+
@@fringe_words[locale] = all_words
|
395
397
|
end
|
396
|
-
|
398
|
+
|
399
|
+
def self.common_fringe_words(locale)
|
400
|
+
@@common_fringe_words ||= {}
|
401
|
+
return @@common_fringe_words[locale] if @@common_fringe_words[locale]
|
402
|
+
common = self.common_words(locale)['words']
|
403
|
+
core = self.core_lists('en').map{|r| r['words'] }.flatten.compact.uniq
|
404
|
+
all_words = common - core
|
405
|
+
@@common_fringe_words[locale] = all_words
|
406
|
+
end
|
407
|
+
|
397
408
|
def self.base_words(locale)
|
398
409
|
@@base_words ||= {}
|
399
410
|
return @@base_words[locale] if @@base_words[locale]
|
data/lib/aac-metrics/metrics.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# TODO:
|
2
2
|
# Qualitative evaluation criteria:
|
3
|
-
# - this set
|
4
|
-
# - this set
|
5
|
-
# -
|
6
|
-
# - this set provides clear
|
7
|
-
# - grammatical forms
|
8
|
-
# -
|
9
|
-
# -
|
10
|
-
# -
|
11
|
-
# -
|
3
|
+
# - this set looks easy to learn for communicators
|
4
|
+
# - this set looks easy to learn for supporters
|
5
|
+
# - this vocabulary organization of this set makes sense
|
6
|
+
# - this set provides clear locations for user-specific words to be added
|
7
|
+
# - this set supports the use of grammatical forms (tenses and other inflections)
|
8
|
+
# - this set provides predefined simplification for beginning communicators
|
9
|
+
# - this set allows for long-term vocabulary growth over time
|
10
|
+
# - this vocabulary looks like it will work well for young users
|
11
|
+
# - this vocabulary looks like it will work well for adult users
|
12
12
|
|
13
13
|
# Effort algorithms for scanning/eyes
|
14
14
|
module AACMetrics::Metrics
|
@@ -54,6 +54,7 @@ module AACMetrics::Metrics
|
|
54
54
|
visited_board_ids = {}
|
55
55
|
to_visit = [{board: obfset[0], level: 0, entry_x: 1.0, entry_y: 1.0}]
|
56
56
|
set_refs = {}
|
57
|
+
cell_refs = {}
|
57
58
|
rows_tally = 0.0
|
58
59
|
cols_tally = 0.0
|
59
60
|
root_rows = nil
|
@@ -73,6 +74,13 @@ module AACMetrics::Metrics
|
|
73
74
|
set_refs[id] += 1
|
74
75
|
end
|
75
76
|
end
|
77
|
+
board['grid']['rows'].times do |row_idx|
|
78
|
+
board['grid']['columns'].times do |col_idx|
|
79
|
+
id = (board['grid']['order'][row_idx] || [])[col_idx]
|
80
|
+
cell_refs["#{row_idx}.#{col_idx}"] ||= 0.0
|
81
|
+
cell_refs["#{row_idx}.#{col_idx}"] += id ? 1.0 : 0.25
|
82
|
+
end
|
83
|
+
end
|
76
84
|
if board['semantic_ids']
|
77
85
|
board['semantic_ids'].each do |id|
|
78
86
|
set_refs[id] ||= 0
|
@@ -88,7 +96,8 @@ module AACMetrics::Metrics
|
|
88
96
|
end
|
89
97
|
set_pcts = {}
|
90
98
|
set_refs.each do |id, cnt|
|
91
|
-
|
99
|
+
loc = id.split(/-/)[1]
|
100
|
+
set_pcts[id] = cnt.to_f / (cell_refs[loc] || obfset.length).to_f
|
92
101
|
end
|
93
102
|
locale = obfset[0]['locale']
|
94
103
|
known_buttons = {}
|
@@ -115,9 +124,9 @@ module AACMetrics::Metrics
|
|
115
124
|
button_id = (board[:board]['grid']['order'][row_idx] || [])[col_idx]
|
116
125
|
button = board[:board]['buttons'].detect{|b| b['id'] == button_id }
|
117
126
|
if button && button['clone_id'] && set_pcts[button['clone_id']]
|
118
|
-
reuse_discount +=
|
127
|
+
reuse_discount += REUSED_CLONE_FROM_OTHER_BONUS * set_pcts[button['clone_id']]
|
119
128
|
elsif button && button['semantic_id'] && set_pcts[button['semantic_id']]
|
120
|
-
reuse_discount +=
|
129
|
+
reuse_discount += REUSED_SEMANTIC_FROM_OTHER_BONUS * set_pcts[button['semantic_id']]
|
121
130
|
end
|
122
131
|
end
|
123
132
|
end
|
@@ -186,9 +195,13 @@ module AACMetrics::Metrics
|
|
186
195
|
button_effort = board_effort
|
187
196
|
if board_pcts[button['semantic_id']]
|
188
197
|
# TODO: Pull out these magic numbers
|
198
|
+
prior = button_effort
|
189
199
|
button_effort = [button_effort, button_effort * SAME_LOCATION_AS_PRIOR_DISCOUNT / board_pcts[button['semantic_id']]].min
|
200
|
+
# puts " #{button['label']} #{prior.round(1)} - #{prior - button_effort}"
|
190
201
|
elsif board_pcts["upstream-#{button['semantic_id']}"]
|
202
|
+
prior = button_effort
|
191
203
|
button_effort = [button_effort, button_effort * RECOGNIZABLE_SEMANTIC_FROM_PRIOR_DISCOUNT / board_pcts["upstream-#{button['semantic_id']}"]].min
|
204
|
+
# puts " #{button['label']} #{prior.round(1)} - #{prior - button_effort}"
|
192
205
|
end
|
193
206
|
if board_pcts[button['clone_id']]
|
194
207
|
button_effort = [button_effort, button_effort * SAME_LOCATION_AS_PRIOR_DISCOUNT / board_pcts[button['clone_id']]].min
|
@@ -237,6 +250,10 @@ module AACMetrics::Metrics
|
|
237
250
|
effort += board[:prior_effort] || 0
|
238
251
|
prior_buttons += 1
|
239
252
|
|
253
|
+
# TODO: If any board links are sticky, or if
|
254
|
+
# the board set isn't auto-home, or any board links
|
255
|
+
# are add_to_sentence, then the logic will be different
|
256
|
+
# for calculating effort scores, since the route matters
|
240
257
|
if button['load_board']
|
241
258
|
try_visit = false
|
242
259
|
# For linked buttons, only traverse if
|
@@ -265,7 +282,8 @@ module AACMetrics::Metrics
|
|
265
282
|
})
|
266
283
|
end
|
267
284
|
end
|
268
|
-
|
285
|
+
end
|
286
|
+
if !button['load_board'] || button['load_board']['add_to_sentence']
|
269
287
|
word = button['label']
|
270
288
|
existing = known_buttons[word]
|
271
289
|
if !existing || effort < existing[:effort] #board[:level] < existing[:level]
|
@@ -326,11 +344,11 @@ module AACMetrics::Metrics
|
|
326
344
|
SKIPPED_VISUAL_SCAN_DISTANCE_MULTIPLIER = 0.5
|
327
345
|
SAME_LOCATION_AS_PRIOR_DISCOUNT = 0.1
|
328
346
|
RECOGNIZABLE_SEMANTIC_FROM_PRIOR_DISCOUNT = 0.5
|
329
|
-
RECOGNIZABLE_SEMANTIC_FROM_OTHER_DISCOUNT = 0.
|
347
|
+
RECOGNIZABLE_SEMANTIC_FROM_OTHER_DISCOUNT = 0.5
|
348
|
+
REUSED_SEMANTIC_FROM_OTHER_BONUS = 0.0025
|
330
349
|
RECOGNIZABLE_CLONE_FROM_PRIOR_DISCOUNT = 0.33
|
331
|
-
RECOGNIZABLE_CLONE_FROM_OTHER_DISCOUNT = 0.
|
332
|
-
|
333
|
-
REUSED_CLONE_FROM_OTHER_DISCOUNT = 0.005
|
350
|
+
RECOGNIZABLE_CLONE_FROM_OTHER_DISCOUNT = 0.33
|
351
|
+
REUSED_CLONE_FROM_OTHER_BONUS = 0.005
|
334
352
|
|
335
353
|
def self.button_size_effort(rows, cols)
|
336
354
|
BUTTON_SIZE_MULTIPLIER * (rows + cols) / 2
|
@@ -407,6 +425,7 @@ module AACMetrics::Metrics
|
|
407
425
|
synonyms = AACMetrics::Loader.synonyms(target[:locale])
|
408
426
|
sentences = AACMetrics::Loader.sentences(target[:locale])
|
409
427
|
fringe = AACMetrics::Loader.fringe_words(target[:locale])
|
428
|
+
common_fringe = AACMetrics::Loader.common_fringe_words(target[:locale])
|
410
429
|
common_words_obj['efforts'].each{|w, e| sortable_efforts[w] ||= e }
|
411
430
|
common_words = common_words_obj['words']
|
412
431
|
|
@@ -476,6 +495,7 @@ module AACMetrics::Metrics
|
|
476
495
|
res[:cores] = {
|
477
496
|
:common => {name: "Common Word List", list: common_words, average_effort: common_effort, comp_effort: comp_effort}
|
478
497
|
}
|
498
|
+
res[:care_components] = {}
|
479
499
|
target_effort_tally = 0.0
|
480
500
|
comp_effort_tally = 0.0
|
481
501
|
# For each core list, find any missing words, and compute
|
@@ -505,6 +525,7 @@ module AACMetrics::Metrics
|
|
505
525
|
end
|
506
526
|
# Fallback penalty for missing word
|
507
527
|
effort ||= spelling_effort(word)
|
528
|
+
reffort = effort
|
508
529
|
list_effort += effort
|
509
530
|
|
510
531
|
effort = comp_efforts[word]
|
@@ -513,6 +534,7 @@ module AACMetrics::Metrics
|
|
513
534
|
end
|
514
535
|
effort ||= spelling_effort(word)
|
515
536
|
comp_effort += effort
|
537
|
+
# puts "#{word} - #{reffort.round(1)} - #{effort.round(1)}"
|
516
538
|
end
|
517
539
|
if missing.length > 0
|
518
540
|
# puts "MISSING FROM #{list['id']} (#{missing.length}):"
|
@@ -525,8 +547,10 @@ module AACMetrics::Metrics
|
|
525
547
|
comp_effort_tally += comp_effort
|
526
548
|
res[:cores][list['id']] = {name: list['name'], list: list['words'], average_effort: list_effort, comp_effort: comp_effort}
|
527
549
|
end
|
528
|
-
|
529
|
-
|
550
|
+
res[:care_components][:core] = (target_effort_tally / core_lists.to_a.length) * 5.0
|
551
|
+
target_effort_tally = res[:care_components][:core]
|
552
|
+
res[:care_components][:comp_core] = (comp_effort_tally / core_lists.to_a.length) * 5.0
|
553
|
+
comp_effort_tally = res[:care_components][:comp_core]
|
530
554
|
|
531
555
|
# TODO: Assemble or allow a battery of word combinations,
|
532
556
|
# and calculate the level of effort for each sequence,
|
@@ -574,8 +598,10 @@ module AACMetrics::Metrics
|
|
574
598
|
comp_effort_score = comp_effort_score / words.length
|
575
599
|
res[:sentences] << {sentence: words.join(' '), words: words, effort: target_effort_score, comp_effort: comp_effort_score}
|
576
600
|
end
|
577
|
-
|
578
|
-
|
601
|
+
res[:care_components][:sentences] = res[:sentences].map{|s| s[:effort] }.sum.to_f / res[:sentences].length.to_f * 3.0
|
602
|
+
target_effort_tally += res[:care_components][:sentences]
|
603
|
+
res[:care_components][:comp_sentences] = res[:sentences].map{|s| s[:comp_effort] }.sum.to_f / res[:sentences].length.to_f * 3.0
|
604
|
+
comp_effort_tally += res[:care_components][:comp_sentences]
|
579
605
|
|
580
606
|
res[:fringe_words] = []
|
581
607
|
fringe.each do |word|
|
@@ -586,6 +612,7 @@ module AACMetrics::Metrics
|
|
586
612
|
if !effort
|
587
613
|
synonym_words.each{|w| effort ||= target_efforts[w] }
|
588
614
|
end
|
615
|
+
# puts "!#{word}" unless effort
|
589
616
|
effort ||= spelling_effort(word)
|
590
617
|
target_effort_score += effort
|
591
618
|
|
@@ -597,16 +624,48 @@ module AACMetrics::Metrics
|
|
597
624
|
comp_effort_score += effort
|
598
625
|
res[:fringe_words] << {word: word, effort: target_effort_score, comp_effort: comp_effort_score}
|
599
626
|
end
|
600
|
-
|
601
|
-
|
627
|
+
res[:care_components][:fringe] = res[:fringe_words].map{|s| s[:effort] }.sum.to_f / res[:fringe_words].length.to_f * 2.0
|
628
|
+
target_effort_tally += res[:care_components][:fringe]
|
629
|
+
res[:care_components][:comp_fringe] = res[:fringe_words].map{|s| s[:comp_effort] }.sum.to_f / res[:fringe_words].length.to_f * 2.0
|
630
|
+
comp_effort_tally += res[:care_components][:comp_fringe]
|
631
|
+
|
632
|
+
res[:common_fringe_words] = []
|
633
|
+
common_fringe.each do |word|
|
634
|
+
target_effort_score = 0.0
|
635
|
+
comp_effort_score = 0.0
|
636
|
+
synonym_words = [word] + (synonyms[word] || [])
|
637
|
+
effort = target_efforts[word] || target_efforts[word.downcase]
|
638
|
+
if !effort
|
639
|
+
synonym_words.each{|w| effort ||= target_efforts[w] }
|
640
|
+
end
|
641
|
+
effort ||= spelling_effort(word)
|
642
|
+
target_effort_score += effort
|
643
|
+
|
644
|
+
effort = comp_efforts[word] || comp_efforts[word.downcase]
|
645
|
+
if !effort
|
646
|
+
synonym_words.each{|w| effort ||= comp_efforts[w] }
|
647
|
+
end
|
648
|
+
effort ||= spelling_effort(word)
|
649
|
+
comp_effort_score += effort
|
650
|
+
res[:common_fringe_words] << {word: word, effort: target_effort_score, comp_effort: comp_effort_score}
|
651
|
+
end
|
652
|
+
res[:care_components][:common_fringe] = res[:common_fringe_words].map{|s| s[:effort] }.sum.to_f / res[:common_fringe_words].length.to_f * 1.0
|
653
|
+
target_effort_tally += res[:care_components][:common_fringe]
|
654
|
+
res[:care_components][:comp_common_fringe] = res[:common_fringe_words].map{|s| s[:comp_effort] }.sum.to_f / res[:common_fringe_words].length.to_f * 1.0
|
655
|
+
comp_effort_tally += res[:care_components][:comp_common_fringe]
|
602
656
|
|
603
|
-
target_effort_tally +=
|
604
|
-
comp_effort_tally +=
|
657
|
+
target_effort_tally += 70 # placeholder value for future added calculations
|
658
|
+
comp_effort_tally += 70
|
605
659
|
|
660
|
+
# puts target_effort_tally
|
661
|
+
# puts comp_effort_tally
|
662
|
+
# puts (target_effort_tally - comp_effort_tally).abs
|
663
|
+
# puts JSON.pretty_generate(res[:care_components])
|
664
|
+
# raise 'arf'
|
606
665
|
|
607
666
|
|
608
|
-
res[:target_effort_score] = target_effort_tally
|
609
|
-
res[:comp_effort_score] = comp_effort_tally
|
667
|
+
res[:target_effort_score] = [0.0, 350.0 - target_effort_tally].max
|
668
|
+
res[:comp_effort_score] = [0.0, 350.0 - comp_effort_tally].max
|
610
669
|
# puts "CONSIDER MAKING EASIER"
|
611
670
|
res[:high_effort_words] = too_hard
|
612
671
|
# puts too_hard.join(' ')
|