diff options
Diffstat (limited to 'archive/2025/summer/bsc_gerg/tests')
| -rw-r--r-- | archive/2025/summer/bsc_gerg/tests/__init__.py | 0 | ||||
| -rw-r--r-- | archive/2025/summer/bsc_gerg/tests/test_definition.py | 49 | ||||
| -rw-r--r-- | archive/2025/summer/bsc_gerg/tests/test_extract.py | 39 | ||||
| -rw-r--r-- | archive/2025/summer/bsc_gerg/tests/test_integration.py | 148 | ||||
| -rw-r--r-- | archive/2025/summer/bsc_gerg/tests/test_performance.ipynb | 439 | ||||
| -rw-r--r-- | archive/2025/summer/bsc_gerg/tests/util.py | 59 |
6 files changed, 734 insertions, 0 deletions
diff --git a/archive/2025/summer/bsc_gerg/tests/__init__.py b/archive/2025/summer/bsc_gerg/tests/__init__.py new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/archive/2025/summer/bsc_gerg/tests/__init__.py diff --git a/archive/2025/summer/bsc_gerg/tests/test_definition.py b/archive/2025/summer/bsc_gerg/tests/test_definition.py new file mode 100644 index 000000000..e7daaebf0 --- /dev/null +++ b/archive/2025/summer/bsc_gerg/tests/test_definition.py @@ -0,0 +1,49 @@ +from unittest import TestCase + +from src.knowledge.openai.definition.generator import OpenAIDefinitionGenerator +from src.terminology.event import OccurrenceResolved, PartialDefinitionGenerated +from src.terminology.terminology import Blackboard +from tests.util import collect_async + + +class TestDefinitionGenerator(TestCase): + + + def test_definition_simple(self): + blackboard = Blackboard(terms=[], sources=[]) + generator = OpenAIDefinitionGenerator(blackboard=blackboard) + + input = "Abstellen\n Züge und Triebfahrzeuge sind abgestellt, wenn sie nicht mit einem Triebfahrzeugführer besetzt sind oder nicht gesteuert werden. Wagen sind abgestellt, sofern sie nicht in Züge eingestellt sind oder nicht rangiert werden.\n Abstoßen\n Abstoßen ist das Bewegen geschobener, nicht mit einem arbeitenden Triebfahrzeug gekuppelter Fahrzeuge durch Beschleunigen, sodass die Fahrzeuge allein weiterfahren, nachdem das Triebfahrzeug angehalten hat." + + term = blackboard.add_term("Abstoßen") + source = blackboard.add_text_source(input) + actual_events = collect_async(generator.activate(OccurrenceResolved(term=term, source=source))) + + if len(term.definitions) == 0: + self.fail("No definition generated for term.") + + expected_definition = "Abstoßen ist das Bewegen geschobener, nicht mit einem arbeitenden Triebfahrzeug gekuppelter Fahrzeuge durch Beschleunigen, sodass die Fahrzeuge allein weiterfahren, nachdem das Triebfahrzeug angehalten hat" + + if expected_definition not in term.definitions[0].text: + self.fail(f"Expected definition does not match the actual definition.\n" + f"Actual: \n{term.definitions[0].text}\n" + f"Expected: \n{expected_definition}") + + if len([event for event in actual_events if type(event) is PartialDefinitionGenerated]) == 0: + self.fail("No PartialDefinitionGenerated event is published.") + + + def test_definition_not_enough_context(self): + blackboard = Blackboard(terms=[], sources=[]) + generator = OpenAIDefinitionGenerator(blackboard=blackboard) + + input = "Dies gilt auch für das Abstoßen, sofern in örtlichen Zusätzen nicht Ausnahmen zugelassen sind." + + term = blackboard.add_term("Abstoßen") + source = blackboard.add_text_source(input) + actual_events = collect_async(generator.activate(OccurrenceResolved(term=term, source=source))) + + if len(term.definitions) != 0: + self.fail(f"A definition was generated, where non should have. Generated Definition: {term.definitions[0].text}") + if len(actual_events) != 0: + self.fail("A PartialDefinitionGenerated event was published, where non should have.") \ No newline at end of file diff --git a/archive/2025/summer/bsc_gerg/tests/test_extract.py b/archive/2025/summer/bsc_gerg/tests/test_extract.py new file mode 100644 index 000000000..c77cd98f3 --- /dev/null +++ b/archive/2025/summer/bsc_gerg/tests/test_extract.py @@ -0,0 +1,39 @@ +from unittest import TestCase + +from src.knowledge.openai.extract import OpenAIExtractor +from src.terminology.event import TextExtracted, TermExtracted, OccurrenceResolved +from src.terminology.terminology import Blackboard +from tests.util import collect_async + + +class TestTermExtractor(TestCase): + + def test_common(self): + blackboard = Blackboard(terms=[], sources=[]) + extractor = OpenAIExtractor(blackboard=blackboard) + + input = """Einseitig gerichtete Sprecheinrichtung verwenden\n Aufträge dürfen über einseitig gerichtete Sprecheinrichtungen gegeben werden, wenn dies im Einzelfall nicht verboten ist und der Empfänger die Ausführung melden muss oder der Auftraggeber die Ausführung selbst erkennen kann. Meldungen dürfen über einseitig gerichtete Sprecheinrichtungen nicht gegeben werden.""" + + expected = ["Einseitig gerichtete Sprecheinrichtung", "Aufträge", "Empfänger", "Auftraggeber", "Meldungen"] + + initial_event = TextExtracted(text=input) + actual_events = collect_async(extractor.activate(initial_event)) + + actual_events_extracted = [event for event in actual_events if type(event) is TermExtracted] + actual_events_occurrence = [event for event in actual_events if type(event) is OccurrenceResolved] + + actual_terms_text = set(event.term.text.lower() for event in actual_events_extracted) + + missing_terms = [] + for term in expected: + if term.lower() not in actual_terms_text: + missing_terms.append(term) + + if len(missing_terms) > 0: + self.fail(f"Missing terms [{', '.join(missing_terms)}] in extracted events ([{', '.join(actual_terms_text)}]).") + + for term in actual_terms_text: + if len([event for event in actual_events_extracted if event.term.text.lower() == term]) == 0: + self.fail(f"Missing TermExtracted event for term {term}.") + if len([event for event in actual_events_occurrence if event.term.text.lower() == term]) == 0: + self.fail(f"Missing OccurrenceResolved event for term {term}.") diff --git a/archive/2025/summer/bsc_gerg/tests/test_integration.py b/archive/2025/summer/bsc_gerg/tests/test_integration.py new file mode 100644 index 000000000..428ea2038 --- /dev/null +++ b/archive/2025/summer/bsc_gerg/tests/test_integration.py @@ -0,0 +1,148 @@ +import random +from unittest import TestCase + +import numpy as np +from fastapi.testclient import TestClient + +from src.main import app +from tests.util import create_completion_openai_sync + +REDUCE_REASONING = False + + +class TestIntegrationTerminology(TestCase): + + def setUp(self): + self.client = TestClient(app) + + def testExtractDomainTerminology(self): + """This test allows manually added variations""" + input = [ + "Servus Zofia!", + "Hallo Markus.", + "Rangiere mir bitte mal den 420er von Gleis 3 auf das Abstellgleis. Passt auf, du musst auf Sicht bis zu den Signalen fahren." + ] + + expectedTerms = [ + ["Rangieren"], + ["420", "420er"], # The variation "420er" was added after evaluation of the test results, as it is also a valid term + ["Abstellgleis"], + ["auf Sicht fahren"], + ["Signal"] + ] + + response = self.client.post("/extractTerminology", json={ + "text": input[-1], + "context": "\n".join(input[:-1]) + }) + + response.raise_for_status() + + response = response.json() + + self.assertIn("terms", response) + terms = [term["normalization"] or term["text"] for term in response["terms"]] + terms_lower = [term.lower() for term in terms] + + missing_terms = [] + for variations in expectedTerms: + missing_terms_variation = [] + for term in variations: + if term.lower() not in terms_lower: + missing_terms_variation.append(term) + # If no variation was matched, the term is not contained in the response + if len(missing_terms_variation) == len(variations): + missing_terms.append(variations) + + if len(missing_terms) > 0: + self.fail(f"Missing the following terms in the response: {missing_terms}") + + + def testExtractDomainTerminology_LLM(self): + input = [ + "Servus Zofia!", + "Hallo Markus.", + "Rangiere mir bitte mal den 420er von Gleis 3 auf das Abstellgleis. Passt auf, du musst auf Sicht bis zu den Signalen fahren." + ] + + expectedTerms = [ + "Rangieren", + "420", + "Abstellgleis", + "Fahrt auf Sicht", + "Signal" + ] + + response = self.client.post("/extractTerminology", json={ + "text": input[-1], + "context": "\n".join(input[:-1]) + }) + + response.raise_for_status() + + response = response.json() + + self.assertIn("terms", response) + terms = [term["normalization"] or term["text"] for term in response["terms"]] + + + probs_all = [] + + no_reasoning = " sofort" if REDUCE_REASONING else "" + + for i in range(5): + print(f"##### TEST {i} #####") + # Note: shuffling the results changed the outcome significantly + random.shuffle(expectedTerms) + random.shuffle(terms) + response, logprobs = create_completion_openai_sync( + messages=[ + ( + "user", + "Bewerte die Ähnlichkeit der Ergebnisse der Term Extraktion. Gegeben ist ein Ausgangstext, " + "aus dem Fachbegriffe extrahiert werden mussten. Der Text ist gegeben. Darunter stehen die erwarteten Begriffe, " + "die extrahiert werden sollten. Zum Schluss stehen die tatsächlich extrahierten Begriffe. " + "Bewerte die Ähnlichkeit der extrahierten Begriffe." + "Nur sprachliche Variationen für einen erwarteten Begriff sind erlaubt." + f"Gibt es für einen erwarteten Begriff keinen ähnlichen extrahierten Begriff, beende{no_reasoning} mit FALSE." + f"Wenn ein erwarteter Begriff gänzlich fehlt, beende{no_reasoning} mit FALSE." + f"Wenn ein Begriff extrahiert wurde, der sicher kein Fachbegriff ist, beende{no_reasoning} mit FALSE." + "Wenn ein Begriff extrahiert wurde, der nicht erwartet wurde, ignoriere diesen. Dies gilt nicht als Unterschied." + f"{'Antworte sofort.' if REDUCE_REASONING else ''}" + f"Ansonsten Ende{no_reasoning} mit TRUE." + "Bewerte die extrahierten Begriffe." + ), + ("user", f"""{input[len(input) - 1]}\n\nErwartete Begriffe: {", ".join(expectedTerms)}\n\nTatsächliche Begriffe: {", ".join(terms)}"""), + ], + logprobs=True + ) + + print(f"{response}") + + # Look at the last 5 output tokens + last_tokens = logprobs.content[-5:] + last_tokens.reverse() + for content in last_tokens: + cur_token = content.token.strip() + probs = {token.token: float(np.exp(token.logprob)) for token in content.top_logprobs} + # print(f"Probs: {probs}") + if "TRUE" in cur_token or "FALSE" in cur_token: + if "TRUE" not in probs.keys() or "FALSE" not in probs.keys(): + continue + probs = {token: prob for token, prob in probs.items() if token == "TRUE" or token == "FALSE"} + total_end = sum(probs.values()) + normalized_probs = {token: value / total_end for token, value in probs.items()} + print(normalized_probs) + probs_all.append(normalized_probs["TRUE"] if "TRUE" in normalized_probs.keys() else 0) + break + print("") + min_prob = min(probs_all) + max_prob = max(probs_all) + avg = sum(probs_all) / len(probs_all) + var = np.var(probs_all) + + print(f"min: {min_prob}, max: {max_prob}, avg: {avg}, var: {var}") + + self.assertLess(var, 0.05) + self.assertGreater(avg, 0.8) + self.assertGreater(min_prob, 0.75) diff --git a/archive/2025/summer/bsc_gerg/tests/test_performance.ipynb b/archive/2025/summer/bsc_gerg/tests/test_performance.ipynb new file mode 100644 index 000000000..9079d123c --- /dev/null +++ b/archive/2025/summer/bsc_gerg/tests/test_performance.ipynb @@ -0,0 +1,439 @@ +{ + "cells": [ + { + "cell_type": "code", + "id": "initial_id", + "metadata": { + "collapsed": true, + "ExecuteTime": { + "end_time": "2025-07-18T09:06:12.226163Z", + "start_time": "2025-07-18T09:06:12.218992Z" + } + }, + "source": [ + "import time\n", + "\n", + "with open(\"./../data/test_performance_input.txt\", \"r\") as f:\n", + " test_input = [input_str.strip() for input_str in f.read().split(\"###\")]\n", + " test_input = [text for text in test_input if text != \"\"]\n", + "\n", + "len(test_input)" + ], + "outputs": [ + { + "data": { + "text/plain": [ + "21" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 19 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-07-18T09:09:03.931293Z", + "start_time": "2025-07-18T09:08:48.597089Z" + } + }, + "cell_type": "code", + "source": [ + "import httpx\n", + "import json\n", + "\n", + "test_results = []\n", + "\n", + "def run_test(input: str, index: int = -1):\n", + " start = time.time()\n", + " result = httpx.post(\"http://localhost:8000/processText\", json={\n", + " \"text\": input\n", + " }, timeout=None)\n", + " end = time.time()\n", + " duration = end - start\n", + " test_results.append({\"duration\": duration, \"input\": input, \"result\": result.json()})\n", + " print(f\"\\033[4mTest result {index}:\\033[0m\")\n", + " print(f\"\\033[1mDuration:\\033[0m {duration}s\")\n", + " print(f\"\\033[1mInput:\\033[0m \\\"{input}\\\"\")\n", + " for term in result.json()[\"terms\"]:\n", + " print(f\"- {term['text'] if term['normalization'] == None else term['normalization']}\")\n", + " for definition in term[\"definitions\"]:\n", + " prefix = \"\"\n", + " if definition[\"partial\"]:\n", + " prefix += \"⚙️\"\n", + " if not definition[\"verified\"]:\n", + " prefix += \"✨\"\n", + " else:\n", + " prefix += \"☑️\"\n", + " print(f\"\\t- {prefix} {definition['text']}\")\n", + " print()\n", + "\n", + "for index, text in enumerate(test_input, start=1):\n", + " try:\n", + " run_test(text, index=index)\n", + " except:\n", + " print(f\"Test failed: {text}\")\n", + "\n", + "with open(\"./../data/test_performance_cvalue_output.json\", \"w\") as f:\n", + " f.write(json.dumps(test_results))" + ], + "id": "1824c2246b2c9a91", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001B[4mTest result 1:\u001B[0m\n", + "\u001B[1mDuration:\u001B[0m 0.7679691314697266s\n", + "\u001B[1mInput:\u001B[0m \"Hier ist der 12772, gerade angekommen in Gleis 31.\n", + "Ich habe jetzt abgehängt und Hemmschuhe unter die ersten beiden Wagen gelegt und eine Handbremse ist auch fest.\"\n", + "- ersten beiden wagen\n", + "- 31.\n", + "- hemmschuhe\n", + "- ersten\n", + "- wagen\n", + "- handbremse\n", + "\n", + "\u001B[4mTest result 2:\u001B[0m\n", + "\u001B[1mDuration:\u001B[0m 0.7423641681671143s\n", + "\u001B[1mInput:\u001B[0m \"Die Effizienz von Transformatoren kann durch Wirbelstromverluste und magnetische Hysterese beeinträchtigt werden. Was bei der Dimensionierung zu berücksichtigen ist.\"\n", + "- effizienz von transformatoren\n", + "- magnetische hysterese\n", + "- effizienz\n", + "- transformatoren\n", + "- wirbelstromverluste\n", + "- magnetische\n", + "- hysterese\n", + "- dimensionierung\n", + "\n", + "\u001B[4mTest result 3:\u001B[0m\n", + "\u001B[1mDuration:\u001B[0m 0.7041819095611572s\n", + "\u001B[1mInput:\u001B[0m \"Feuerlöscher sind tragbare Geräte, die damals entwickelt wurden, um kleine Brände in der Anfangsphase zu löschen.\"\n", + "- tragbare geräte\n", + "- kleine brände\n", + "- feuerlöscher\n", + "- tragbare\n", + "- geräte\n", + "- kleine\n", + "- brände\n", + "- anfangsphase\n", + "\n", + "\u001B[4mTest result 4:\u001B[0m\n", + "\u001B[1mDuration:\u001B[0m 0.7359318733215332s\n", + "\u001B[1mInput:\u001B[0m \"Die Verwendung von Leistungselektronik ermöglicht eine effiziente Umwandlung und Steuerung elektrischer Energie, insbesondere in erneuerbaren Energiesystemen.\"\n", + "- verwendung von leistungselektronik\n", + "- steuerung elektrischer energie\n", + "- effiziente umwandlung\n", + "- elektrischer energie\n", + "- erneuerbaren energiesystemen\n", + "- steuerung elektrischer\n", + "- verwendung\n", + "- leistungselektronik\n", + "- effiziente\n", + "- umwandlung\n", + "- steuerung\n", + "- elektrischer\n", + "- energie\n", + "- erneuerbaren\n", + "- energiesystemen\n", + "\n", + "\u001B[4mTest result 5:\u001B[0m\n", + "\u001B[1mDuration:\u001B[0m 0.6899619102478027s\n", + "\u001B[1mInput:\u001B[0m \"Die Dimensionierung der Kabelquerschnitte muss auf Grundlage der Strombelastbarkeit und der zulässigen Spannungsabfälle berechnet werden, um Überhitzung zu vermeiden.\"\n", + "- zulässigen spannungsabfälle\n", + "- dimensionierung der kabelquerschnitte\n", + "- grundlage der strombelastbarkeit\n", + "- dimensionierung\n", + "- kabelquerschnitte\n", + "- grundlage\n", + "- strombelastbarkeit\n", + "- zulässigen\n", + "- spannungsabfälle\n", + "- überhitzung\n", + "\n", + "\u001B[4mTest result 6:\u001B[0m\n", + "\u001B[1mDuration:\u001B[0m 0.7219328880310059s\n", + "\u001B[1mInput:\u001B[0m \"Die DB Energie setzt Netzqualitätsanalysegeräte der Firma Janitza ein, um ihre Netze 50 Hertz besser beurteilen zu können, um den Kunden besser zu versorgen beziehungsweise die Strombelastbarkeit an den Anlagen zu berechnen.\"\n", + "- db energie\n", + "- netzqualitätsanalysegeräte der firma\n", + "- db\n", + "- energie\n", + "- netzqualitätsanalysegeräte\n", + "- firma\n", + "- netze\n", + "- hertz\n", + "- kunden\n", + "- strombelastbarkeit\n", + "- anlagen\n", + "\n", + "\u001B[4mTest result 7:\u001B[0m\n", + "\u001B[1mDuration:\u001B[0m 0.6928410530090332s\n", + "\u001B[1mInput:\u001B[0m \"Auch das Arbeiten an elektrischen Anlagen benötigt persönliche Schutzausrüstung wie Sicherheitsschuhe, lichtbogengeschützte Kleidung und eventuell Sicherheitshelm.\"\n", + "- elektrischen anlagen\n", + "- persönliche schutzausrüstung\n", + "- lichtbogengeschützte kleidung\n", + "- arbeiten an elektrischen\n", + "- arbeiten\n", + "- elektrischen\n", + "- anlagen\n", + "- persönliche\n", + "- schutzausrüstung\n", + "- lichtbogengeschützte\n", + "- kleidung\n", + "\n", + "\u001B[4mTest result 8:\u001B[0m\n", + "\u001B[1mDuration:\u001B[0m 0.6837880611419678s\n", + "\u001B[1mInput:\u001B[0m \"Ich buchstabiere meinen Namen. B U R A K. Burak.\"\n", + "- namen\n", + "\n", + "\u001B[4mTest result 9:\u001B[0m\n", + "\u001B[1mDuration:\u001B[0m 1.547395944595337s\n", + "\u001B[1mInput:\u001B[0m \"Moderne Brandmeldeanlagen sind oft mit einer automatischen Benachrichtigung an die Feuerwehr verbunden, um schnelle Hilfe im Brandfall zu gewährleisten.\"\n", + "- hilfe im brandfall\n", + "- moderne brandmeldeanlagen\n", + "- automatischen benachrichtigung\n", + "- schnelle hilfe\n", + "- moderne\n", + "- brandmeldeanlagen\n", + "- automatischen\n", + "- benachrichtigung\n", + "- feuerwehr\n", + "- schnelle\n", + "- hilfe\n", + "- brandfall\n", + "\n", + "\u001B[4mTest result 10:\u001B[0m\n", + "\u001B[1mDuration:\u001B[0m 0.6423039436340332s\n", + "\u001B[1mInput:\u001B[0m \"Die Verwendung von Leistungselektronik ermöglicht eine effiziente Umwandlung und Steuerung elektrischer Energie, insbesondere in erneuerbaren Energiesystemen.\"\n", + "- verwendung von leistungselektronik\n", + "- steuerung elektrischer energie\n", + "- effiziente umwandlung\n", + "- elektrischer energie\n", + "- erneuerbaren energiesystemen\n", + "- steuerung elektrischer\n", + "- verwendung\n", + "- leistungselektronik\n", + "- effiziente\n", + "- umwandlung\n", + "- steuerung\n", + "- elektrischer\n", + "- energie\n", + "- erneuerbaren\n", + "- energiesystemen\n", + "\n", + "\u001B[4mTest result 11:\u001B[0m\n", + "\u001B[1mDuration:\u001B[0m 0.6417520046234131s\n", + "\u001B[1mInput:\u001B[0m \"Brandmeldeanlagen sind sicherheitstechnische Systeme, die Rauch, Hitze oder Flammen erkennen und im Brandfall sofort Alarm auslösen.\"\n", + "- sicherheitstechnische systeme\n", + "- sicherheitstechnische\n", + "- systeme\n", + "- rauch\n", + "- hitze\n", + "- flammen\n", + "- brandfall\n", + "\n", + "\u001B[4mTest result 12:\u001B[0m\n", + "\u001B[1mDuration:\u001B[0m 0.6495020389556885s\n", + "\u001B[1mInput:\u001B[0m \"Der Ortsnetztransformator ist ein zentraler Bestandteil des Niederspannungsnetzes und sorgt dafür, dass elektrische Energien mit der passenden Spannung zum Endverbraucher gelangt.\"\n", + "- zentraler bestandteil\n", + "- elektrische energien\n", + "- passenden spannung\n", + "- bestandteil des niederspannungsnetzes\n", + "- ortsnetztransformator\n", + "- zentraler\n", + "- bestandteil\n", + "- niederspannungsnetzes\n", + "- elektrische\n", + "- energien\n", + "- passenden\n", + "- spannung\n", + "\n", + "\u001B[4mTest result 13:\u001B[0m\n", + "\u001B[1mDuration:\u001B[0m 0.6467278003692627s\n", + "\u001B[1mInput:\u001B[0m \"Krananweisung.\"\n", + "- krananweisung\n", + "\n", + "\u001B[4mTest result 14:\u001B[0m\n", + "\u001B[1mDuration:\u001B[0m 0.6659259796142578s\n", + "\u001B[1mInput:\u001B[0m \"Die galvanische Trennung in Netzteilen ist entscheidend, um eine sichere Isolation zwischen den Primär- und Sekundärkreisen zu gewährleisten und potenzielle Störungen zu minimieren.\"\n", + "- galvanische trennung\n", + "- sichere isolation\n", + "- potenzielle störungen\n", + "- galvanische\n", + "- trennung\n", + "- sichere\n", + "- isolation\n", + "- sekundärkreisen\n", + "- potenzielle\n", + "- störungen\n", + "\n", + "\u001B[4mTest result 15:\u001B[0m\n", + "\u001B[1mDuration:\u001B[0m 0.6520569324493408s\n", + "\u001B[1mInput:\u001B[0m \"In explosionsgefährdeten Bereichen müssen elektrische Anlagen als explosionsgeschützt ausgeführt werden, um eine Entzündung durch Funkenbildung zu verhindern.\"\n", + "- entzündung durch funkenbildung\n", + "- explosionsgefährdeten bereichen\n", + "- elektrische anlagen\n", + "- explosionsgefährdeten\n", + "- bereichen\n", + "- elektrische\n", + "- anlagen\n", + "- entzündung\n", + "- funkenbildung\n", + "\n", + "\u001B[4mTest result 16:\u001B[0m\n", + "\u001B[1mDuration:\u001B[0m 0.6554341316223145s\n", + "\u001B[1mInput:\u001B[0m \"Um Kurzschlüsse zu vermeiden, muss die Sicherung regelmäßig überprüft werden.\"\n", + "- kurzschlüsse\n", + "- sicherung\n", + "\n", + "\u001B[4mTest result 17:\u001B[0m\n", + "\u001B[1mDuration:\u001B[0m 0.6606340408325195s\n", + "\u001B[1mInput:\u001B[0m \"Grüß dich, du ich steh jetzt hinterm Paula 33, das ist auf Halt zurückgefallen, was ist los bei dir?\"\n", + "- paula\n", + "\n", + "\u001B[4mTest result 18:\u001B[0m\n", + "\u001B[1mDuration:\u001B[0m 0.6834249496459961s\n", + "\u001B[1mInput:\u001B[0m \"Grüßt euch, hier große Probleme, da hängt der Fahrdraht runter.\"\n", + "- große probleme\n", + "- große\n", + "- probleme\n", + "- fahrdraht\n", + "\n", + "\u001B[4mTest result 19:\u001B[0m\n", + "\u001B[1mDuration:\u001B[0m 0.6872987747192383s\n", + "\u001B[1mInput:\u001B[0m \"Also von mir aus kanns sofort losgehen. Wir können auch vor Plan abfahren.\"\n", + "- plan\n", + "\n", + "\u001B[4mTest result 20:\u001B[0m\n", + "\u001B[1mDuration:\u001B[0m 0.7242209911346436s\n", + "\u001B[1mInput:\u001B[0m \"Guten Morgen Kollege Lorenz. Du kriegst gleich von mir einen Befehl für die Engstelle in Rüdesheim.\"\n", + "- guten morgen kollege\n", + "- morgen kollege lorenz\n", + "- guten morgen\n", + "- morgen kollege\n", + "- kollege lorenz\n", + "- guten\n", + "- morgen\n", + "- kollege\n", + "- lorenz\n", + "- befehl\n", + "- engstelle\n", + "\n", + "\u001B[4mTest result 21:\u001B[0m\n", + "\u001B[1mDuration:\u001B[0m 0.7287449836730957s\n", + "\u001B[1mInput:\u001B[0m \"Guten Morgen, Müller. Eisenbahnbundesamt hier, mein Name ist Müller. Ich äh, möchte mal gerne die Gleise 520 bis 523, äh aus UV Gründen sperren und mir dort die Kesselwagen angucken.\"\n", + "- guten morgen\n", + "- guten\n", + "- morgen\n", + "- name\n", + "- gründen\n", + "- kesselwagen\n", + "\n" + ] + } + ], + "execution_count": 23 + }, + { + "metadata": {}, + "cell_type": "markdown", + "source": "## Evaluate C-Value gold labels", + "id": "24c4f3199487ba0d" + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-07-18T09:05:00.467834Z", + "start_time": "2025-07-18T09:05:00.464474Z" + } + }, + "cell_type": "code", + "source": [ + "with open(\"./../data/test_performance_expected.txt\", \"r\") as f:\n", + " expected = f.read().split(\"###\")\n", + " expected = [text.strip().split(\"\\t\") for text in expected]\n", + "\n", + "\n", + "for test_result, expected in zip(test_results, expected):\n", + " terms = test_result[\"result\"][\"terms\"]\n", + " actual = [term[\"text\"] if term[\"normalization\"] is None else term[\"normalization\"] for term in terms]\n" + ], + "id": "2dfe10a8f83f64d5", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6/6\n", + "8/3\n", + "8/3\n", + "15/3\n", + "10/4\n", + "11/7\n", + "11/5\n", + "1/1\n", + "12/4\n", + "15/3\n", + "7/2\n", + "12/5\n", + "1/1\n", + "10/6\n", + "9/5\n", + "2/2\n", + "1/4\n", + "4/1\n", + "1/1\n", + "11/2\n", + "6/5\n" + ] + } + ], + "execution_count": 18 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2025-07-18T09:00:16.250680Z", + "start_time": "2025-07-18T09:00:16.247154Z" + } + }, + "cell_type": "code", + "source": [ + "import json\n", + "\n", + "with open(\"./../data/test_performance_output.json\", \"r\") as f:\n", + " test_results = json.loads(f.read())\n", + "\n", + "with open(\"./../data/test_performance_expected.txt\", \"w\") as f:\n", + " f.write(\"\\n\\n###\\n\\n\".join(\"\\t\".join(sample[\"expected\"]) for sample in test_results))" + ], + "id": "81cb7b8dbbd1ff29", + "outputs": [], + "execution_count": 13 + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/archive/2025/summer/bsc_gerg/tests/util.py b/archive/2025/summer/bsc_gerg/tests/util.py new file mode 100644 index 000000000..b1da26375 --- /dev/null +++ b/archive/2025/summer/bsc_gerg/tests/util.py @@ -0,0 +1,59 @@ +import asyncio +from typing import AsyncIterable, Tuple + +import dotenv +from openai import OpenAI + +SEED = 42 + +def collect_async(iterable: AsyncIterable): + """Synchronously collect all items in the AsyncIterable and return them as a list.""" + async def do(): + return [event async for event in iterable] + return asyncio.run(do()) + + +client: OpenAI | None = None +def get_openai_client() -> OpenAI: + global client + if client is None: + dotenv.load_dotenv() + client = OpenAI() + return client + + +def create_completion_openai_sync( + messages: list[Tuple[str, str]], + model: str = "gpt-4o-mini", + temperature=0.0, + max_completion_tokens=2048, + top_p=0.0, + frequency_penalty=0, + presence_penalty=0, + store=False, + logprobs=False, + ): + response = get_openai_client().chat.completions.create( + model=model, + messages=[ + { + "role": role, + "content": prompt + } for role, prompt in messages + ], + response_format={"type": "text"}, + temperature=temperature, + max_completion_tokens=max_completion_tokens, + top_p=top_p, + frequency_penalty=frequency_penalty, + presence_penalty=presence_penalty, + store=store, + logprobs=logprobs, + seed=SEED, + top_logprobs=20 if logprobs else None + ) + + if logprobs: + return response.choices[0].message.content, response.choices[0].logprobs + else: + return response.choices[0].message.content |