diff --git a/tools/aoptk/.shed.yml b/tools/aoptk/.shed.yml index a44aadf1..9824bac6 100644 --- a/tools/aoptk/.shed.yml +++ b/tools/aoptk/.shed.yml @@ -4,13 +4,13 @@ remote_repository_url: "https://github.com/rdurnik/aoptk" homepage_url: "https://github.com/rdurnik/aoptk" categories: - Machine Learning -description: "AOP-toolkit (aoptk) is a Python package designed to support the development of Adverse Outcome Pathways (AOPs) that require extensive data mining." +description: "AOP-toolkit (aoptk) is a Python package designed to support data mining and analysis of toxicological outcomes." long_description: | - "AOP-toolkit (aoptk) is a Python package developed to support the construction of Adverse Outcome Pathways (AOPs) that require extensive mining and integration of toxicological data from heterogeneous sources. It enables researchers to collect literature from databases such as PubMed and Europe PMC, extract relevant information from full-text publications, and analyze complex, unstructured data using large language models. The toolkit also provides functionality for normalizing chemical names across publications, helping ensure consistency and interoperability." + "AOP-toolkit (aoptk) is a Python package for mining and analyzing toxicological and biomedical literature. Originally developed to support the construction of Adverse Outcome Pathways (AOPs), it provides general-purpose tools for retrieving, processing, and analyzing scientific publications." auto_tool_repositories: name_template: "{{ tool_id }}" description_template: "{{ tool_name }} tool from the aoptk package" suite: name: suite_aoptk - description: AOP-toolkit (aoptk) is a Python package developed to support the construction of Adverse Outcome Pathways (AOPs) that require extensive mining and integration of toxicological data from heterogeneous sources. + description: AOP-toolkit (aoptk) is a Python package for mining and analyzing toxicological and biomedical literature. Originally developed to support the construction of Adverse Outcome Pathways (AOPs), it provides general-purpose tools for retrieving, processing, and analyzing scientific publications. type: repository_suite_definition \ No newline at end of file diff --git a/tools/aoptk/aoptk_chemical_identifier.xml b/tools/aoptk/aoptk_chemical_identifier.xml index 2d5b66e8..2f530247 100644 --- a/tools/aoptk/aoptk_chemical_identifier.xml +++ b/tools/aoptk/aoptk_chemical_identifier.xml @@ -6,19 +6,21 @@ + - + + @@ -31,13 +33,13 @@ - + - + diff --git a/tools/aoptk/aoptk_chemical_matching.xml b/tools/aoptk/aoptk_chemical_matching.xml new file mode 100644 index 00000000..3f027850 --- /dev/null +++ b/tools/aoptk/aoptk_chemical_matching.xml @@ -0,0 +1,58 @@ + + Match chemical entities. + + macros.xml + + + + + + + + + + +import os +import pandas as pd + +chemicals_df_1 = pd.read_csv("$input_file_1", sep="\t") +chemicals_df_2 = pd.read_csv("$input_file_2", sep="\t") +merged_files = chemicals_df_1.merge( + chemicals_df_2, + left_on="heading", + right_on="heading", + how="outer", +) +merged_files.to_csv("merged_chemicals.tsv", sep="\t", index=False) + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/aoptk/aoptk_chemical_normalization_llm.xml b/tools/aoptk/aoptk_chemical_normalization_llm.xml new file mode 100644 index 00000000..9ab43265 --- /dev/null +++ b/tools/aoptk/aoptk_chemical_normalization_llm.xml @@ -0,0 +1,62 @@ + + Normalize chemical entities using LLMs. + + macros.xml + + + + + + + + + + + +import os +from aoptk.text_generation_api import TextGenerationAPI +from aoptk.chemical import Chemical +import pandas as pd + +openai_key = os.environ.get("OPENAI_KEY") +text_generation_api = TextGenerationAPI(model="$llm_model", api_key=openai_key) +chemical_list = pd.read_csv("$chemical_list", sep="\t")["chemical"].tolist() +chemicals = pd.read_csv("$chemicals", sep="\t") +chemicals["chemical"] = chemicals["chemical"].apply( + lambda x: TextGenerationAPI(model="$llm_model", api_key=openai_key).normalize_chemical(chemical=Chemical(x), chemical_list=chemical_list) + ) +chemicals["heading"] = chemicals["chemical"].apply(lambda chem: chem.heading) +chemicals.to_csv("normalized_chemicals.tsv", sep="\t", index=False) + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/aoptk/aoptk_chemical_normalization_mesh.xml b/tools/aoptk/aoptk_chemical_normalization_mesh.xml new file mode 100644 index 00000000..ef204e6a --- /dev/null +++ b/tools/aoptk/aoptk_chemical_normalization_mesh.xml @@ -0,0 +1,55 @@ + + Normalize chemical entities using MeshTerms. + + macros.xml + + + + + + + + + + +from aoptk.chemical import Chemical +from aoptk.normalization.mesh_terms import MeshTerms +import os +import pandas as pd + +chemicals = pd.read_csv("$input_file", sep="\t") +chemicals["chemical"] = chemicals["chemical"].apply( + lambda x: MeshTerms().normalize_chemical(Chemical(x)) + ) +chemicals["heading"] = chemicals["chemical"].apply(lambda chem: chem.heading) +chemicals.to_csv("normalized_chemicals.tsv", sep="\t", index=False) + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/aoptk/aoptk_chemical_normalization_pubchem.xml b/tools/aoptk/aoptk_chemical_normalization_pubchem.xml new file mode 100644 index 00000000..ee1bd67a --- /dev/null +++ b/tools/aoptk/aoptk_chemical_normalization_pubchem.xml @@ -0,0 +1,55 @@ + + Normalize chemical entities using PubChem API. + + macros.xml + + + + + + + + + + +from aoptk.normalization.pubchem_api import PubChemAPI +from aoptk.chemical import Chemical +import os +import pandas as pd + +chemicals = pd.read_csv("$input_file", sep="\t") +chemicals["chemical"] = chemicals["chemical"].apply( + lambda x: PubChemAPI().normalize_chemical(Chemical(x)) + ) +chemicals["heading"] = chemicals["chemical"].apply(lambda chem: chem.heading) +chemicals.to_csv("normalized_chemicals.tsv", sep="\t", index=False) + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/aoptk/aoptk_download_abstracts.xml b/tools/aoptk/aoptk_download_abstracts.xml new file mode 100644 index 00000000..0294deea --- /dev/null +++ b/tools/aoptk/aoptk_download_abstracts.xml @@ -0,0 +1,74 @@ + + Download abstracts for a list of publication IDs. + + macros.xml + + + + + + + + + + + +from aoptk.literature.databases.pubmed import PubMed +from aoptk.literature.databases.europepmc import EuropePMC +from aoptk.literature.abstract import Abstract +from Bio import Entrez +import os + +with open("$input_file", "r") as f: + ids = [line.strip() for line in f.readlines()] +email = os.environ.get("EMAIL") + + +if "${literature_database_pubmed_europepmc}" == "pubmed": + Entrez.email = email + pubmed = PubMed.__new__(PubMed) + pubmed.id_list = ids + abstracts = pubmed.get_abstracts() +elif "${literature_database_pubmed_europepmc}" == "europepmc": + europepmc = EuropePMC("") + europepmc.id_list = ids + abstracts = europepmc.get_abstracts() +else: + raise ValueError("Select valid database.") + +for abstract in abstracts: + with open(f"{abstract.publication_id}.txt", "w") as f: + f.write(abstract.text) + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/aoptk/aoptk_download_fulltext.xml b/tools/aoptk/aoptk_download_fulltext.xml new file mode 100644 index 00000000..4b6f3b5d --- /dev/null +++ b/tools/aoptk/aoptk_download_fulltext.xml @@ -0,0 +1,76 @@ + + Download full texts for a list of publication IDs. + + macros.xml + + + + + + + + + + + +from aoptk.literature.databases.pmc import PMC +from aoptk.literature.databases.europepmc import EuropePMC +from Bio import Entrez +import os + +with open("$input_file", "r") as f: + ids = [line.strip() for line in f.readlines()] +email = os.environ.get("EMAIL") + + +if "${literature_database_europepmc_pmc}" == "pmc": + Entrez.email = email + pmc = PMC("", storage = "./", figure_storage="./figures") + pmc.id_list = ids + publications = pmc.get_publications() +elif "${literature_database_europepmc_pmc}" == "europepmc": + europepmc = EuropePMC("", storage = "./", figure_storage="./figures") + europepmc.id_list = ids + publications = europepmc.get_publications() +else: + raise ValueError("Select valid database.") + +for publication in publications: + with open(f"{publication.publication_id}.txt", "w") as f: + f.write(publication.full_text) + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/aoptk/aoptk_download_pdf.xml b/tools/aoptk/aoptk_download_pdf.xml new file mode 100644 index 00000000..4df1a824 --- /dev/null +++ b/tools/aoptk/aoptk_download_pdf.xml @@ -0,0 +1,55 @@ + + Download PDFs for a list of publication IDs. + + macros.xml + + + + + + + + + + +from aoptk.literature.databases.pmc import PMC +import os + +with open("$input_file", "r") as f: + ids = [line.strip() for line in f.readlines()] + +pmc = PMC("", storage = "./") +pmc.id_list = ids +pdfs = pmc.get_pdfs() + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/aoptk/aoptk_find_chemicals.xml b/tools/aoptk/aoptk_find_chemicals.xml new file mode 100644 index 00000000..6c45b081 --- /dev/null +++ b/tools/aoptk/aoptk_find_chemicals.xml @@ -0,0 +1,73 @@ + + Detect chemicals in text. + + macros.xml + + + + + + + + + + + +import os +from aoptk.text_generation_api import TextGenerationAPI +from aoptk.literature.pdf import PDF +from aoptk.literature.pymupdf_parser import PymupdfParser + +publication_id = os.path.splitext("$input_file.element_identifier")[0] +openai_key = os.environ.get("OPENAI_KEY") +text_generation_api = TextGenerationAPI(model="$llm_model", api_key=openai_key) + +if "${input_file.ext}" == "pdf": + text = PymupdfParser([PDF("$input_file")]).get_publications()[0].full_text + chemicals = text_generation_api.find_chemicals(text) + +elif "${input_file.ext}" == "txt": + with open("$input_file", "r") as f_in: + text = f_in.read() + chemicals = text_generation_api.find_chemicals(text) +else: + raise ValueError(f"Unsupported input file format: {input_ext}") + +with open("chemicals.tsv", "w") as f_out: + f_out.write("id\tchemical\n") + for chemical in chemicals: + f_out.write(f"{publication_id}\t{chemical.name}\n") + + + + + + + + + [0-9a-zA-Z]+ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/aoptk/aoptk_find_chemicals_non_llm.xml b/tools/aoptk/aoptk_find_chemicals_non_llm.xml new file mode 100644 index 00000000..2b1619a5 --- /dev/null +++ b/tools/aoptk/aoptk_find_chemicals_non_llm.xml @@ -0,0 +1,65 @@ + + Detect chemicals in text. + + macros.xml + + + + + + + + + + +from aoptk.spacy_text_processor import SpacyText +from aoptk.literature.pdf import PDF +from aoptk.literature.pymupdf_parser import PymupdfParser +import os + +publication_id = os.path.splitext("$input_file.element_identifier")[0] + +if "${input_file.ext}" == "pdf": + text = PymupdfParser([PDF("$input_file")]).get_publications()[0].full_text + chemicals = SpacyText().find_chemical(text) + +elif "${input_file.ext}" == "txt": + with open("$input_file", "r") as f_in: + text = f_in.read() + chemicals = SpacyText().find_chemical(text) +else: + raise ValueError(f"Unsupported input file format: {input_ext}") + +with open("chemicals.tsv", "w") as f_out: + f_out.write("id\tchemical\n") + for chemical in chemicals: + f_out.write(f"{publication_id}\t{chemical.name}\n") + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/aoptk/aoptk_find_relationships_non_llm.xml b/tools/aoptk/aoptk_find_relationships_non_llm.xml new file mode 100644 index 00000000..12f8b20d --- /dev/null +++ b/tools/aoptk/aoptk_find_relationships_non_llm.xml @@ -0,0 +1,84 @@ + + Detect relationships between chemicals and effects in text. + + macros.xml + + + + + + + + + + +import os +import sys + +os.environ.setdefault("TORCHINDUCTOR_CACHE_DIR", os.path.join(os.getcwd(), ".torchinductor_cache")) +os.makedirs(os.environ["TORCHINDUCTOR_CACHE_DIR"], exist_ok=True) + +from aoptk.spacy_text_processor import SpacyText +from aoptk.relationships.zero_shot_classification_single import ZeroShotClassificationSingle +from aoptk.literature.pdf import PDF +from aoptk.literature.pymupdf_parser import PymupdfParser + +publication_id = os.path.splitext("$input_file.element_identifier")[0] +effects = ["${effect}"] +email = os.environ.get("EMAIL") + +if "${input_file.ext}" == "pdf": + text = PymupdfParser([PDF("$input_file")]).get_publications()[0].full_text + chemicals = SpacyText().find_chemical(text) + relationships = ZeroShotClassificationSingle().find_relationships( + text=text, chemicals=chemicals, effects=effects +) + +elif "${input_file.ext}" == "txt": + with open("$input_file", "r") as f_in: + text = f_in.read() + chemicals = SpacyText().find_chemical(text) + relationships = ZeroShotClassificationSingle().find_relationships( + text=text, chemicals=chemicals, effects=effects + ) + +else: + raise ValueError(f"Unsupported input file format: ${input_file.ext}") + +with open("relationships.tsv", "w") as f_out: + f_out.write("id\tchemical\teffect\trelationship\n") + for relationship in relationships: + f_out.write(f"{publication_id}\t{relationship.chemical}\t{relationship.effect}\t{relationship.relationship_type}\n") + + + + + + + [0-9a-zA-Z]+ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/aoptk/aoptk_find_relationships_text.xml b/tools/aoptk/aoptk_find_relationships_text.xml new file mode 100644 index 00000000..2545c60f --- /dev/null +++ b/tools/aoptk/aoptk_find_relationships_text.xml @@ -0,0 +1,86 @@ + + Detect relationships between chemicals and effects in text. + + macros.xml + + + + + + + + + + + +import os +from aoptk.text_generation_api import TextGenerationAPI +from aoptk.relationship_type import Causative +from aoptk.relationship_type import Inhibitive +from aoptk.relationship_type import RelationshipType +from aoptk.relationships.relationship import Relationship +from aoptk.effect import Effect + +publication_id = os.path.splitext("$input_file.element_identifier")[0] +effects = ["${effect}"] +openai_key = os.environ.get("OPENAI_KEY") +text_generation_api = TextGenerationAPI(model="$llm_model", api_key=openai_key) +text_generation_api.specification_relationship_text_prompt="$prompt_specification" + +if "${input_file.ext}" == "pdf": + text = PymupdfParser([PDF("$input_file")]).inject_text_generation(TextGenerationAPI(model="redhatai-scout")).get_publications()[0].full_text + chemicals = text_generation_api.find_chemicals(text) + relationships = text_generation_api.find_relationships_in_text( + text=text, chemicals=chemicals, effects=effects +) + +elif "${input_file.ext}" == "txt": + with open("$input_file", "r") as f_in: + text = f_in.read() + chemicals = text_generation_api.find_chemicals(text) + relationships = text_generation_api.find_relationships_in_text( + text=text, chemicals=chemicals, effects=effects + ) + +else: + raise ValueError(f"Unsupported input file format: ${input_file.ext}") + +with open("relationships.tsv", "w") as f_out: + f_out.write("id\tchemical\teffect\trelationship\n") + for relationship in relationships: + f_out.write(f"{publication_id}\t{relationship.chemical}\t{relationship.effect}\t{relationship.relationship_type}\n") + + + + + + + + + [0-9a-zA-Z]+ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/aoptk/aoptk_find_relationships_text_images.xml b/tools/aoptk/aoptk_find_relationships_text_images.xml new file mode 100644 index 00000000..88cb1295 --- /dev/null +++ b/tools/aoptk/aoptk_find_relationships_text_images.xml @@ -0,0 +1,105 @@ + + Detect relationships between chemicals and effects in text. + + macros.xml + + + + + + + + + + + +import os +from aoptk.text_generation_api import TextGenerationAPI +from aoptk.relationship_type import Causative +from aoptk.relationship_type import Inhibitive +from aoptk.relationship_type import RelationshipType +from aoptk.relationships.relationship import Relationship +from aoptk.effect import Effect + +publication_id = os.path.splitext("$input_file.element_identifier")[0] +effects = ["${effect}"] +openai_key = os.environ.get("OPENAI_KEY") +text_generation_api = TextGenerationAPI(model="$llm_model", api_key=openai_key) +text_generation_api.specification_relationship_text_prompt="$prompt_specification" + +if "${input_file.ext}" == "pdf": + text = "" + publication = PymupdfParser([PDF("$input_file")]).inject_text_generation(TextGenerationAPI(model="$llm_models_images")).get_publications()[0] + text += publication.full_text + + for image in publication.images: + text_image = TextGenerationAPI(model="$llm_models_images").convert_image( + image_path=image.path, + text=publication.full_text, + ) + text += f"\n\n{image.name}:\n{text_image}" + + chemicals = text_generation_api.find_chemicals(text) + relationships = text_generation_api.find_relationships_in_text( + text=text, chemicals=chemicals, effects=effects +) + +elif "${input_file.ext}" == "txt": + with open("$input_file", "r") as f_in: + text = "" + text += f_in.read() + text += "\n\n\n\nALSO ANALYZE THESE FIGURES CONVERTED TO TEXT:" + for image in publication_images_folder.iterdir(): + text_image = TextGenerationAPI(model="$llm_models_images").convert_image( + image_path=image, + text=matching_pub_data["publication.full_text"], + ) + text += f"\n\n{image.name}:\n{text_image}" + + chemicals = text_generation_api.find_chemicals(text) + relationships = text_generation_api.find_relationships_in_text( + text=text, chemicals=chemicals, effects=effects + ) +else: + raise ValueError(f"Unsupported input file format: ${input_file.ext}") + +with open("relationships.tsv", "w") as f_out: + f_out.write("id\tchemical\teffect\trelationship\n") + for relationship in relationships: + f_out.write(f"{publication_id}\t{relationship.chemical}\t{relationship.effect}\t{relationship.relationship_type}\n") + + + + + + + + + + [0-9a-zA-Z]+ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/aoptk/aoptk_parse_pdf.xml b/tools/aoptk/aoptk_parse_pdf.xml new file mode 100644 index 00000000..798c1240 --- /dev/null +++ b/tools/aoptk/aoptk_parse_pdf.xml @@ -0,0 +1,63 @@ + + Parse PDF files. + + macros.xml + + + + + + + + + + + +from aoptk.literature.pdf import PDF +from aoptk.literature.pymupdf_parser import PymupdfParser +from aoptk.text_generation_api import TextGenerationAPI +import os + +publication_id = os.path.splitext("$input_file.element_identifier")[0] +if "${input_file.ext}" == "pdf": + parser = PymupdfParser([PDF("$input_file")]) + if os.environ.get("OPENAI_KEY"): + parser = parser.inject_text_generation(TextGenerationAPI(model="$llm_models_images", api_key=os.environ.get("OPENAI_KEY"))) + + pdf = parser.get_publications() + text = pdf[0].full_text + with open(f"{publication_id}.txt", "w") as f: + f.write(text) + +else: + raise ValueError(f"Unsupported input file format: ${input_file.ext}") + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/aoptk/aoptk_publication_tracker.xml b/tools/aoptk/aoptk_publication_tracker.xml index b20a13ab..05e4a82d 100644 --- a/tools/aoptk/aoptk_publication_tracker.xml +++ b/tools/aoptk/aoptk_publication_tracker.xml @@ -6,6 +6,7 @@ + - + @@ -46,7 +47,7 @@ - + @@ -54,7 +55,7 @@ - + @@ -62,7 +63,7 @@ - + diff --git a/tools/aoptk/aoptk_query_literature.xml b/tools/aoptk/aoptk_query_literature.xml new file mode 100644 index 00000000..095cf849 --- /dev/null +++ b/tools/aoptk/aoptk_query_literature.xml @@ -0,0 +1,71 @@ + + Query literature for a list of publication IDs. + + macros.xml + + + + + + + + + + + +from aoptk.literature.databases.pubmed import PubMed +from aoptk.literature.databases.europepmc import EuropePMC +from aoptk.literature.databases.pmc import PMC +from Bio import Entrez +import os + +email = os.environ.get("EMAIL") + + +if "${literature_database_pubmed_europepmc_pmc}" == "pubmed": + Entrez.email = email + ids = PubMed("${query}").get_id() +elif "${literature_database_pubmed_europepmc_pmc}" == "europepmc": + ids = EuropePMC("${query}").get_id() +elif "${literature_database_pubmed_europepmc_pmc}" == "pmc": + Entrez.email = email + ids = PMC("${query}").get_id() + +else: + raise ValueError("Select valid database.") + +with open(f"ids.txt", "w") as f: + for id in ids: + f.write(f"{id}\n") + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tools/aoptk/macros.xml b/tools/aoptk/macros.xml index 5c0881e5..3826a7a0 100644 --- a/tools/aoptk/macros.xml +++ b/tools/aoptk/macros.xml @@ -1,18 +1,30 @@ - 0.1.6 + 0.2.0 0 aoptk + + + - + + + + + + + - + @@ -82,11 +94,109 @@ [0-9a-zA-Z_ ()*'"[\]\[\]\-:.\[\]α-ωΑ-Ω]+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [0-9a-zA-Z_ ()*'"[\]\[\]\-:.\[\]α-ωΑ-Ω]+ + + + diff --git a/tools/aoptk/test-data/chemicals.tsv b/tools/aoptk/test-data/chemicals.tsv new file mode 100644 index 00000000..a373f17c --- /dev/null +++ b/tools/aoptk/test-data/chemicals.tsv @@ -0,0 +1,4 @@ +id chemical +123 thioacetamide +456 acetaminophen +789 paracetamol \ No newline at end of file diff --git a/tools/aoptk/test-data/ids.txt b/tools/aoptk/test-data/ids.txt new file mode 100644 index 00000000..45504114 --- /dev/null +++ b/tools/aoptk/test-data/ids.txt @@ -0,0 +1,2 @@ +41480994 +PMC12930283 \ No newline at end of file diff --git a/tools/aoptk/test-data/normalized.tsv b/tools/aoptk/test-data/normalized.tsv new file mode 100644 index 00000000..774b0683 --- /dev/null +++ b/tools/aoptk/test-data/normalized.tsv @@ -0,0 +1,4 @@ +heading chemical +thioacetamide thioacetamide +acetaminophen acetaminophen +acetaminophen paracetamol \ No newline at end of file diff --git a/tools/aoptk/test-data/relationships.tsv b/tools/aoptk/test-data/relationships.tsv new file mode 100644 index 00000000..62e0c8a8 --- /dev/null +++ b/tools/aoptk/test-data/relationships.tsv @@ -0,0 +1,2 @@ +id chemical effect relationship +text thioacetamide liver fibrosis positive \ No newline at end of file diff --git a/tools/aoptk/test-data/text.pdf b/tools/aoptk/test-data/text.pdf new file mode 100644 index 00000000..4fc5b3dc Binary files /dev/null and b/tools/aoptk/test-data/text.pdf differ diff --git a/tools/aoptk/test-data/text.txt b/tools/aoptk/test-data/text.txt new file mode 100644 index 00000000..5b5f97da --- /dev/null +++ b/tools/aoptk/test-data/text.txt @@ -0,0 +1 @@ +Thioacetamide is a chemical that causes liver fibrosis. \ No newline at end of file