From 8685bbb2771e54e7571ae1accba63221dc44d735 Mon Sep 17 00:00:00 2001 From: s495724 Date: Sat, 25 May 2024 14:53:24 +0200 Subject: [PATCH] Upload files to "lab" --- lab/lab_11.ipynb | 269 +++++++++++++++++--- lab/lab_12.ipynb | 183 +++++++++++--- lab/lab_13-14.ipynb | 144 ++++++++--- lab/lab_15.ipynb | 582 ++++++++++++++++++++++++++++++-------------- 4 files changed, 900 insertions(+), 278 deletions(-) diff --git a/lab/lab_11.ipynb b/lab/lab_11.ipynb index 0a8ce14..8ac51ef 100644 --- a/lab/lab_11.ipynb +++ b/lab/lab_11.ipynb @@ -2,7 +2,6 @@ "cells": [ { "cell_type": "markdown", - "id": "expanded-entrance", "metadata": {}, "source": [ "# Komputerowe wspomaganie tłumaczenia" @@ -10,7 +9,6 @@ }, { "cell_type": "markdown", - "id": "atlantic-greenhouse", "metadata": {}, "source": [ "# Zajęcia 11 - urównoleglanie" @@ -18,7 +16,6 @@ }, { "cell_type": "markdown", - "id": "hungarian-davis", "metadata": {}, "source": [ "Na poprzednich zajęciach poznaliśmy techniki pozyskiwania tekstu z Internetu. Jeśli uda nam się w ten sposób pozyskać tekst w jednym języku oraz jego tłumaczenie na inny język, jesteśmy tylko o krok od uzyskania najbardziej przydatnego zasobu z punktu widzenia wspomagania tłumaczenia - pamięci tłumaczeń. Krokiem tym jest automatyczne urównoleglanie tekstu." @@ -26,7 +23,6 @@ }, { "cell_type": "markdown", - "id": "bronze-removal", "metadata": {}, "source": [ "Automatyczne urównoleglanie tekstu składa się z dwóch kroków:\n", @@ -36,7 +32,6 @@ }, { "cell_type": "markdown", - "id": "junior-works", "metadata": {}, "source": [ "Zdania, o których mowa w punkcie 1., powinniśmy rozumieć jako segmenty, tj. niekoniecznie kompletne zdania w sensie gramatycznym. Standardowym sposobem podziału tekstu na segmenty jest dzielenie po znaku nowej linii lub zaraz po kropce, o ile jest ona częścią sekwencji: \".[spacja][Wielka litera]\"" @@ -44,7 +39,6 @@ }, { "cell_type": "markdown", - "id": "legitimate-corrections", "metadata": {}, "source": [ "### Ćwiczenie 1: Zaimplementuj podstawowy algorytm segmentacji tekstu. Użyj odpowiedniego wyrażenia regularnego, łapiącego wielkie litery w dowolnym języku, np. \"Ż\" (użyj klasy unikodowej). Zwróć listę segmentów." @@ -52,18 +46,34 @@ }, { "cell_type": "code", - "execution_count": 1, - "id": "german-dispute", + "execution_count": 23, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['To ', 'Jest', 'Żywy.przykład', 'Żeby', 'Ładnie ', 'Zademonstrować', 'Segmentację']\n" + ] + } + ], "source": [ + "import regex\n", + "\n", "def sentence_split(text):\n", - " return []" + " pattern = r'(?=\\p{Lu})'\n", + " segments = regex.split(pattern, text)\n", + " \n", + " segments = [segment for segment in segments if segment]\n", + " return segments\n", + " \n", + "text = \"To JestŻywy.przykładŻebyŁadnie ZademonstrowaćSegmentację\"\n", + "segments = sentence_split(text)\n", + "print(segments)" ] }, { "cell_type": "markdown", - "id": "continued-assessment", "metadata": {}, "source": [ "### Ćwiczenie 2: Uruchom powyższy algorytm na treści wybranej przez siebie strony internetowej (do ściągnięcia treści strony wykorzystaj kod z laboratoriów nr 7). Zidentyfikuj co najmniej dwa wyjątki od ogólnej reguły podziału na segmenty i ulepsz algorytm." @@ -71,18 +81,147 @@ }, { "cell_type": "code", - "execution_count": 3, - "id": "guilty-morocco", + "execution_count": 19, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "-\n", + "Dużo mówi się o tym, że to pszczoły miodne zagrażają dzikim pszczołom.\n", + "Tak przewrotnie postawione pytanie zmusza do zastanowienia, czy negatywna interakcja w drugą stronę jest możliwa - mówi dr\n", + "Jacek\n", + "Wendzonka.\n", + "I dodaje: -\n", + "Niestety, odpowiedź pozostaje ciągle taka sama.\n", + "Pszczoły, i dzikie i miodne, ewoluowały i współwystępowały razem przez miliony lat.\n", + "Oczywiście konkurowały one o zasoby pokarmowe, co doprowadzało do tworzenia rozmaitych strategii oraz specjalizacji i było jedną z sił napędowych ewolucji.\n", + "Pszczoła miodna (\n", + "Apis mellifera) jako gatunek społeczny, magazynujący zapasy i potrafiący wielokrotnie zimować w gnieździe jako rodzina, jest na szczycie drabiny ewolucyjnej.\n", + "Daje to szereg korzyści takich jak lepsza obrona przed wrogami, korzystanie z zapasów w okresach niedostatków, regulacja temperatury gniazda itp.\n", + "Niestety (dla dalszych rozważań), rodzina taka licząca nawet 30 – 50 tys. osobników, ma duże zapotrzebowanie energetyczne i wymaga odpowiedniej ilości pokarmu.\n", + "Przekłada się to bezpośrednio na odpowiednią liczbę kwiatów i powierzchnię terenu.\n", + "W praktyce oznacza to, że w środowisku naturalnym gniazda takie nie mogą istnieć w dużym zagęszczeniu i muszą być rozproszone tak, aby uniknąć konkurencji między rodzinami.\n", + "Rozproszenie to nie wpływało negatywnie na kondycję gatunków samotnych.\n", + "Sytuacja zmieniła się wraz z pojawieniem się człowieka i wykorzystywaniem pszczół miodnych.\n", + "Na początku był to zwykły rabunek miodu, z czasem połączony z opieką polegającą na ochronie pszczół przed konkurencją np. niedźwiedziami.\n", + "Kolejnymi etapami było bartnictwo i pszczelarstwo współczesne, które to w przeciągu ostatniego stulecia doprowadziło do diametralnych przetasowań na pszczelej szachownicy zależności ekologicznych.\n", + "Przede wszystkim powstały pasieki, czyli doszło do dużego zagęszczenia rodzin pszczelich na danej jednostce powierzchni.\n", + "Współcześnie, za pasiekę opłacalną, średniej wielkości, uważa się taką, liczącą ok. 20 rodzin.\n", + "To tworzy bardzo duży lokalny nacisk ekologiczny, który bez pomocy pszczelarzy (okresowe dokarmianie cukrem, leczenie itp.) zagrażałby samym pszczołom miodnym.\n", + "A przecież na tej samej powierzchni żyją także liczne gatunki pszczół dzikich, w większości nieprzekraczających kilku milimetrów, a więc \"niewidocznych\" dla przeciętnego człowieka.\n", + "Przy takim zagęszczeniu pszczoły miodnej nie mają one szansy na uczciwą, ekologiczną rywalizację i ich liczebność spada, a nawet giną: bezgłośnie i niewidocznie – bezproblemowo!\n", + "Całą sytuację można by porównać do meczu piłkarskiego, gdzie po jednej stronie jest ekipa 11 kumpli z osiedla, a po drugiej drużyna z ekstraklasy z zapleczem finansowym, trenerskim, medycznym i ławką rezerwowych na 2 równorzędne drużyny.\n", + "Każdy od razu powie, że to nie pieniądze grają i że wszystko jest możliwe.\n", + "Faktycznie, raz na jakiś czas romantyczny heroizm jest górą.\n", + "Jednakże w przyrodzie, gdzie stawką jest życie nie tyle osobników, ale całych gatunków, na częstotliwości takich wyczynów nie można polegać.\n", + "Wynik rywalizacji jest przesądzony.\n", + "Jeżeli mamy poważnie podchodzić do ochrony dzikich zapylaczy, to uregulowanie kwestii kontroli zagęszczenia uli (napszczelenia) staje się zadaniem najważniejszym, także na poziomie legislacyjnym.\n", + "W świadomości społecznej pszczoła miodna jest uznawana za najważniejszego, wręcz jedynego zapylacza całkowicie wystarczającego do zapylania wszystkiego, co nie jest prawdą.\n", + "Najważniejsze, o czym musimy pamiętać, to to, że jest to tylko pojedynczy gatunek i nie jest nieśmiertelny.\n", + "Dalsze osłabianie poprzez hodowlę czy wybuch globalnej pandemii nowej nieznanej choroby (skąd to znamy?), może doprowadzić do wyginięcia gatunku.\n", + "I co wtedy?\n", + "Miodu nie będzie, to fakt, ale dzikie pszczoły poradzą sobie z zapylaniem.\n", + "Trzeba \"tylko\" dopilnować, żeby w dobrej kondycji dotrwały do tego momentu.\n", + "Zapylanie przez pszczoły jest procesem naturalnym, darmowym.\n", + "Człowiek jak za coś nie zapłaci, to nie zawsze potrafi to docenić czy uszanować.\n", + "Właśnie w tym aspekcie musi się dokonać największa zmiana w ludzkiej mentalności, czego wszystkim pszczołom w ich dniu życzę - dodaje naukowiec z\n", + "U\n", + "A\n", + "M.\n", + "Fot.\n", + "Adrian\n", + "Wykrota\n" + ] + } + ], + "source": [ + "import requests\n", + "from bs4 import BeautifulSoup\n", + "import regex\n", + "\n", + "url = 'https://amu.edu.pl/dla-mediow/komunikaty-prasowe/czy-dzikie-pszczoly-zagrazaja-pszczolom-miodnym'\n", + "\n", + "def sentence_split(text):\n", + " pattern = r'(?=\\p{Lu})'\n", + " segments = regex.split(pattern, text)\n", + " segments = [segment.strip() for segment in segments if segment.strip()]\n", + " return segments\n", + "\n", + "page = requests.get(url)\n", + "soup = BeautifulSoup(page.content, 'html.parser')\n", + "\n", + "article_content = soup.find('div', {'class': 'news__body'}).get_text()\n", + "\n", + "segments = sentence_split(article_content)\n", + "\n", + "for i, segment in enumerate(segments, 1):\n", + " print(segment)" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dużo mówi się o tym, że to pszczoły miodne zagrażają dzikim pszczołom.\n", + "Tak przewrotnie postawione pytanie zmusza do zastanowienia, czy negatywna interakcja w drugą stronę jest możliwa - mówi dr Jacek Wendzonka.\n", + "I dodaje: - Niestety, odpowiedź pozostaje ciągle taka sama.\n", + "Pszczoły, i dzikie i miodne, ewoluowały i współwystępowały razem przez miliony lat.\n", + "Oczywiście konkurowały one o zasoby pokarmowe, co doprowadzało do tworzenia rozmaitych strategii oraz specjalizacji i było jedną z sił napędowych ewolucji.\n", + "Pszczoła miodna (Apis mellifera) jako gatunek społeczny, magazynujący zapasy i potrafiący wielokrotnie zimować w gnieździe jako rodzina, jest na szczycie drabiny ewolucyjnej.\n", + "Daje to szereg korzyści takich jak lepsza obrona przed wrogami, korzystanie z zapasów w okresach niedostatków, regulacja temperatury gniazda itp.\n", + "Niestety (dla dalszych rozważań), rodzina taka licząca nawet 30 – 50 tys. osobników, ma duże zapotrzebowanie energetyczne i wymaga odpowiedniej ilości pokarmu.\n", + "Przekłada się to bezpośrednio na odpowiednią liczbę kwiatów i powierzchnię terenu.\n", + "W praktyce oznacza to, że w środowisku naturalnym gniazda takie nie mogą istnieć w dużym zagęszczeniu i muszą być rozproszone tak, aby uniknąć konkurencji między rodzinami.\n", + "Rozproszenie to nie wpływało negatywnie na kondycję gatunków samotnych.\n", + "Sytuacja zmieniła się wraz z pojawieniem się człowieka i wykorzystywaniem pszczół miodnych.\n", + "Na początku był to zwykły rabunek miodu, z czasem połączony z opieką polegającą na ochronie pszczół przed konkurencją np. niedźwiedziami.\n", + "Kolejnymi etapami było bartnictwo i pszczelarstwo współczesne, które to w przeciągu ostatniego stulecia doprowadziło do diametralnych przetasowań na pszczelej szachownicy zależności ekologicznych.\n", + "Przede wszystkim powstały pasieki, czyli doszło do dużego zagęszczenia rodzin pszczelich na danej jednostce powierzchni.\n", + "Współcześnie, za pasiekę opłacalną, średniej wielkości, uważa się taką, liczącą ok. 20 rodzin.\n", + "To tworzy bardzo duży lokalny nacisk ekologiczny, który bez pomocy pszczelarzy (okresowe dokarmianie cukrem, leczenie itp.) zagrażałby samym pszczołom miodnym.\n", + "A przecież na tej samej powierzchni żyją także liczne gatunki pszczół dzikich, w większości nieprzekraczających kilku milimetrów, a więc \"niewidocznych\" dla przeciętnego człowieka.\n", + "Przy takim zagęszczeniu pszczoły miodnej nie mają one szansy na uczciwą, ekologiczną rywalizację i ich liczebność spada, a nawet giną: bezgłośnie i niewidocznie – bezproblemowo! Całą sytuację można by porównać do meczu piłkarskiego, gdzie po jednej stronie jest ekipa 11 kumpli z osiedla, a po drugiej drużyna z ekstraklasy z zapleczem finansowym, trenerskim, medycznym i ławką rezerwowych na 2 równorzędne drużyny.\n", + "Każdy od razu powie, że to nie pieniądze grają i że wszystko jest możliwe.\n", + "Faktycznie, raz na jakiś czas romantyczny heroizm jest górą.\n", + "Jednakże w przyrodzie, gdzie stawką jest życie nie tyle osobników, ale całych gatunków, na częstotliwości takich wyczynów nie można polegać.\n", + "Wynik rywalizacji jest przesądzony.\n", + "Jeżeli mamy poważnie podchodzić do ochrony dzikich zapylaczy, to uregulowanie kwestii kontroli zagęszczenia uli (napszczelenia) staje się zadaniem najważniejszym, także na poziomie legislacyjnym.\n", + "W świadomości społecznej pszczoła miodna jest uznawana za najważniejszego, wręcz jedynego zapylacza całkowicie wystarczającego do zapylania wszystkiego, co nie jest prawdą.\n", + "Najważniejsze, o czym musimy pamiętać, to to, że jest to tylko pojedynczy gatunek i nie jest nieśmiertelny.\n", + "Dalsze osłabianie poprzez hodowlę czy wybuch globalnej pandemii nowej nieznanej choroby (skąd to znamy?), może doprowadzić do wyginięcia gatunku.\n", + "I co wtedy? Miodu nie będzie, to fakt, ale dzikie pszczoły poradzą sobie z zapylaniem.\n", + "Trzeba \"tylko\" dopilnować, żeby w dobrej kondycji dotrwały do tego momentu.\n", + "Zapylanie przez pszczoły jest procesem naturalnym, darmowym.\n", + "Człowiek jak za coś nie zapłaci, to nie zawsze potrafi to docenić czy uszanować.\n", + "Właśnie w tym aspekcie musi się dokonać największa zmiana w ludzkiej mentalności, czego wszystkim pszczołom w ich dniu życzę - dodaje naukowiec z UAM.\n", + "Fot.\n" + ] + } + ], "source": [ "def sentence_split_enhanced(text):\n", - " return []" + " pattern = r'(?\n", @@ -166,7 +334,6 @@ }, { "cell_type": "markdown", - "id": "falling-greenhouse", "metadata": {}, "source": [ "### Ćwiczenie 4: Napisz konwerter formatu hunaligna na XLIFF." @@ -174,28 +341,61 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "remarkable-pillow", + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ - "def convert2xliff(hunalign_file_name):\n", - " return 0" + "import xml.etree.ElementTree as ET\n", + "\n", + "def convert2xliff(hunalign_file, xliff_file):\n", + " xliff = ET.Element('xliff', {\n", + " 'version': '1.2',\n", + " 'xmlns': 'urn:oasis:names:tc:xliff:document:1.2'\n", + " })\n", + " \n", + " file_elem = ET.SubElement(xliff, 'file', {\n", + " 'source-language': 'pl',\n", + " 'target-language': 'cs',\n", + " 'datatype': 'plaintext',\n", + " 'original': hunalign_file\n", + " })\n", + " \n", + " body = ET.SubElement(file_elem, 'body')\n", + " \n", + " with open(hunalign_file, 'r', encoding='utf-8') as f:\n", + " lines = f.readlines()\n", + " \n", + " for i in range(0, len(lines), 2):\n", + " source_text = lines[i].strip()\n", + " target_text = lines[i + 1].strip()\n", + " \n", + " trans_unit = ET.SubElement(body, 'trans-unit', {\n", + " 'id': str(i // 2 + 1)\n", + " })\n", + " \n", + " source = ET.SubElement(trans_unit, 'source')\n", + " source.text = source_text\n", + " \n", + " target = ET.SubElement(trans_unit, 'target')\n", + " target.text = target_text\n", + " \n", + " tree = ET.ElementTree(xliff)\n", + " with open(xliff_file, 'wb') as f:\n", + " tree.write(f, encoding='utf-8', xml_declaration=True)\n", + "\n", + "convert2xliff('hunalign_format', 'xliff_format')" ] } ], "metadata": { "author": "Rafał Jaworski", "email": "rjawor@amu.edu.pl", - "lang": "pl", - "subtitle": "11. Urównoleglanie", - "title": "Komputerowe wspomaganie tłumaczenia", - "year": "2021", "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, + "lang": "pl", "language_info": { "codemirror_mode": { "name": "ipython", @@ -206,8 +406,11 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.10" - } + "version": "3.7.0" + }, + "subtitle": "11. Urównoleglanie", + "title": "Komputerowe wspomaganie tłumaczenia", + "year": "2021" }, "nbformat": 4, "nbformat_minor": 5 diff --git a/lab/lab_12.ipynb b/lab/lab_12.ipynb index c4dc223..883d20e 100644 --- a/lab/lab_12.ipynb +++ b/lab/lab_12.ipynb @@ -2,7 +2,6 @@ "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", @@ -17,7 +16,6 @@ }, { "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." @@ -25,7 +23,6 @@ }, { "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." @@ -33,7 +30,6 @@ }, { "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. " @@ -41,7 +37,6 @@ }, { "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." @@ -49,7 +44,6 @@ }, { "cell_type": "markdown", - "id": "incredible-stress", "metadata": {}, "source": [ "Zapoznajmy się najpierw z programem typu key logger:" @@ -57,7 +51,6 @@ }, { "cell_type": "markdown", - "id": "arctic-horror", "metadata": {}, "source": [ "`sudo pip3 install keyboard`" @@ -65,14 +58,30 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "broken-workstation", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Defaulting to user installation because normal site-packages is not writeable\n", + "Requirement already satisfied: keyboard in /home/michal/.local/lib/python3.10/site-packages (0.13.5)\n" + ] + } + ], + "source": [ + "!pip3 install keyboard" + ] + }, + { + "cell_type": "code", + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "import keyboard\n", "\n", - "\n", "def report_key(event):\n", " print(event)\n", "\n", @@ -82,7 +91,6 @@ }, { "cell_type": "markdown", - "id": "polish-census", "metadata": {}, "source": [ "UWAGA! Aby uruchomić powyższy kod na Linuxie konieczne są uprawnienia administratora (pytanie poza konkursem - dlaczego?)" @@ -90,15 +98,34 @@ }, { "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": 10, + "metadata": {}, + "outputs": [], + "source": [ + "import keyboard\n", + "from datetime import datetime\n", + "\n", + "def report_key(event):\n", + " current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')\n", + " log_entry = f\"{current_time} - {event.name}\\n\"\n", + " \n", + " with open(\"keylog.txt\", \"a\") as file:\n", + " file.write(log_entry)\n", + "\n", + "keyboard.on_release(callback=report_key)\n", + "\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." @@ -106,7 +133,6 @@ }, { "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ę." @@ -114,18 +140,58 @@ }, { "cell_type": "code", - "execution_count": 1, - "id": "possible-holder", + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "(150.9090909090909, 30.18181818181818)" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ - "def calculate_typing_speed():\n", - " return 0" + "from datetime import datetime, timedelta\n", + "\n", + "def calculate_typing_speed(file_path):\n", + " with open(file_path, \"r\") as file:\n", + " lines = file.readlines()\n", + " \n", + " timestamps = []\n", + " for line in lines:\n", + " timestamp_str = line.split(\" - \")[0]\n", + " timestamp = datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S.%f')\n", + " timestamps.append(timestamp)\n", + " \n", + " active_time = timedelta()\n", + " start_time = timestamps[0]\n", + " total_characters = len(timestamps)\n", + " \n", + " for i in range(1, len(timestamps)):\n", + " if (timestamps[i] - timestamps[i-1]).total_seconds() > 5:\n", + " start_time = timestamps[i]\n", + " else:\n", + " active_time += (timestamps[i] - start_time)\n", + " start_time = timestamps[i]\n", + " \n", + " active_minutes = active_time.total_seconds() / 60\n", + " chars_per_minute = total_characters / active_minutes if active_minutes > 0 else 0\n", + " words_per_minute = chars_per_minute / 5\n", + " \n", + " return chars_per_minute, words_per_minute\n", + "\n", + "file_path = \"keylog.txt\"\n", + "\n", + "chars_per_minute, words_per_minute = calculate_typing_speed(file_path)\n", + "chars_per_minute, words_per_minute\n" ] }, { "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." @@ -133,7 +199,6 @@ }, { "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." @@ -141,28 +206,77 @@ }, { "cell_type": "code", - "execution_count": 2, - "id": "close-riverside", + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Przerwa: 5.0 sekund\n", + "Kontekst: eractivedevelopmente | nvironmentallowingea\n", + "\n", + "Przerwa: 5.0 sekund\n", + "Kontekst: exibleandcanintegrat | ethird-partyextensio\n", + "\n" + ] + } + ], "source": [ - "def find_pauses():\n", - " return []" + "from datetime import datetime, timedelta\n", + "\n", + "def find_pauses(file_path):\n", + " with open(file_path, \"r\") as file:\n", + " lines = file.readlines()\n", + " \n", + " entries = []\n", + " for line in lines:\n", + " if \" - \" in line:\n", + " parts = line.strip().split(\" - \")\n", + " if len(parts) == 2:\n", + " timestamp_str, key = parts\n", + " try:\n", + " timestamp = datetime.strptime(timestamp_str, '%Y-%m-%d %H:%M:%S.%f')\n", + " entries.append((timestamp, key))\n", + " except ValueError as ve:\n", + " print(f\"Błąd parsowania daty: {ve} w linii: {line.strip()}\")\n", + " \n", + " pauses = []\n", + " for i in range(1, len(entries)):\n", + " current_time, current_key = entries[i]\n", + " previous_time, previous_key = entries[i - 1]\n", + " pause_duration = (current_time - previous_time).total_seconds()\n", + " if pause_duration > 3:\n", + " # Zbieranie kontekstu\n", + " start_context_index = max(0, i - 20)\n", + " end_context_index = min(len(entries), i + 20)\n", + " context_before = ''.join([k for t, k in entries[start_context_index:i]])\n", + " context_after = ''.join([k for t, k in entries[i:end_context_index]])\n", + " context = f\"{context_before} | {context_after}\"\n", + " pauses.append({\"Przerwa\": pause_duration, \"Kontekst\": context})\n", + " \n", + " pauses.sort(reverse=True, key=lambda x: x[\"Przerwa\"])\n", + " \n", + " return pauses\n", + "\n", + "file_path = \"keylog.txt\"\n", + "\n", + "pauses_report = find_pauses(file_path)\n", + "for pause in pauses_report:\n", + " print(f\"Przerwa: {pause['Przerwa']} sekund\")\n", + " print(f\"Kontekst: {pause['Kontekst']}\\n\")" ] } ], "metadata": { "author": "Rafał Jaworski", "email": "rjawor@amu.edu.pl", - "lang": "pl", - "subtitle": "12. Key logging", - "title": "Komputerowe wspomaganie tłumaczenia", - "year": "2021", "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, + "lang": "pl", "language_info": { "codemirror_mode": { "name": "ipython", @@ -173,8 +287,11 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.10" - } + "version": "3.7.0" + }, + "subtitle": "12. Key logging", + "title": "Komputerowe wspomaganie tłumaczenia", + "year": "2021" }, "nbformat": 4, "nbformat_minor": 5 diff --git a/lab/lab_13-14.ipynb b/lab/lab_13-14.ipynb index 740d7d9..93b4721 100644 --- a/lab/lab_13-14.ipynb +++ b/lab/lab_13-14.ipynb @@ -2,7 +2,6 @@ "cells": [ { "cell_type": "markdown", - "id": "ordered-wrestling", "metadata": {}, "source": [ "![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n", @@ -17,7 +16,6 @@ }, { "cell_type": "markdown", - "id": "featured-afghanistan", "metadata": {}, "source": [ "Współczesne programy typu CAT nie mogą obyć się bez korektora pisowni. Na bieżąco kontrolują one pisownię wyrazów po stronie docelowej, czyli tam, gdzie tłumacz wpisuje tłumaczenie. Jest to niezwykle istotne w sytuacji, gdy język docelowy nie jest dla tłumacza językiem ojczystym. Co więcej, badania wykazują, iż korekta pisowni wydatnie zmniejsza liczbę błędów w każdych scenariuszach." @@ -25,7 +23,6 @@ }, { "cell_type": "markdown", - "id": "seventh-genre", "metadata": {}, "source": [ "Co poprawia korekta pisowni? Słowa. Tylko lub aż słowa. Program dokonujący korekty pisowni przegląda tekst słowo po słowie i sprawdza, czy należy ono do słownika. Jeśli nie, sygnalizowany jest błąd oraz, jeśli to możliwe, podawane sugestie poprawy. Co istotne, korektor pisowni nie zajmuje się szeregiem błędów, które mieszczą się w dziedzinie korekty gramatycznej, w tym:\n", @@ -36,7 +33,6 @@ }, { "cell_type": "markdown", - "id": "sticky-society", "metadata": {}, "source": [ "Aby zaimplementować korektor pisowni bez wątpienia potrzebny jest słownik. Skorzystajmy ze słownika, który znajdziemy w folderze data, pochodzącego z narzędzia Hunspell. Jest on spakowany - użyjmy techniki czytania z archiwum zip bez rozpakowywania. Poniższy kod wypisze fragment ze środka słownika." @@ -44,11 +40,8 @@ }, { "cell_type": "code", - "execution_count": 3, - "id": "familiar-terrace", - "metadata": { - "scrolled": true - }, + "execution_count": 6, + "metadata": {}, "outputs": [ { "name": "stdout", @@ -81,8 +74,11 @@ "source": [ "from zipfile import ZipFile\n", "\n", - "with ZipFile('data/hunspell_pl.zip') as zipped_dictionary:\n", - " with zipped_dictionary.open('hunspell_pl.txt') as dictionary_file:\n", + "plik_zip = 'data/hunspell_pl.zip'\n", + "plik_txt = 'hunspell_pl.txt'\n", + "\n", + "with ZipFile(plik_zip) as zipped_dictionary:\n", + " with zipped_dictionary.open(plik_txt) as dictionary_file:\n", " count = 0\n", " for line_bytes in dictionary_file:\n", " count += 1\n", @@ -93,7 +89,6 @@ }, { "cell_type": "markdown", - "id": "dominant-insurance", "metadata": {}, "source": [ "Miejmy na uwadze, że powyższy słownik zawiera tylko formy podstawowe słowa, np. zawiera słowo \"kalendarz\", ale nie zawiera \"kalendarze\", \"kalendarza\", \"kalendarzy\" itp. " @@ -101,7 +96,6 @@ }, { "cell_type": "markdown", - "id": "single-brighton", "metadata": {}, "source": [ "Algorytm korekty pisowni na podstawie słownika powinien działać według następujących kroków:\n", @@ -112,7 +106,6 @@ }, { "cell_type": "markdown", - "id": "needed-watson", "metadata": {}, "source": [ "### Ćwiczenie 1: Zaimplementuj podstawowy algorytm korekty pisowni według powyższych wytycznych." @@ -120,18 +113,53 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "economic-southeast", + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "'To' - nok\n", + "'jest' - ok\n", + "'przykładowy' - ok\n", + "'tekst' - ok\n", + "'do' - ok\n", + "'sprawdzenia' - nok\n", + "'pisowni.' - nok\n" + ] + } + ], "source": [ - "def correct_text(text):\n", - " return []" + "import zipfile\n", + "\n", + "def load_dictionary(zip_filepath, dictionary_filename):\n", + " with zipfile.ZipFile(zip_filepath, 'r') as zip_ref:\n", + " with zip_ref.open(dictionary_filename) as file:\n", + " words = set(word.strip().decode('utf-8') for word in file.readlines())\n", + " return words\n", + "\n", + "def correct_text(text, dictionary):\n", + " words = text.split()\n", + " results = []\n", + " for word in words:\n", + " if word in dictionary:\n", + " results.append(f\"'{word}' - ok\")\n", + " else:\n", + " results.append(f\"'{word}' - nok\")\n", + " return results\n", + "\n", + "dictionary = load_dictionary(plik_zip, plik_txt)\n", + "\n", + "text_to_check = \"To jest przykładowy tekst do sprawdzenia pisowni.\"\n", + "results = correct_text(text_to_check, dictionary)\n", + "\n", + "for result in results:\n", + " print(result)" ] }, { "cell_type": "markdown", - "id": "endless-slide", "metadata": {}, "source": [ "To jednak oczywiście nie wszystko. Do tej pory mamy funkcjonalność sygnalizowania słów błędnych, ale każdy dobry korektor pisowni potrafi podać sugestie poprawek. W tym celu musimy stawić czoła następującemu problemowi - wygenerowanie listy słów podobnych do danego słowa błędnego, które znajdują się w słowniku." @@ -139,7 +167,6 @@ }, { "cell_type": "markdown", - "id": "adult-freight", "metadata": {}, "source": [ "W pierwszej kolejności musimy zdefiniować podobieństwo między wyrazami. Posłuży do tego dobrze nam znana odległość Levenshteina - wyrazy podobne to takie, dla których dystans Levenshteina jest niewielki (np. równy 1 lub 2). Teraz brakuje tylko algorytmu wyszukiwania wyrazów w danym słowniku, które znajdują się niedaleko (w sensie Levenshteina) danego błędnego słowa." @@ -147,7 +174,6 @@ }, { "cell_type": "markdown", - "id": "everyday-things", "metadata": {}, "source": [ "Rozważmy następujący algorytm: dla danego słownika $D$ i błędnego słowa $w \\notin D$:\n", @@ -160,7 +186,6 @@ }, { "cell_type": "markdown", - "id": "industrial-convert", "metadata": {}, "source": [ "### Ćwiczenie 2: Napisz funkcję do generowania zbioru $L_1(w)$ - wszystkich słów znajdujących się w odległości Levenshteina 1 od danego słowa w." @@ -168,18 +193,35 @@ }, { "cell_type": "code", - "execution_count": 1, - "id": "built-sally", + "execution_count": 11, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'przykbad', 'przykłay', 'przukład', 'crzykład', 'przykqład', 'wprzykład', 'przykładi', 'przykłtad', 'yprzykład', 'przykłsd', 'przykłvad', 'przxykład', 'przykzład', 'przykładg', 'pyrzykład', 'przyoład', 'prjykład', 'przeykład', 'przykkład', 'przikład', 'przyksad', 'sprzykład', 'pozykład', 'przyxkład', 'przyiład', 'pzrzykład', 'pwrzykład', 'jprzykład', 'przykła', 'grzykład', 'przykvad', 'przykładh', 'przykłae', 'przcykład', 'przmykład', 'plrzykład', 'przyckład', 'wrzykład', 'prvykład', 'erzykład', 'pzzykład', 'jrzykład', 'przykvład', 'przykpad', 'przmkład', 'przykłkd', 'przyeład', 'przyzład', 'przykłas', 'xprzykład', 'przykcład', 'przdkład', 'przykeład', 'przytkład', 'przykłap', 'przvkład', 'zrzykład', 'przynład', 'przfkład', 'przykłrd', 'mrzykład', 'przyktład', 'przyskład', 'frzykład', 'przykłnad', 'przykłaj', 'przykłqd', 'przyhkład', 'purzykład', 'przwykład', 'przykłod', 'przbykład', 'ptrzykład', 'przykłao', 'przykłal', 'porzykład', 'perzykład', 'przrykład', 'przkkład', 'przykłag', 'pqzykład', 'przykław', 'przykfład', 'prcykład', 'przyktad', 'praykład', 'przlykład', 'przykładk', 'tprzykład', 'drzykład', 'ppzykład', 'pruzykład', 'przyfład', 'przykmad', 'przymład', 'przykhad', 'prznykład', 'mprzykład', 'przgkład', 'przyzkład', 'pxrzykład', 'przykładm', 'przykłpd', 'przykzad', 'przykyad', 'przwkład', 'qrzykład', 'pirzykład', 'przekład', 'przykłado', 'srzykład', 'przykłabd', 'przhkład', 'iprzykład', 'przykłwad', 'przgykład', 'xrzykład', 'rrzykład', 'przykładz', 'pvzykład', 'prgzykład', 'pryzykład', 'przbkład', 'przyaład', 'fprzykład', 'przykłgd', 'prhykład', 'przykoad', 'nrzykład', 'przhykład', 'pezykład', 'przykładl', 'przsykład', 'przykłgad', 'przykłamd', 'przykłhd', 'prszykład', 'przyrład', 'przykaład', 'przykłads', 'phzykład', 'przykłayd', 'nprzykład', 'przydład', 'przykuad', 'pvrzykład', 'przyekład', 'przykładc', 'przykładr', 'lrzykład', 'orzykład', 'prrzykład', 'przybkład', 'przykdład', 'brzykład', 'przykłjad', 'prznkład', 'przykłlad', 'przykładw', 'zprzykład', 'przyhład', 'przykwład', 'przakład', 'przykmład', 'przykłaid', 'ptzykład', 'przyykład', 'eprzykład', 'pfrzykład', 'pgzykład', 'przykłkad', 'przyjład', 'pgrzykład', 'pkzykład', 'przykłxad', 'dprzykład', 'gprzykład', 'pfzykład', 'przykłmd', 'przykiad', 'rprzykład', 'przypład', 'przykłakd', 'przykłfd', 'przyuład', 'pmrzykład', 'przykłsad', 'prhzykład', 'przpykład', 'przyyład', 'prgykład', 'przykładx', 'przykłade', 'przvykład', 'przykłhad', 'przykłzd', 'przykłnd', 'prsykład', 'przqkład', 'vrzykład', 'przykłld', 'przykoład', 'przjykład', 'psrzykład', 'pyzykład', 'przykłmad', 'pryykład', 'przylład', 'przykłid', 'prqzykład', 'przykłiad', 'przykłazd', 'przykłbd', 'przykłaf', 'przckład', 'pmzykład', 'prjzykład', 'przykłatd', 'hprzykład', 'pxzykład', 'kprzykład', 'przykładp', 'prczykład', 'pdzykład', 'prmzykład', 'przykłaz', 'przuykład', 'przykłxd', 'prziykład', 'przykbład', 'przykłau', 'priykład', 'pszykład', 'przzkład', 'przykładt', 'proykład', 'przrkład', 'przymkład', 'pzykład', 'prezykład', 'przykłald', 'uprzykład', 'przqykład', 'przykłafd', 'prvzykład', 'przykłapd', 'przykłand', 'przykyład', 'przfykład', 'pizykład', 'przykwad', 'hrzykład', 'przykławd', 'przykładu', 'pczykład', 'prazykład', 'prlzykład', 'przykłud', 'przlkład', 'przykłada', 'przykjład', 'prnykład', 'przyikład', 'przywkład', 'pwzykład', 'przyknad', 'prfykład', 'przykłbad', 'parzykład', 'przykłdad', 'prztkład', 'pjrzykład', 'przykrad', 'przzykład', 'przyvkład', 'przjkład', 'puzykład', 'pjzykład', 'pcrzykład', 'przykładb', 'przykłaqd', 'przykpład', 'prxzykład', 'prpykład', 'przykłab', 'prdzykład', 'przylkład', 'prmykład', 'przykładf', 'irzykład', 'yrzykład', 'przynkład', 'przyakład', 'pnrzykład', 'przykłqad', 'pruykład', 'przokład', 'przyvład', 'przpkład', 'prozykład', 'pbzykład', 'przykiład', 'prwykład', 'przykłak', 'pbrzykład', 'przykładq', 'przykłfad', 'przykjad', 'przyukład', 'przykłyad', 'przykłtd', 'przdykład', 'przykad', 'przykłard', 'prpzykład', 'przykłdd', 'przykłai', 'preykład', 'prtzykład', 'przykłwd', 'przykłax', 'przoykład', 'przykłcad', 'cprzykład', 'przyxład', 'krzykład', 'przykłead', 'przykłaud', 'przydkład', 'przykłvd', 'przykłcd', 'przykłah', 'przykłyd', 'przykłaa', 'pprzykład', 'prztykład', 'aprzykład', 'przykłagd', 'przypkład', 'przyrkład', 'przxkład', 'przykłoad', 'przykłasd', 'prwzykład', 'przykłd', 'przyklład', 'prxykład', 'przykłam', 'przykłaod', 'vprzykład', 'przygkład', 'rzykład', 'przykłady', 'prdykład', 'przaykład', 'prbykład', 'przykłaxd', 'przkład', 'przykłajd', 'przykłac', 'przyfkład', 'prtykład', 'przykead', 'przybład', 'lprzykład', 'przykgad', 'prrykład', 'przyknład', 'przykłaq', 'qprzykład', 'przykłpad', 'pnzykład', 'pqrzykład', 'plzykład', 'przykqad', 'oprzykład', 'przykxad', 'przyokład', 'przytład', 'przykkad', 'przykcad', 'przykłuad', 'przykłrad', 'przykłaed', 'przkykład', 'przykładj', 'przykłjd', 'przysład', 'przykładd', 'przykład', 'prlykład', 'przykaad', 'przykxład', 'przykłahd', 'przykładn', 'pazykład', 'prfzykład', 'przyksład', 'przyqład', 'przyqkład', 'prqykład', 'przyład', 'prnzykład', 'przykgład', 'przykdad', 'przykłed', 'przykłar', 'przycład', 'przykłan', 'przykłaad', 'przykłat', 'przskład', 'pkrzykład', 'przykłav', 'trzykład', 'przygład', 'przykładv', 'prbzykład', 'pdrzykład', 'przykrład', 'prkzykład', 'przykfad', 'przykłacd', 'przykuład', 'przyklad', 'arzykład', 'przykłavd', 'przyjkład', 'przywład', 'prykład', 'prizykład', 'urzykład', 'prkykład', 'bprzykład', 'przykłzad', 'przykhład', 'phrzykład'}\n" + ] + } + ], "source": [ "def L1(w):\n", - " return []" + " letters = 'abcdefghijklmnopqrstuvwxyz'\n", + " splits = [(w[:i], w[i:]) for i in range(len(w) + 1)]\n", + " \n", + " deletes = [L + R[1:] for L, R in splits if R]\n", + " inserts = [L + c + R for L, R in splits for c in letters]\n", + " replaces = [L + c + R[1:] for L, R in splits if R for c in letters]\n", + " \n", + " return set(deletes + inserts + replaces)\n", + "\n", + "word = \"przykład\"\n", + "L1_set = L1(word)\n", + "print(L1_set)" ] }, { "cell_type": "markdown", - "id": "wireless-uncle", "metadata": {}, "source": [ "### Ćwiczenie 3: Napisz funkcję do generowania sugestii poprawek dla danego słowa według opisanego wcześniej algorytmu." @@ -187,13 +229,45 @@ }, { "cell_type": "code", - "execution_count": 2, - "id": "coordinated-cooperation", + "execution_count": 15, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "'To' - nok (sugerowane poprawki: T, Tb, Tt, Tot, o, no, to, oo, Tc, Tl, Ta, co, do, po, bo, Th, ko, Te, eo, go, Tm, ho, Tob, Tom, Ti, Tr)\n", + "'jest' - ok\n", + "'przykładowy' - ok\n", + "'tekst' - ok\n", + "'do' - ok\n", + "'sprawdzenia' - nok (brak sugestii)\n", + "'pisowni.' - nok (sugerowane poprawki: pisownia)\n" + ] + } + ], "source": [ - "def generate_suggestions(w):\n", - " return []" + "def generate_suggestions(text, dictionary):\n", + " words = text.split()\n", + " results = []\n", + " for word in words:\n", + " if word in dictionary:\n", + " results.append(f\"'{word}' - ok\")\n", + " else:\n", + " suggestions = L1(word)\n", + " valid_suggestions = [s for s in suggestions if s in dictionary]\n", + " if valid_suggestions:\n", + " suggestion_str = \", \".join(valid_suggestions)\n", + " results.append(f\"'{word}' - nok (sugerowane poprawki: {suggestion_str})\")\n", + " else:\n", + " results.append(f\"'{word}' - nok (brak sugestii)\")\n", + " return results\n", + "\n", + "text_to_check = \"To jest przykładowy tekst do sprawdzenia pisowni.\"\n", + "results = generate_suggestions(text_to_check, dictionary)\n", + "\n", + "for result in results:\n", + " print(result)" ] } ], @@ -201,7 +275,7 @@ "author": "Rafał Jaworski", "email": "rjawor@amu.edu.pl", "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -216,7 +290,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.10" + "version": "3.7.0" }, "subtitle": "13,14. Korekta pisowni", "title": "Komputerowe wspomaganie tłumaczenia", diff --git a/lab/lab_15.ipynb b/lab/lab_15.ipynb index cb0382e..aa7fd6a 100644 --- a/lab/lab_15.ipynb +++ b/lab/lab_15.ipynb @@ -1,181 +1,409 @@ { - "cells": [ - { - "cell_type": "markdown", - "id": "marine-termination", - "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", - "

15. Korekta gramatyczna [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": [ - "Ostatnią z omawianych przez nas technik stosowaną podczas wspomagania tłumaczenia jest korekta gramatyczna. Automatyczna korekta gramatyczna tekstu to ambitne zadanie odnalezienia możliwych błędów niezwiązanych bezpośrednio z pisownią. Są to między innymi:\n", - "* błędy gramatyczne\n", - "* źle użyte słowa\n", - "* złe połączenia wyrazowe\n", - "* błędy interpunkcyjne\n", - "* kolokwializmy\n", - "* redundancja (np. \"tylko i wyłącznie\")" - ] - }, - { - "cell_type": "markdown", - "id": "peaceful-kingston", - "metadata": {}, - "source": [ - "Warto zwrócić uwagę, iż systemy do korekcji gramatycznej można traktować jako klasyfikatory binarne. Przyjmijmy, że odpowiedź pozytywna korektora to wykrycie błędu w tekście, natomiast negatywna - brak błędu. Wówczas rozróżniamy dwa typy pomyłek: false positive oraz false negative. False positive to tzw. \"fałszywy alarm\" - zbyt duża ich ilość spowoduje wydłużenie czasu pracy użytkownika przez konieczność analizowania zgłoszeń, które w istocie błędami nie są. Co jednak jeszcze gorsze, zbyt duża ilość false positives powoduje spadek zaufania użytkownika do systemu oraz drastyczny spadek satysfakcji z używania systemu. Te drugie błędy - false negatives - to z kolei faktyczne błędy w tekście, które nie zostały wyłapane przez system korekty. Stare polskie porzekadło głosi, że \"czego oko nie widzi, tego sercu nie żal\". Niestety jednak problem pojawia się, kiedy dostrzeże to jakieś inne oko... Wysoka liczba false negatives wprawdzie skraca czas korekty (sic!), ale odbywa się to kosztem jakości całego procesu. Idealnie zatem byłoby zminimalizować zarówno liczbę false positives, jak i false negatives. Jak jednak łatwo się domyślić, nie jest to zawsze możliwe. Korektor gramatyczny, który jest bardzo restrykcyjny i raportuje wiele błędów, będzie miał tendencję do popełniania false positives. Natomiast korektor bardziej pobłażliwy niechybnie popełni wiele false negatives. Co zatem jest ważniejsze? Praktyka wskazuje, że oba parametry mają podobną wagę, ale jednak odrobinę ważniejsze jest powstrzymanie się od false positives." - ] - }, - { - "cell_type": "markdown", - "id": "soviet-highland", - "metadata": {}, - "source": [ - "Do najbardziej popularnych narzędzi wspomagających korektę gramatyczną tekstu należą Grammarly oraz LanguageTool. Na dzisiejszych zajęciach zajmiemy się tym drugim. LanguageTool został pierwotnie napisany jako praca dyplomowa Daniela Nabera, a następnie intensywnie rozwijany wspólnie z Marcinem Miłkowskim. Aż do dziś projekt jest ciągle rozwijany, zwiększana jest liczba obsługiwanych języków oraz dokładność działania." - ] - }, - { - "cell_type": "markdown", - "id": "arbitrary-reconstruction", - "metadata": {}, - "source": [ - "LanguageTool jest systemem opartym na regułach. W dobie wszechobecnej sztucznej inteligencji opartej na uczeniu maszynowym rozwiązanie to wydaje się nieco przestarzałe. Jednak to właśnie reguły stanowią o sile LanguageToola - pozwalają one na zwiększenie precyzji korektora poprzez minimalizację false positives. Warto wspomnieć, iż liczne reguły LanguageToola dotyczą również korekty pisowni. Czyni to z LanguageToola kompletne narzędzie do korekty tekstu. Polecam przejrzenie zestawu reguł LanguageToola dla języka angielskiego: https://community.languagetool.org/rule/list?lang=en" - ] - }, - { - "cell_type": "markdown", - "id": "piano-satellite", - "metadata": {}, - "source": [ - "Czas uruchomić to narzędzie. Skorzystajmy z Pythona." - ] - }, - { - "cell_type": "raw", - "id": "academic-crest", - "metadata": {}, - "source": [ - "pip3 install language_tool_python" - ] - }, - { - "cell_type": "markdown", - "id": "italian-cheese", - "metadata": {}, - "source": [ - "Następnie możemy użyć LanguageToola w programie Pythonowym: (przykład zaczerpnięty z oficjalnego tutoriala: https://pypi.org/project/language-tool-python/)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "relative-anaheim", - "metadata": {}, - "outputs": [ + "cells": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "[Match({'ruleId': 'EN_A_VS_AN', 'message': 'Use “an” instead of ‘a’ if the following word starts with a vowel sound, e.g. ‘an article’, ‘an hour’.', 'replacements': ['an'], 'offsetInContext': 16, 'context': 'A sentence with a error in the Hitchhiker’s Guide tot he ...', 'offset': 16, 'errorLength': 1, 'category': 'MISC', 'ruleIssueType': 'misspelling', 'sentence': 'A sentence with a error in the Hitchhiker’s Guide tot he Galaxy'}),\n", - " Match({'ruleId': 'TOT_HE', 'message': 'Did you mean “to the”?', 'replacements': ['to the'], 'offsetInContext': 43, 'context': '... with a error in the Hitchhiker’s Guide tot he Galaxy', 'offset': 50, 'errorLength': 6, 'category': 'TYPOS', 'ruleIssueType': 'misspelling', 'sentence': 'A sentence with a error in the Hitchhiker’s Guide tot he Galaxy'})]\n" - ] + "cell_type": "markdown", + "metadata": { + "id": "marine-termination" + }, + "source": [ + "![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n", + "
\n", + "

Komputerowe wspomaganie tłumaczenia

\n", + "

15. Korekta gramatyczna [laboratoria]

\n", + "

Rafał Jaworski (2021)

\n", + "
\n", + "\n", + "![Logo 2](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech2.jpg)" + ], + "id": "marine-termination" + }, + { + "cell_type": "markdown", + "metadata": { + "id": "featured-afghanistan" + }, + "source": [ + "Ostatnią z omawianych przez nas technik stosowaną podczas wspomagania tłumaczenia jest korekta gramatyczna. Automatyczna korekta gramatyczna tekstu to ambitne zadanie odnalezienia możliwych błędów niezwiązanych bezpośrednio z pisownią. Są to między innymi:\n", + "* błędy gramatyczne\n", + "* źle użyte słowa\n", + "* złe połączenia wyrazowe\n", + "* błędy interpunkcyjne\n", + "* kolokwializmy\n", + "* redundancja (np. \"tylko i wyłącznie\")" + ], + "id": "featured-afghanistan" + }, + { + "cell_type": "markdown", + "metadata": { + "id": "peaceful-kingston" + }, + "source": [ + "Warto zwrócić uwagę, iż systemy do korekcji gramatycznej można traktować jako klasyfikatory binarne. Przyjmijmy, że odpowiedź pozytywna korektora to wykrycie błędu w tekście, natomiast negatywna - brak błędu. Wówczas rozróżniamy dwa typy pomyłek: false positive oraz false negative. False positive to tzw. \"fałszywy alarm\" - zbyt duża ich ilość spowoduje wydłużenie czasu pracy użytkownika przez konieczność analizowania zgłoszeń, które w istocie błędami nie są. Co jednak jeszcze gorsze, zbyt duża ilość false positives powoduje spadek zaufania użytkownika do systemu oraz drastyczny spadek satysfakcji z używania systemu. Te drugie błędy - false negatives - to z kolei faktyczne błędy w tekście, które nie zostały wyłapane przez system korekty. Stare polskie porzekadło głosi, że \"czego oko nie widzi, tego sercu nie żal\". Niestety jednak problem pojawia się, kiedy dostrzeże to jakieś inne oko... Wysoka liczba false negatives wprawdzie skraca czas korekty (sic!), ale odbywa się to kosztem jakości całego procesu. Idealnie zatem byłoby zminimalizować zarówno liczbę false positives, jak i false negatives. Jak jednak łatwo się domyślić, nie jest to zawsze możliwe. Korektor gramatyczny, który jest bardzo restrykcyjny i raportuje wiele błędów, będzie miał tendencję do popełniania false positives. Natomiast korektor bardziej pobłażliwy niechybnie popełni wiele false negatives. Co zatem jest ważniejsze? Praktyka wskazuje, że oba parametry mają podobną wagę, ale jednak odrobinę ważniejsze jest powstrzymanie się od false positives." + ], + "id": "peaceful-kingston" + }, + { + "cell_type": "markdown", + "metadata": { + "id": "soviet-highland" + }, + "source": [ + "Do najbardziej popularnych narzędzi wspomagających korektę gramatyczną tekstu należą Grammarly oraz LanguageTool. Na dzisiejszych zajęciach zajmiemy się tym drugim. LanguageTool został pierwotnie napisany jako praca dyplomowa Daniela Nabera, a następnie intensywnie rozwijany wspólnie z Marcinem Miłkowskim. Aż do dziś projekt jest ciągle rozwijany, zwiększana jest liczba obsługiwanych języków oraz dokładność działania." + ], + "id": "soviet-highland" + }, + { + "cell_type": "markdown", + "metadata": { + "id": "arbitrary-reconstruction" + }, + "source": [ + "LanguageTool jest systemem opartym na regułach. W dobie wszechobecnej sztucznej inteligencji opartej na uczeniu maszynowym rozwiązanie to wydaje się nieco przestarzałe. Jednak to właśnie reguły stanowią o sile LanguageToola - pozwalają one na zwiększenie precyzji korektora poprzez minimalizację false positives. Warto wspomnieć, iż liczne reguły LanguageToola dotyczą również korekty pisowni. Czyni to z LanguageToola kompletne narzędzie do korekty tekstu. Polecam przejrzenie zestawu reguł LanguageToola dla języka angielskiego: https://community.languagetool.org/rule/list?lang=en" + ], + "id": "arbitrary-reconstruction" + }, + { + "cell_type": "markdown", + "metadata": { + "id": "piano-satellite" + }, + "source": [ + "Czas uruchomić to narzędzie. Skorzystajmy z Pythona." + ], + "id": "piano-satellite" + }, + { + "cell_type": "raw", + "metadata": { + "id": "academic-crest" + }, + "source": [ + "pip3 install language_tool_python" + ], + "id": "academic-crest" + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "990ee426-481e-4fa6-8ed0-e5dbb78f7a44", + "outputId": "46c5ddd6-07a1-4d98-d574-d674be2b03bc" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Collecting language_tool_python\n", + " Downloading language_tool_python-2.8-py3-none-any.whl (35 kB)\n", + "Requirement already satisfied: pip in /usr/local/lib/python3.10/dist-packages (from language_tool_python) (23.1.2)\n", + "Requirement already satisfied: requests in /usr/local/lib/python3.10/dist-packages (from language_tool_python) (2.31.0)\n", + "Requirement already satisfied: tqdm in /usr/local/lib/python3.10/dist-packages (from language_tool_python) (4.66.4)\n", + "Requirement already satisfied: wheel in /usr/local/lib/python3.10/dist-packages (from language_tool_python) (0.43.0)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests->language_tool_python) (3.3.2)\n", + "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests->language_tool_python) (3.7)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests->language_tool_python) (2.0.7)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests->language_tool_python) (2024.2.2)\n", + "Installing collected packages: language_tool_python\n", + "Successfully installed language_tool_python-2.8\n" + ] + } + ], + "source": [ + "!pip3 install language_tool_python" + ], + "id": "990ee426-481e-4fa6-8ed0-e5dbb78f7a44" + }, + { + "cell_type": "markdown", + "metadata": { + "id": "italian-cheese" + }, + "source": [ + "Następnie możemy użyć LanguageToola w programie Pythonowym: (przykład zaczerpnięty z oficjalnego tutoriala: https://pypi.org/project/language-tool-python/)" + ], + "id": "italian-cheese" + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "relative-anaheim", + "outputId": "9c6269b7-5b21-4eb3-a2ac-bf724a80f0d9" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "Downloading LanguageTool 6.4: 100%|██████████| 246M/246M [00:08<00:00, 29.1MB/s]\n", + "INFO:language_tool_python.download_lt:Unzipping /tmp/tmpk9z9693r.zip to /root/.cache/language_tool_python.\n", + "INFO:language_tool_python.download_lt:Downloaded https://www.languagetool.org/download/LanguageTool-6.4.zip to /root/.cache/language_tool_python.\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "[Match({'ruleId': 'EN_A_VS_AN', 'message': 'Use “an” instead of ‘a’ if the following word starts with a vowel sound, e.g. ‘an article’, ‘an hour’.', 'replacements': ['an'], 'offsetInContext': 16, 'context': 'A sentence with a error in the Hitchhiker’s Guide tot he ...', 'offset': 16, 'errorLength': 1, 'category': 'MISC', 'ruleIssueType': 'misspelling', 'sentence': \"A sentence with a error in the Hitchhiker's Guide tot he Galaxy\"}),\n", + " Match({'ruleId': 'TOT_HE', 'message': 'Did you mean “to the”?', 'replacements': ['to the'], 'offsetInContext': 43, 'context': '... with a error in the Hitchhiker’s Guide tot he Galaxy', 'offset': 50, 'errorLength': 6, 'category': 'TYPOS', 'ruleIssueType': 'misspelling', 'sentence': \"A sentence with a error in the Hitchhiker's Guide tot he Galaxy\"})]\n" + ] + } + ], + "source": [ + "import language_tool_python\n", + "import pprint\n", + "tool = language_tool_python.LanguageTool('en-US')\n", + "\n", + "text = 'A sentence with a error in the Hitchhiker’s Guide tot he Galaxy'\n", + "\n", + "pp = pprint.PrettyPrinter(depth=2)\n", + "errors = tool.check(text)\n", + "pp.pprint(errors)" + ], + "id": "relative-anaheim" + }, + { + "cell_type": "markdown", + "metadata": { + "id": "gorgeous-million" + }, + "source": [ + "Przeanalizujmy format zwracanego wyniku. Otrzymujemy listę obiektów Match - zawiadomień o potencjalnym błędzie. Razem z każdym błędem otrzymujemy m.in. identyfikator użytej reguły, opis błędu, rekomendancję poprawy, kontekst." + ], + "id": "gorgeous-million" + }, + { + "cell_type": "markdown", + "metadata": { + "id": "reasonable-cornwall" + }, + "source": [ + "\n", + "### Ćwiczenie 1: Użyj LanguageTool do znalezienia jak największej liczby prawdziwych błędów na swoim ulubionym portalu internetowym. Skorzystaj z poznanych wcześniej technik web scrapingu. Uwaga - LanguageTool najprawdopodobniej oznaczy nazwy własne jako literówki - ten typ błędu nie powinien być brany pod uwagę." + ], + "id": "reasonable-cornwall" + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "viOEpEZk7TES", + "outputId": "62dc43b4-763d-4f17-e88f-60e97dd69ec4" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "[Match({'ruleId': 'DYWIZ', 'message': 'Spacje wokół dywizu (w przeciwieństwie do myślnika) są zbędne: \"możliwa-mówi\"; jeśli to miał być myślnik, to należy napisać \"możliwa — mówi\".', 'replacements': ['możliwa-mówi', 'możliwa — mówi'], 'offsetInContext': 43, 'context': '...egatywna interakcja w drugą stronę jest możliwa - mówi dr', 'offset': 105, 'errorLength': 14, 'category': 'TYPOGRAPHY', 'ruleIssueType': 'typographical', 'sentence': 'Tak przewrotnie postawione pytanie zmusza do zastanowienia, czy negatywna interakcja w drugą stronę jest możliwa - mówi dr'}),\n", + " Match({'ruleId': 'MORFOLOGIK_RULE_PL_PL', 'message': 'Wykryto prawdopodobny błąd pisowni', 'replacements': ['Wędzonka', 'Wędzonką', 'Wędzona', 'Wędzonki', 'Wędzonko', 'Wędzonkę', 'Wędzoną', 'Wędząca', 'Wędzącą'], 'offsetInContext': 0, 'context': 'Wendzonka.', 'offset': 0, 'errorLength': 9, 'category': 'TYPOS', 'ruleIssueType': 'misspelling', 'sentence': 'Wendzonka.'}),\n", + " Match({'ruleId': 'PRZECINEK_ANI', 'message': 'Prawdopodobnie zbędny przecinek, powinno być: \" i\".', 'replacements': [' i'], 'offsetInContext': 8, 'context': 'Pszczoły, i dzikie i miodne, ewoluowały i współwyst...', 'offset': 8, 'errorLength': 3, 'category': 'PUNCTUATION', 'ruleIssueType': 'typographical', 'sentence': 'Pszczoły, i dzikie i miodne, ewoluowały i współwystępowały razem przez miliony lat.'}),\n", + " Match({'ruleId': 'PL_UNPAIRED_BRACKETS', 'message': 'Brak niesparowanego symbolu: „(”', 'replacements': [], 'offsetInContext': 14, 'context': 'Apis mellifera) jako gatunek społeczny, magazynujący za...', 'offset': 14, 'errorLength': 1, 'category': 'PUNCTUATION', 'ruleIssueType': 'typographical', 'sentence': 'Apis mellifera) jako gatunek społeczny, magazynujący zapasy i potrafiący wielokrotnie zimować w gnieździe jako rodzina, jest na szczycie drabiny ewolucyjnej.'}),\n", + " Match({'ruleId': 'POTRAFIACY', 'message': 'Czasownik „potrafić” nie ma imiesłowu czynnego. Poprawnie: \"umiejący\".', 'replacements': ['umiejący'], 'offsetInContext': 43, 'context': '...atunek społeczny, magazynujący zapasy i potrafiący wielokrotnie zimować w gnieździe jako r...', 'offset': 62, 'errorLength': 10, 'category': 'STYLE', 'ruleIssueType': 'style', 'sentence': 'Apis mellifera) jako gatunek społeczny, magazynujący zapasy i potrafiący wielokrotnie zimować w gnieździe jako rodzina, jest na szczycie drabiny ewolucyjnej.'}),\n", + " Match({'ruleId': 'NIE_TYLE_ALE', 'message': 'Czy chodziło o \"ile\"? (Zdanie występuje po spójniku skorelowanym „nie tyle...”).', 'replacements': ['ile'], 'offsetInContext': 43, 'context': '...e stawką jest życie nie tyle osobników, ale całych gatunków, na częstotliwości taki...', 'offset': 67, 'errorLength': 3, 'category': 'SYNTAX', 'ruleIssueType': 'grammar', 'sentence': 'Jednakże w przyrodzie, gdzie stawką jest życie nie tyle osobników, ale całych gatunków, na częstotliwości takich wyczynów nie można polegać.'}),\n", + " Match({'ruleId': 'MORFOLOGIK_RULE_PL_PL', 'message': 'Wykryto prawdopodobny błąd pisowni', 'replacements': [], 'offsetInContext': 43, 'context': '...anie kwestii kontroli zagęszczenia uli (napszczelenia) staje się zadaniem najważniejszym, tak...', 'offset': 113, 'errorLength': 13, 'category': 'TYPOS', 'ruleIssueType': 'misspelling', 'sentence': 'Jeżeli mamy poważnie podchodzić do ochrony dzikich zapylaczy, to uregulowanie kwestii kontroli zagęszczenia uli (napszczelenia) staje się zadaniem najważniejszym, także na poziomie legislacyjnym.'}),\n", + " Match({'ruleId': 'DYWIZ', 'message': 'Spacje wokół dywizu (w przeciwieństwie do myślnika) są zbędne: \"życzę-dodaje\"; jeśli to miał być myślnik, to należy napisać \"życzę — dodaje\".', 'replacements': ['życzę-dodaje', 'życzę — dodaje'], 'offsetInContext': 43, 'context': '...i, czego wszystkim pszczołom w ich dniu życzę - dodaje naukowiec z', 'offset': 119, 'errorLength': 14, 'category': 'TYPOGRAPHY', 'ruleIssueType': 'typographical', 'sentence': 'Właśnie w tym aspekcie musi się dokonać największa zmiana w ludzkiej mentalności, czego wszystkim pszczołom w ich dniu życzę - dodaje naukowiec z'}),\n", + " Match({'ruleId': 'MORFOLOGIK_RULE_PL_PL', 'message': 'Wykryto prawdopodobny błąd pisowni', 'replacements': ['Wykryta', 'Wykrytą', 'Wąkrota', 'Wykroją', 'Wykrot', 'Wykrotu', 'Wykroty', 'Wąkrotą', 'Wyk rota', 'Wykrot a'], 'offsetInContext': 0, 'context': 'Wykrota', 'offset': 0, 'errorLength': 7, 'category': 'TYPOS', 'ruleIssueType': 'misspelling', 'sentence': 'Wykrota'})]\n" + ] + } + ], + "source": [ + "import requests\n", + "from bs4 import BeautifulSoup\n", + "import regex\n", + "import language_tool_python\n", + "import pprint\n", + "\n", + "def sentence_split(text):\n", + " pattern = r'(?=\\p{Lu})'\n", + " segments = regex.split(pattern, text)\n", + " segments = [segment.strip() for segment in segments if segment.strip()]\n", + " return segments\n", + "\n", + "url = 'https://amu.edu.pl/dla-mediow/komunikaty-prasowe/czy-dzikie-pszczoly-zagrazaja-pszczolom-miodnym'\n", + "page = requests.get(url)\n", + "soup = BeautifulSoup(page.content, 'html.parser')\n", + "\n", + "article_content = soup.find('div', {'class': 'news__body'}).get_text()\n", + "\n", + "sentences = sentence_split(article_content)\n", + "\n", + "tool = language_tool_python.LanguageTool('pl')\n", + "\n", + "def is_proper_noun_error(error):\n", + " return 'MORFOLOGIA' in error.ruleId and 'Proper noun' in error.message\n", + "\n", + "all_errors = []\n", + "for sentence in sentences:\n", + " errors = tool.check(sentence)\n", + " filtered_errors = [error for error in errors if not is_proper_noun_error(error)]\n", + " all_errors.extend(filtered_errors)\n", + "\n", + "pp = pprint.PrettyPrinter(depth=2)\n", + "pp.pprint(all_errors)" + ], + "id": "viOEpEZk7TES" + }, + { + "cell_type": "markdown", + "metadata": { + "id": "coupled-extra" + }, + "source": [ + "### Ćwiczenie 2: Napisz skrypt, który poszuka błędów w komentarzach klasy Javowej (zwykłych // oraz w javadocach). Uruchom ten skrypt na źródłach wybranego opensourcowego projektu w Javie." + ], + "id": "coupled-extra" + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "spuSfkNX8j3c", + "outputId": "181f448a-328e-49cb-bd35-3b9dc3d5e8b3" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Collecting gitpython\n", + " Downloading GitPython-3.1.43-py3-none-any.whl (207 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m207.3/207.3 kB\u001b[0m \u001b[31m1.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hCollecting gitdb<5,>=4.0.1 (from gitpython)\n", + " Downloading gitdb-4.0.11-py3-none-any.whl (62 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m62.7/62.7 kB\u001b[0m \u001b[31m7.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hCollecting smmap<6,>=3.0.1 (from gitdb<5,>=4.0.1->gitpython)\n", + " Downloading smmap-5.0.1-py3-none-any.whl (24 kB)\n", + "Installing collected packages: smmap, gitdb, gitpython\n", + "Successfully installed gitdb-4.0.11 gitpython-3.1.43 smmap-5.0.1\n" + ] + } + ], + "source": [ + "!pip install gitpython" + ], + "id": "spuSfkNX8j3c" + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "id": "vIu0t2qcc3oy" + }, + "outputs": [], + "source": [ + "import requests\n", + "import re\n", + "import language_tool_python\n", + "from bs4 import BeautifulSoup\n", + "from pathlib import Path\n", + "\n", + "def extract_comments_from_java(content):\n", + " comments = []\n", + " single_line_comment_pattern = re.compile(r'//.*')\n", + " multi_line_comment_pattern = re.compile(r'/\\*[\\s\\S]*?\\*/')\n", + "\n", + " single_line_comments = single_line_comment_pattern.findall(content)\n", + " multi_line_comments = multi_line_comment_pattern.findall(content)\n", + " comments.extend(single_line_comments)\n", + " comments.extend(multi_line_comments)\n", + "\n", + " return comments\n", + "\n", + "def check_comments_for_errors(comments, language_tool):\n", + " all_errors = []\n", + " for comment in comments:\n", + " errors = language_tool.check(comment)\n", + " all_errors.extend(errors)\n", + " return all_errors\n", + "\n", + "def correct_java_grammar(java_file_path):\n", + " response = requests.get(java_file_path)\n", + " if response.status_code != 200:\n", + " print(f\"Problem z otwarciem strony: {java_file_path}\")\n", + " return []\n", + "\n", + " content = response.text\n", + " comments = extract_comments_from_java(content)\n", + " tool = language_tool_python.LanguageTool('en-US')\n", + " errors = check_comments_for_errors(comments, tool)\n", + "\n", + " return errors\n", + "\n", + "def fetch_java_files(url):\n", + " response = requests.get(url)\n", + " if response.status_code != 200:\n", + " print(f\"Problem z otwarciem strony: {url}\")\n", + " return []\n", + "\n", + " soup = BeautifulSoup(response.content, 'html.parser')\n", + " java_files = []\n", + "\n", + " for link in soup.find_all('a', href=True):\n", + " href = link['href']\n", + " if href.endswith('.java'):\n", + " java_files.append(f\"https://raw.githubusercontent.com{href.replace('/blob/', '/')}\")\n", + "\n", + " return java_files\n", + "\n", + "github_url = 'https://github.com/gavalian/groot/tree/master/src/main/java/org/jlab/jnp/groot'\n", + "java_files = fetch_java_files(github_url)\n", + "\n", + "for java_file in java_files:\n", + " errors = correct_java_grammar(java_file)\n", + " if errors:\n", + " print(f\"Errors in {java_file}:\")\n", + " for error in errors:\n", + " print(f'Error: {error.message}')\n", + " print(f'Sentence: {error.context}')\n", + " print(f'Rule: {error.ruleId}')\n", + " print()\n" + ], + "id": "vIu0t2qcc3oy" } - ], - "source": [ - "import language_tool_python\n", - "import pprint\n", - "tool = language_tool_python.LanguageTool('en-US') \n", - "\n", - "text = 'A sentence with a error in the Hitchhiker’s Guide tot he Galaxy'\n", - "\n", - "pp = pprint.PrettyPrinter(depth=2)\n", - "errors = tool.check(text)\n", - "pp.pprint(errors)" - ] + ], + "metadata": { + "author": "Rafał Jaworski", + "colab": { + "provenance": [] + }, + "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.7.0" + }, + "subtitle": "15. Korekta gramatyczna", + "title": "Komputerowe wspomaganie tłumaczenia", + "year": "2021" }, - { - "cell_type": "markdown", - "id": "gorgeous-million", - "metadata": {}, - "source": [ - "Przeanalizujmy format zwracanego wyniku. Otrzymujemy listę obiektów Match - zawiadomień o potencjalnym błędzie. Razem z każdym błędem otrzymujemy m.in. identyfikator użytej reguły, opis błędu, rekomendancję poprawy, kontekst." - ] - }, - { - "cell_type": "markdown", - "id": "reasonable-cornwall", - "metadata": {}, - "source": [ - "### Ćwiczenie 1: Użyj LanguageTool do znalezienia jak największej liczby prawdziwych błędów na swoim ulubionym portalu internetowym. Skorzystaj z poznanych wcześniej technik web scrapingu. Uwaga - LanguageTool najprawdopodobniej oznaczy nazwy własne jako literówki - ten typ błędu nie powinien być brany pod uwagę." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "sound-teaching", - "metadata": {}, - "outputs": [], - "source": [ - "def find_errors(website_url):\n", - " return []" - ] - }, - { - "cell_type": "markdown", - "id": "coupled-extra", - "metadata": {}, - "source": [ - "### Ćwiczenie 2: Napisz skrypt, który poszuka błędów w komentarzach klasy Javowej (zwykłych // oraz w javadocach). Uruchom ten skrypt na źródłach wybranego opensourcowego projektu w Javie." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "settled-armor", - "metadata": {}, - "outputs": [], - "source": [ - "def correct_java_grammar(java_file_path):\n", - " return []" - ] - } - ], - "metadata": { - "author": "Rafał Jaworski", - "email": "rjawor@amu.edu.pl", - "kernelspec": { - "display_name": "Python 3", - "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.8.10" - }, - "subtitle": "15. Korekta gramatyczna", - "title": "Komputerowe wspomaganie tłumaczenia", - "year": "2021" - }, - "nbformat": 4, - "nbformat_minor": 5 -} + "nbformat": 4, + "nbformat_minor": 5 +} \ No newline at end of file