Compare commits

..

3 Commits
main ... main

Author SHA1 Message Date
8685bbb277 Upload files to "lab" 2024-05-25 14:53:24 +02:00
9cc45ec99e Upload files to "lab" 2024-04-23 11:15:21 +02:00
9a804fe3dd Upload files to "lab" 2024-04-16 13:36:13 +02:00
11 changed files with 10192 additions and 444 deletions

View File

@ -213,13 +213,34 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 7, "execution_count": 13,
"id": "protected-rings", "id": "protected-rings",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def tm_lookup(sentence):\n", "def tm_lookup(sentence):\n",
" return ''" " return [entry[1].casefold() for entry in translation_memory if entry[0] == sentence]"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "99d75100-0f9d-4586-82ef-ab42180472a2",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['press the enter button', 'press the enter key']"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tm_lookup('Wciśnij przycisk Enter')"
] ]
}, },
{ {
@ -232,17 +253,17 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 18, "execution_count": 15,
"id": "severe-alloy", "id": "severe-alloy",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"''" "[]"
] ]
}, },
"execution_count": 18, "execution_count": 15,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -261,13 +282,17 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 11, "execution_count": 16,
"id": "structural-diesel", "id": "structural-diesel",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"import string \n",
"\n",
"def tm_lookup(sentence):\n", "def tm_lookup(sentence):\n",
" return ''" " return [entry[1].casefold() for entry in translation_memory if entry[0] == sentence]\n",
" translator = str.maketrans('', '', string.punctuation) \n",
" return sentence.translate(translator)"
] ]
}, },
{ {
@ -280,17 +305,17 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 12, "execution_count": 20,
"id": "brief-senegal", "id": "brief-senegal",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"''" "[]"
] ]
}, },
"execution_count": 12, "execution_count": 20,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -317,15 +342,41 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 14, "execution_count": 24,
"id": "mathematical-customs", "id": "mathematical-customs",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def tm_lookup(sentence):\n", "def tm_lookup(sentence):\n",
" translator = str.maketrans('', '', string.punctuation)\n",
" sentence = sentence.translate(translator).casefold()\n",
" for entry in translation_memory:\n",
" if any(word in entry[0].casefold() for word in sentence.split()):\n",
" return entry[1]\n",
" return ''" " return ''"
] ]
}, },
{
"cell_type": "code",
"execution_count": 25,
"id": "f6537825-62a6-4503-91a5-bbb17d84170b",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'System restart required'"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tm_lookup('Wymagane ponowne uruchomienie maszyny')"
]
},
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "meaningful-virus", "id": "meaningful-virus",
@ -344,7 +395,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 15, "execution_count": 26,
"id": "humanitarian-wrong", "id": "humanitarian-wrong",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -362,7 +413,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 16, "execution_count": 27,
"id": "located-perception", "id": "located-perception",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -374,7 +425,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 17, "execution_count": 28,
"id": "advised-casting", "id": "advised-casting",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -384,7 +435,7 @@
"[('przycisk', 'button'), ('drukarka', 'printer')]" "[('przycisk', 'button'), ('drukarka', 'printer')]"
] ]
}, },
"execution_count": 17, "execution_count": 28,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -419,13 +470,35 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 19, "execution_count": 37,
"id": "original-tunisia", "id": "original-tunisia",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def glossary_lookup(sentence):\n", "def glossary_lookup(sentence):\n",
" return ''" " sentence_words = sentence.casefold().split()\n",
" return [entry for entry in glossary if entry[0] in sentence_words]"
]
},
{
"cell_type": "code",
"execution_count": 39,
"id": "b3ae5504-4168-4fe0-ad25-60558242a31d",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[('przycisk', 'button'), ('drukarka', 'printer')]"
]
},
"execution_count": 39,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"glossary_lookup('Każda Drukarka posiada przycisk wznowienia drukowania')"
] ]
}, },
{ {
@ -438,7 +511,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 20, "execution_count": 38,
"id": "adolescent-semiconductor", "id": "adolescent-semiconductor",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -452,7 +525,7 @@
"author": "Rafał Jaworski", "author": "Rafał Jaworski",
"email": "rjawor@amu.edu.pl", "email": "rjawor@amu.edu.pl",
"kernelspec": { "kernelspec": {
"display_name": "Python 3", "display_name": "Python 3 (ipykernel)",
"language": "python", "language": "python",
"name": "python3" "name": "python3"
}, },
@ -467,7 +540,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.8.10" "version": "3.10.12"
}, },
"subtitle": "1. Podstawowe techniki wspomagania tłumaczenia", "subtitle": "1. Podstawowe techniki wspomagania tłumaczenia",
"title": "Komputerowe wspomaganie tłumaczenia", "title": "Komputerowe wspomaganie tłumaczenia",

View File

@ -57,7 +57,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 1, "execution_count": 31,
"id": "confident-prison", "id": "confident-prison",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -80,13 +80,49 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 2, "execution_count": 29,
"id": "continental-submission", "id": "continental-submission",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def ice_lookup(sentence, prev_sentence, next_sentence):\n", "def ice_lookup(sentence, prev_sentence, next_sentence, translation_memory):\n",
" return []" " \n",
" ice_previous = \"\"\n",
" ice_next = \"\"\n",
" \n",
" for original, translation in translation_memory:\n",
" if sentence == original:\n",
" index = translation_memory.index((original, translation))\n",
" if index > 0:\n",
" ice_previous = translation_memory[index - 1][1]\n",
" if index < len(translation_memory) - 1:\n",
" ice_next = translation_memory[index + 1][1]\n",
" break\n",
" \n",
" return (ice_previous, ice_next)"
]
},
{
"cell_type": "code",
"execution_count": 35,
"id": "f125ddd2-89fc-4496-93d9-9d640b7f616e",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"prev: Press the ENTER button , next: The printer is switched off\n"
]
}
],
"source": [
"sentence = \"Sprawdź ustawienia sieciowe\"\n",
"prev_sentence = \"Wciśnij przycisk Enter\"\n",
"next_sentence = \"Wymagane ponowne uruchomienie komputera\"\n",
"\n",
"ice_result = ice_lookup(sentence, prev_sentence, next_sentence, translation_memory)\n",
"print('prev: ', ice_result[0], ', next: ', ice_result[1])"
] ]
}, },
{ {
@ -119,7 +155,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 36,
"id": "fourth-pillow", "id": "fourth-pillow",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -141,7 +177,7 @@
"id": "graduate-theorem", "id": "graduate-theorem",
"metadata": {}, "metadata": {},
"source": [ "source": [
"Odpowiedź:" "Odpowiedź: Funkcja nie jest dobrą funkcją dystansu, gdyż bierze pod uwagaę jedynie różnice w długości zdań."
] ]
}, },
{ {
@ -154,7 +190,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 56,
"id": "continued-christopher", "id": "continued-christopher",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -179,7 +215,7 @@
"id": "metallic-leave", "id": "metallic-leave",
"metadata": {}, "metadata": {},
"source": [ "source": [
"Odpowiedź:" "Odpowiedź: Nie jest to dobra funkcja dystansu, gdyż znajduje jedynie fakt, że zdania się mogą między sobą różnić."
] ]
}, },
{ {
@ -206,7 +242,7 @@
"id": "bibliographic-stopping", "id": "bibliographic-stopping",
"metadata": {}, "metadata": {},
"source": [ "source": [
"Odpowiedź:" "Odpowiedź: Dystans Lavenshteina jest poprawną funkcją dystansu, opisuje ilość operacji, które należy wykonać, aby porównywane do siebie zdania były takie same (np. zamiana liter, wstawienie innej litery, usunięcie litery, itp)"
] ]
}, },
{ {
@ -223,7 +259,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 5, "execution_count": 62,
"id": "secondary-wrist", "id": "secondary-wrist",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -233,7 +269,7 @@
"2" "2"
] ]
}, },
"execution_count": 5, "execution_count": 62,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -254,7 +290,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 6, "execution_count": 63,
"id": "associate-tuner", "id": "associate-tuner",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -273,7 +309,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 7, "execution_count": 64,
"id": "focal-pathology", "id": "focal-pathology",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -283,7 +319,7 @@
"0.9166666666666666" "0.9166666666666666"
] ]
}, },
"execution_count": 7, "execution_count": 64,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -294,7 +330,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 8, "execution_count": 65,
"id": "roman-ceiling", "id": "roman-ceiling",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -304,7 +340,7 @@
"0.9428571428571428" "0.9428571428571428"
] ]
}, },
"execution_count": 8, "execution_count": 65,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -315,7 +351,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 9, "execution_count": 66,
"id": "invisible-cambodia", "id": "invisible-cambodia",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -325,7 +361,7 @@
"0.631578947368421" "0.631578947368421"
] ]
}, },
"execution_count": 9, "execution_count": 66,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -344,13 +380,43 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 10, "execution_count": 71,
"id": "genetic-cradle", "id": "genetic-cradle",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def fuzzy_lookup(sentence, threshold):\n", "import difflib\n",
" return []" "\n",
"def fuzzy_lookup(sentence, threshold, translation_memory):\n",
" fuzzy_matches = []\n",
" for original, translation in translation_memory:\n",
" similarity = difflib.SequenceMatcher(None, sentence, original).ratio()\n",
" if similarity >= threshold:\n",
" fuzzy_matches.append((original, translation, similarity))\n",
" return fuzzy_matches"
]
},
{
"cell_type": "code",
"execution_count": 80,
"id": "6bebcb12-8c73-4beb-b4c2-00553d3b375f",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[('Wciśnij przycisk Enter', 'Press the ENTER button', 0.8636363636363636)]"
]
},
"execution_count": 80,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sentence = 'Wcisnij pszycisk ęnter'\n",
"threshold = 0.8\n",
"fuzzy_lookup(sentence, threshold, translation_memory)"
] ]
} }
], ],
@ -358,7 +424,7 @@
"author": "Rafał Jaworski", "author": "Rafał Jaworski",
"email": "rjawor@amu.edu.pl", "email": "rjawor@amu.edu.pl",
"kernelspec": { "kernelspec": {
"display_name": "Python 3", "display_name": "Python 3 (ipykernel)",
"language": "python", "language": "python",
"name": "python3" "name": "python3"
}, },
@ -373,7 +439,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.8.10" "version": "3.10.12"
}, },
"subtitle": "2. Zaawansowane użycie pamięci tłumaczeń", "subtitle": "2. Zaawansowane użycie pamięci tłumaczeń",
"title": "Komputerowe wspomaganie tłumaczenia", "title": "Komputerowe wspomaganie tłumaczenia",

View File

@ -63,7 +63,7 @@
"id": "diverse-sunglasses", "id": "diverse-sunglasses",
"metadata": {}, "metadata": {},
"source": [ "source": [
"Odpowiedź:" "Odpowiedź: metal cabinets guides. Proz.com"
] ]
}, },
{ {
@ -128,13 +128,41 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 7,
"id": "cognitive-cedar", "id": "cognitive-cedar",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def terminology_lookup():\n", "import re\n",
" return []" "\n",
"def terminology_lookup(text, dictionary):\n",
" pattern = re.compile(r'\\b(?:' + '|'.join(dictionary) + r')\\b', re.IGNORECASE)\n",
" matches = pattern.finditer(text)\n",
" occurance = ''\n",
" for match in matches:\n",
" occurance += (f\"({match.start()}, {match.end()})\")\n",
" return occurance"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "5781b95b-3af9-4c82-8388-b98a11e6c343",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'(80, 91)(164, 175)(468, 475)(516, 523)(533, 540)'"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"terminology_lookup(text, dictionary)"
] ]
}, },
{ {
@ -161,7 +189,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 12,
"id": "tribal-attention", "id": "tribal-attention",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -205,7 +233,7 @@
"IDE\n", "IDE\n",
",\n", ",\n",
"see\n", "see\n",
"Running\n", "run\n",
"Tutorial\n", "Tutorial\n",
"Examples\n", "Examples\n",
"in\n", "in\n",
@ -218,7 +246,7 @@
"work\n", "work\n",
"for\n", "for\n",
"all\n", "all\n",
"swing\n", "Swing\n",
"program\n", "program\n",
"—\n", "—\n",
"applet\n", "applet\n",
@ -232,7 +260,7 @@
"be\n", "be\n",
"the\n", "the\n",
"step\n", "step\n",
"-PRON-\n", "you\n",
"need\n", "need\n",
"to\n", "to\n",
"follow\n", "follow\n",
@ -248,7 +276,7 @@
"platform\n", "platform\n",
",\n", ",\n",
"if\n", "if\n",
"-PRON-\n", "you\n",
"have\n", "have\n",
"not\n", "not\n",
"already\n", "already\n",
@ -260,7 +288,7 @@
"program\n", "program\n",
"that\n", "that\n",
"use\n", "use\n",
"Swing\n", "swing\n",
"component\n", "component\n",
".\n", ".\n",
"compile\n", "compile\n",
@ -302,13 +330,31 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 5, "execution_count": 19,
"id": "surgical-demonstration", "id": "surgical-demonstration",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def terminology_lookup():\n", "def terminology_lookup(text, dictionary):\n",
" return []" " nlp = spacy.load(\"en_core_web_sm\")\n",
" doc = nlp(text)\n",
"\n",
" word_forms = set()\n",
" for word in dictionary:\n",
" word_forms.add(word)\n",
" for token in doc:\n",
" if token.text.lower() == word:\n",
" word_forms.add(token.lemma_)\n",
"\n",
" matches = []\n",
" for token in doc:\n",
" if token.text.lower() in word_forms:\n",
" matches.append((token.idx, token.idx + len(token)))\n",
"\n",
" occurrences = ''\n",
" for match in matches:\n",
" occurrences += f\"({match[0]}, {match[1]})\"\n",
" return occurrences"
] ]
}, },
{ {
@ -337,13 +383,59 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 6, "execution_count": 23,
"id": "superb-butterfly", "id": "superb-butterfly",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def get_nouns(text):\n", "def get_nouns(text):\n",
" return []" " nlp = spacy.load(\"en_core_web_sm\")\n",
" doc = nlp(text)\n",
" nouns = [token.text for token in doc if token.pos_ == \"NOUN\"]\n",
" \n",
" return nouns"
]
},
{
"cell_type": "code",
"execution_count": 24,
"id": "8203c3e5-74a6-42c1-add1-e378f09164fd",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['programmers',\n",
" 'section',\n",
" 'Swing',\n",
" 'application',\n",
" 'command',\n",
" 'line',\n",
" 'information',\n",
" 'Swing',\n",
" 'application',\n",
" 'compilation',\n",
" 'instructions',\n",
" 'programs',\n",
" 'applets',\n",
" 'applications',\n",
" 'steps',\n",
" 'release',\n",
" 'platform',\n",
" 'program',\n",
" 'Swing',\n",
" 'components',\n",
" 'program',\n",
" 'program']"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"get_nouns(text)"
] ]
}, },
{ {
@ -356,7 +448,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 7, "execution_count": 25,
"id": "acting-tolerance", "id": "acting-tolerance",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -374,13 +466,29 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 8, "execution_count": 30,
"id": "eight-redhead", "id": "eight-redhead",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def extract_terms(text):\n", "def extract_terms(text):\n",
" return []" " nlp = spacy.load(\"en_core_web_sm\")\n",
" doc = nlp(text)\n",
" \n",
" tally = {}\n",
" \n",
" for token in doc:\n",
" if token.pos_ != \"NOUN\":\n",
" continue\n",
" \n",
" lemma = token.lemma_.lower()\n",
" \n",
" if lemma in tally:\n",
" tally[lemma] += 1\n",
" else:\n",
" tally[lemma] = 1\n",
" \n",
" return tally"
] ]
}, },
{ {
@ -393,13 +501,29 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 9, "execution_count": 32,
"id": "monetary-mambo", "id": "monetary-mambo",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def extract_terms(text):\n", "def extract_terms(text):\n",
" return []" " nlp = spacy.load(\"en_core_web_sm\")\n",
" doc = nlp(text)\n",
" \n",
" tally = {}\n",
" \n",
" for token in doc:\n",
" if token.pos_ not in ['NOUN', 'VERB', 'ADJ']:\n",
" continue\n",
" \n",
" lemma = token.lemma_.lower()\n",
" \n",
" if lemma in tally:\n",
" tally[lemma] += 1\n",
" else:\n",
" tally[lemma] = 1\n",
" \n",
" return tally"
] ]
} }
], ],
@ -407,7 +531,7 @@
"author": "Rafał Jaworski", "author": "Rafał Jaworski",
"email": "rjawor@amu.edu.pl", "email": "rjawor@amu.edu.pl",
"kernelspec": { "kernelspec": {
"display_name": "Python 3", "display_name": "Python 3 (ipykernel)",
"language": "python", "language": "python",
"name": "python3" "name": "python3"
}, },
@ -422,7 +546,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.8.10" "version": "3.10.12"
}, },
"subtitle": "3. Terminologia", "subtitle": "3. Terminologia",
"title": "Komputerowe wspomaganie tłumaczenia", "title": "Komputerowe wspomaganie tłumaczenia",

File diff suppressed because one or more lines are too long

View File

@ -55,13 +55,40 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 1, "execution_count": 2,
"id": "documented-hacker", "id": "documented-hacker",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"import re\n",
"\n",
"def find_tags(text):\n", "def find_tags(text):\n",
" return []" " pattern = re.compile(r'</?\\w+.*?>')\n",
" \n",
" matches = pattern.finditer(text)\n",
" \n",
" results = [(match.group(), match.start(), match.end()) for match in matches]\n",
" return results"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "8d1c8b3a-a3b0-43ca-a6c1-7b3481e58b87",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[('<note>', 0, 6), ('<to>', 6, 10), ('</to>', 14, 19), ('<from>', 19, 25), ('</from>', 29, 36), ('<heading>', 36, 45), ('</heading>', 53, 63), ('<body>', 63, 69), ('</body>', 98, 105), ('</note>', 105, 112)]\n"
]
}
],
"source": [
"tekst = \"<note><to>Tove</to><from>Jani</from><heading>Reminder</heading><body>Don't forget me this weekend!</body></note>\"\n",
"tagi = find_tags(tekst)\n",
"print(tagi)"
] ]
}, },
{ {
@ -74,15 +101,55 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 2, "execution_count": 8,
"id": "unauthorized-study", "id": "unauthorized-study",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def is_translatable(text):\n", "def is_translatable(text):\n",
" if re.search(r'\\b(v?\\d+(\\.\\d+)+)\\b', text):\n",
" return False\n",
" \n",
" if re.search(r'function\\s+\\w+\\s*\\(|if\\s+\\(|\\w+\\s*=\\s*\\w+', text):\n",
" return False\n",
" \n",
" if re.search(r'\\b[A-Z]{2,}\\b', text):\n",
" return False\n",
" \n",
" return True" " return True"
] ]
}, },
{
"cell_type": "code",
"execution_count": 10,
"id": "1051142c-8170-43fc-b55a-0c367bf69e31",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"'This should be translated.': True\n",
"'Version 4.2.1 should not be translated.': False\n",
"'Contact API_KEY for more details.': True\n",
"'if (x == 10) { return x; }': False\n",
"'Welcome to New York City!': True\n"
]
}
],
"source": [
"examples = [\n",
" \"This should be translated.\",\n",
" \"Version 4.2.1 should not be translated.\",\n",
" \"Contact API_KEY for more details.\",\n",
" \"if (x == 10) { return x; }\",\n",
" \"Welcome to New York City!\"\n",
"]\n",
"\n",
"for example in examples:\n",
" print(f\"'{example}': {is_translatable(example)}\")\n"
]
},
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "plastic-crown", "id": "plastic-crown",
@ -93,13 +160,61 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 11,
"id": "beautiful-mathematics", "id": "beautiful-mathematics",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def find_dates(text):\n", "def find_dates(text):\n",
" return []" " \n",
" date_patterns = re.compile(\n",
" r'(?:\\b(\\d{2})[-.](\\d{2})[-.](\\d{4})\\b)|' # DD-MM-YYYY DD.MM.YYYY\n",
" r'(?:\\b(\\d{2})[/](\\d{2})[/](\\d{4})\\b)|' # MM/DD/YYYY\n",
" r'(?:\\b(\\d{4})[/](\\d{2})[/](\\d{2})\\b)|' # YYYY/MM/DD\n",
" r'(?:\\b(\\d{4})[-](\\d{2})[-](\\d{2})\\b)' # YYYY-MM-DD\n",
" )\n",
"\n",
" results = []\n",
" for match in date_patterns.finditer(text):\n",
" groups = match.groups()\n",
" if groups[:3] != (None, None, None):\n",
" day, month, year = groups[:3]\n",
" elif groups[3:6] != (None, None, None):\n",
" month, day, year = groups[3:6]\n",
" elif groups[6:9] != (None, None, None):\n",
" year, month, day = groups[6:9]\n",
" elif groups[9:] != (None, None, None):\n",
" year, month, day = groups[9:]\n",
" \n",
" results.append({\n",
" \"date\": f\"{day.zfill(2)}-{month.zfill(2)}-{year}\",\n",
" \"position\": (match.start(), match.end()),\n",
" \"day\": day,\n",
" \"month\": month,\n",
" \"year\": year\n",
" })\n",
" \n",
" return results"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "48cf2ad7-b34d-4af6-84c8-5d941f2e323c",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[{'date': '21-03-2023', 'position': (20, 30), 'day': '21', 'month': '03', 'year': '2023'}, {'date': '21-03-2023', 'position': (32, 42), 'day': '21', 'month': '03', 'year': '2023'}, {'date': '21-03-2023', 'position': (44, 54), 'day': '21', 'month': '03', 'year': '2023'}, {'date': '21-03-2023', 'position': (56, 66), 'day': '21', 'month': '03', 'year': '2023'}, {'date': '21-03-2023', 'position': (72, 82), 'day': '21', 'month': '03', 'year': '2023'}]\n"
]
}
],
"source": [
"example_text = \"Important dates are 21-03-2023, 03/21/2023, 2023/03/21, 21.03.2023, and 2023-03-21.\"\n",
"found_dates = find_dates(example_text)\n",
"print(found_dates)"
] ]
}, },
{ {
@ -125,13 +240,67 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 23,
"id": "finished-essex", "id": "finished-essex",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def correct_dates(source_segment, target_segment, date_format):\n", "def correct_dates(source_segment, target_segment, date_format):\n",
" return ''" " format_map = {\n",
" \"Europe\": \"{2}-{1}-{0}\", # DD-MM-YYYY\n",
" \"US\": \"{1}/{2}/{0}\", # MM/DD/YYYY\n",
" \"digit-dot\": \"{2}.{1}.{0}\" # DD.MM.YYYY\n",
" }\n",
" \n",
" if date_format not in format_map:\n",
" raise ValueError(\"Błędny format\")\n",
"\n",
" source_dates = find_dates(source_segment)\n",
" target_dates = find_dates(target_segment)\n",
" \n",
" if len(source_dates) != len(target_dates):\n",
" return f\"Liczba dat w segmencie źródłowym ({len(source_dates)}) i tłumaczeniu ({len(target_dates)}) się nie zgadza.\"\n",
"\n",
" new_target_segment = target_segment\n",
" for source, target in zip(source_dates, target_dates):\n",
" if source[\"day\"] != target[\"day\"] or source[\"month\"] != target[\"month\"] or source[\"year\"] != target[\"year\"]:\n",
" return \"Daty się nie zgadzają\"\n",
"\n",
" formatted_date = format_map[date_format].format(target[\"year\"], target[\"month\"].zfill(2), target[\"day\"].zfill(2))\n",
" new_target_segment = new_target_segment[:target[\"position\"][0]] + formatted_date + new_target_segment[target[\"position\"][1]:]\n",
"\n",
" return new_target_segment"
]
},
{
"cell_type": "code",
"execution_count": 28,
"id": "7dfb44fd-297f-41ea-8f46-a647c98341a3",
"metadata": {},
"outputs": [],
"source": [
"source_text = \"The contract starts on 2023-12-21 and ends on 2023-06-21.\"\n",
"target_text = \"Umowa zaczyna się 21.12.2023 i kończy 21.06.2023.\"\n",
"expected_format = \"digit-dot\""
]
},
{
"cell_type": "code",
"execution_count": 29,
"id": "f0922192-bb51-4194-aeea-4c41c5d195a5",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Umowa zaczyna się 21.12.2023 i kończy 21.06.2023.\n"
]
}
],
"source": [
"text = correct_dates(source_text, target_text, expected_format)\n",
"print(text)"
] ]
}, },
{ {
@ -176,13 +345,63 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 5, "execution_count": 32,
"id": "romance-judge", "id": "romance-judge",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def tokenize(text):\n",
" tokens = re.split(r'(\\s+|<[^>]+>)', text)\n",
" return [token for token in tokens if token.strip()]\n",
"\n",
"def transfer_tags(source_segment, target_segment):\n", "def transfer_tags(source_segment, target_segment):\n",
" return ''" " source_tokens = tokenize(source_segment)\n",
" target_tokens = [token for token in tokenize(target_segment) if not re.match(r'<[^>]+>', token)]\n",
"\n",
" source_tags = [(token, i) for i, token in enumerate(source_tokens) if re.match(r'<[^>]+>', token)]\n",
"\n",
" if len(source_tags) > 0:\n",
" target_with_tags = []\n",
" source_word_count = len([token for token in source_tokens if not re.match(r'<[^>]+>', token)])\n",
" target_word_count = len(target_tokens)\n",
" tag_index = 0\n",
" tag_positions = [int(round(tag[1] * target_word_count / source_word_count)) for tag in source_tags]\n",
"\n",
" for i, token in enumerate(target_tokens):\n",
" while tag_index < len(tag_positions) and i == tag_positions[tag_index]:\n",
" target_with_tags.append(source_tags[tag_index][0])\n",
" tag_index += 1\n",
" target_with_tags.append(token)\n",
" \n",
" while tag_index < len(tag_positions):\n",
" target_with_tags.append(source_tags[tag_index][0])\n",
" tag_index += 1\n",
"\n",
" return ' '.join(target_with_tags)\n",
" else:\n",
" return ' '.join(target_tokens)"
]
},
{
"cell_type": "code",
"execution_count": 33,
"id": "c1ebe058-1da6-43a1-8d99-78999aefca17",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"To jest <b> pogrubienie i </b> to jest kursywa. <i> </i>\n"
]
}
],
"source": [
"source_segment = \"This is <b>bold</b> and this is <i>italic</i>.\"\n",
"target_segment = \"To jest pogrubienie i to jest kursywa.\"\n",
"\n",
"result = transfer_tags(source_segment, target_segment)\n",
"print(result)"
] ]
} }
], ],
@ -190,7 +409,7 @@
"author": "Rafał Jaworski", "author": "Rafał Jaworski",
"email": "rjawor@amu.edu.pl", "email": "rjawor@amu.edu.pl",
"kernelspec": { "kernelspec": {
"display_name": "Python 3", "display_name": "Python 3 (ipykernel)",
"language": "python", "language": "python",
"name": "python3" "name": "python3"
}, },
@ -205,7 +424,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.8.10" "version": "3.10.12"
}, },
"subtitle": "6,7. Preprocessing i postprocessing", "subtitle": "6,7. Preprocessing i postprocessing",
"title": "Komputerowe wspomaganie tłumaczenia", "title": "Komputerowe wspomaganie tłumaczenia",

View File

@ -57,13 +57,53 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 1, "execution_count": 18,
"id": "moving-clothing", "id": "moving-clothing",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def calculate_bleu():\n", "import zipfile\n",
" return 0" "from nltk.translate.bleu_score import corpus_bleu\n",
"import io\n",
"\n",
"def calculate_bleu(zip_path):\n",
" references = []\n",
" candidates = []\n",
"\n",
" with zipfile.ZipFile(zip_path, 'r') as z:\n",
" with z.open('EMEA.en-pl.en', 'r') as file_ref, z.open('EMEA.en-pl.pl', 'r') as file_trans:\n",
" ref_buffer = io.TextIOWrapper(file_ref, encoding='utf-8')\n",
" trans_buffer = io.TextIOWrapper(file_trans, encoding='utf-8')\n",
" \n",
" for ref_line, trans_line in zip(ref_buffer, trans_buffer):\n",
" ref_tokens = [ref_line.strip().split()]\n",
" trans_tokens = trans_line.strip().split()\n",
" \n",
" references.append(ref_tokens)\n",
" candidates.append(trans_tokens)\n",
"\n",
" score = corpus_bleu(references, candidates)\n",
" return score"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "b312fc2a-8d95-4eb5-a49f-a8b0707be8bf",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Ocena BLEU: 0.05086746137866238\n"
]
}
],
"source": [
"zip_file_path = 'korpusy/emea.zip'\n",
"bleu_score = calculate_bleu(zip_file_path)\n",
"print(f\"Ocena BLEU: {bleu_score}\")"
] ]
}, },
{ {
@ -76,13 +116,59 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 2, "execution_count": 20,
"id": "lasting-rolling", "id": "lasting-rolling",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def analyze_bleu():\n", "def analyze_bleu(zip_path, start_end_pairs):\n",
" return []" " results = {}\n",
" \n",
" with zipfile.ZipFile(zip_path, 'r') as z:\n",
" with z.open('EMEA.en-pl.en', 'r') as file_ref, z.open('EMEA.en-pl.pl', 'r') as file_trans:\n",
" ref_buffer = io.TextIOWrapper(file_ref, encoding='utf-8')\n",
" trans_buffer = io.TextIOWrapper(file_trans, encoding='utf-8')\n",
" \n",
" references_full = [line.strip().split() for line in ref_buffer]\n",
" candidates_full = [line.strip().split() for line in trans_buffer]\n",
"\n",
" for label, (start, end) in start_end_pairs.items():\n",
"\n",
" references_segment = [references_full[i] for i in range(start, min(end, len(references_full)))]\n",
" candidates_segment = [candidates_full[i] for i in range(start, min(end, len(candidates_full)))]\n",
" \n",
" references_segment = [[ref] for ref in references_segment]\n",
"\n",
" score = corpus_bleu(references_segment, candidates_segment)\n",
" results[label] = score\n",
" \n",
" return results"
]
},
{
"cell_type": "code",
"execution_count": 21,
"id": "8c218410-048d-40fb-b609-9553f8dae28b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Ocena BLEU dla First 100 sentences: 0.03940935286156434\n",
"Ocena BLEU dla Sentences 500-600: 1.9718207266585256e-155\n"
]
}
],
"source": [
"fragments = {\n",
" \"First 100 sentences\": (0, 100),\n",
" \"Sentences 500-600\": (500, 600)\n",
"}\n",
"\n",
"bleu_scores = analyze_bleu(zip_file_path, fragments)\n",
"for label, score in bleu_scores.items():\n",
" print(f\"Ocena BLEU dla {label}: {score}\")\n"
] ]
}, },
{ {
@ -120,13 +206,91 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 36,
"id": "occupied-swing", "id": "occupied-swing",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def calculate_wer():\n", "import jiwer\n",
" return 0" "\n",
"def calculate_wer(zip_path):\n",
" def wer(reference, hypothesis):\n",
" ref_words = reference.split()\n",
" hyp_words = hypothesis.split()\n",
" R = len(ref_words)\n",
" H = len(hyp_words)\n",
" cost_matrix = [[0] * (H + 1) for _ in range(R + 1)]\n",
"\n",
" for i in range(1, R + 1):\n",
" cost_matrix[i][0] = i\n",
" for j in range(1, H + 1):\n",
" cost_matrix[0][j] = j\n",
"\n",
" for i in range(1, R + 1):\n",
" for j in range(1, H + 1):\n",
" substitution_cost = 0 if ref_words[i - 1] == hyp_words[j - 1] else 1\n",
" cost_matrix[i][j] = min(\n",
" cost_matrix[i - 1][j] + 1,\n",
" cost_matrix[i][j - 1] + 1,\n",
" cost_matrix[i - 1][j - 1] + substitution_cost\n",
" )\n",
"\n",
" i, j = R, H\n",
" substitutions = insertions = deletions = correct = 0\n",
" while i > 0 and j > 0:\n",
" if ref_words[i - 1] == hyp_words[j - 1]:\n",
" correct += 1\n",
" i -= 1\n",
" j -= 1\n",
" elif cost_matrix[i][j] == cost_matrix[i - 1][j - 1] + 1:\n",
" substitutions += 1\n",
" i -= 1\n",
" j -= 1\n",
" elif cost_matrix[i][j] == cost_matrix[i][j - 1] + 1:\n",
" insertions += 1\n",
" j -= 1\n",
" else:\n",
" deletions += 1\n",
" i -= 1\n",
"\n",
" N = substitutions + deletions + correct\n",
" WER = (substitutions + deletions + insertions) / N if N > 0 else 0\n",
" return WER\n",
"\n",
" total_wer = 0\n",
" num_sentences = 0\n",
"\n",
" with zipfile.ZipFile(zip_path, 'r') as z:\n",
" with z.open('EMEA.en-pl.en', 'r') as file_ref, z.open('EMEA.en-pl.pl', 'r') as file_trans:\n",
" ref_buffer = io.TextIOWrapper(file_ref, encoding='utf-8')\n",
" trans_buffer = io.TextIOWrapper(file_trans, encoding='utf-8')\n",
"\n",
" for ref_line, hyp_line in zip(ref_buffer, trans_buffer):\n",
" total_wer += wer(ref_line.strip(), hyp_line.strip())\n",
" num_sentences += 1\n",
"\n",
" average_wer = total_wer / num_sentences if num_sentences > 0 else 0\n",
" return average_wer"
]
},
{
"cell_type": "code",
"execution_count": 37,
"id": "ceccd005-714b-4dfb-b210-d13a9c5238c9",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"WER (Word Error Rate): 82.13%\n"
]
}
],
"source": [
"zip_file_path = 'korpusy/emea.zip'\n",
"wer_result = calculate_wer(zip_file_path)\n",
"print(f\"WER (Word Error Rate): {wer_result:.2%}\")"
] ]
}, },
{ {
@ -147,13 +311,48 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 41,
"id": "immediate-element", "id": "immediate-element",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def calculate_levenshtein():\n", "import Levenshtein as lev\n",
" return 0" "\n",
"def calculate_levenshtein(zip_path):\n",
" total_distance = 0\n",
" num_sentences = 0\n",
"\n",
" with zipfile.ZipFile(zip_path, 'r') as z:\n",
" with z.open('EMEA.en-pl.en', 'r') as file_ref, z.open('EMEA.en-pl.pl', 'r') as file_trans:\n",
" ref_buffer = io.TextIOWrapper(file_ref, encoding='utf-8')\n",
" trans_buffer = io.TextIOWrapper(file_trans, encoding='utf-8')\n",
"\n",
" for ref_line, hyp_line in zip(ref_buffer, trans_buffer):\n",
" distance = lev.distance(ref_line.strip(), hyp_line.strip())\n",
" total_distance += distance\n",
" num_sentences += 1\n",
"\n",
" average_distance = total_distance / num_sentences if num_sentences > 0 else 0\n",
" return average_distance"
]
},
{
"cell_type": "code",
"execution_count": 43,
"id": "a4581547-7219-4a8d-913d-e0e4fa4d0914",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Średnia wartość dystancu Levenshteina: 61.29\n"
]
}
],
"source": [
"average_distance = calculate_levenshtein(zip_file_path)\n",
"print(f\"Średnia wartość dystancu Levenshteina: {average_distance:.2f}\")"
] ]
}, },
{ {
@ -177,28 +376,45 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 5, "execution_count": null,
"id": "descending-easter", "id": "c0e3f109-795d-4844-b41d-9e0b570577c5",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def analyze_translations():\n", "from PyDictionary import PyDictionary\n",
" return []" "\n",
"def translate_corpus(zip_path, filename):\n",
" dictionary = PyDictionary()\n",
" translations = {}\n",
"\n",
" with zipfile.ZipFile(zip_path, 'r') as z:\n",
" with z.open(filename, 'r') as file:\n",
" buffer = io.TextIOWrapper(file, encoding='utf-8')\n",
"\n",
" for line in buffer:\n",
" words = line.strip().split()\n",
" for word in words:\n",
" if word not in translations:\n",
" try:\n",
" german_translation = dictionary.translate(word, \"German\")\n",
" translations[word] = german_translation\n",
" except Exception as e:\n",
" print(f\"Error translating {word}: {str(e)}\")\n",
" translations[word] = None\n",
"\n",
" return translations"
] ]
} }
], ],
"metadata": { "metadata": {
"author": "Rafał Jaworski", "author": "Rafał Jaworski",
"email": "rjawor@amu.edu.pl", "email": "rjawor@amu.edu.pl",
"lang": "pl",
"subtitle": "8. Wykorzystanie tłumaczenia automatycznego we wspomaganiu tłumaczenia",
"title": "Komputerowe wspomaganie tłumaczenia",
"year": "2021",
"kernelspec": { "kernelspec": {
"display_name": "Python 3", "display_name": "Python 3 (ipykernel)",
"language": "python", "language": "python",
"name": "python3" "name": "python3"
}, },
"lang": "pl",
"language_info": { "language_info": {
"codemirror_mode": { "codemirror_mode": {
"name": "ipython", "name": "ipython",
@ -209,8 +425,11 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.8.10" "version": "3.10.12"
} },
"subtitle": "8. Wykorzystanie tłumaczenia automatycznego we wspomaganiu tłumaczenia",
"title": "Komputerowe wspomaganie tłumaczenia",
"year": "2021"
}, },
"nbformat": 4, "nbformat": 4,
"nbformat_minor": 5 "nbformat_minor": 5

File diff suppressed because one or more lines are too long

View File

@ -2,7 +2,6 @@
"cells": [ "cells": [
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "expanded-entrance",
"metadata": {}, "metadata": {},
"source": [ "source": [
"# Komputerowe wspomaganie tłumaczenia" "# Komputerowe wspomaganie tłumaczenia"
@ -10,7 +9,6 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "atlantic-greenhouse",
"metadata": {}, "metadata": {},
"source": [ "source": [
"# Zajęcia 11 - urównoleglanie" "# Zajęcia 11 - urównoleglanie"
@ -18,7 +16,6 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "hungarian-davis",
"metadata": {}, "metadata": {},
"source": [ "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." "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", "cell_type": "markdown",
"id": "bronze-removal",
"metadata": {}, "metadata": {},
"source": [ "source": [
"Automatyczne urównoleglanie tekstu składa się z dwóch kroków:\n", "Automatyczne urównoleglanie tekstu składa się z dwóch kroków:\n",
@ -36,7 +32,6 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "junior-works",
"metadata": {}, "metadata": {},
"source": [ "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]\"" "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", "cell_type": "markdown",
"id": "legitimate-corrections",
"metadata": {}, "metadata": {},
"source": [ "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." "### Ć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", "cell_type": "code",
"execution_count": 1, "execution_count": 23,
"id": "german-dispute",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['To ', 'Jest', 'Żywy.przykład', 'Żeby', 'Ładnie ', 'Zademonstrować', 'Segmentację']\n"
]
}
],
"source": [ "source": [
"import regex\n",
"\n",
"def sentence_split(text):\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", "cell_type": "markdown",
"id": "continued-assessment",
"metadata": {}, "metadata": {},
"source": [ "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." "### Ć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", "cell_type": "code",
"execution_count": 3, "execution_count": 19,
"id": "guilty-morocco",
"metadata": {}, "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": [ "source": [
"def sentence_split_enhanced(text):\n", "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", "cell_type": "markdown",
"id": "experimental-recipient",
"metadata": {}, "metadata": {},
"source": [ "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", "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", "cell_type": "markdown",
"id": "australian-hundred",
"metadata": {}, "metadata": {},
"source": [ "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." "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", "cell_type": "markdown",
"id": "russian-chambers",
"metadata": {}, "metadata": {},
"source": [ "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." "### Ć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", "cell_type": "markdown",
"id": "controlled-pacific",
"metadata": {}, "metadata": {},
"source": [ "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." "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", "cell_type": "markdown",
"id": "divided-chain",
"metadata": {}, "metadata": {},
"source": [ "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:" "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", "cell_type": "raw",
"id": "appropriate-timber",
"metadata": {}, "metadata": {},
"source": [ "source": [
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
@ -166,7 +334,6 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "falling-greenhouse",
"metadata": {}, "metadata": {},
"source": [ "source": [
"### Ćwiczenie 4: Napisz konwerter formatu hunaligna na XLIFF." "### Ćwiczenie 4: Napisz konwerter formatu hunaligna na XLIFF."
@ -174,28 +341,61 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": 10,
"id": "remarkable-pillow",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def convert2xliff(hunalign_file_name):\n", "import xml.etree.ElementTree as ET\n",
" return 0" "\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": { "metadata": {
"author": "Rafał Jaworski", "author": "Rafał Jaworski",
"email": "rjawor@amu.edu.pl", "email": "rjawor@amu.edu.pl",
"lang": "pl",
"subtitle": "11. Urównoleglanie",
"title": "Komputerowe wspomaganie tłumaczenia",
"year": "2021",
"kernelspec": { "kernelspec": {
"display_name": "Python 3", "display_name": "Python 3 (ipykernel)",
"language": "python", "language": "python",
"name": "python3" "name": "python3"
}, },
"lang": "pl",
"language_info": { "language_info": {
"codemirror_mode": { "codemirror_mode": {
"name": "ipython", "name": "ipython",
@ -206,8 +406,11 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "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": 4,
"nbformat_minor": 5 "nbformat_minor": 5

View File

@ -2,7 +2,6 @@
"cells": [ "cells": [
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "virtual-accreditation",
"metadata": {}, "metadata": {},
"source": [ "source": [
"![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n", "![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n",
@ -17,7 +16,6 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "featured-afghanistan",
"metadata": {}, "metadata": {},
"source": [ "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." "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", "cell_type": "markdown",
"id": "severe-protein",
"metadata": {}, "metadata": {},
"source": [ "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." "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", "cell_type": "markdown",
"id": "constant-underground",
"metadata": {}, "metadata": {},
"source": [ "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. " "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", "cell_type": "markdown",
"id": "analyzed-lodging",
"metadata": {}, "metadata": {},
"source": [ "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." "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", "cell_type": "markdown",
"id": "incredible-stress",
"metadata": {}, "metadata": {},
"source": [ "source": [
"Zapoznajmy się najpierw z programem typu key logger:" "Zapoznajmy się najpierw z programem typu key logger:"
@ -57,7 +51,6 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "arctic-horror",
"metadata": {}, "metadata": {},
"source": [ "source": [
"`sudo pip3 install keyboard`" "`sudo pip3 install keyboard`"
@ -65,14 +58,30 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": 2,
"id": "broken-workstation", "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": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"import keyboard\n", "import keyboard\n",
"\n", "\n",
"\n",
"def report_key(event):\n", "def report_key(event):\n",
" print(event)\n", " print(event)\n",
"\n", "\n",
@ -82,7 +91,6 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "polish-census",
"metadata": {}, "metadata": {},
"source": [ "source": [
"UWAGA! Aby uruchomić powyższy kod na Linuxie konieczne są uprawnienia administratora (pytanie poza konkursem - dlaczego?)" "UWAGA! Aby uruchomić powyższy kod na Linuxie konieczne są uprawnienia administratora (pytanie poza konkursem - dlaczego?)"
@ -90,15 +98,34 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "incoming-hands",
"metadata": {}, "metadata": {},
"source": [ "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." "### Ć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", "cell_type": "markdown",
"id": "valuable-bearing",
"metadata": {}, "metadata": {},
"source": [ "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." "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", "cell_type": "markdown",
"id": "boxed-maple",
"metadata": {}, "metadata": {},
"source": [ "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ę." "### Ć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", "cell_type": "code",
"execution_count": 1, "execution_count": 6,
"id": "possible-holder",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [
{
"data": {
"text/plain": [
"(150.9090909090909, 30.18181818181818)"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [ "source": [
"def calculate_typing_speed():\n", "from datetime import datetime, timedelta\n",
" return 0" "\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", "cell_type": "markdown",
"id": "ceramic-birth",
"metadata": {}, "metadata": {},
"source": [ "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." "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", "cell_type": "markdown",
"id": "great-cable",
"metadata": {}, "metadata": {},
"source": [ "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." "### Ć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", "cell_type": "code",
"execution_count": 2, "execution_count": 9,
"id": "close-riverside",
"metadata": {}, "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": [ "source": [
"def find_pauses():\n", "from datetime import datetime, timedelta\n",
" return []" "\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": { "metadata": {
"author": "Rafał Jaworski", "author": "Rafał Jaworski",
"email": "rjawor@amu.edu.pl", "email": "rjawor@amu.edu.pl",
"lang": "pl",
"subtitle": "12. Key logging",
"title": "Komputerowe wspomaganie tłumaczenia",
"year": "2021",
"kernelspec": { "kernelspec": {
"display_name": "Python 3", "display_name": "Python 3 (ipykernel)",
"language": "python", "language": "python",
"name": "python3" "name": "python3"
}, },
"lang": "pl",
"language_info": { "language_info": {
"codemirror_mode": { "codemirror_mode": {
"name": "ipython", "name": "ipython",
@ -173,8 +287,11 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "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": 4,
"nbformat_minor": 5 "nbformat_minor": 5

File diff suppressed because one or more lines are too long

View File

@ -2,23 +2,26 @@
"cells": [ "cells": [
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "marine-termination", "metadata": {
"metadata": {}, "id": "marine-termination"
},
"source": [ "source": [
"![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n", "![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", "<div class=\"alert alert-block alert-info\">\n",
"<h1> Komputerowe wspomaganie tłumaczenia </h1>\n", "<h1> Komputerowe wspomaganie tłumaczenia </h1>\n",
"<h2> 15. <i>Korekta gramatyczna</i> [laboratoria]</h2> \n", "<h2> 15. <i>Korekta gramatyczna</i> [laboratoria]</h2>\n",
"<h3>Rafał Jaworski (2021)</h3>\n", "<h3>Rafał Jaworski (2021)</h3>\n",
"</div>\n", "</div>\n",
"\n", "\n",
"![Logo 2](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech2.jpg)" "![Logo 2](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech2.jpg)"
] ],
"id": "marine-termination"
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "featured-afghanistan", "metadata": {
"metadata": {}, "id": "featured-afghanistan"
},
"source": [ "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", "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", "* błędy gramatyczne\n",
@ -27,135 +30,360 @@
"* błędy interpunkcyjne\n", "* błędy interpunkcyjne\n",
"* kolokwializmy\n", "* kolokwializmy\n",
"* redundancja (np. \"tylko i wyłącznie\")" "* redundancja (np. \"tylko i wyłącznie\")"
] ],
"id": "featured-afghanistan"
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "peaceful-kingston", "metadata": {
"metadata": {}, "id": "peaceful-kingston"
},
"source": [ "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." "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", "cell_type": "markdown",
"id": "soviet-highland", "metadata": {
"metadata": {}, "id": "soviet-highland"
},
"source": [ "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." "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", "cell_type": "markdown",
"id": "arbitrary-reconstruction", "metadata": {
"metadata": {}, "id": "arbitrary-reconstruction"
},
"source": [ "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" "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", "cell_type": "markdown",
"id": "piano-satellite", "metadata": {
"metadata": {}, "id": "piano-satellite"
},
"source": [ "source": [
"Czas uruchomić to narzędzie. Skorzystajmy z Pythona." "Czas uruchomić to narzędzie. Skorzystajmy z Pythona."
] ],
"id": "piano-satellite"
}, },
{ {
"cell_type": "raw", "cell_type": "raw",
"id": "academic-crest", "metadata": {
"metadata": {}, "id": "academic-crest"
},
"source": [ "source": [
"pip3 install language_tool_python" "pip3 install language_tool_python"
] ],
}, "id": "academic-crest"
{
"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", "cell_type": "code",
"execution_count": 6, "execution_count": 1,
"id": "relative-anaheim", "metadata": {
"metadata": {}, "colab": {
"base_uri": "https://localhost:8080/"
},
"id": "990ee426-481e-4fa6-8ed0-e5dbb78f7a44",
"outputId": "46c5ddd6-07a1-4d98-d574-d674be2b03bc"
},
"outputs": [ "outputs": [
{ {
"name": "stdout",
"output_type": "stream", "output_type": "stream",
"name": "stdout",
"text": [ "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 Hitchhikers Guide tot he ...', 'offset': 16, 'errorLength': 1, 'category': 'MISC', 'ruleIssueType': 'misspelling', 'sentence': 'A sentence with a error in the Hitchhikers Guide tot he Galaxy'}),\n", "Collecting language_tool_python\n",
" Match({'ruleId': 'TOT_HE', 'message': 'Did you mean “to the”?', 'replacements': ['to the'], 'offsetInContext': 43, 'context': '... with a error in the Hitchhikers Guide tot he Galaxy', 'offset': 50, 'errorLength': 6, 'category': 'TYPOS', 'ruleIssueType': 'misspelling', 'sentence': 'A sentence with a error in the Hitchhikers Guide tot he Galaxy'})]\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 Hitchhikers 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 Hitchhikers 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": [ "source": [
"import language_tool_python\n", "import language_tool_python\n",
"import pprint\n", "import pprint\n",
"tool = language_tool_python.LanguageTool('en-US') \n", "tool = language_tool_python.LanguageTool('en-US')\n",
"\n", "\n",
"text = 'A sentence with a error in the Hitchhikers Guide tot he Galaxy'\n", "text = 'A sentence with a error in the Hitchhikers Guide tot he Galaxy'\n",
"\n", "\n",
"pp = pprint.PrettyPrinter(depth=2)\n", "pp = pprint.PrettyPrinter(depth=2)\n",
"errors = tool.check(text)\n", "errors = tool.check(text)\n",
"pp.pprint(errors)" "pp.pprint(errors)"
] ],
"id": "relative-anaheim"
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "gorgeous-million", "metadata": {
"metadata": {}, "id": "gorgeous-million"
},
"source": [ "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." "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", "cell_type": "markdown",
"id": "reasonable-cornwall", "metadata": {
"metadata": {}, "id": "reasonable-cornwall"
},
"source": [ "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ę." "### Ć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": 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", "cell_type": "code",
"execution_count": 3, "execution_count": 3,
"id": "settled-armor", "metadata": {
"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": [], "outputs": [],
"source": [ "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", "def correct_java_grammar(java_file_path):\n",
" return []" " 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"
} }
], ],
"metadata": { "metadata": {
"author": "Rafał Jaworski", "author": "Rafał Jaworski",
"colab": {
"provenance": []
},
"email": "rjawor@amu.edu.pl", "email": "rjawor@amu.edu.pl",
"kernelspec": { "kernelspec": {
"display_name": "Python 3", "display_name": "Python 3 (ipykernel)",
"language": "python", "language": "python",
"name": "python3" "name": "python3"
}, },
@ -170,7 +398,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.8.10" "version": "3.7.0"
}, },
"subtitle": "15. Korekta gramatyczna", "subtitle": "15. Korekta gramatyczna",
"title": "Komputerowe wspomaganie tłumaczenia", "title": "Komputerowe wspomaganie tłumaczenia",