diff --git a/Makefile b/Makefile index 3cf9fd9..90af875 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,8 @@ ensure_env: -@python3 -m venv .venv plot: ensure_env - $(PYTHON) plot.py + time $(PYTHON) plot.py + time $(PYTHON) merge.py graph: graph.c gcc -o graph graph.c -I/usr/include/SDL2 -L/usr/lib -lSDL2 @@ -22,3 +23,9 @@ graph2: graph2.c gcc -o graph2 graph2.c -I/usr/include/SDL2 -L/usr/lib -lSDL2 ./graph2 +index: + $(PYTHON) tags.py --index + +popular: + $(PYTHON) tags.py --popular + diff --git a/merge.py b/merge.py new file mode 100644 index 0000000..d814750 --- /dev/null +++ b/merge.py @@ -0,0 +1,39 @@ +import pathlib + + +all_content = [] + +for file in pathlib.Path("logs_summaries").glob("*.txt"): + with open(file, "r") as f: + all_content.append(f.read()) + +with open("logs_summaries/merged.txt", "w") as f: + f.write("\n\n".join(all_content)) + +html_content = ['', +""" + +""", +'
'] + + +graph_images = list(pathlib.Path(".").glob("*.png")) +graph_images.sort(key=lambda graph: graph.name) + +for graph_image in graph_images: + html_content.append(f'') +html_content.append("") + +with open("graphs.html", "w") as f: + f.write("\n".join(html_content)) + +print("graphs.html generated!") diff --git a/plot.py b/plot.py index 1e9f563..e2bb41e 100644 --- a/plot.py +++ b/plot.py @@ -150,7 +150,7 @@ def get_score_per_week(): def get_score_per_day(): - sql ="SELECT count(0) as total, CASE WHEN strftime('%w', timestamp) = 0 THEN 'Sunday' WHEN strftime('%w', timestamp) = 1 THEN 'Monday' WHEN strftime('%w', timestamp) = 2 THEN 'Tuesday' WHEN strftime('%w', timestamp) = 3 THEN 'Wednesday' WHEN strftime('%w', timestamp) = 4 THEN 'Thursday' WHEN strftime('%w', timestamp) = 5 THEN 'Friday' WHEN strftime('%w', timestamp) = 6 THEN 'Saturday' END as weekday, strftime('%w', timestamp) as day, strftime('%U', timestamp) as week FROM kevent WHERE event = 'REPEATED' AND week = '50' GROUP BY week, day ORDER BY day" + sql ="SELECT count(0) as total, CASE WHEN strftime('%w', timestamp) = 0 THEN 'Sunday' WHEN strftime('%w', timestamp) = 1 THEN 'Monday' WHEN strftime('%w', timestamp) = 2 THEN 'Tuesday' WHEN strftime('%w', timestamp) = 3 THEN 'Wednesday' WHEN strftime('%w', timestamp) = 4 THEN 'Thursday' WHEN strftime('%w', timestamp) = 5 THEN 'Friday' WHEN strftime('%w', timestamp) = 6 THEN 'Saturday' END as weekday, strftime('%w', timestamp) as day, strftime('%U', timestamp) as week FROM kevent WHERE event = 'REPEATED' GROUP BY week, day ORDER BY day" sql = ( f"SELECT strftime('%U',timestamp) as week, {weekday_sql} as wday, event, COUNT(0) as total " @@ -215,5 +215,15 @@ if __name__ == "__main__": print("Done") f.write(response) print(response) - + for file in pathlib.Path(".").glob("logs_summaries/*.txt"): + dest_file = file.parent.parent.joinpath("logs_lines").joinpath(file.name) + if dest_file.exists(): + print("One liner already exists for" + file.name) + continue + with dest_file.open("w+") as f: + source = file.read_text().replace("@","").replace("`","") + response = api.gpt4o_mini("The following data is a hour of work summarized from the user. Describe what user was doing in a onliner.: "+source) + f.write(response) + print("Made one liner for" + file.name) + print("Duration: {}".format(time.time() - time_start)) diff --git a/tags.py b/tags.py new file mode 100644 index 0000000..8c54350 --- /dev/null +++ b/tags.py @@ -0,0 +1,167 @@ +# Written by retoor@molodetz.nl + +# This script processes text files to identify words, their positions, and their frequency of occurrence. It uses command-line arguments to query or display popular words and stores results in a SQLite database. + +# Imports: +# - argparse: For handling command-line arguments +# - sqlite3: A library to control and manage SQLite databases +# - pathlib: To work with filesystem paths in an object-oriented way + +# MIT License: +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + + +import argparse +import sqlite3 +import pathlib + +parser = argparse.ArgumentParser() +parser.add_argument('--find', type=str, required=False, default="") +parser.add_argument('--index', action='store_true') +parser.add_argument('--popular', action='store_true') + +args = parser.parse_args() + +def is_valid_char(c): + return c.isalnum() or c == '_' + +def process_file(file_path): + word = [] + word_start = -1 + word_end = 0 + word_line = 0 + word_alinia = 0 + word_length = 0 + new_line_count = 0 + pos = 0 + line = 1 + alinia = 1 + words = {} + with open(file_path, 'r') as f: + while c := f.read(1): + + pos += 1 + valid = True + + if c == '.': + line += 1 + valid = False + + if c == '\n': + new_line_count += 1 + valid = False + + if not is_valid_char(c): + valid = False + + if not valid: + if word_start > -1: + word_end = pos - 1 + word_length = word_end - word_start + word_str = ''.join(word) + print(f"{word_str} {word_start} {word_end} {word_length} {word_line} {word_alinia} {alinia}") + if word_str not in words: + words[word_str] = 0 + words[word_str] += 1 + + word_start = -1 + word = [] + continue + + if new_line_count >= 2: + new_line_count = 0 + alinia += 1 + + word.append(c) + + if word_start == -1: + word_start = pos + word_line = line + word_alinia = alinia + return words + +class WordDb: + def __init__(self, path): + self.path = path + self.conn = sqlite3.connect(path) + self.cursor = self.conn.cursor() + self.conn.commit() + self.words = {} + + def reset(self): + self.words = {} + self.cursor.execute("DROP TABLE IF EXISTS words") + self.cursor.execute(""" + CREATE TABLE words ( + word TEXT NOT NULL, + count INTEGER NOT NULL + ) + """) + self.conn.commit() + + def insert(self, word, count): + if word not in self.words: + self.words[word] = count + self.cursor.execute("INSERT INTO words (word, count) VALUES (?, ?)", (word, count)) + else: + self.words[word] += count + self.cursor.execute("UPDATE words SET count = ? WHERE word = ?", (self.words[word], word)) + + def commit(self): + self.conn.commit() + + def total_count(self): + self.cursor.execute("SELECT SUM(count) FROM words") + return self.cursor.fetchone()[0] + + def get(self, word): + self.cursor.execute("SELECT count FROM words WHERE word = ?", (word,)) + return self.cursor.fetchone()[0] + + def most_popular(self, count): + self.cursor.execute("SELECT word, count FROM words ORDER BY count DESC LIMIT ?", (count,)) + return list(self.cursor.fetchall()) + + def __del__(self): + self.commit() + self.conn.close() + print("Database closed") + +db = WordDb("tags.db") + +def index(): + words = {} + for f in pathlib.Path("logs_plain").iterdir(): + for key, value in process_file(f).items(): + db.insert(key, value) + + from pprint import pprint as pp + pp(db.most_popular(100)) + db.commit() + print(len(words.keys())) + +if args.find: + print(db.get(args.find)) + +if args.popular: + for item in db.most_popular(300): + print(item) + print(db.total_count()) + +if args.index: + db.reset() + index() diff --git a/tikker b/tikker index bed9ef1..74621b0 100755 Binary files a/tikker and b/tikker differ diff --git a/tikker.c b/tikker.c index aa885ba..882cd19 100644 --- a/tikker.c +++ b/tikker.c @@ -70,13 +70,45 @@ char *resolve_device_name(int fd) { return device_name; } +char * sormgetc(char *result,int index){ + char * end = NULL; + int current_index = 0; + while((end = strstr((char *)result, ";")) != NULL){ + if(index == current_index){ + result[end - (char *)result] = 0; + return result; + } + result = end + 1; + current_index++; + } + *end = 0; + return result; +} + int main(int argc, char *argv[]) { char *device_to_read = rargs_get_option_string(argc, argv, "--device", DEVICE_TO_READ_DEFAULT); + //printf("%s\n", device_to_read); + int db = sormc(DATABASE_NAME); ulonglong times_repeated = 0; ulonglong times_pressed = 0; ulonglong times_released = 0; sormq(db, "CREATE TABLE IF NOT EXISTS kevent (id INTEGER PRIMARY KEY AUTOINCREMENT, code,event,name,timestamp,char)"); + + if(argc > 1 && !strcmp(argv[1],"presses_today")){ + time_t now = time(NULL); + char time_string[32]; + strftime(time_string, sizeof(time_string), "%Y-%m-%d", localtime(&now)); + + sorm_ptr result = sormq(db, "SELECT COUNT(id) as total FROM kevent WHERE timestamp >= %s AND event = 'PRESSED'",time_string); + + printf("%s",sormgetc((char *)result,1)); + //fflush(stdout); + free(result); + exit(0); + } + + int keyboard_fds[MAX_DEVICES]; int num_keyboards = 0;