def nextText(self): type = Settings.get('select_method') if type != 1: # Not in order v = DB.execute("select id,source,text from text where disabled is null order by random() limit %d" % Settings.get('num_rand')).fetchall() if len(v) == 0: v = None elif type == 2: v = min(v, key=self.diff_eval) elif type == 3: v = max(v, key=self.diff_eval) else: v = v[0] # random, just pick the first else: # Fetch in order lastid = (0,) g = DB.fetchone("""select r.text_id from result as r left join source as s on (r.source = s.rowid) where (s.discount is null) or (s.discount = 1) order by r.w desc limit 1""", None) if g is not None: lastid = DB.fetchone("select rowid from text where id = ?", lastid, g) v = DB.fetchone("select id,source,text from text where rowid > ? and disabled is null order by rowid asc limit 1", None, lastid) if v is None: v = self.defaultText self.emit(SIGNAL("setText"), v)
def next_text(self): kind = Settings.get("select_method") if kind != 1: # Not in order targets = DB.execute( f"""select id,source,text from text where disabled is null order by random() limit {Settings.get("num_rand")}""" ).fetchall() if not targets: target = None elif kind == 2: target = min(targets, key=self.diff_eval) elif kind == 3: target = max(targets, key=self.diff_eval) else: target = targets[0] # random, just pick the first else: # Fetch in order prev = (0, ) result = DB.fetchone( """select r.text_id from result as r left join source as s on (r.source = s.rowid) where (s.discount is null) or (s.discount = 1) order by r.w desc limit 1""", None) if result is not None: prev = DB.fetchone("select rowid from text where id = ?", prev, result) target = DB.fetchone( """select id,source,text from text where rowid > ? and disabled is null order by rowid asc limit 1""", None, prev) if target is None: target = self.default_text self.emit("set-text", *target)
def update(self): self.progress_.show() n_text = DB.fetchone("""select count(*) from text""", (0,))[0] self.progress_.inc(2) n_res = DB.fetchone("""select count(*) from result""", (0,))[0] self.progress_.inc(2) n_words = DB.fetchall( """select count(*),sum(count) from statistic group by type order by type""" ) self.progress_.inc(2) if len(n_words) != 3: n_words = [(0, 0), (0, 0), (0, 0)] n_first = DB.fetchone("""select w from result order by w asc limit 1""", (time.time(),))[0] self.progress_.hide() self.stats_.setText( locale.format_string( """Texts: %d Results: %d Analysis data: %d (%d keys, %d trigrams, %d words) %d characters and %d words typed total\n""" + ("First result was %.2f days ago.\n" % ((time.time() - n_first) / 86400.0)), tuple( [n_text, n_res, sum(map(lambda x: x[0], n_words))] + map(lambda x: x[0], n_words) + [n_words[0][1], n_words[2][1]] ), True, ) )
def update(self): self.progress_.show() n_text = DB.fetchone('''select count(*) from text''', (0, ))[0] self.progress_.inc(2) n_res = DB.fetchone('''select count(*) from result''', (0, ))[0] self.progress_.inc(2) n_words = DB.fetchall('''select count(*), sum(count) from statistic group by type order by type''') self.progress_.inc(2) if len(n_words) != 3: n_words = [(0, 0), (0, 0), (0, 0)] n_first = DB.fetchone( '''select w from result order by w asc limit 1''', (time.time(), ))[0] self.progress_.hide() self.stats_.setText( locale.format_string( '''Texts: %d Results: %d Analysis data: %d (%d keys, %d trigrams, %d words) %d characters and %d words typed total\n''' + ("First result was %.2f days ago.\n" % ((time.time() - n_first) / 86400.0)), tuple([n_text, n_res, sum(map(lambda x: x[0], n_words))] + list(map(lambda x: x[0], n_words)) + [n_words[0][1], n_words[2][1]]), True))
def lastText(self): # Fetch in order lastResultGuid = DB.fetchone("""select r.text_id from result as r left join source as s on (r.source = s.rowid) where (s.discount is null) or (s.discount = 1) order by r.w desc limit 1""", None) if lastResultGuid is not None: v = DB.fetchone("select id, source, text from text where id = ?", None, lastResultGuid) else: v = self.defaultText if v is None: v = self.defaultText self.emit(SIGNAL("setText"), v)
def newReview(self, review): q = self.addTexts("<Reviews>", [review], lesson=2, update=False) if q: v = DB.fetchone("select id,source,text from text where id = ?", self.defaultText, q) self.emit(SIGNAL("setText"), v) else: self.nextText()
def setTarget(self, text, guid): self.editflag = True self.target = text self.when = [0] * (len(self.target) + 1) # time for each character typed self.times = [0] * len(self.target) # whether each character was a mistake self.mistake = [False] * len(self.target) # mistake characters ( must be what was actually typed ) self.mistakes = {} #collections.defaultdict(lambda: []) self.where = 0 self.clear() self.setPalette(self.palettes['inactive']) self.setText(self.getWaitText()) self.selectAll() self.editflag = False self.is_lesson = DB.fetchone( "select discount from source where rowid=?", (None, ), (guid, ))[0] if self.is_lesson: self.mins = (Settings.get("min_lesson_wpm"), Settings.get("min_lesson_acc")) else: self.mins = (Settings.get("min_wpm"), Settings.get("min_acc"))
def getStats(self): if self.when[0] == -1: t = self.times[1:] t.sort(reverse=True) v = DB.fetchone('select time from statistic where type = 0 and data = ? order by rowid desc limit 1', (t[len(t)//5], ), (self.target[0], )) self.times[0] = v[0] self.when[0] = self.when[1] - self.times[0] return self.when[self.where]-self.when[0], self.where, self.times, self.mistake, self.getMistakes()
def double_clicked(self, treeview, where, _column): row = Gtk.TreeModelRow(treeview.get_model(), where) target = DB.fetchone("select id,source,text from text where id = ?", None, (row[0], )) if target is None: return self.emit("set-text", *target) self.emit("go-to-text")
def new_review(self, review): added = self.add_texts("<Reviews>", [review], lesson=2, update=False) if added: tgt = DB.fetchone("select id,source,text from text where id = ?", self.default_text, added) self.emit("set-text", *tgt) else: self.next_text()
def updateResultLabel(self): spc = self.typer.getSpeed() accuracy = self.typer.getAccuracy() v2 = DB.fetchone("""select agg_median(wpm), agg_median(acc) from (select wpm, 100.0*accuracy as acc from result order by w desc limit %d)""" % Settings.get('def_group_by'), (0.0, 100.0)) if Settings.get('show_since_fail_counter'): self.result.setText("Last: %.1fwpm (%.1f%%), last 10 average: %.1fwpm (%.1f%%) \n\nPerfect Count: (Current :%1d) (Max : %1d) (Last : %1d)" % ((spc, 100.0*accuracy) + v2 + ( self.typer.count, self.typer.max_count, self.typer.last_count))) else: self.result.setText("Last: %.1fwpm (%.1f%%), last 10 average: %.1fwpm (%.1f%%)" % ((spc, 100.0*accuracy) + v2 ))
def getStats(self): if self.when[0] == -1: # my refactoring mean this may never get hit, I'm not sure what when and times are for, so i'm not sure if I'm breaking some edge case here?? t = self.times[1:] t.sort(reverse=True) v = DB.fetchone('select time from statistic where type = 0 and data = ? order by rowid desc limit 1', (t[len(t)//5], ), (self.target[0], )) self.times[0] = v[0] self.when[0] = self.when[1] - self.times[0] return self.getElapsed(), self.where, self.times, self.mistake, self.getMistakes()
def doubleClicked(self, idx): r = self.model.rows[idx.row()] v = DB.fetchone('select id,source,text from text where id = ?', None, (r[0], )) if v == None: return # silently ignore self.emit(SIGNAL("setText"), v) self.emit(SIGNAL("gotoText"))
def get_stats(self): if self.when[0] == -1: times = sorted(self.times[1:], reverse=True) self.times[0] = DB.fetchone( "select time from statistic where type=0 and data=? order by rowid desc limit 1", (times[len(times) // 5], ), (self.target[0], ))[0] self.when[0] = self.when[1] - self.times[0] return (self.when[self.where] - self.when[0], self.where, self.times, self.mistake, self.get_mistakes())
def update(self): texts = DB.fetchone("select count(*) from text", (0,))[0] self.progressbar.set_fraction(1/4) results = DB.fetchone("select count(*) from result", (0,))[0] self.progressbar.set_fraction(2/4) keys, trigrams, words = DB.fetchall( "select count(*),sum(count) from statistic group by type order by type") self.progressbar.set_fraction(3/4) first = DB.fetchone("select w from result order by w asc limit 1", (time.time(), ))[0] self.progressbar.set_fraction(4/4) total = keys[0] + trigrams[0] + words[0] history = (time.time() - first) / 86400 self.stats.set_text(f""" Texts: {texts} Results: {results} Analysis data: {total} ({keys[0]} keys, {trigrams[0]} trigrams, {words[0]} words) {keys[1]} characters and {words[1]} words typed in total. First result was {round(history, 2)} days ago. """) self.progressbar.set_fraction(0)
def getStats(self): #TODO: redo when, times to avoid guessing time taken to hit zeroth char from old stat if self.when[0] == -1: t = self.times[1:] t.sort(reverse=True) v = DB.fetchone('select time from statistic where type = 0 and data = ? order by rowid desc limit 1', (t[len(t)//5], ), (self.target[0], )) self.when[0] = self.when[1] - v[0] if not self.when[-1]: self.when[-1] = timer() self.when = list(linearly_interpolate(self.when)) for i in range(len(self.times)): #prevent division by zero when 0 time time = self.when[i+1] - self.when[i] self.times[i] = MINIMUM_CHAR_TYPING_TIME if time == 0 else time return self.when[-1]-self.when[0], len(self.target), self.times, self.mistake, self.getMistakes()
def getStats(self): #TODO: redo when, times to avoid guessing time taken to hit zeroth char from old stat if self.when[0] == -1: t = self.times[1:] t.sort(reverse=True) v = DB.fetchone( 'select time from statistic where type = 0 and data = ? order by rowid desc limit 1', (t[len(t) // 5], ), (self.target[0], )) self.when[0] = self.when[1] - v[0] if not self.when[-1]: self.when[-1] = timer() self.when = list(linearly_interpolate(self.when)) for i in range(len(self.times)): #prevent division by zero when 0 time time = self.when[i + 1] - self.when[i] self.times[i] = MINIMUM_CHAR_TYPING_TIME if time == 0 else time return self.when[-1] - self.when[0], len( self.target), self.times, self.mistake, self.getMistakes()
def setTarget(self, text, guid): self.editflag = True self.target = text self.when = [0] * (len(self.target)+1) # time for each character typed self.times = [0] * len(self.target) # whether each character was a mistake self.mistake = [False] * len(self.target) # mistake characters ( must be what was actually typed ) self.mistakes = {} #collections.defaultdict(lambda: []) self.where = 0 self.clear() self.setPalette(self.palettes['inactive']) self.setText(self.getWaitText()) self.selectAll() self.editflag = False self.is_lesson = DB.fetchone("select discount from source where rowid=?", (None, ), (guid, ))[0] if self.is_lesson: self.mins = (Settings.get("min_lesson_wpm"), Settings.get("min_lesson_acc")) else: self.mins = (Settings.get("min_wpm"), Settings.get("min_acc"))
def done(self): print("DONE") # TODO split into smaller bits now = timer() elapsed, chars, times, mis, mistakes = self.typer.get_stats() text = self.text[2] assert chars == len(text) accuracy = 1.0 - sum(1 for f in mis if f) / chars spc = elapsed / chars viscosity = sum((t / spc - 1)**2 for t in times) / chars DB.execute( """insert into result (w, text_id, source, wpm, accuracy, viscosity) values (?,?,?,?,?,?)""", (now, self.text[0], self.text[1], 12.0 / spc, accuracy, viscosity)) wpm_median, acc_median = DB.fetchone( f"""select agg_median(wpm),agg_median(acc) from (select wpm,100.0*accuracy as acc from result order by w desc limit {Settings.get("def_group_by")})""", (0.0, 100.0)) self.result.set_text( "Last: {:.1f}wpm ({:.1f}%), last 10 average: {:.1f}wpm ({:.1f}%)". format(12.0 / spc, 100.0 * accuracy, wpm_median, acc_median)) self.emit("stats-changed") stats = collections.defaultdict(Statistic) viscs = collections.defaultdict(Statistic) for char, time, mistake in zip(text, times, mis): stats[char].append(time, mistake) viscs[char].append((time / spc - 1)**2) def gen_tup(start, end): span = end - start char_avg = sum(times[start:end]) / span visc = sum((t / char_avg - 1)**2 for t in times[start:end]) / span return (text[start:end], char_avg, sum(1 for f in mis[start:end] if f), visc) for trigraph, time, mist, visc in [ gen_tup(i, i + 3) for i in range(0, chars - 2) ]: stats[trigraph].append(time, mist > 0) viscs[trigraph].append(visc) regex = re.compile(r"(\w|'(?![A-Z]))+(-\w(\w|')*)*") for word, time, mist, visc in [ gen_tup(*m.span()) for m in regex.finditer(text) if m.end() - m.start() > 3 ]: stats[word].append(time, mist > 0) viscs[word].append(visc) def kind(key): if len(key) == 1: return 0 if len(key) == 3: return 1 return 2 vals = [] for key, stat in stats.items(): visc = viscs[key].median() vals.append((stat.median(), visc * 100.0, now, len(stat), stat.flawed(), kind(key), key)) is_lesson = DB.fetchone("select discount from source where rowid=?", (None, ), (self.text[1], ))[0] if Settings.get("use_lesson_stats") or not is_lesson: DB.executemany( """insert into statistic (time,viscosity,w,count,mistakes,type,data) values (?,?,?,?,?,?,?)""", vals) DB.executemany( "insert into mistake (w,target,mistake,count) values (?,?,?,?)", [(now, k[0], k[1], v) for k, v in mistakes.items()]) if is_lesson: mins = (Settings.get("min_lesson_wpm"), Settings.get("min_lesson_acc")) else: mins = (Settings.get("min_wpm"), Settings.get("min_acc")) if 12.0 / spc < mins[0] or accuracy < mins[1] / 100.0: self.set_target(self.text) elif not is_lesson and Settings.get('auto_review'): words = [x for x in vals if x[5] == 2] if not words: self.emit("want-text") return words.sort(key=lambda x: (x[4], x[0]), reverse=True) i = 0 while words[i][4] != 0: i += 1 i += (len(words) - i) // 4 # TODO support want-review # self.emit("want-review", [x[6] for x in words[0:i]]) else: self.emit("want-text")
def done(self): now = time.time() elapsed, chars, times, mis, mistakes = self.typer.getStats() assert chars == len(self.text[2]) accuracy = 1.0 - len(filter(None, mis)) / chars spc = elapsed / chars viscosity = sum(map(lambda x: ((x-spc)/spc)**2, times)) / chars DB.execute('insert into result (w,text_id,source,wpm,accuracy,viscosity) values (?,?,?,?,?,?)', (now, self.text[0], self.text[1], 12.0/spc, accuracy, viscosity)) v2 = DB.fetchone("""select agg_median(wpm),agg_median(acc) from (select wpm,100.0*accuracy as acc from result order by w desc limit %d)""" % Settings.get('def_group_by'), (0.0, 100.0)) self.result.setText("Last: %.1fwpm (%.1f%%), last 10 average: %.1fwpm (%.1f%%)" % ((12.0/spc, 100.0*accuracy) + v2)) self.emit(SIGNAL("statsChanged")) stats = collections.defaultdict(Statistic) visc = collections.defaultdict(Statistic) text = self.text[2] for c, t, m in zip(text, times, mis): stats[c].append(t, m) visc[c].append(((t-spc)/spc)**2) def gen_tup(s, e): perch = sum(times[s:e])/(e-s) visc = sum(map(lambda x: ((x-perch)/perch)**2, times[s:e]))/(e-s) return (text[s:e], perch, len(filter(None, mis[s:e])), visc) for tri, t, m, v in [gen_tup(i, i+3) for i in xrange(0, chars-2)]: stats[tri].append(t, m > 0) visc[tri].append(v) regex = re.compile(r"(\w|'(?![A-Z]))+(-\w(\w|')*)*") for w, t, m, v in [gen_tup(*x.span()) for x in regex.finditer(text) if x.end()-x.start() > 3]: stats[w].append(t, m > 0) visc[w].append(v) def type(k): if len(k) == 1: return 0 elif len(k) == 3: return 1 return 2 vals = [] for k, s in stats.iteritems(): v = visc[k].median() vals.append( (s.median(), v*100.0, now, len(s), s.flawed(), type(k), k) ) is_lesson = DB.fetchone("select discount from source where rowid=?", (None,), (self.text[1], ))[0] if Settings.get('use_lesson_stats') or not is_lesson: DB.executemany_('''insert into statistic (time,viscosity,w,count,mistakes,type,data) values (?,?,?,?,?,?,?)''', vals) DB.executemany_('insert into mistake (w,target,mistake,count) values (?,?,?,?)', [(now, k[0], k[1], v) for k, v in mistakes.iteritems()]) if is_lesson: mins = (Settings.get("min_lesson_wpm"), Settings.get("min_lesson_acc")) else: mins = (Settings.get("min_wpm"), Settings.get("min_acc")) if 12.0/spc < mins[0] or accuracy < mins[1]/100.0: self.setText(self.text) elif not is_lesson and Settings.get('auto_review'): ws = filter(lambda x: x[5] == 2, vals) if len(ws) == 0: self.emit(SIGNAL("wantText")) return ws.sort(key=lambda x: (x[4],x[0]), reverse=True) i = 0 while ws[i][4] != 0: i += 1 i += (len(ws) - i) // 4 self.emit(SIGNAL("wantReview"), map(lambda x:x[6], ws[0:i])) else: self.emit(SIGNAL("wantText"))
def isLesson(self): is_lesson = DB.fetchone("select discount from source where rowid=?", (None, ), (self.text[1], ))[0] return is_lesson
def done(self): now = time.time() elapsed, chars, times, mis, mistakes = self.typer.getStats() assert chars == len(self.text[2]) accuracy = 1.0 - len(filter(None, mis)) / chars spc = elapsed / chars viscosity = sum(map(lambda x: ((x - spc) / spc)**2, times)) / chars DB.execute( 'insert into result (w,text_id,source,wpm,accuracy,viscosity) values (?,?,?,?,?,?)', (now, self.text[0], self.text[1], 12.0 / spc, accuracy, viscosity)) v2 = DB.fetchone( """select agg_median(wpm),agg_median(acc) from (select wpm,100.0*accuracy as acc from result order by w desc limit %d)""" % Settings.get('def_group_by'), (0.0, 100.0)) self.result.setText( "Last: %.1fwpm (%.1f%%), last 10 average: %.1fwpm (%.1f%%)" % ((12.0 / spc, 100.0 * accuracy) + v2)) self.emit(SIGNAL("statsChanged")) stats = collections.defaultdict(Statistic) visc = collections.defaultdict(Statistic) text = self.text[2] for c, t, m in zip(text, times, mis): stats[c].append(t, m) visc[c].append(((t - spc) / spc)**2) def gen_tup(s, e): perch = sum(times[s:e]) / (e - s) visc = sum(map(lambda x: ((x - perch) / perch)**2, times[s:e])) / (e - s) return (text[s:e], perch, len(filter(None, mis[s:e])), visc) for tri, t, m, v in [gen_tup(i, i + 3) for i in xrange(0, chars - 2)]: stats[tri].append(t, m > 0) visc[tri].append(v) regex = re.compile(r"(\w|'(?![A-Z]))+(-\w(\w|')*)*") for w, t, m, v in [ gen_tup(*x.span()) for x in regex.finditer(text) if x.end() - x.start() > 3 ]: stats[w].append(t, m > 0) visc[w].append(v) def type(k): if len(k) == 1: return 0 elif len(k) == 3: return 1 return 2 vals = [] for k, s in stats.iteritems(): v = visc[k].median() vals.append( (s.median(), v * 100.0, now, len(s), s.flawed(), type(k), k)) is_lesson = DB.fetchone("select discount from source where rowid=?", (None, ), (self.text[1], ))[0] if Settings.get('use_lesson_stats') or not is_lesson: DB.executemany_( '''insert into statistic (time,viscosity,w,count,mistakes,type,data) values (?,?,?,?,?,?,?)''', vals) DB.executemany_( 'insert into mistake (w,target,mistake,count) values (?,?,?,?)', [(now, k[0], k[1], v) for k, v in mistakes.iteritems()]) if is_lesson: mins = (Settings.get("min_lesson_wpm"), Settings.get("min_lesson_acc")) else: mins = (Settings.get("min_wpm"), Settings.get("min_acc")) if 12.0 / spc < mins[0] or accuracy < mins[1] / 100.0: self.setText(self.text) elif not is_lesson and Settings.get('auto_review'): ws = filter(lambda x: x[5] == 2, vals) if len(ws) == 0: self.emit(SIGNAL("wantText")) return ws.sort(key=lambda x: (x[4], x[0]), reverse=True) i = 0 while ws[i][4] != 0: i += 1 i += (len(ws) - i) // 4 self.emit(SIGNAL("wantReview"), map(lambda x: x[6], ws[0:i])) else: self.emit(SIGNAL("wantText"))