{ "cells": [ { "cell_type": "markdown", "id": "virtual-accreditation", "metadata": {}, "source": [ "![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n", "
\n", "

Komputerowe wspomaganie tłumaczenia

\n", "

12. Key logging [laboratoria]

\n", "

Rafał Jaworski (2021)

\n", "
\n", "\n", "![Logo 2](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech2.jpg)" ] }, { "cell_type": "markdown", "id": "featured-afghanistan", "metadata": {}, "source": [ "Badania nad komputerowym wspomaganiem tłumaczenia często prowadzone są przy użyciu metodologii testowania interfejsów użytkownika - UI/UX testing. Program typu CAT traktuje się wówczas jak każdy inny program komputerowy i przeprowadza testy wydajności i użyteczności." ] }, { "cell_type": "markdown", "id": "severe-protein", "metadata": {}, "source": [ "Testy takie prowadzone są zawsze na użytkownikach końcowych, w tym przypadku - na tłumaczach. Podstawowym celem testów jest próba zaobserwowania faktycznego sposobu pracy tłumacza - które funkcje programu są przez niego wykorzystywane najczęściej, jakich innych narzędzi poza CAT-em używa on do swojej pracy, które funkcje programu działają zgodnie, a które niezgodnie z intuicją użytkownika oraz wiele innych czynników. Aby wszystkie te analizy były możliwe, konieczne jest zgromadzenie jak największej ilości danych dotyczących przebiegu testu." ] }, { "cell_type": "markdown", "id": "constant-underground", "metadata": {}, "source": [ "Testy są przede wszystkim nagrywane. Nagrywany jest zarówno ekran komputera (screen capture), jak i sam użytkownik pracujący przy komputerze. To jednak nie wszystko - często stosuje się specjalne techniki eye-trackingu, które są w stanie określić, w który punk ekranu użytkownik aktualnie patrzy. Dane pozyskane w ten sposób używane są do analizy czasu znalezienia przez użytkownika potrzebnej mu funkcji oraz zidentyfikowania miejsc, gdzie tej funkcji poszukiwał. Można również wyznaczyć obszary ekranu, które często skupiają uwagę użytkownika. " ] }, { "cell_type": "markdown", "id": "analyzed-lodging", "metadata": {}, "source": [ "Dodatkowo stosuje się jeszcze jedną technikę, która jest szczególnie przydatna z punktu widzenia analizy procesu tłumaczenia. Wykonuje się pełny key logging, tj. zapisuje się każde uderzenie użytkownika w dowolny klawisz na klawiaturze wraz z precyzyjnym czasem tego uderzenia. Dane pozyskane w ten sposób pozwalają na przeprowadzenie szeregu interesujących analiz." ] }, { "cell_type": "markdown", "id": "incredible-stress", "metadata": {}, "source": [ "Zapoznajmy się najpierw z programem typu key logger:" ] }, { "cell_type": "markdown", "id": "arctic-horror", "metadata": {}, "source": [ "`sudo pip3 install keyboard`" ] }, { "cell_type": "code", "execution_count": null, "id": "broken-workstation", "metadata": {}, "outputs": [], "source": [ "import keyboard\n", "\n", "\n", "def report_key(event):\n", " print(event)\n", "\n", "keyboard.on_release(callback=report_key)\n", "keyboard.wait()" ] }, { "cell_type": "markdown", "id": "polish-census", "metadata": {}, "source": [ "UWAGA! Aby uruchomić powyższy kod na Linuxie konieczne są uprawnienia administratora (pytanie poza konkursem - dlaczego?)" ] }, { "cell_type": "markdown", "id": "incoming-hands", "metadata": {}, "source": [ "### Ćwiczenie 1: Wykorzystując powyższy kod napisz keylogger, który zapisuje wszystkie uderzenia w klawisze do pliku. Format pliku jest dowolny, każdy wpis musi zawierać precyzyjną godzinę uderzenia oraz uderzony klawisz. Uruchom program i przepisz paragraf dowolnie wybranego tekstu." ] }, { "cell_type": "code", "execution_count": null, "id": "8663ef15-88a0-4bb5-aff9-f19cbb3178c1", "metadata": {}, "outputs": [], "source": [ "import keyboard\n", "\n", "\n", "def report_key(event: keyboard.KeyboardEvent):\n", " file = open('test.txt', 'a')\n", " file.write(f'[{event.time}] {event.name}\\n')\n", " file.close()\n", "\n", "\n", "keyboard.on_release(callback=report_key)\n", "keyboard.wait()" ] }, { "cell_type": "markdown", "id": "valuable-bearing", "metadata": {}, "source": [ "Celem powyższego ćwiczenia jest pozyskanie danych testowych. Dalsze analizy będziemy prowadzili już bez key loggera, starając się korzystać jedynie z danych zapisanych w pliku. Oczywiście, jeśli zajdzie taka konieczność, można w każdej chwili wygenerować sobie nowy plik." ] }, { "cell_type": "markdown", "id": "boxed-maple", "metadata": {}, "source": [ "### Ćwiczenie 2: Napisz program, który wyliczy średnią prędkość pisania. Wykryj, kiedy użytkownik zaczął pisać. Nie bierz pod uwagę przerw dłuższych niż 5 sekund. Podaj prędkość pisania w znakach na minutę oraz słowach na minutę." ] }, { "cell_type": "code", "execution_count": 1, "id": "possible-holder", "metadata": {}, "outputs": [], "source": [ "def calculate_typing_speed():\n", " import re\n", " import numpy\n", "\n", " def parse(line_l: str) -> (float, str):\n", " res = re.findall(r'(\\d+.\\d+)|([a-zA-Z,.]+)', ''.join(line_l.split()))\n", " return float(res[0][0]), res[1][1]\n", "\n", " file = open('test.txt', 'r')\n", " time_per_word = []\n", " time_per_character = []\n", " local_time_per_word = []\n", "\n", " prev_char_timestamp = None\n", " for line in file:\n", " time, key = parse(line)\n", " if prev_char_timestamp is None or time - prev_char_timestamp > 5:\n", " prev_char_timestamp = time\n", " local_time_per_word = []\n", " continue\n", " elapsed = time - prev_char_timestamp\n", " time_per_character.append(elapsed)\n", " if key == 'space' or key == 'enter' or key == ',' or key == '.':\n", " if len(local_time_per_word) > 0:\n", " time_per_word.append(numpy.sum(local_time_per_word))\n", " local_time_per_word = []\n", " time_per_character.append(elapsed)\n", " prev_char_timestamp = time\n", " continue\n", " local_time_per_word.append(elapsed)\n", " prev_char_timestamp = time\n", " file.close()\n", " time_per_word.append(numpy.sum(local_time_per_word))\n", " \n", " return 60 / numpy.average(time_per_character), 60 / numpy.average(time_per_word)" ] }, { "cell_type": "markdown", "id": "ceramic-birth", "metadata": {}, "source": [ "Wróćmy teraz do procesu tłumaczenia. Analiza uderzeń klawiszy wykonanych podczas tłumaczenia pozwala wykryć dłuższe pauzy. Pauzy te najczęściej wskazują miejsca, w których tłumacz musi się głębiej zastanowić nad tłumaczeniem danego słowa lub frazy. Przerwę tę wykorzystuje na przykład na sprawdzenie tłumaczenia lub definicji w słowniku, przeglądanie wyników z pamięci tłumaczeń lub korzystanie z innych pomocy (eye-tracking mógłby w tym przypadku rozstrzygnąć, czym w istocie zajmuje się w tym momencie tłuamcz). Jest też możliwe, że tłumacz poświęca pauzę na tzw. cognitive pause-and-unload - rodzaj zamyślenia, pozwalający oczyścić myśli. Z punktu widzenia projektowania systemu wspomagającego tłumaczenie niezwykle istotna jest informacja, nad czym tłumacz musi się dłużej zastanowić. Minimalizacja liczby i czasu trwania takich przerw jest szansą na usprawnienie procesu tłumaczenia." ] }, { "cell_type": "markdown", "id": "great-cable", "metadata": {}, "source": [ "### Ćwiczenie 3: Napisz program do wykrywania przerw w pisaniu. Raportuj długość oraz miejsce wystąpienia przerwy podając 20-znakowy kontekst z każdej strony. Wykryj każdą przerwę dłuższą niż 3 sekundy, posortuj wyniki malejąco po długości przerwy." ] }, { "cell_type": "code", "execution_count": 2, "id": "close-riverside", "metadata": {}, "outputs": [], "source": [ "def find_pauses():\n", " import re\n", "\n", " def parse(line_l: str) -> (float, str):\n", " res = re.findall(r'(\\d+.\\d+)|([a-zA-Z,.]+)', ''.join(line_l.split()))\n", " return float(res[0][0]), res[1][1]\n", "\n", " file = open('test.txt', 'r')\n", " stops = []\n", " stop_reporting_time = 1\n", "\n", " prev_char_timestamp = None\n", " lines = file.readlines()\n", " file.close()\n", " for i in range(len(lines)):\n", " time, key = parse(lines[i])\n", " if prev_char_timestamp is None:\n", " prev_char_timestamp = time\n", " continue\n", " elapsed = time - prev_char_timestamp\n", " if elapsed > stop_reporting_time:\n", " context_start = max(0, i - 20)\n", " context_end = min(len(lines), i + 20)\n", " context_before = ''\n", " context_after = ''\n", " for j in range(context_start, i):\n", " time_l, key_l = parse(lines[j])\n", " context_before += key_l\n", " for j in range(i, context_end):\n", " time_l, key_l = parse(lines[j])\n", " context_after += key_l\n", " stops.append((elapsed, (context_before, context_after)))\n", " prev_char_timestamp = time\n", "\n", " def stop_sort(record: tuple):\n", " return record[0]\n", "\n", " stops.sort(reverse=True, key=stop_sort)\n", " \n", " return stops" ] } ], "metadata": { "author": "Rafał Jaworski", "email": "rjawor@amu.edu.pl", "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "lang": "pl", "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.4" }, "subtitle": "12. Key logging", "title": "Komputerowe wspomaganie tłumaczenia", "year": "2021" }, "nbformat": 4, "nbformat_minor": 5 }