forked from bfijalkowski/KWT-2024
Upload files to "lab"
This commit is contained in:
parent
9cc45ec99e
commit
8685bbb277
269
lab/lab_11.ipynb
269
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'(?<!\\w)(\\p{Lu}.*?\\.)(?=\\s*\\p{Lu}|\\s*$)'\n",
|
||||
" segments = regex.findall(pattern, text, regex.DOTALL)\n",
|
||||
" segments = [segment.strip() for segment in segments if segment.strip()]\n",
|
||||
" return segments\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"article_content = soup.find('div', {'class': 'news__body'}).get_text()\n",
|
||||
"segments = sentence_split_enhanced(article_content)\n",
|
||||
"\n",
|
||||
"for i, segment in enumerate(segments, 1):\n",
|
||||
" print(segment)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "experimental-recipient",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Po podziale tekstu na segmenty po stronie źródłowej oraz docelowej, możemy przystąpić do kroku drugiego - dopasowania segmentów. Głównym wyzwaniem tego kroku jest fakt, iż po stronie źródłowej może być inna liczba segmentów, niż po stronie docelowej. Takie rozbieżności są bardzo częste, a wynikają między innymi z:\n",
|
||||
@ -95,7 +234,6 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "australian-hundred",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Problemy te rozwiązwyane są na różne sposoby. Najpopularniejszym programem do przeprowadzania urównoleglania jest [Hunalign](https://github.com/danielvarga/hunalign). Wejściem do programu są dwa pliki, zawierające po jednym segmencie w linii. Wyjściem - plik urównoleglony w wewnętrznym formacie hunaligna."
|
||||
@ -103,15 +241,47 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "russian-chambers",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Ćwiczenie 3: Odnajdź dowolną stronę, która jest dostępna w wielu językach. Pobierz z tej strony tekst oryginalny (tylko ze strony głównej) oraz przetłumaczony na dowolny inny język. Przy użyciu Pythona przygotuj pliki dla Hunaligna i uruchom go."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import requests\n",
|
||||
"from bs4 import BeautifulSoup\n",
|
||||
"\n",
|
||||
"def fetch_and_save_text(url, filename):\n",
|
||||
" response = requests.get(url)\n",
|
||||
" response.raise_for_status()\n",
|
||||
" \n",
|
||||
" soup = BeautifulSoup(response.content, 'html.parser')\n",
|
||||
" text = soup.get_text()\n",
|
||||
" \n",
|
||||
" with open(filename, 'w', encoding='utf-8') as file:\n",
|
||||
" file.write(text)\n",
|
||||
"\n",
|
||||
"def create_hunalign_file(file1, file2, output):\n",
|
||||
" with open(file1, 'r', encoding='utf-8') as f1, open(file2, 'r', encoding='utf-8') as f2:\n",
|
||||
" text1 = f1.read().strip().split('\\n')\n",
|
||||
" text2 = f2.read().strip().split('\\n')\n",
|
||||
" \n",
|
||||
" with open(output, 'w', encoding='utf-8') as out:\n",
|
||||
" for line1, line2 in zip(text1, text2):\n",
|
||||
" out.write(f\"{line1}\\n{line2}\\n\")\n",
|
||||
"\n",
|
||||
"fetch_and_save_text('https://wolften.pl/pl/', 'wolften_pl.txt')\n",
|
||||
"fetch_and_save_text('https://wolften.pl/cs/', 'wolften_cs.txt')\n",
|
||||
"\n",
|
||||
"create_hunalign_file('wolften_pl.txt', 'wolften_cs.txt', 'hunalign_format')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "controlled-pacific",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Wyjściem z Hunaligna jest plik w specjalnym formacie Hunaligna. Problem jednak w tym, że niestety nie można go w prosty sposób zaimportować do jakiegokolwiek narzędzia typu CAT. Potrzebna jest konwersja do któregoś z bardziej popularnych formatów, np. XLIFF."
|
||||
@ -119,7 +289,6 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "divided-chain",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"XLIFF jest formatem do przechowywania pamięci tłumaczeń, który opiera się na XML-u. Przykładowy plik XLIFF wygląda następująco:"
|
||||
@ -127,7 +296,6 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "raw",
|
||||
"id": "appropriate-timber",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\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
|
||||
|
183
lab/lab_12.ipynb
183
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
|
||||
|
File diff suppressed because one or more lines are too long
582
lab/lab_15.ipynb
582
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",
|
||||
"<div class=\"alert alert-block alert-info\">\n",
|
||||
"<h1> Komputerowe wspomaganie tłumaczenia </h1>\n",
|
||||
"<h2> 15. <i>Korekta gramatyczna</i> [laboratoria]</h2> \n",
|
||||
"<h3>Rafał Jaworski (2021)</h3>\n",
|
||||
"</div>\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",
|
||||
"<div class=\"alert alert-block alert-info\">\n",
|
||||
"<h1> Komputerowe wspomaganie tłumaczenia </h1>\n",
|
||||
"<h2> 15. <i>Korekta gramatyczna</i> [laboratoria]</h2>\n",
|
||||
"<h3>Rafał Jaworski (2021)</h3>\n",
|
||||
"</div>\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
|
||||
}
|
Loading…
Reference in New Issue
Block a user