Compare commits

...

8 Commits
main ... main

Author SHA1 Message Date
Marek Susniak 73507debe7 Clear commit. 2024-06-15 19:15:54 +02:00
Marek Susniak 81bf450aa6 Laboratorium 13,14,15. 2024-06-15 19:14:48 +02:00
Marek Susniak 1ff5f22caf Laboratorium #12 2024-06-15 16:02:09 +02:00
Marek Susniak 9e978980fd Laboratorium #11. 2024-06-15 13:12:26 +02:00
Marek Susniak 2923d74c1f Lab numer 9 oraz 10. 2024-06-10 22:42:57 +02:00
Marek Susniak e580651f9f Lab vol.2 2024-04-23 23:54:26 +02:00
Marek Susniak 7c845bcf8d Laboratoria 13.04.2024 2024-04-15 21:15:24 +02:00
Marek Susniak 957bd22d58 Laboratoria 13.04.2024 2024-04-15 19:34:20 +02:00
13 changed files with 2783 additions and 1950 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View File

@ -52,7 +52,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 1, "execution_count": 77,
"id": "narrow-romantic", "id": "narrow-romantic",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -71,7 +71,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 2, "execution_count": 78,
"id": "indonesian-electron", "id": "indonesian-electron",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -82,7 +82,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 79,
"id": "compact-trinidad", "id": "compact-trinidad",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -92,7 +92,7 @@
"['Press the ENTER button']" "['Press the ENTER button']"
] ]
}, },
"execution_count": 3, "execution_count": 79,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -119,7 +119,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 80,
"id": "exposed-daniel", "id": "exposed-daniel",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -139,7 +139,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 5, "execution_count": 81,
"id": "serial-velvet", "id": "serial-velvet",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -149,7 +149,7 @@
"['Press the ENTER button', 'Press the ENTER key']" "['Press the ENTER button', 'Press the ENTER key']"
] ]
}, },
"execution_count": 5, "execution_count": 81,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -176,7 +176,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 6, "execution_count": 82,
"id": "every-gibson", "id": "every-gibson",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -186,7 +186,7 @@
"[]" "[]"
] ]
}, },
"execution_count": 6, "execution_count": 82,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -213,13 +213,15 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 7, "execution_count": 83,
"id": "protected-rings", "id": "protected-rings",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def tm_lookup(sentence):\n", "def tm_lookup(sentence):\n",
" return ''" " lowerSentence = sentence.lower()\n",
"\n",
" return [entry[1] for entry in translation_memory if entry[0].lower() == lowerSentence]"
] ]
}, },
{ {
@ -232,17 +234,17 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 18, "execution_count": 84,
"id": "severe-alloy", "id": "60a6c976",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"''" "[]"
] ]
}, },
"execution_count": 18, "execution_count": 84,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -261,13 +263,21 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 11, "execution_count": 85,
"id": "structural-diesel", "id": "structural-diesel",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"import string\n",
"\n",
"def prepare_sentence(sentence):\n",
" translator = str.maketrans('', '', string.punctuation)\n",
"\n",
" return sentence.lower().translate(translator)\n",
"\n",
"def tm_lookup(sentence):\n", "def tm_lookup(sentence):\n",
" return ''" " lowerSentence = prepare_sentence(sentence)\n",
" return [entry[1] for entry in translation_memory if prepare_sentence(entry[0]) == lowerSentence]"
] ]
}, },
{ {
@ -280,17 +290,17 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 12, "execution_count": 86,
"id": "brief-senegal", "id": "brief-senegal",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"''" "[]"
] ]
}, },
"execution_count": 12, "execution_count": 86,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -317,13 +327,43 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 14, "execution_count": 87,
"id": "mathematical-customs", "id": "mathematical-customs",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"import string\n",
"\n",
"def prepare_sentence(sentence):\n",
" translator = str.maketrans('', '', string.punctuation)\n",
"\n",
" return sentence.lower().translate(translator)\n",
"\n",
"def sentence_similar(sentence1, sentence2):\n",
" words1 = sentence1.split()\n",
" words2 = sentence2.split()\n",
" \n",
" min_length = min(len(words1), len(words2))\n",
" \n",
" matched_count = 0\n",
" for i in range(min_length):\n",
" if prepare_sentence(words1[i]) == prepare_sentence(words2[i]):\n",
" matched_count += 1\n",
" \n",
" return {\n",
" \"count\": matched_count,\n",
" \"length\": min_length\n",
" }\n",
"\n",
"def tm_lookup(sentence):\n", "def tm_lookup(sentence):\n",
" return ''" " collection = []\n",
"\n",
" for entry in translation_memory:\n",
" similarity = sentence_similar(sentence, entry[0])\n",
" if similarity[\"length\"] - similarity[\"count\"] <= 1:\n",
" collection.append(entry[1])\n",
"\n",
" return collection\n"
] ]
}, },
{ {
@ -344,7 +384,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 15, "execution_count": 88,
"id": "humanitarian-wrong", "id": "humanitarian-wrong",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -362,7 +402,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 16, "execution_count": 89,
"id": "located-perception", "id": "located-perception",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -374,7 +414,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 17, "execution_count": 90,
"id": "advised-casting", "id": "advised-casting",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -384,7 +424,7 @@
"[('przycisk', 'button'), ('drukarka', 'printer')]" "[('przycisk', 'button'), ('drukarka', 'printer')]"
] ]
}, },
"execution_count": 17, "execution_count": 90,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -406,7 +446,7 @@
"id": "defensive-fifteen", "id": "defensive-fifteen",
"metadata": {}, "metadata": {},
"source": [ "source": [
"Odpowiedź:" "Odpowiedź: Jest to n przeszukiwań po liście m-elementowej co daje złozonosc O(n*m)"
] ]
}, },
{ {
@ -419,13 +459,40 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 19, "execution_count": 91,
"id": "original-tunisia", "id": "original-tunisia",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def prepare_sentence(sentence):\n",
" return sentence.lower()\n",
"\n",
"def glossary_lookup(sentence):\n", "def glossary_lookup(sentence):\n",
" return ''" " sentence_words = sentence.split()\n",
" lowered_words = list(map(prepare_sentence, sentence_words))\n",
"\n",
" return [entry for entry in glossary if prepare_sentence(entry[0]) in lowered_words]"
]
},
{
"cell_type": "code",
"execution_count": 92,
"id": "df948bb3",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[('komputer', 'computer')]"
]
},
"execution_count": 92,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"glossary_lookup(\"Komputer\")"
] ]
}, },
{ {
@ -438,13 +505,44 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 20, "execution_count": 93,
"id": "adolescent-semiconductor", "id": "adolescent-semiconductor",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def prepare_dictionary(sentences):\n",
" dict = {}\n",
"\n",
" for entry in sentences:\n",
" dict[entry[0].lower()] = entry\n",
"\n",
" return dict\n",
"\n",
"glossary_dict = prepare_dictionary(glossary)\n",
"\n",
"def glossary_lookup(sentence):\n", "def glossary_lookup(sentence):\n",
" return ''" " return glossary_dict[sentence.lower()]"
]
},
{
"cell_type": "code",
"execution_count": 94,
"id": "98e9ff56",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"('komputer', 'computer')"
]
},
"execution_count": 94,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"glossary_lookup(\"Komputer\")"
] ]
} }
], ],
@ -467,7 +565,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.8.10" "version": "3.7.9"
}, },
"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": 92,
"id": "confident-prison", "id": "confident-prison",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -80,15 +80,51 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 2, "execution_count": 93,
"id": "continental-submission", "id": "continental-submission",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def ice_lookup(sentence, prev_sentence, next_sentence):\n", "def prepare_dictionary(sentences):\n",
" dict = {}\n",
"\n",
" for entry in sentences:\n",
" dict[entry[0].lower()] = entry\n",
"\n",
" return dict\n",
"\n",
"memory_dict = prepare_dictionary(translation_memory)\n",
"\n",
"def ice_lookup(input, prev_sentence, next_sentence): \n",
" sentence = input.lower()\n",
"\n",
" if prev_sentence.lower() in memory_dict and next_sentence.lower() in memory_dict and sentence in memory_dict:\n",
" return memory_dict[sentence]\n",
"\n",
" return []" " return []"
] ]
}, },
{
"cell_type": "code",
"execution_count": 94,
"id": "bdc1df76",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"('Wciśnij przycisk Enter', 'Press the ENTER button')"
]
},
"execution_count": 94,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ice_lookup(\"Wciśnij przycisk Enter\", \"Sprawdź ustawienia sieciowe\", \"Drukarka jest wyłączona\")"
]
},
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "figured-server", "id": "figured-server",
@ -119,7 +155,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 95,
"id": "fourth-pillow", "id": "fourth-pillow",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -141,7 +177,11 @@
"id": "graduate-theorem", "id": "graduate-theorem",
"metadata": {}, "metadata": {},
"source": [ "source": [
"Odpowiedź:" "Odpowiedź: Nie, nie jest poprawna. Cechy:\n",
"- nieujemna (abs > 0)\n",
"- identyfikacja nie jest spelniona -> moga miec taka sama dlugosc, a byc inne\n",
"- symetryczna - wynik z wartosci bezwglednej\n",
"- nierownosc trojkata nie jest spelniona"
] ]
}, },
{ {
@ -154,7 +194,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 96,
"id": "continued-christopher", "id": "continued-christopher",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -179,7 +219,7 @@
"id": "metallic-leave", "id": "metallic-leave",
"metadata": {}, "metadata": {},
"source": [ "source": [
"Odpowiedź:" "Odpowiedź: z punktu widzenia cech, wszystkie cechy sa spelnione, jednak funkcja sama w sobie jest bezuyteczna poprzez to, ze wartosci sa stale. "
] ]
}, },
{ {
@ -206,7 +246,10 @@
"id": "bibliographic-stopping", "id": "bibliographic-stopping",
"metadata": {}, "metadata": {},
"source": [ "source": [
"Odpowiedź:" "Odpowiedź: Tak, poniewaz spelnia cechy: \n",
"- nieujemnosci - zawsze dodatni lub zero gdy a i b jest rowny sobie\n",
"- symetria - dystans od a i b jest taki sam jak b i a\n",
"- nierownosc trojkata - dystans od ciągu A do C przez B jest zawsze mniejszy lub równy sumie dystansów od A do B i od B do C"
] ]
}, },
{ {
@ -223,7 +266,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 5, "execution_count": 97,
"id": "secondary-wrist", "id": "secondary-wrist",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -233,7 +276,7 @@
"2" "2"
] ]
}, },
"execution_count": 5, "execution_count": 97,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -254,7 +297,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 6, "execution_count": 98,
"id": "associate-tuner", "id": "associate-tuner",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -273,7 +316,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 7, "execution_count": 99,
"id": "focal-pathology", "id": "focal-pathology",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -283,7 +326,7 @@
"0.9166666666666666" "0.9166666666666666"
] ]
}, },
"execution_count": 7, "execution_count": 99,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -294,7 +337,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 8, "execution_count": 100,
"id": "roman-ceiling", "id": "roman-ceiling",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -304,7 +347,7 @@
"0.9428571428571428" "0.9428571428571428"
] ]
}, },
"execution_count": 8, "execution_count": 100,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -315,7 +358,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 9, "execution_count": 101,
"id": "invisible-cambodia", "id": "invisible-cambodia",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -325,7 +368,7 @@
"0.631578947368421" "0.631578947368421"
] ]
}, },
"execution_count": 9, "execution_count": 101,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -344,13 +387,61 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 10, "execution_count": 102,
"id": "genetic-cradle", "id": "genetic-cradle",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def fuzzy_lookup(sentence, threshold):\n", "def fuzzy_lookup(sentence, threshold):\n",
" return []" " col = []\n",
"\n",
" for entry in translation_memory:\n",
" if (levenshtein_similarity(entry[0], sentence)) >= threshold:\n",
" col.append(entry)\n",
" \n",
" return col"
]
},
{
"cell_type": "code",
"execution_count": 103,
"id": "57fb39b9",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[]"
]
},
"execution_count": 103,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"fuzzy_lookup('Spróbuj wyłączyć i włączyć komputer', 0.7)"
]
},
{
"cell_type": "code",
"execution_count": 104,
"id": "94e1b3be",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[('Wciśnij przycisk Enter', 'Press the ENTER button')]"
]
},
"execution_count": 104,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"fuzzy_lookup('Wciśnij przycisk escape', 0.7)"
] ]
} }
], ],
@ -373,7 +464,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.8.10" "version": "3.7.9"
}, },
"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 cabinet guides lub metal cabinet slides. Skorzystalem z dwoch slownikow oraz duzego modelu jezykowego."
] ]
}, },
{ {
@ -86,7 +86,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 1, "execution_count": 102,
"id": "loving-prince", "id": "loving-prince",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -110,12 +110,12 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 2, "execution_count": 103,
"id": "bound-auction", "id": "bound-auction",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"dictionary = ['program', 'application', 'applet' 'compile']" "dictionary = ['program', 'application', 'applet', 'compile']"
] ]
}, },
{ {
@ -128,13 +128,47 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 104,
"id": "cognitive-cedar", "id": "cognitive-cedar",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def terminology_lookup():\n", "import re\n",
" return []" "\n",
"def terminology_lookup(txt, labels):\n",
" results = []\n",
"\n",
" for label in labels:\n",
" results.append((\n",
" label,\n",
" [(m.start(), m.end() - 1) for m in re.finditer(label, txt)]\n",
" ))\n",
"\n",
" return results"
]
},
{
"cell_type": "code",
"execution_count": 105,
"id": "7cc3ad1f",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[('program', [(14, 20), (291, 297), (468, 474), (516, 522), (533, 539)]),\n",
" ('application', [(80, 90), (164, 174), (322, 332)]),\n",
" ('applet', [(302, 307)]),\n",
" ('compile', [(56, 62)])]"
]
},
"execution_count": 105,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"terminology_lookup(text, dictionary)"
] ]
}, },
{ {
@ -161,7 +195,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 106,
"id": "tribal-attention", "id": "tribal-attention",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -169,108 +203,108 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
" \n", " 0\n",
"for\n", "For for 1\n",
"all\n", "all all 5\n",
"Java\n", "Java Java 9\n",
"programmer\n", "programmers programmer 14\n",
":\n", ": : 25\n",
"this\n", "This this 27\n",
"section\n", "section section 32\n",
"explain\n", "explains explain 40\n",
"how\n", "how how 49\n",
"to\n", "to to 53\n",
"compile\n", "compile compile 56\n",
"and\n", "and and 64\n",
"run\n", "run run 68\n",
"a\n", "a a 72\n",
"swing\n", "Swing swing 74\n",
"application\n", "application application 80\n",
"from\n", "from from 92\n",
"the\n", "the the 97\n",
"command\n", "command command 101\n",
"line\n", "line line 109\n",
".\n", ". . 113\n",
"for\n", "For for 115\n",
"information\n", "information information 119\n",
"on\n", "on on 131\n",
"compile\n", "compiling compile 134\n",
"and\n", "and and 144\n",
"run\n", "running run 148\n",
"a\n", "a a 156\n",
"swing\n", "Swing swing 158\n",
"application\n", "application application 164\n",
"use\n", "using use 176\n",
"NetBeans\n", "NetBeans NetBeans 182\n",
"IDE\n", "IDE IDE 191\n",
",\n", ", , 194\n",
"see\n", "see see 196\n",
"Running\n", "Running run 200\n",
"Tutorial\n", "Tutorial Tutorial 208\n",
"Examples\n", "Examples Examples 217\n",
"in\n", "in in 226\n",
"NetBeans\n", "NetBeans NetBeans 229\n",
"IDE\n", "IDE IDE 238\n",
".\n", ". . 241\n",
"the\n", "The the 243\n",
"compilation\n", "compilation compilation 247\n",
"instruction\n", "instructions instruction 259\n",
"work\n", "work work 272\n",
"for\n", "for for 277\n",
"all\n", "all all 281\n",
"swing\n", "Swing Swing 285\n",
"program\n", "programs program 291\n",
"—\n", "— — 300\n",
"applet\n", "applets applet 302\n",
",\n", ", , 309\n",
"as\n", "as as 311\n",
"well\n", "well well 314\n",
"as\n", "as as 319\n",
"application\n", "applications application 322\n",
".\n", ". . 334\n",
"here\n", "Here here 336\n",
"be\n", "are be 341\n",
"the\n", "the the 345\n",
"step\n", "steps step 349\n",
"-PRON-\n", "you you 355\n",
"need\n", "need need 359\n",
"to\n", "to to 364\n",
"follow\n", "follow follow 367\n",
":\n", ": : 373\n",
"install\n", "Install install 375\n",
"the\n", "the the 383\n",
"late\n", "latest late 387\n",
"release\n", "release release 394\n",
"of\n", "of of 402\n",
"the\n", "the the 405\n",
"Java\n", "Java Java 409\n",
"SE\n", "SE SE 414\n",
"platform\n", "platform platform 417\n",
",\n", ", , 425\n",
"if\n", "if if 427\n",
"-PRON-\n", "you you 430\n",
"have\n", "have have 434\n",
"not\n", "n't not 438\n",
"already\n", "already already 442\n",
"do\n", "done do 450\n",
"so\n", "so so 455\n",
".\n", ". . 457\n",
"create\n", "Create create 459\n",
"a\n", "a a 466\n",
"program\n", "program program 468\n",
"that\n", "that that 476\n",
"use\n", "uses use 481\n",
"Swing\n", "Swing swing 486\n",
"component\n", "components component 492\n",
".\n", ". . 502\n",
"compile\n", "Compile compile 504\n",
"the\n", "the the 512\n",
"program\n", "program program 516\n",
".\n", ". . 523\n",
"run\n", "Run run 525\n",
"the\n", "the the 529\n",
"program\n", "program program 533\n",
".\n" ". . 540\n"
] ]
} }
], ],
@ -281,7 +315,7 @@
"doc = nlp(text)\n", "doc = nlp(text)\n",
"\n", "\n",
"for token in doc:\n", "for token in doc:\n",
" print(token.lemma_)" " print(token, token.lemma_, token.idx)"
] ]
}, },
{ {
@ -302,13 +336,50 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 5, "execution_count": 107,
"id": "surgical-demonstration", "id": "surgical-demonstration",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def terminology_lookup():\n", "import spacy\n",
" return []" "nlp = spacy.load(\"en_core_web_sm\")\n",
"\n",
"\n",
"def terminology_lookup(txt, labels):\n",
" result = {};\n",
" doc = nlp(txt)\n",
"\n",
" for token in doc:\n",
" if token.lemma_ in labels: \n",
" if token.lemma_ not in result:\n",
" result[token.lemma_] = []\n",
" result[token.lemma_].append((token.idx, token.idx + len(token)))\n",
"\n",
" return result"
]
},
{
"cell_type": "code",
"execution_count": 108,
"id": "4772c1b1",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'compile': [(56, 63), (134, 143), (504, 511)],\n",
" 'application': [(80, 91), (164, 175), (322, 334)],\n",
" 'program': [(291, 299), (468, 475), (516, 523), (533, 540)],\n",
" 'applet': [(302, 309)]}"
]
},
"execution_count": 108,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"terminology_lookup(text, dictionary)"
] ]
}, },
{ {
@ -337,13 +408,56 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 6, "execution_count": 109,
"id": "superb-butterfly", "id": "superb-butterfly",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def get_nouns(text):\n", "def get_nouns(text):\n",
" return []" " doc = nlp(text)\n",
" return [token.lemma_ for token in doc if token.pos_ == 'NOUN']"
]
},
{
"cell_type": "code",
"execution_count": 110,
"id": "3c916a3e",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['programmer',\n",
" 'section',\n",
" 'swing',\n",
" 'application',\n",
" 'command',\n",
" 'line',\n",
" 'information',\n",
" 'swing',\n",
" 'application',\n",
" 'compilation',\n",
" 'instruction',\n",
" 'program',\n",
" 'applet',\n",
" 'application',\n",
" 'step',\n",
" 'release',\n",
" 'platform',\n",
" 'program',\n",
" 'swing',\n",
" 'component',\n",
" 'program',\n",
" 'program']"
]
},
"execution_count": 110,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"get_nouns(text)"
] ]
}, },
{ {
@ -356,7 +470,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 7, "execution_count": 111,
"id": "acting-tolerance", "id": "acting-tolerance",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -374,13 +488,57 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 8, "execution_count": 112,
"id": "eight-redhead", "id": "eight-redhead",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def count_words(words):\n",
" word_count = {}\n",
" for word in words:\n",
" if word in word_count:\n",
" word_count[word] += 1\n",
" else:\n",
" word_count[word] = 1\n",
" return word_count\n",
"\n",
"def extract_terms(text):\n", "def extract_terms(text):\n",
" return []" " return count_words(get_nouns(text))"
]
},
{
"cell_type": "code",
"execution_count": 113,
"id": "374550d8",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'programmer': 1,\n",
" 'section': 1,\n",
" 'swing': 3,\n",
" 'application': 3,\n",
" 'command': 1,\n",
" 'line': 1,\n",
" 'information': 1,\n",
" 'compilation': 1,\n",
" 'instruction': 1,\n",
" 'program': 4,\n",
" 'applet': 1,\n",
" 'step': 1,\n",
" 'release': 1,\n",
" 'platform': 1,\n",
" 'component': 1}"
]
},
"execution_count": 113,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"extract_terms(text)"
] ]
}, },
{ {
@ -393,13 +551,85 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 9, "execution_count": 114,
"id": "monetary-mambo", "id": "monetary-mambo",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"def get_verbs(text):\n",
" doc = nlp(text)\n",
" return [token.lemma_ for token in doc if token.pos_ == 'VERB']\n",
"\n",
"def get_adjectives(text):\n",
" doc = nlp(text)\n",
" return [token.lemma_ for token in doc if token.pos_ == 'ADJ']\n",
"\n",
"def extract_terms(text):\n", "def extract_terms(text):\n",
" return []" " return {\n",
" \"nouns\": get_nouns(text),\n",
" \"verbs\": get_verbs(text),\n",
" \"adjectives\": get_adjectives(text)\n",
" }"
]
},
{
"cell_type": "code",
"execution_count": 115,
"id": "95494ac9",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'nouns': ['programmer',\n",
" 'section',\n",
" 'swing',\n",
" 'application',\n",
" 'command',\n",
" 'line',\n",
" 'information',\n",
" 'swing',\n",
" 'application',\n",
" 'compilation',\n",
" 'instruction',\n",
" 'program',\n",
" 'applet',\n",
" 'application',\n",
" 'step',\n",
" 'release',\n",
" 'platform',\n",
" 'program',\n",
" 'swing',\n",
" 'component',\n",
" 'program',\n",
" 'program'],\n",
" 'verbs': ['explain',\n",
" 'compile',\n",
" 'run',\n",
" 'compile',\n",
" 'run',\n",
" 'use',\n",
" 'see',\n",
" 'run',\n",
" 'work',\n",
" 'need',\n",
" 'follow',\n",
" 'install',\n",
" 'do',\n",
" 'create',\n",
" 'use',\n",
" 'compile',\n",
" 'run'],\n",
" 'adjectives': ['late']}"
]
},
"execution_count": 115,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"extract_terms(text)"
] ]
} }
], ],
@ -422,7 +652,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.8.10" "version": "3.7.9"
}, },
"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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,214 +1,423 @@
{ {
"cells": [ "cells": [
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "expanded-entrance", "id": "expanded-entrance",
"metadata": {}, "metadata": {
"source": [ "id": "expanded-entrance"
"# Komputerowe wspomaganie tłumaczenia" },
] "source": [
"# Komputerowe wspomaganie tłumaczenia"
]
},
{
"cell_type": "markdown",
"id": "atlantic-greenhouse",
"metadata": {
"id": "atlantic-greenhouse"
},
"source": [
"# Zajęcia 11 - urównoleglanie"
]
},
{
"cell_type": "markdown",
"id": "hungarian-davis",
"metadata": {
"id": "hungarian-davis"
},
"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."
]
},
{
"cell_type": "markdown",
"id": "bronze-removal",
"metadata": {
"id": "bronze-removal"
},
"source": [
"Automatyczne urównoleglanie tekstu składa się z dwóch kroków:\n",
"1. Podziału tekstu źródłowego oraz docelowego na zdania.\n",
"2. Dopasowaniu zdań źródłowych do docelowych."
]
},
{
"cell_type": "markdown",
"id": "junior-works",
"metadata": {
"id": "junior-works"
},
"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]\""
]
},
{
"cell_type": "markdown",
"id": "legitimate-corrections",
"metadata": {
"id": "legitimate-corrections"
},
"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."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "german-dispute",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "german-dispute",
"outputId": "740c001c-1646-4464-9314-b0327fe927f7"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"['To', 'Jest', 'Przykładowy', 'Ź', 'Ź', 'Ź', 'Tekst', 'Wielkimi', 'Literami', 'Na', 'Początku', 'Segmentów', 'Ź', 'Ź', 'Ź']\n"
]
}
],
"source": [
"import regex as re\n",
"\n",
"def sentence_split(text):\n",
" pattern = r'(?<!^)(?=\\p{Lu})'\n",
" regex = re.compile(pattern, re.UNICODE)\n",
" return regex.split(text)\n",
"\n",
"text = \"ToJestPrzykładowyŹŹŹTekstWielkimiLiteramiNaPoczątkuSegmentówŹŹŹ\"\n",
"print(sentence_split(text))"
]
},
{
"cell_type": "markdown",
"id": "continued-assessment",
"metadata": {
"id": "continued-assessment"
},
"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."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "guilty-morocco",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "guilty-morocco",
"outputId": "ba053e0b-eb0c-4ab6-e955-bea360848bfd"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"['Python (język programowania) ', 'Wikipedia, wolna encyklopedia ', 'Przejdź do zawartości ', 'Menu główne ', 'Menu główne przypnij ukryj ', 'Nawigacja ', 'Strona główna', 'Losuj artykuł', 'Kategorie artykułów', 'Najlepsze artykuły', 'Częste pytania (FA', 'Q) ', 'Dla czytelników ', 'O ', 'Wikipedii', 'Kontakt', 'Wspomóż ', 'Wikipedię ', 'Dla wikipedystów ', 'Pierwsze kroki', 'Portal wikipedystów', 'Ogłoszenia', 'Zasady', 'Pomoc', 'Ostatnie zmiany ', 'Szukaj ', 'Szukaj ', 'Wygląd ', 'Utwórz konto ', 'Zaloguj się ', 'Narzędzia osobiste ', 'Utwórz konto ', 'Zaloguj się ', 'Strony dla anonimowych edytorów dowiedz się więcej ', 'Edycje', 'Dyskusja ', 'Python (język programowania) ', 'Dodaj języki ', 'Treść strony nie jest dostępna w innych językach. ', 'Artykuł', 'Dyskusja polski ', 'Utwórz', 'Utwórz kod źródłowy ', 'Narzędzia ', 'Narzędzia przypnij ukryj ', 'Działania ', 'Utwórz', 'Utwórz kod źródłowy ', 'Ogólne ', 'Linkujące', 'Prześlij plik', 'Strony specjalne', 'Wersja do druku', 'Informacje o tej stronie', 'Zobacz skrócony adres URL', 'Pobierz kod Q', 'R ', 'Wygląd przypnij ukryj ', 'Z ', 'Wikipedii, wolnej encyklopedii ', 'W ', 'Wikipedii nie ma jeszcze artykułu o takiej nazwie. ', 'Możesz: utworzyć go, zaproponować, żeby inni go napisali, poszukać tekstu „', 'Python (język programowania)” w artykułach, poszukać strony o tym tytule na jednym z siostrzanych projektów ', 'Wikipedii: ', 'Commons ', 'Wikiźródła ', 'Wikisłownik ', 'Wikicytaty ', 'Wikibooks ', 'Wikinews ', 'Źródło: „https://pl.wikipedia.org/wiki/', 'Python_(język_programowania)” ', 'Polityka prywatności ', 'O ', 'Wikipedii ', 'Korzystasz z ', 'Wikipedii tylko na własną odpowiedzialność ', 'Powszechne ', 'Zasady ', 'Postępowania ', 'Dla deweloperów ', 'Statystyki ', 'Komunikat na temat ciasteczek ', 'Wersja mobilna']\n"
]
}
],
"source": [
"import requests\n",
"from bs4 import BeautifulSoup\n",
"\n",
"def get_page_text(url):\n",
" page = requests.get(url)\n",
" soup = BeautifulSoup(page.content, 'html.parser')\n",
" for script_or_style in soup(['script', 'style']):\n",
" script_or_style.extract()\n",
" text = soup.get_text()\n",
" text = ' '.join(text.split())\n",
" return text\n",
"\n",
"def sentence_split_enhanced(text):\n",
" segments = sentence_split(text)\n",
" improved_segments = []\n",
" for segment in segments:\n",
" if len(segment) == 1 and segment.isupper():\n",
" if improved_segments:\n",
" improved_segments[-1] += segment\n",
" else:\n",
" improved_segments.append(segment)\n",
" else:\n",
" improved_segments.append(segment)\n",
" return improved_segments\n",
"\n",
"text = get_page_text(\"https://pl.wikipedia.org/wiki/Python_(język_programowania)\")\n",
"print(sentence_split_enhanced(text))"
]
},
{
"cell_type": "markdown",
"id": "experimental-recipient",
"metadata": {
"id": "experimental-recipient"
},
"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",
"* tłumaczenia jednego zdania źródłowego przy użyciu więcej niż jednego zdania\n",
"* tłumaczenia więcej niż jednego zdania źródłowego przy użyciu jednego zdania\n",
"* pominięcia zdania podczas tłumaczenia\n",
"* rozbieżności pomiędzy wersjami tekstu źródłowego i docelowego (np. tekst źródłowy mógł być modyfikowany po przetłumaczeniu i tłumaczenie nie zostało zaktualizowane)\n",
"* przetłumaczenia tekstu źródłowego tylko częściowo"
]
},
{
"cell_type": "markdown",
"id": "australian-hundred",
"metadata": {
"id": "australian-hundred"
},
"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."
]
},
{
"cell_type": "markdown",
"id": "russian-chambers",
"metadata": {
"id": "russian-chambers"
},
"source": [
"### Ćwiczenie 3: Odnajdź dowolną stronę, która jest dostępna w wielu językach. Pobierz z tej strony tekst oryginalny (tylko ze strony głównej) oraz przetłumaczony na dowolny inny język. Przy użyciu Pythona przygotuj pliki dla Hunaligna i uruchom go."
]
},
{
"cell_type": "markdown",
"id": "controlled-pacific",
"metadata": {
"id": "controlled-pacific"
},
"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."
]
},
{
"cell_type": "markdown",
"id": "divided-chain",
"metadata": {
"id": "divided-chain"
},
"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:"
]
},
{
"cell_type": "raw",
"id": "appropriate-timber",
"metadata": {
"id": "appropriate-timber"
},
"source": [
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
"<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n",
" <file datatype=\"plaintext\" original=\"self\" source-language=\"en\" target-language=\"es\">\n",
" <header>\n",
" <sxmd:metadata xmlns:sxmd=\"urn:x-sap:mlt:xliff12:metadata:1.0\" xmlns=\"urn:x-sap:mlt:tsmetadata:1.0\">\n",
" <object-name>sample</object-name>\n",
" <collection>KWT</collection>\n",
" <domain>KWT</domain>\n",
" <developer>123</developer>\n",
" <description>sample XLIFF file</description>\n",
" </sxmd:metadata>\n",
" </header>\n",
" <body>\n",
" <trans-unit>\n",
" <source>Hello world!</source>\n",
" <target>Hola mundo!</target>\n",
" </trans-unit>\n",
" <trans-unit>\n",
" <source>File</source>\n",
" <target>Archivo</target>\n",
" </trans-unit>\n",
" <trans-unit>\n",
" <source>New</source>\n",
" <target>Nuevo</target>\n",
" </trans-unit>\n",
" <trans-unit>\n",
" <source>Exit</source>\n",
" <target>Salir</target>\n",
" </trans-unit>\n",
" </body>\n",
" </file>\n",
"</xliff>"
]
},
{
"cell_type": "code",
"source": [
"import requests\n",
"from bs4 import BeautifulSoup\n",
"\n",
"\n",
"def create_hunaligna_file(text_en, text_pl, output_file):\n",
" sentences_en = text_en.split('. ')\n",
" sentences_pl = text_pl.split('. ')\n",
"\n",
" with open(output_file, \"w\", encoding=\"utf-8\") as f:\n",
" f.write(\"# Sentence pairs\\n\")\n",
" for i, (en, pl) in enumerate(zip(sentences_en, sentences_pl)):\n",
" f.write(f\"{i}\\n\")\n",
" f.write(\"# Source\\n\")\n",
" f.write(f\"{en.strip()}\\n\")\n",
" f.write(\"# Target\\n\")\n",
" f.write(f\"{pl.strip()}\\n\")\n",
"\n",
"def main():\n",
" url_en = \"https://en.wikipedia.org/wiki/Main_Page\"\n",
" url_pl = \"https://pl.wikipedia.org/wiki/Strona_g%C5%82%C3%B3wna\"\n",
"\n",
" text_en = get_page_text(url_pl)\n",
" text_pl = get_page_text(url_en)\n",
"\n",
" with open(\"english.txt\", \"w\", encoding=\"utf-8\") as f_en:\n",
" f_en.write(text_en)\n",
"\n",
" with open(\"polish.txt\", \"w\", encoding=\"utf-8\") as f_pl:\n",
" f_pl.write(text_pl)\n",
"\n",
" create_hunaligna_file(text_en, text_pl, \"hunaligna.txt\")\n",
"\n",
" print(\"Texts have been saved to 'english.txt' and 'polish.txt'\")\n",
" print(\"Hunaligna file has been created as 'hunaligna.txt'\")\n",
"\n",
"main()"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "yJFtZ0FwksXG",
"outputId": "867cfbf2-b2ad-405c-e8d0-19dcdaed82bd"
},
"id": "yJFtZ0FwksXG",
"execution_count": 11,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Texts have been saved to 'english.txt' and 'polish.txt'\n",
"Hunaligna file has been created as 'hunaligna.txt'\n"
]
}
]
},
{
"cell_type": "markdown",
"id": "falling-greenhouse",
"metadata": {
"id": "falling-greenhouse"
},
"source": [
"### Ćwiczenie 4: Napisz konwerter formatu hunaligna na XLIFF."
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "remarkable-pillow",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "remarkable-pillow",
"outputId": "59a072b2-79a0-4a57-8b00-cc704f9d1a7b"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"XLIFF file has been created as 'output.xliff'\n"
]
}
],
"source": [
"import xml.etree.ElementTree as ET\n",
"\n",
"def parse_hunaligna_file(filepath):\n",
" segments = []\n",
" with open(filepath, 'r', encoding='utf-8') as file:\n",
" segment = {}\n",
" for line in file:\n",
" line = line.strip()\n",
" if line.startswith(\"# Source\"):\n",
" segment['source'] = next(file).strip()\n",
" elif line.startswith(\"# Target\"):\n",
" segment['target'] = next(file).strip()\n",
" segments.append(segment)\n",
" segment = {}\n",
" return segments\n",
"\n",
"def create_xliff(segments, source_lang, target_lang, output_file):\n",
" xliff = ET.Element('xliff', version=\"1.2\")\n",
" file_elem = ET.SubElement(xliff, 'file', {\n",
" 'source-language': source_lang,\n",
" 'target-language': target_lang,\n",
" 'datatype': \"plaintext\",\n",
" 'original': \"file.txt\"\n",
" })\n",
" body = ET.SubElement(file_elem, 'body')\n",
"\n",
" for i, segment in enumerate(segments):\n",
" trans_unit = ET.SubElement(body, 'trans-unit', id=str(i))\n",
" source = ET.SubElement(trans_unit, 'source')\n",
" source.text = segment['source']\n",
" target = ET.SubElement(trans_unit, 'target')\n",
" target.text = segment['target']\n",
"\n",
" tree = ET.ElementTree(xliff)\n",
" tree.write(output_file, encoding='UTF-8', xml_declaration=True)\n",
"\n",
"def convert2xliff(hunalign_file_name, xliff_file):\n",
" source_lang = 'en'\n",
" target_lang = 'pl'\n",
"\n",
" segments = parse_hunaligna_file(hunalign_file_name)\n",
" create_xliff(segments, source_lang, target_lang, xliff_file)\n",
" print(f\"XLIFF file has been created as '{xliff_file}'\")\n",
"\n",
"\n",
"convert2xliff('hunaligna.txt', 'output.xliff')"
]
}
],
"metadata": {
"author": "Rafał Jaworski",
"email": "rjawor@amu.edu.pl",
"lang": "pl",
"subtitle": "11. Urównoleglanie",
"title": "Komputerowe wspomaganie tłumaczenia",
"year": "2021",
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.10"
},
"colab": {
"provenance": []
}
}, },
{ "nbformat": 4,
"cell_type": "markdown", "nbformat_minor": 5
"id": "atlantic-greenhouse",
"metadata": {},
"source": [
"# Zajęcia 11 - urównoleglanie"
]
},
{
"cell_type": "markdown",
"id": "hungarian-davis",
"metadata": {},
"source": [
"Na poprzednich zajęciach poznaliśmy techniki pozyskiwania tekstu z Internetu. Jeśli uda nam się w ten sposób pozyskać tekst w jednym języku oraz jego tłumaczenie na inny język, jesteśmy tylko o krok od uzyskania najbardziej przydatnego zasobu z punktu widzenia wspomagania tłumaczenia - pamięci tłumaczeń. Krokiem tym jest automatyczne urównoleglanie tekstu."
]
},
{
"cell_type": "markdown",
"id": "bronze-removal",
"metadata": {},
"source": [
"Automatyczne urównoleglanie tekstu składa się z dwóch kroków:\n",
"1. Podziału tekstu źródłowego oraz docelowego na zdania.\n",
"2. Dopasowaniu zdań źródłowych do docelowych."
]
},
{
"cell_type": "markdown",
"id": "junior-works",
"metadata": {},
"source": [
"Zdania, o których mowa w punkcie 1., powinniśmy rozumieć jako segmenty, tj. niekoniecznie kompletne zdania w sensie gramatycznym. Standardowym sposobem podziału tekstu na segmenty jest dzielenie po znaku nowej linii lub zaraz po kropce, o ile jest ona częścią sekwencji: \".[spacja][Wielka litera]\""
]
},
{
"cell_type": "markdown",
"id": "legitimate-corrections",
"metadata": {},
"source": [
"### Ćwiczenie 1: Zaimplementuj podstawowy algorytm segmentacji tekstu. Użyj odpowiedniego wyrażenia regularnego, łapiącego wielkie litery w dowolnym języku, np. \"Ż\" (użyj klasy unikodowej). Zwróć listę segmentów."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "german-dispute",
"metadata": {},
"outputs": [],
"source": [
"def sentence_split(text):\n",
" return []"
]
},
{
"cell_type": "markdown",
"id": "continued-assessment",
"metadata": {},
"source": [
"### Ćwiczenie 2: Uruchom powyższy algorytm na treści wybranej przez siebie strony internetowej (do ściągnięcia treści strony wykorzystaj kod z laboratoriów nr 7). Zidentyfikuj co najmniej dwa wyjątki od ogólnej reguły podziału na segmenty i ulepsz algorytm."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "guilty-morocco",
"metadata": {},
"outputs": [],
"source": [
"def sentence_split_enhanced(text):\n",
" return []"
]
},
{
"cell_type": "markdown",
"id": "experimental-recipient",
"metadata": {},
"source": [
"Po podziale tekstu na segmenty po stronie źródłowej oraz docelowej, możemy przystąpić do kroku drugiego - dopasowania segmentów. Głównym wyzwaniem tego kroku jest fakt, iż po stronie źródłowej może być inna liczba segmentów, niż po stronie docelowej. Takie rozbieżności są bardzo częste, a wynikają między innymi z:\n",
"* tłumaczenia jednego zdania źródłowego przy użyciu więcej niż jednego zdania\n",
"* tłumaczenia więcej niż jednego zdania źródłowego przy użyciu jednego zdania\n",
"* pominięcia zdania podczas tłumaczenia\n",
"* rozbieżności pomiędzy wersjami tekstu źródłowego i docelowego (np. tekst źródłowy mógł być modyfikowany po przetłumaczeniu i tłumaczenie nie zostało zaktualizowane)\n",
"* przetłumaczenia tekstu źródłowego tylko częściowo"
]
},
{
"cell_type": "markdown",
"id": "australian-hundred",
"metadata": {},
"source": [
"Problemy te rozwiązwyane są na różne sposoby. Najpopularniejszym programem do przeprowadzania urównoleglania jest [Hunalign](https://github.com/danielvarga/hunalign). Wejściem do programu są dwa pliki, zawierające po jednym segmencie w linii. Wyjściem - plik urównoleglony w wewnętrznym formacie hunaligna."
]
},
{
"cell_type": "markdown",
"id": "russian-chambers",
"metadata": {},
"source": [
"### Ćwiczenie 3: Odnajdź dowolną stronę, która jest dostępna w wielu językach. Pobierz z tej strony tekst oryginalny (tylko ze strony głównej) oraz przetłumaczony na dowolny inny język. Przy użyciu Pythona przygotuj pliki dla Hunaligna i uruchom go."
]
},
{
"cell_type": "markdown",
"id": "controlled-pacific",
"metadata": {},
"source": [
"Wyjściem z Hunaligna jest plik w specjalnym formacie Hunaligna. Problem jednak w tym, że niestety nie można go w prosty sposób zaimportować do jakiegokolwiek narzędzia typu CAT. Potrzebna jest konwersja do któregoś z bardziej popularnych formatów, np. XLIFF."
]
},
{
"cell_type": "markdown",
"id": "divided-chain",
"metadata": {},
"source": [
"XLIFF jest formatem do przechowywania pamięci tłumaczeń, który opiera się na XML-u. Przykładowy plik XLIFF wygląda następująco:"
]
},
{
"cell_type": "raw",
"id": "appropriate-timber",
"metadata": {},
"source": [
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
"<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n",
" <file datatype=\"plaintext\" original=\"self\" source-language=\"en\" target-language=\"es\">\n",
" <header>\n",
" <sxmd:metadata xmlns:sxmd=\"urn:x-sap:mlt:xliff12:metadata:1.0\" xmlns=\"urn:x-sap:mlt:tsmetadata:1.0\">\n",
" <object-name>sample</object-name>\n",
" <collection>KWT</collection>\n",
" <domain>KWT</domain>\n",
" <developer>123</developer>\n",
" <description>sample XLIFF file</description>\n",
" </sxmd:metadata>\n",
" </header>\n",
" <body>\n",
" <trans-unit>\n",
" <source>Hello world!</source>\n",
" <target>Hola mundo!</target>\n",
" </trans-unit>\n",
" <trans-unit>\n",
" <source>File</source>\n",
" <target>Archivo</target>\n",
" </trans-unit>\n",
" <trans-unit>\n",
" <source>New</source>\n",
" <target>Nuevo</target>\n",
" </trans-unit>\n",
" <trans-unit>\n",
" <source>Exit</source>\n",
" <target>Salir</target>\n",
" </trans-unit>\n",
" </body>\n",
" </file>\n",
"</xliff>"
]
},
{
"cell_type": "markdown",
"id": "falling-greenhouse",
"metadata": {},
"source": [
"### Ćwiczenie 4: Napisz konwerter formatu hunaligna na XLIFF."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "remarkable-pillow",
"metadata": {},
"outputs": [],
"source": [
"def convert2xliff(hunalign_file_name):\n",
" return 0"
]
}
],
"metadata": {
"author": "Rafał Jaworski",
"email": "rjawor@amu.edu.pl",
"lang": "pl",
"subtitle": "11. Urównoleglanie",
"title": "Komputerowe wspomaganie tłumaczenia",
"year": "2021",
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
} }

View File

@ -1,181 +1,340 @@
{ {
"cells": [ "cells": [
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "virtual-accreditation", "id": "virtual-accreditation",
"metadata": {}, "metadata": {
"source": [ "id": "virtual-accreditation"
"![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", "source": [
"<h1> Komputerowe wspomaganie tłumaczenia </h1>\n", "![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n",
"<h2> 12. <i>Key logging</i> [laboratoria]</h2> \n", "<div class=\"alert alert-block alert-info\">\n",
"<h3>Rafał Jaworski (2021)</h3>\n", "<h1> Komputerowe wspomaganie tłumaczenia </h1>\n",
"</div>\n", "<h2> 12. <i>Key logging</i> [laboratoria]</h2>\n",
"\n", "<h3>Rafał Jaworski (2021)</h3>\n",
"![Logo 2](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech2.jpg)" "</div>\n",
] "\n",
"![Logo 2](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech2.jpg)"
]
},
{
"cell_type": "markdown",
"id": "featured-afghanistan",
"metadata": {
"id": "featured-afghanistan"
},
"source": [
"Badania nad komputerowym wspomaganiem tłumaczenia często prowadzone są przy użyciu metodologii testowania interfejsów użytkownika - UI/UX testing. Program typu CAT traktuje się wówczas jak każdy inny program komputerowy i przeprowadza testy wydajności i użyteczności."
]
},
{
"cell_type": "markdown",
"id": "severe-protein",
"metadata": {
"id": "severe-protein"
},
"source": [
"Testy takie prowadzone są zawsze na użytkownikach końcowych, w tym przypadku - na tłumaczach. Podstawowym celem testów jest próba zaobserwowania faktycznego sposobu pracy tłumacza - które funkcje programu są przez niego wykorzystywane najczęściej, jakich innych narzędzi poza CAT-em używa on do swojej pracy, które funkcje programu działają zgodnie, a które niezgodnie z intuicją użytkownika oraz wiele innych czynników. Aby wszystkie te analizy były możliwe, konieczne jest zgromadzenie jak największej ilości danych dotyczących przebiegu testu."
]
},
{
"cell_type": "markdown",
"id": "constant-underground",
"metadata": {
"id": "constant-underground"
},
"source": [
"Testy są przede wszystkim nagrywane. Nagrywany jest zarówno ekran komputera (screen capture), jak i sam użytkownik pracujący przy komputerze. To jednak nie wszystko - często stosuje się specjalne techniki eye-trackingu, które są w stanie określić, w który punk ekranu użytkownik aktualnie patrzy. Dane pozyskane w ten sposób używane są do analizy czasu znalezienia przez użytkownika potrzebnej mu funkcji oraz zidentyfikowania miejsc, gdzie tej funkcji poszukiwał. Można również wyznaczyć obszary ekranu, które często skupiają uwagę użytkownika."
]
},
{
"cell_type": "markdown",
"id": "analyzed-lodging",
"metadata": {
"id": "analyzed-lodging"
},
"source": [
"Dodatkowo stosuje się jeszcze jedną technikę, która jest szczególnie przydatna z punktu widzenia analizy procesu tłumaczenia. Wykonuje się pełny key logging, tj. zapisuje się każde uderzenie użytkownika w dowolny klawisz na klawiaturze wraz z precyzyjnym czasem tego uderzenia. Dane pozyskane w ten sposób pozwalają na przeprowadzenie szeregu interesujących analiz."
]
},
{
"cell_type": "markdown",
"id": "incredible-stress",
"metadata": {
"id": "incredible-stress"
},
"source": [
"Zapoznajmy się najpierw z programem typu key logger:"
]
},
{
"cell_type": "markdown",
"id": "arctic-horror",
"metadata": {
"id": "arctic-horror"
},
"source": [
"`sudo pip3 install keyboard`"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "broken-workstation",
"metadata": {
"id": "broken-workstation"
},
"outputs": [],
"source": [
"!pip install keyboard\n",
"\n",
"import keyboard\n",
"\n",
"\n",
"def report_key(event):\n",
" print(event)\n",
"\n",
"keyboard.on_release(callback=report_key)\n",
"keyboard.wait()"
]
},
{
"cell_type": "markdown",
"id": "polish-census",
"metadata": {
"id": "polish-census"
},
"source": [
"UWAGA! Aby uruchomić powyższy kod na Linuxie konieczne są uprawnienia administratora (pytanie poza konkursem - dlaczego?)"
]
},
{
"cell_type": "markdown",
"id": "incoming-hands",
"metadata": {
"id": "incoming-hands"
},
"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.\n"
]
},
{
"cell_type": "code",
"source": [
"import keyboard\n",
"import datetime\n",
"\n",
"# Funkcja zapisu do pliku\n",
"def log_key(event):\n",
" with open(\"key_log.txt\", \"a\") as log_file:\n",
" log_file.write(f\"{datetime.datetime.now()}: {event.name}\\n\")\n",
"\n",
"keyboard.on_release(callback=log_key)\n",
"keyboard.wait()"
],
"metadata": {
"id": "CjzM4sFTGIfJ"
},
"id": "CjzM4sFTGIfJ",
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"id": "valuable-bearing",
"metadata": {
"id": "valuable-bearing"
},
"source": [
"Celem powyższego ćwiczenia jest pozyskanie danych testowych. Dalsze analizy będziemy prowadzili już bez key loggera, starając się korzystać jedynie z danych zapisanych w pliku. Oczywiście, jeśli zajdzie taka konieczność, można w każdej chwili wygenerować sobie nowy plik."
]
},
{
"cell_type": "markdown",
"id": "boxed-maple",
"metadata": {
"id": "boxed-maple"
},
"source": [
"### Ćwiczenie 2: Napisz program, który wyliczy średnią prędkość pisania. Wykryj, kiedy użytkownik zaczął pisać. Nie bierz pod uwagę przerw dłuższych niż 5 sekund. Podaj prędkość pisania w znakach na minutę oraz słowach na minutę."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "possible-holder",
"metadata": {
"id": "possible-holder"
},
"outputs": [],
"source": [
"import datetime\n",
"\n",
"def read_log_file(file_path):\n",
" with open(file_path, \"r\") as file:\n",
" lines = file.readlines()\n",
" return lines\n",
"\n",
"def parse_log_lines(lines):\n",
" key_events = []\n",
" for line in lines:\n",
" timestamp_str, key = line.strip().split(\": \")\n",
" timestamp = datetime.datetime.strptime(timestamp_str, \"%Y-%m-%d %H:%M:%S.%f\")\n",
" key_events.append((timestamp, key))\n",
" return key_events\n",
"\n",
"def calculate_typing_speed(key_events):\n",
" total_chars = 0\n",
" total_words = 0\n",
" start_time = None\n",
" end_time = None\n",
" last_time = None\n",
" time_intervals = []\n",
"\n",
" for timestamp, key in key_events:\n",
" if start_time is None:\n",
" start_time = timestamp\n",
" if last_time is not None and (timestamp - last_time).total_seconds() > 5:\n",
" start_time = timestamp\n",
" last_time = timestamp\n",
" total_chars += 1\n",
" if key == 'space':\n",
" total_words += 1\n",
" end_time = timestamp\n",
"\n",
" if total_chars == 0:\n",
" return 0, 0 # No typing detected\n",
"\n",
" total_time = (end_time - start_time).total_seconds() / 60 # in minutes\n",
" cpm = total_chars / total_time\n",
" wpm = total_words / total_time\n",
"\n",
" return cpm, wpm\n",
"\n",
"\n",
"\n",
"def calculate_typing_speed(file_name):\n",
" log_lines = read_log_file(file_name)\n",
" key_events = parse_log_lines(log_lines)\n",
" cpm, wpm = calculate_typing_speed(key_events)\n",
"\n",
" print(f\"Średnia prędkość pisania: {cpm:.2f} znaków na minutę\")\n",
" print(f\"Średnia prędkość pisania: {wpm:.2f} słów na minutę\")\n",
" return cpm, wpm\n",
"\n",
"calculate_typing_speed(\"key_log.txt\")"
]
},
{
"cell_type": "markdown",
"id": "ceramic-birth",
"metadata": {
"id": "ceramic-birth"
},
"source": [
"Wróćmy teraz do procesu tłumaczenia. Analiza uderzeń klawiszy wykonanych podczas tłumaczenia pozwala wykryć dłuższe pauzy. Pauzy te najczęściej wskazują miejsca, w których tłumacz musi się głębiej zastanowić nad tłumaczeniem danego słowa lub frazy. Przerwę tę wykorzystuje na przykład na sprawdzenie tłumaczenia lub definicji w słowniku, przeglądanie wyników z pamięci tłumaczeń lub korzystanie z innych pomocy (eye-tracking mógłby w tym przypadku rozstrzygnąć, czym w istocie zajmuje się w tym momencie tłuamcz). Jest też możliwe, że tłumacz poświęca pauzę na tzw. cognitive pause-and-unload - rodzaj zamyślenia, pozwalający oczyścić myśli. Z punktu widzenia projektowania systemu wspomagającego tłumaczenie niezwykle istotna jest informacja, nad czym tłumacz musi się dłużej zastanowić. Minimalizacja liczby i czasu trwania takich przerw jest szansą na usprawnienie procesu tłumaczenia."
]
},
{
"cell_type": "markdown",
"id": "great-cable",
"metadata": {
"id": "great-cable"
},
"source": [
"### Ćwiczenie 3: Napisz program do wykrywania przerw w pisaniu. Raportuj długość oraz miejsce wystąpienia przerwy podając 20-znakowy kontekst z każdej strony. Wykryj każdą przerwę dłuższą niż 3 sekundy, posortuj wyniki malejąco po długości przerwy."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "close-riverside",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 305
},
"id": "close-riverside",
"outputId": "f26a611b-3cba-4e96-f922-8af210c7bf45"
},
"outputs": [
{
"output_type": "error",
"ename": "NameError",
"evalue": "name 'read_log_file' is not defined",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-4-edc7383ffb03>\u001b[0m in \u001b[0;36m<cell line: 32>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 31\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 32\u001b[0;31m \u001b[0mreport_pauses\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfind_pauses\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"key_log.txt\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m<ipython-input-4-edc7383ffb03>\u001b[0m in \u001b[0;36mfind_pauses\u001b[0;34m(file_name, min_pause_duration)\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mfind_pauses\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfile_name\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mmin_pause_duration\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mlog_lines\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mread_log_file\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfile_name\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0mkey_events\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mparse_log_lines\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlog_lines\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0mpauses\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfind_pauses\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mkey_events\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mprevious_time\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mNameError\u001b[0m: name 'read_log_file' is not defined"
]
}
],
"source": [
"def find_pauses(file_name, min_pause_duration=3):\n",
" log_lines = read_log_file(file_name)\n",
" key_events = parse_log_lines(log_lines)\n",
" pauses = find_pauses(key_events)\n",
" previous_time = None\n",
" context = []\n",
"\n",
" for i, (timestamp, key) in enumerate(key_events):\n",
" if previous_time:\n",
" pause_duration = (timestamp - previous_time).total_seconds()\n",
" if pause_duration > min_pause_duration:\n",
" start_context = max(0, i-20)\n",
" end_context = min(len(key_events), i+20)\n",
" context_before = ''.join(key[1] for key in key_events[start_context:i])\n",
" context_after = ''.join(key[1] for key in key_events[i:end_context])\n",
" pauses.append((pause_duration, context_before, context_after))\n",
" previous_time = timestamp\n",
" context.append(key)\n",
"\n",
" pauses.sort(reverse=True, key=lambda x: x[0])\n",
" return pauses\n",
"\n",
"def report_pauses(pauses):\n",
" for pause in pauses:\n",
" duration, context_before, context_after = pause\n",
" print(f\"Przerwa: {duration:.2f} sekund\")\n",
" print(f\"Kontekst przed: {context_before[-20:]}\")\n",
" print(f\"Kontekst po: {context_after[:20]}\")\n",
" print(\"-\" * 40)\n",
"\n",
"\n",
"report_pauses(find_pauses(\"key_log.txt\"))\n"
]
}
],
"metadata": {
"author": "Rafał Jaworski",
"email": "rjawor@amu.edu.pl",
"lang": "pl",
"subtitle": "12. Key logging",
"title": "Komputerowe wspomaganie tłumaczenia",
"year": "2021",
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.10"
},
"colab": {
"provenance": []
}
}, },
{ "nbformat": 4,
"cell_type": "markdown", "nbformat_minor": 5
"id": "featured-afghanistan",
"metadata": {},
"source": [
"Badania nad komputerowym wspomaganiem tłumaczenia często prowadzone są przy użyciu metodologii testowania interfejsów użytkownika - UI/UX testing. Program typu CAT traktuje się wówczas jak każdy inny program komputerowy i przeprowadza testy wydajności i użyteczności."
]
},
{
"cell_type": "markdown",
"id": "severe-protein",
"metadata": {},
"source": [
"Testy takie prowadzone są zawsze na użytkownikach końcowych, w tym przypadku - na tłumaczach. Podstawowym celem testów jest próba zaobserwowania faktycznego sposobu pracy tłumacza - które funkcje programu są przez niego wykorzystywane najczęściej, jakich innych narzędzi poza CAT-em używa on do swojej pracy, które funkcje programu działają zgodnie, a które niezgodnie z intuicją użytkownika oraz wiele innych czynników. Aby wszystkie te analizy były możliwe, konieczne jest zgromadzenie jak największej ilości danych dotyczących przebiegu testu."
]
},
{
"cell_type": "markdown",
"id": "constant-underground",
"metadata": {},
"source": [
"Testy są przede wszystkim nagrywane. Nagrywany jest zarówno ekran komputera (screen capture), jak i sam użytkownik pracujący przy komputerze. To jednak nie wszystko - często stosuje się specjalne techniki eye-trackingu, które są w stanie określić, w który punk ekranu użytkownik aktualnie patrzy. Dane pozyskane w ten sposób używane są do analizy czasu znalezienia przez użytkownika potrzebnej mu funkcji oraz zidentyfikowania miejsc, gdzie tej funkcji poszukiwał. Można również wyznaczyć obszary ekranu, które często skupiają uwagę użytkownika. "
]
},
{
"cell_type": "markdown",
"id": "analyzed-lodging",
"metadata": {},
"source": [
"Dodatkowo stosuje się jeszcze jedną technikę, która jest szczególnie przydatna z punktu widzenia analizy procesu tłumaczenia. Wykonuje się pełny key logging, tj. zapisuje się każde uderzenie użytkownika w dowolny klawisz na klawiaturze wraz z precyzyjnym czasem tego uderzenia. Dane pozyskane w ten sposób pozwalają na przeprowadzenie szeregu interesujących analiz."
]
},
{
"cell_type": "markdown",
"id": "incredible-stress",
"metadata": {},
"source": [
"Zapoznajmy się najpierw z programem typu key logger:"
]
},
{
"cell_type": "markdown",
"id": "arctic-horror",
"metadata": {},
"source": [
"`sudo pip3 install keyboard`"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "broken-workstation",
"metadata": {},
"outputs": [],
"source": [
"import keyboard\n",
"\n",
"\n",
"def report_key(event):\n",
" print(event)\n",
"\n",
"keyboard.on_release(callback=report_key)\n",
"keyboard.wait()"
]
},
{
"cell_type": "markdown",
"id": "polish-census",
"metadata": {},
"source": [
"UWAGA! Aby uruchomić powyższy kod na Linuxie konieczne są uprawnienia administratora (pytanie poza konkursem - dlaczego?)"
]
},
{
"cell_type": "markdown",
"id": "incoming-hands",
"metadata": {},
"source": [
"### Ćwiczenie 1: Wykorzystując powyższy kod napisz keylogger, który zapisuje wszystkie uderzenia w klawisze do pliku. Format pliku jest dowolny, każdy wpis musi zawierać precyzyjną godzinę uderzenia oraz uderzony klawisz. Uruchom program i przepisz paragraf dowolnie wybranego tekstu."
]
},
{
"cell_type": "markdown",
"id": "valuable-bearing",
"metadata": {},
"source": [
"Celem powyższego ćwiczenia jest pozyskanie danych testowych. Dalsze analizy będziemy prowadzili już bez key loggera, starając się korzystać jedynie z danych zapisanych w pliku. Oczywiście, jeśli zajdzie taka konieczność, można w każdej chwili wygenerować sobie nowy plik."
]
},
{
"cell_type": "markdown",
"id": "boxed-maple",
"metadata": {},
"source": [
"### Ćwiczenie 2: Napisz program, który wyliczy średnią prędkość pisania. Wykryj, kiedy użytkownik zaczął pisać. Nie bierz pod uwagę przerw dłuższych niż 5 sekund. Podaj prędkość pisania w znakach na minutę oraz słowach na minutę."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "possible-holder",
"metadata": {},
"outputs": [],
"source": [
"def calculate_typing_speed():\n",
" return 0"
]
},
{
"cell_type": "markdown",
"id": "ceramic-birth",
"metadata": {},
"source": [
"Wróćmy teraz do procesu tłumaczenia. Analiza uderzeń klawiszy wykonanych podczas tłumaczenia pozwala wykryć dłuższe pauzy. Pauzy te najczęściej wskazują miejsca, w których tłumacz musi się głębiej zastanowić nad tłumaczeniem danego słowa lub frazy. Przerwę tę wykorzystuje na przykład na sprawdzenie tłumaczenia lub definicji w słowniku, przeglądanie wyników z pamięci tłumaczeń lub korzystanie z innych pomocy (eye-tracking mógłby w tym przypadku rozstrzygnąć, czym w istocie zajmuje się w tym momencie tłuamcz). Jest też możliwe, że tłumacz poświęca pauzę na tzw. cognitive pause-and-unload - rodzaj zamyślenia, pozwalający oczyścić myśli. Z punktu widzenia projektowania systemu wspomagającego tłumaczenie niezwykle istotna jest informacja, nad czym tłumacz musi się dłużej zastanowić. Minimalizacja liczby i czasu trwania takich przerw jest szansą na usprawnienie procesu tłumaczenia."
]
},
{
"cell_type": "markdown",
"id": "great-cable",
"metadata": {},
"source": [
"### Ćwiczenie 3: Napisz program do wykrywania przerw w pisaniu. Raportuj długość oraz miejsce wystąpienia przerwy podając 20-znakowy kontekst z każdej strony. Wykryj każdą przerwę dłuższą niż 3 sekundy, posortuj wyniki malejąco po długości przerwy."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "close-riverside",
"metadata": {},
"outputs": [],
"source": [
"def find_pauses():\n",
" return []"
]
}
],
"metadata": {
"author": "Rafał Jaworski",
"email": "rjawor@amu.edu.pl",
"lang": "pl",
"subtitle": "12. Key logging",
"title": "Komputerowe wspomaganie tłumaczenia",
"year": "2021",
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.10"
}
},
"nbformat": 4,
"nbformat_minor": 5
} }

View File

@ -1,227 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "ordered-wrestling",
"metadata": {},
"source": [
"![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n",
"<div class=\"alert alert-block alert-info\">\n",
"<h1> Komputerowe wspomaganie tłumaczenia </h1>\n",
"<h2> 13,14. <i>Korekta pisowni</i> [laboratoria]</h2> \n",
"<h3>Rafał Jaworski (2021)</h3>\n",
"</div>\n",
"\n",
"![Logo 2](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech2.jpg)"
]
},
{
"cell_type": "markdown",
"id": "featured-afghanistan",
"metadata": {},
"source": [
"Współczesne programy typu CAT nie mogą obyć się bez korektora pisowni. Na bieżąco kontrolują one pisownię wyrazów po stronie docelowej, czyli tam, gdzie tłumacz wpisuje tłumaczenie. Jest to niezwykle istotne w sytuacji, gdy język docelowy nie jest dla tłumacza językiem ojczystym. Co więcej, badania wykazują, iż korekta pisowni wydatnie zmniejsza liczbę błędów w każdych scenariuszach."
]
},
{
"cell_type": "markdown",
"id": "seventh-genre",
"metadata": {},
"source": [
"Co poprawia korekta pisowni? Słowa. Tylko lub aż słowa. Program dokonujący korekty pisowni przegląda tekst słowo po słowie i sprawdza, czy należy ono do słownika. Jeśli nie, sygnalizowany jest błąd oraz, jeśli to możliwe, podawane sugestie poprawy. Co istotne, korektor pisowni nie zajmuje się szeregiem błędów, które mieszczą się w dziedzinie korekty gramatycznej, w tym:\n",
"* interpunkcją\n",
"* powtórzeniami wyrazów\n",
"* stylistyką."
]
},
{
"cell_type": "markdown",
"id": "sticky-society",
"metadata": {},
"source": [
"Aby zaimplementować korektor pisowni bez wątpienia potrzebny jest słownik. Skorzystajmy ze słownika, który znajdziemy w folderze data, pochodzącego z narzędzia Hunspell. Jest on spakowany - użyjmy techniki czytania z archiwum zip bez rozpakowywania. Poniższy kod wypisze fragment ze środka słownika."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "familiar-terrace",
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"kalecząc\n",
"kaledonidy\n",
"kaledoński\n",
"kalefaktor\n",
"kalejdofon\n",
"kalejdoskop\n",
"kalejdoskopowość\n",
"kalejdoskopowy\n",
"kaleka\n",
"kaleki\n",
"kalema\n",
"kalendarium\n",
"kalendarz\n",
"kalendarzowy\n",
"kalendarzyk\n",
"kalendy\n",
"kalenica\n",
"kalenicowy\n",
"kalepin\n",
"kalesonki\n",
"kalesony\n"
]
}
],
"source": [
"from zipfile import ZipFile\n",
"\n",
"with ZipFile('data/hunspell_pl.zip') as zipped_dictionary:\n",
" with zipped_dictionary.open('hunspell_pl.txt') as dictionary_file:\n",
" count = 0\n",
" for line_bytes in dictionary_file:\n",
" count += 1\n",
" if count >= 100000 and count <= 100020:\n",
" line = line_bytes.decode('utf-8')\n",
" print(line.rstrip())"
]
},
{
"cell_type": "markdown",
"id": "dominant-insurance",
"metadata": {},
"source": [
"Miejmy na uwadze, że powyższy słownik zawiera tylko formy podstawowe słowa, np. zawiera słowo \"kalendarz\", ale nie zawiera \"kalendarze\", \"kalendarza\", \"kalendarzy\" itp. "
]
},
{
"cell_type": "markdown",
"id": "single-brighton",
"metadata": {},
"source": [
"Algorytm korekty pisowni na podstawie słownika powinien działać według następujących kroków:\n",
"1. Wczytanie słownika do zbioru (set)\n",
"2. Podział tekstu do korekty na słowa (podział po spacji)\n",
"3. Dla każdego słowa wypisać, czy jest ono poprawne (znajduje się w słowniku) czy nie."
]
},
{
"cell_type": "markdown",
"id": "needed-watson",
"metadata": {},
"source": [
"### Ćwiczenie 1: Zaimplementuj podstawowy algorytm korekty pisowni według powyższych wytycznych."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "economic-southeast",
"metadata": {},
"outputs": [],
"source": [
"def correct_text(text):\n",
" return []"
]
},
{
"cell_type": "markdown",
"id": "endless-slide",
"metadata": {},
"source": [
"To jednak oczywiście nie wszystko. Do tej pory mamy funkcjonalność sygnalizowania słów błędnych, ale każdy dobry korektor pisowni potrafi podać sugestie poprawek. W tym celu musimy stawić czoła następującemu problemowi - wygenerowanie listy słów podobnych do danego słowa błędnego, które znajdują się w słowniku."
]
},
{
"cell_type": "markdown",
"id": "adult-freight",
"metadata": {},
"source": [
"W pierwszej kolejności musimy zdefiniować podobieństwo między wyrazami. Posłuży do tego dobrze nam znana odległość Levenshteina - wyrazy podobne to takie, dla których dystans Levenshteina jest niewielki (np. równy 1 lub 2). Teraz brakuje tylko algorytmu wyszukiwania wyrazów w danym słowniku, które znajdują się niedaleko (w sensie Levenshteina) danego błędnego słowa."
]
},
{
"cell_type": "markdown",
"id": "everyday-things",
"metadata": {},
"source": [
"Rozważmy następujący algorytm: dla danego słownika $D$ i błędnego słowa $w \\notin D$:\n",
"1. Wygeneruj zbiór $L_1(w)$ wszystkich słów, których odległość Levenshteina od $w$ wynosi 1.\n",
"2. Wyznacz zbiór $S_1(w)=L_1(w) \\cap D$\n",
"3. Wyznacz zbiór $L_2(w)=\\bigcup_{v \\in L_1(w)} L_1(v)$\n",
"4. Wyznacz zbiór $S_2(w)=L_2(w) \\cap D$\n",
"5. Zwróć jako listę sugestii: $S_1 \\cup S_2$"
]
},
{
"cell_type": "markdown",
"id": "industrial-convert",
"metadata": {},
"source": [
"### Ćwiczenie 2: Napisz funkcję do generowania zbioru $L_1(w)$ - wszystkich słów znajdujących się w odległości Levenshteina 1 od danego słowa w."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "built-sally",
"metadata": {},
"outputs": [],
"source": [
"def L1(w):\n",
" return []"
]
},
{
"cell_type": "markdown",
"id": "wireless-uncle",
"metadata": {},
"source": [
"### Ćwiczenie 3: Napisz funkcję do generowania sugestii poprawek dla danego słowa według opisanego wcześniej algorytmu."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "coordinated-cooperation",
"metadata": {},
"outputs": [],
"source": [
"def generate_suggestions(w):\n",
" return []"
]
}
],
"metadata": {
"author": "Rafał Jaworski",
"email": "rjawor@amu.edu.pl",
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"lang": "pl",
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.10"
},
"subtitle": "13,14. Korekta pisowni",
"title": "Komputerowe wspomaganie tłumaczenia",
"year": "2021"
},
"nbformat": 4,
"nbformat_minor": 5
}

342
lab/lab_13_14.ipynb Normal file
View File

@ -0,0 +1,342 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "ordered-wrestling",
"metadata": {
"id": "ordered-wrestling"
},
"source": [
"![Logo 1](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech1.jpg)\n",
"<div class=\"alert alert-block alert-info\">\n",
"<h1> Komputerowe wspomaganie tłumaczenia </h1>\n",
"<h2> 13,14. <i>Korekta pisowni</i> [laboratoria]</h2>\n",
"<h3>Rafał Jaworski (2021)</h3>\n",
"</div>\n",
"\n",
"![Logo 2](https://git.wmi.amu.edu.pl/AITech/Szablon/raw/branch/master/Logotyp_AITech2.jpg)"
]
},
{
"cell_type": "markdown",
"id": "featured-afghanistan",
"metadata": {
"id": "featured-afghanistan"
},
"source": [
"Współczesne programy typu CAT nie mogą obyć się bez korektora pisowni. Na bieżąco kontrolują one pisownię wyrazów po stronie docelowej, czyli tam, gdzie tłumacz wpisuje tłumaczenie. Jest to niezwykle istotne w sytuacji, gdy język docelowy nie jest dla tłumacza językiem ojczystym. Co więcej, badania wykazują, iż korekta pisowni wydatnie zmniejsza liczbę błędów w każdych scenariuszach."
]
},
{
"cell_type": "markdown",
"id": "seventh-genre",
"metadata": {
"id": "seventh-genre"
},
"source": [
"Co poprawia korekta pisowni? Słowa. Tylko lub aż słowa. Program dokonujący korekty pisowni przegląda tekst słowo po słowie i sprawdza, czy należy ono do słownika. Jeśli nie, sygnalizowany jest błąd oraz, jeśli to możliwe, podawane sugestie poprawy. Co istotne, korektor pisowni nie zajmuje się szeregiem błędów, które mieszczą się w dziedzinie korekty gramatycznej, w tym:\n",
"* interpunkcją\n",
"* powtórzeniami wyrazów\n",
"* stylistyką."
]
},
{
"cell_type": "markdown",
"id": "sticky-society",
"metadata": {
"id": "sticky-society"
},
"source": [
"Aby zaimplementować korektor pisowni bez wątpienia potrzebny jest słownik. Skorzystajmy ze słownika, który znajdziemy w folderze data, pochodzącego z narzędzia Hunspell. Jest on spakowany - użyjmy techniki czytania z archiwum zip bez rozpakowywania. Poniższy kod wypisze fragment ze środka słownika."
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "familiar-terrace",
"metadata": {
"scrolled": true,
"colab": {
"base_uri": "https://localhost:8080/",
"height": 341
},
"id": "familiar-terrace",
"outputId": "1d74751b-6962-4d5a-ca3c-2d1e9f8f4b60"
},
"outputs": [
{
"output_type": "error",
"ename": "FileNotFoundError",
"evalue": "[Errno 2] No such file or directory: 'data/hunspell_pl.zip'",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mFileNotFoundError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-9-cf46e3e07935>\u001b[0m in \u001b[0;36m<cell line: 3>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mzipfile\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mZipFile\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0;32mwith\u001b[0m \u001b[0mZipFile\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'data/hunspell_pl.zip'\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mzipped_dictionary\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0mzipped_dictionary\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'hunspell_pl.txt'\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mdictionary_file\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0mcount\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m/usr/lib/python3.10/zipfile.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, file, mode, compression, allowZip64, compresslevel, strict_timestamps)\u001b[0m\n\u001b[1;32m 1249\u001b[0m \u001b[0;32mwhile\u001b[0m \u001b[0;32mTrue\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1250\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1251\u001b[0;31m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mio\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfile\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfilemode\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1252\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mOSError\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1253\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mfilemode\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mmodeDict\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: 'data/hunspell_pl.zip'"
]
}
],
"source": [
"from zipfile import ZipFile\n",
"\n",
"with ZipFile('data/hunspell_pl.zip') as zipped_dictionary:\n",
" with zipped_dictionary.open('hunspell_pl.txt') as dictionary_file:\n",
" count = 0\n",
" for line_bytes in dictionary_file:\n",
" count += 1\n",
" if count >= 100000 and count <= 100020:\n",
" line = line_bytes.decode('utf-8')\n",
" print(line.rstrip())"
]
},
{
"cell_type": "markdown",
"id": "dominant-insurance",
"metadata": {
"id": "dominant-insurance"
},
"source": [
"Miejmy na uwadze, że powyższy słownik zawiera tylko formy podstawowe słowa, np. zawiera słowo \"kalendarz\", ale nie zawiera \"kalendarze\", \"kalendarza\", \"kalendarzy\" itp."
]
},
{
"cell_type": "markdown",
"id": "single-brighton",
"metadata": {
"id": "single-brighton"
},
"source": [
"Algorytm korekty pisowni na podstawie słownika powinien działać według następujących kroków:\n",
"1. Wczytanie słownika do zbioru (set)\n",
"2. Podział tekstu do korekty na słowa (podział po spacji)\n",
"3. Dla każdego słowa wypisać, czy jest ono poprawne (znajduje się w słowniku) czy nie."
]
},
{
"cell_type": "markdown",
"id": "needed-watson",
"metadata": {
"id": "needed-watson"
},
"source": [
"### Ćwiczenie 1: Zaimplementuj podstawowy algorytm korekty pisowni według powyższych wytycznych."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "economic-southeast",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "economic-southeast",
"outputId": "3b304305-23e5-4ced-e65d-bdc6e1b06fbe"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"{'Kalendarz': True, 'jest': True, 'pełen': True, 'wydarzeń.': True, 'kalendarze': False, 'są': True, 'używane': True, 'codziennie.': True, 'albo': False, 'i': False, 'nie': False}\n"
]
}
],
"source": [
"def correct_text(text, dictionary_set):\n",
" words_to_check = text.split()\n",
" correction_results = {}\n",
" for word in words_to_check:\n",
" word_cleaned = word.strip(\",.!?\").lower()\n",
" is_correct = word_cleaned in dictionary_set\n",
" correction_results[word] = is_correct\n",
"\n",
" return correction_results\n",
"\n",
"dictionary_set = {\n",
" 'kalendarz', 'jest', 'pełen', 'wydarzeń', 'są', 'używane', 'codziennie'\n",
"}\n",
"text_to_check = \"Kalendarz jest pełen wydarzeń. kalendarze są używane codziennie. albo i nie\"\n",
"correction_results = correct_text(text_to_check, dictionary_set)\n",
"print(correction_results)"
]
},
{
"cell_type": "markdown",
"id": "endless-slide",
"metadata": {
"id": "endless-slide"
},
"source": [
"To jednak oczywiście nie wszystko. Do tej pory mamy funkcjonalność sygnalizowania słów błędnych, ale każdy dobry korektor pisowni potrafi podać sugestie poprawek. W tym celu musimy stawić czoła następującemu problemowi - wygenerowanie listy słów podobnych do danego słowa błędnego, które znajdują się w słowniku."
]
},
{
"cell_type": "markdown",
"id": "adult-freight",
"metadata": {
"id": "adult-freight"
},
"source": [
"W pierwszej kolejności musimy zdefiniować podobieństwo między wyrazami. Posłuży do tego dobrze nam znana odległość Levenshteina - wyrazy podobne to takie, dla których dystans Levenshteina jest niewielki (np. równy 1 lub 2). Teraz brakuje tylko algorytmu wyszukiwania wyrazów w danym słowniku, które znajdują się niedaleko (w sensie Levenshteina) danego błędnego słowa."
]
},
{
"cell_type": "markdown",
"id": "everyday-things",
"metadata": {
"id": "everyday-things"
},
"source": [
"Rozważmy następujący algorytm: dla danego słownika $D$ i błędnego słowa $w \\notin D$:\n",
"1. Wygeneruj zbiór $L_1(w)$ wszystkich słów, których odległość Levenshteina od $w$ wynosi 1.\n",
"2. Wyznacz zbiór $S_1(w)=L_1(w) \\cap D$\n",
"3. Wyznacz zbiór $L_2(w)=\\bigcup_{v \\in L_1(w)} L_1(v)$\n",
"4. Wyznacz zbiór $S_2(w)=L_2(w) \\cap D$\n",
"5. Zwróć jako listę sugestii: $S_1 \\cup S_2$"
]
},
{
"cell_type": "markdown",
"id": "industrial-convert",
"metadata": {
"id": "industrial-convert"
},
"source": [
"### Ćwiczenie 2: Napisz funkcję do generowania zbioru $L_1(w)$ - wszystkich słów znajdujących się w odległości Levenshteina 1 od danego słowa w."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "built-sally",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "built-sally",
"outputId": "f52b9f96-8dfe-42be-dbc6-1ac1279aa9d0"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"{'ykot', 'tot', 'kfot', 'kgot', 'kotv', 'koxt', 'koto', 'hkot', 'kotc', 'dot', 'kjt', 'kolt', 'koti', 'kzot', 'kott', 'kat', 'kotx', 'kit', 'kpt', 'kowt', 'koo', 'kxt', 'koz', 'koyt', 'koa', 'kon', 'klot', 'iot', 'kotp', 'kozt', 'jot', 'klt', 'yot', 'krt', 'kort', 'ikot', 'kodt', 'kost', 'koit', 'fot', 'ekot', 'kdot', 'kbt', 'kotz', 'krot', 'xot', 'kotb', 'cot', 'rkot', 'ktot', 'kotl', 'kote', 'kop', 'kou', 'kots', 'kt', 'kmt', 'kox', 'dkot', 'kof', 'koc', 'fkot', 'ot', 'koat', 'kzt', 'kok', 'kuot', 'kos', 'sot', 'mkot', 'mot', 'koi', 'tkot', 'kotf', 'kmot', 'kut', 'kor', 'xkot', 'kotg', 'koft', 'pot', 'nkot', 'aot', 'rot', 'khot', 'ktt', 'kow', 'koq', 'jkot', 'kkot', 'kotw', 'kdt', 'kojt', 'kcot', 'kotm', 'okot', 'kct', 'akot', 'kst', 'kod', 'kwt', 'uot', 'kotn', 'kxot', 'ko', 'koot', 'koet', 'keot', 'gkot', 'kota', 'zkot', 'kft', 'koh', 'kjot', 'kgt', 'kotr', 'qkot', 'kht', 'pkot', 'koth', 'koty', 'kbot', 'kiot', 'koe', 'kvot', 'eot', 'hot', 'bkot', 'kog', 'kwot', 'kotq', 'not', 'kpot', 'kotj', 'kqt', 'kob', 'vkot', 'kvt', 'komt', 'ckot', 'lot', 'kaot', 'kol', 'koy', 'koj', 'qot', 'ket', 'kobt', 'bot', 'koct', 'koqt', 'wot', 'skot', 'kogt', 'got', 'kom', 'koht', 'kovt', 'kout', 'oot', 'knt', 'kov', 'kotk', 'kont', 'wkot', 'kqot', 'vot', 'kyt', 'kopt', 'kkt', 'lkot', 'ukot', 'kotu', 'knot', 'kyot', 'kokt', 'kotd', 'zot', 'ksot'}\n"
]
}
],
"source": [
"def L1(word):\n",
" letters = 'abcdefghijklmnopqrstuvwxyz'\n",
" n = len(word)\n",
" results = set()\n",
"\n",
" for i in range(n):\n",
" results.add(word[:i] + word[i+1:])\n",
"\n",
" for i in range(n):\n",
" for c in letters:\n",
" if c != word[i]:\n",
" results.add(word[:i] + c + word[i+1:])\n",
"\n",
" for i in range(n + 1):\n",
" for c in letters:\n",
" results.add(word[:i] + c + word[i:])\n",
"\n",
" return results\n",
"\n",
"\n",
"word = \"kot\"\n",
"l1_words = L1(word)\n",
"print(l1_words)"
]
},
{
"cell_type": "markdown",
"id": "wireless-uncle",
"metadata": {
"id": "wireless-uncle"
},
"source": [
"### Ćwiczenie 3: Napisz funkcję do generowania sugestii poprawek dla danego słowa według opisanego wcześniej algorytmu."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "coordinated-cooperation",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "coordinated-cooperation",
"outputId": "a19fcc88-b7c6-46d0-9a2c-f0b2a53f087a"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"{'cute', 'cut', 'cuts'}\n"
]
}
],
"source": [
"import string\n",
"\n",
"def generate_edits(word):\n",
" letters = string.ascii_lowercase\n",
" splits = [(word[:i], word[i:]) for i in range(len(word) + 1)]\n",
" deletes = [L + R[1:] for L, R in splits if R]\n",
" transposes = [L + R[1] + R[0] + R[2:] for L, R in splits if len(R) > 1]\n",
" replaces = [L + c + R[1:] for L, R in splits if R for c in letters]\n",
" inserts = [L + c + R for L, R in splits for c in letters]\n",
" return set(deletes + transposes + replaces + inserts)\n",
"\n",
"def find_correct_words(words, dictionary):\n",
" return set(word for word in words if word in dictionary)\n",
"\n",
"def generate_suggestions(word, dictionary):\n",
" return find_correct_words(generate_edits(word), dictionary)\n",
"\n",
"dictionary = set([\"cat\", \"cot\", \"dog\", \"dot\", \"cute\", \"cuts\", \"cup\", \"cut\", \"cots\"])\n",
"\n",
"word = \"cutz\"\n",
"suggestions = generate_suggestions(word, dictionary)\n",
"print(suggestions)"
]
}
],
"metadata": {
"author": "Rafał Jaworski",
"email": "rjawor@amu.edu.pl",
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"lang": "pl",
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.10"
},
"subtitle": "13,14. Korekta pisowni",
"title": "Komputerowe wspomaganie tłumaczenia",
"year": "2021",
"colab": {
"provenance": []
}
},
"nbformat": 4,
"nbformat_minor": 5
}

File diff suppressed because one or more lines are too long