aiagents4pharma 1.44.0__py3-none-any.whl → 1.45.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aiagents4pharma/__init__.py +2 -2
- aiagents4pharma/talk2aiagents4pharma/.dockerignore +13 -0
- aiagents4pharma/talk2aiagents4pharma/Dockerfile +105 -0
- aiagents4pharma/talk2aiagents4pharma/README.md +1 -0
- aiagents4pharma/talk2aiagents4pharma/__init__.py +4 -5
- aiagents4pharma/talk2aiagents4pharma/agents/__init__.py +3 -2
- aiagents4pharma/talk2aiagents4pharma/agents/main_agent.py +24 -23
- aiagents4pharma/talk2aiagents4pharma/configs/__init__.py +2 -2
- aiagents4pharma/talk2aiagents4pharma/configs/agents/__init__.py +2 -2
- aiagents4pharma/talk2aiagents4pharma/configs/agents/main_agent/default.yaml +2 -2
- aiagents4pharma/talk2aiagents4pharma/configs/config.yaml +1 -1
- aiagents4pharma/talk2aiagents4pharma/docker-compose/cpu/.env.example +23 -0
- aiagents4pharma/talk2aiagents4pharma/docker-compose/cpu/docker-compose.yml +93 -0
- aiagents4pharma/talk2aiagents4pharma/docker-compose/gpu/.env.example +23 -0
- aiagents4pharma/talk2aiagents4pharma/docker-compose/gpu/docker-compose.yml +108 -0
- aiagents4pharma/talk2aiagents4pharma/install.md +127 -0
- aiagents4pharma/talk2aiagents4pharma/states/__init__.py +3 -2
- aiagents4pharma/talk2aiagents4pharma/states/state_talk2aiagents4pharma.py +5 -3
- aiagents4pharma/talk2aiagents4pharma/tests/__init__.py +2 -2
- aiagents4pharma/talk2aiagents4pharma/tests/test_main_agent.py +72 -50
- aiagents4pharma/talk2biomodels/.dockerignore +13 -0
- aiagents4pharma/talk2biomodels/Dockerfile +104 -0
- aiagents4pharma/talk2biomodels/README.md +1 -0
- aiagents4pharma/talk2biomodels/__init__.py +4 -8
- aiagents4pharma/talk2biomodels/agents/__init__.py +3 -2
- aiagents4pharma/talk2biomodels/agents/t2b_agent.py +47 -42
- aiagents4pharma/talk2biomodels/api/__init__.py +4 -5
- aiagents4pharma/talk2biomodels/api/kegg.py +14 -10
- aiagents4pharma/talk2biomodels/api/ols.py +13 -10
- aiagents4pharma/talk2biomodels/api/uniprot.py +7 -6
- aiagents4pharma/talk2biomodels/configs/__init__.py +3 -4
- aiagents4pharma/talk2biomodels/configs/agents/__init__.py +2 -2
- aiagents4pharma/talk2biomodels/configs/agents/t2b_agent/__init__.py +2 -2
- aiagents4pharma/talk2biomodels/configs/agents/t2b_agent/default.yaml +1 -1
- aiagents4pharma/talk2biomodels/configs/config.yaml +1 -1
- aiagents4pharma/talk2biomodels/configs/tools/__init__.py +4 -5
- aiagents4pharma/talk2biomodels/configs/tools/ask_question/__init__.py +2 -2
- aiagents4pharma/talk2biomodels/configs/tools/ask_question/default.yaml +1 -2
- aiagents4pharma/talk2biomodels/configs/tools/custom_plotter/__init__.py +2 -2
- aiagents4pharma/talk2biomodels/configs/tools/custom_plotter/default.yaml +1 -1
- aiagents4pharma/talk2biomodels/configs/tools/get_annotation/__init__.py +2 -2
- aiagents4pharma/talk2biomodels/configs/tools/get_annotation/default.yaml +1 -1
- aiagents4pharma/talk2biomodels/install.md +63 -0
- aiagents4pharma/talk2biomodels/models/__init__.py +4 -4
- aiagents4pharma/talk2biomodels/models/basico_model.py +36 -28
- aiagents4pharma/talk2biomodels/models/sys_bio_model.py +13 -10
- aiagents4pharma/talk2biomodels/states/__init__.py +3 -2
- aiagents4pharma/talk2biomodels/states/state_talk2biomodels.py +12 -8
- aiagents4pharma/talk2biomodels/tests/BIOMD0000000449_url.xml +1585 -0
- aiagents4pharma/talk2biomodels/tests/__init__.py +2 -2
- aiagents4pharma/talk2biomodels/tests/article_on_model_537.pdf +0 -0
- aiagents4pharma/talk2biomodels/tests/test_api.py +18 -14
- aiagents4pharma/talk2biomodels/tests/test_ask_question.py +8 -9
- aiagents4pharma/talk2biomodels/tests/test_basico_model.py +15 -9
- aiagents4pharma/talk2biomodels/tests/test_get_annotation.py +54 -55
- aiagents4pharma/talk2biomodels/tests/test_getmodelinfo.py +28 -27
- aiagents4pharma/talk2biomodels/tests/test_integration.py +21 -33
- aiagents4pharma/talk2biomodels/tests/test_load_biomodel.py +14 -11
- aiagents4pharma/talk2biomodels/tests/test_param_scan.py +21 -20
- aiagents4pharma/talk2biomodels/tests/test_query_article.py +129 -29
- aiagents4pharma/talk2biomodels/tests/test_search_models.py +9 -13
- aiagents4pharma/talk2biomodels/tests/test_simulate_model.py +16 -15
- aiagents4pharma/talk2biomodels/tests/test_steady_state.py +12 -22
- aiagents4pharma/talk2biomodels/tests/test_sys_bio_model.py +33 -29
- aiagents4pharma/talk2biomodels/tools/__init__.py +15 -12
- aiagents4pharma/talk2biomodels/tools/ask_question.py +42 -32
- aiagents4pharma/talk2biomodels/tools/custom_plotter.py +51 -43
- aiagents4pharma/talk2biomodels/tools/get_annotation.py +99 -75
- aiagents4pharma/talk2biomodels/tools/get_modelinfo.py +57 -51
- aiagents4pharma/talk2biomodels/tools/load_arguments.py +52 -32
- aiagents4pharma/talk2biomodels/tools/load_biomodel.py +8 -2
- aiagents4pharma/talk2biomodels/tools/parameter_scan.py +107 -90
- aiagents4pharma/talk2biomodels/tools/query_article.py +14 -13
- aiagents4pharma/talk2biomodels/tools/search_models.py +37 -26
- aiagents4pharma/talk2biomodels/tools/simulate_model.py +47 -37
- aiagents4pharma/talk2biomodels/tools/steady_state.py +76 -58
- aiagents4pharma/talk2biomodels/tools/utils.py +4 -3
- aiagents4pharma/talk2cells/README.md +1 -0
- aiagents4pharma/talk2cells/__init__.py +4 -5
- aiagents4pharma/talk2cells/agents/__init__.py +3 -2
- aiagents4pharma/talk2cells/agents/scp_agent.py +21 -19
- aiagents4pharma/talk2cells/states/__init__.py +3 -2
- aiagents4pharma/talk2cells/states/state_talk2cells.py +4 -2
- aiagents4pharma/talk2cells/tests/scp_agent/test_scp_agent.py +8 -9
- aiagents4pharma/talk2cells/tools/__init__.py +3 -2
- aiagents4pharma/talk2cells/tools/scp_agent/__init__.py +4 -4
- aiagents4pharma/talk2cells/tools/scp_agent/display_studies.py +5 -3
- aiagents4pharma/talk2cells/tools/scp_agent/search_studies.py +21 -22
- aiagents4pharma/talk2knowledgegraphs/.dockerignore +13 -0
- aiagents4pharma/talk2knowledgegraphs/Dockerfile +103 -0
- aiagents4pharma/talk2knowledgegraphs/README.md +1 -0
- aiagents4pharma/talk2knowledgegraphs/__init__.py +4 -7
- aiagents4pharma/talk2knowledgegraphs/agents/__init__.py +3 -2
- aiagents4pharma/talk2knowledgegraphs/agents/t2kg_agent.py +40 -30
- aiagents4pharma/talk2knowledgegraphs/configs/__init__.py +3 -6
- aiagents4pharma/talk2knowledgegraphs/configs/agents/t2kg_agent/__init__.py +2 -2
- aiagents4pharma/talk2knowledgegraphs/configs/agents/t2kg_agent/default.yaml +8 -8
- aiagents4pharma/talk2knowledgegraphs/configs/app/__init__.py +3 -2
- aiagents4pharma/talk2knowledgegraphs/configs/app/frontend/__init__.py +2 -2
- aiagents4pharma/talk2knowledgegraphs/configs/app/frontend/default.yaml +1 -1
- aiagents4pharma/talk2knowledgegraphs/configs/config.yaml +1 -1
- aiagents4pharma/talk2knowledgegraphs/configs/tools/__init__.py +4 -5
- aiagents4pharma/talk2knowledgegraphs/configs/tools/graphrag_reasoning/__init__.py +2 -2
- aiagents4pharma/talk2knowledgegraphs/configs/tools/graphrag_reasoning/default.yaml +1 -1
- aiagents4pharma/talk2knowledgegraphs/configs/tools/subgraph_extraction/__init__.py +2 -2
- aiagents4pharma/talk2knowledgegraphs/configs/tools/subgraph_extraction/default.yaml +1 -1
- aiagents4pharma/talk2knowledgegraphs/configs/tools/subgraph_summarization/__init__.py +2 -2
- aiagents4pharma/talk2knowledgegraphs/configs/tools/subgraph_summarization/default.yaml +1 -1
- aiagents4pharma/talk2knowledgegraphs/configs/utils/enrichments/ols_terms/default.yaml +1 -1
- aiagents4pharma/talk2knowledgegraphs/configs/utils/enrichments/reactome_pathways/default.yaml +1 -1
- aiagents4pharma/talk2knowledgegraphs/configs/utils/enrichments/uniprot_proteins/default.yaml +1 -1
- aiagents4pharma/talk2knowledgegraphs/configs/utils/pubchem_utils/default.yaml +1 -1
- aiagents4pharma/talk2knowledgegraphs/datasets/__init__.py +4 -6
- aiagents4pharma/talk2knowledgegraphs/datasets/biobridge_primekg.py +115 -67
- aiagents4pharma/talk2knowledgegraphs/datasets/dataset.py +2 -0
- aiagents4pharma/talk2knowledgegraphs/datasets/primekg.py +35 -24
- aiagents4pharma/talk2knowledgegraphs/datasets/starkqa_primekg.py +29 -21
- aiagents4pharma/talk2knowledgegraphs/docker-compose/cpu/.env.example +23 -0
- aiagents4pharma/talk2knowledgegraphs/docker-compose/cpu/docker-compose.yml +93 -0
- aiagents4pharma/talk2knowledgegraphs/docker-compose/gpu/.env.example +23 -0
- aiagents4pharma/talk2knowledgegraphs/docker-compose/gpu/docker-compose.yml +108 -0
- aiagents4pharma/talk2knowledgegraphs/entrypoint.sh +190 -0
- aiagents4pharma/talk2knowledgegraphs/install.md +140 -0
- aiagents4pharma/talk2knowledgegraphs/milvus_data_dump.py +31 -65
- aiagents4pharma/talk2knowledgegraphs/states/__init__.py +3 -2
- aiagents4pharma/talk2knowledgegraphs/states/state_talk2knowledgegraphs.py +1 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_agents_t2kg_agent.py +65 -40
- aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_biobridge_primekg.py +54 -48
- aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_dataset.py +4 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_primekg.py +17 -4
- aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_starkqa_primekg.py +33 -24
- aiagents4pharma/talk2knowledgegraphs/tests/test_tools_graphrag_reasoning.py +116 -69
- aiagents4pharma/talk2knowledgegraphs/tests/test_tools_milvus_multimodal_subgraph_extraction.py +334 -216
- aiagents4pharma/talk2knowledgegraphs/tests/test_tools_multimodal_subgraph_extraction.py +22 -15
- aiagents4pharma/talk2knowledgegraphs/tests/test_tools_subgraph_extraction.py +19 -12
- aiagents4pharma/talk2knowledgegraphs/tests/test_tools_subgraph_summarization.py +95 -48
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_embeddings.py +4 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_huggingface.py +5 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_nim_molmim.py +13 -18
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_ollama.py +10 -3
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_enrichments.py +4 -3
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_ollama.py +3 -2
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_ols.py +1 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_pubchem.py +9 -4
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_reactome.py +6 -6
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_uniprot.py +4 -0
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_extractions_milvus_multimodal_pcst.py +160 -97
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_kg_utils.py +3 -4
- aiagents4pharma/talk2knowledgegraphs/tests/test_utils_pubchem_utils.py +87 -13
- aiagents4pharma/talk2knowledgegraphs/tools/__init__.py +10 -7
- aiagents4pharma/talk2knowledgegraphs/tools/graphrag_reasoning.py +15 -20
- aiagents4pharma/talk2knowledgegraphs/tools/milvus_multimodal_subgraph_extraction.py +145 -142
- aiagents4pharma/talk2knowledgegraphs/tools/multimodal_subgraph_extraction.py +92 -90
- aiagents4pharma/talk2knowledgegraphs/tools/subgraph_extraction.py +25 -37
- aiagents4pharma/talk2knowledgegraphs/tools/subgraph_summarization.py +10 -13
- aiagents4pharma/talk2knowledgegraphs/utils/__init__.py +4 -7
- aiagents4pharma/talk2knowledgegraphs/utils/embeddings/__init__.py +4 -7
- aiagents4pharma/talk2knowledgegraphs/utils/embeddings/embeddings.py +4 -0
- aiagents4pharma/talk2knowledgegraphs/utils/embeddings/huggingface.py +11 -14
- aiagents4pharma/talk2knowledgegraphs/utils/embeddings/nim_molmim.py +7 -7
- aiagents4pharma/talk2knowledgegraphs/utils/embeddings/ollama.py +12 -6
- aiagents4pharma/talk2knowledgegraphs/utils/embeddings/sentence_transformer.py +8 -6
- aiagents4pharma/talk2knowledgegraphs/utils/enrichments/__init__.py +9 -6
- aiagents4pharma/talk2knowledgegraphs/utils/enrichments/enrichments.py +1 -0
- aiagents4pharma/talk2knowledgegraphs/utils/enrichments/ollama.py +15 -9
- aiagents4pharma/talk2knowledgegraphs/utils/enrichments/ols_terms.py +23 -20
- aiagents4pharma/talk2knowledgegraphs/utils/enrichments/pubchem_strings.py +12 -10
- aiagents4pharma/talk2knowledgegraphs/utils/enrichments/reactome_pathways.py +16 -10
- aiagents4pharma/talk2knowledgegraphs/utils/enrichments/uniprot_proteins.py +26 -18
- aiagents4pharma/talk2knowledgegraphs/utils/extractions/__init__.py +4 -5
- aiagents4pharma/talk2knowledgegraphs/utils/extractions/milvus_multimodal_pcst.py +14 -34
- aiagents4pharma/talk2knowledgegraphs/utils/extractions/multimodal_pcst.py +53 -47
- aiagents4pharma/talk2knowledgegraphs/utils/extractions/pcst.py +18 -14
- aiagents4pharma/talk2knowledgegraphs/utils/kg_utils.py +22 -23
- aiagents4pharma/talk2knowledgegraphs/utils/pubchem_utils.py +11 -10
- aiagents4pharma/talk2scholars/.dockerignore +13 -0
- aiagents4pharma/talk2scholars/Dockerfile +104 -0
- aiagents4pharma/talk2scholars/README.md +1 -0
- aiagents4pharma/talk2scholars/agents/__init__.py +1 -5
- aiagents4pharma/talk2scholars/agents/main_agent.py +6 -4
- aiagents4pharma/talk2scholars/agents/paper_download_agent.py +5 -4
- aiagents4pharma/talk2scholars/agents/pdf_agent.py +4 -2
- aiagents4pharma/talk2scholars/agents/s2_agent.py +2 -2
- aiagents4pharma/talk2scholars/agents/zotero_agent.py +10 -11
- aiagents4pharma/talk2scholars/configs/__init__.py +1 -3
- aiagents4pharma/talk2scholars/configs/agents/talk2scholars/__init__.py +1 -4
- aiagents4pharma/talk2scholars/configs/agents/talk2scholars/main_agent/default.yaml +1 -1
- aiagents4pharma/talk2scholars/configs/agents/talk2scholars/pdf_agent/default.yaml +1 -1
- aiagents4pharma/talk2scholars/configs/agents/talk2scholars/s2_agent/default.yaml +8 -8
- aiagents4pharma/talk2scholars/configs/agents/talk2scholars/zotero_agent/default.yaml +7 -7
- aiagents4pharma/talk2scholars/configs/tools/__init__.py +8 -6
- aiagents4pharma/talk2scholars/docker-compose/cpu/.env.example +21 -0
- aiagents4pharma/talk2scholars/docker-compose/cpu/docker-compose.yml +90 -0
- aiagents4pharma/talk2scholars/docker-compose/gpu/.env.example +21 -0
- aiagents4pharma/talk2scholars/docker-compose/gpu/docker-compose.yml +105 -0
- aiagents4pharma/talk2scholars/install.md +122 -0
- aiagents4pharma/talk2scholars/state/state_talk2scholars.py +8 -8
- aiagents4pharma/talk2scholars/tests/{test_main_agent.py → test_agents_main_agent.py} +41 -23
- aiagents4pharma/talk2scholars/tests/{test_paper_download_agent.py → test_agents_paper_agents_download_agent.py} +10 -16
- aiagents4pharma/talk2scholars/tests/{test_pdf_agent.py → test_agents_pdf_agent.py} +6 -10
- aiagents4pharma/talk2scholars/tests/{test_s2_agent.py → test_agents_s2_agent.py} +8 -16
- aiagents4pharma/talk2scholars/tests/{test_zotero_agent.py → test_agents_zotero_agent.py} +5 -7
- aiagents4pharma/talk2scholars/tests/{test_s2_display_dataframe.py → test_s2_tools_display_dataframe.py} +6 -7
- aiagents4pharma/talk2scholars/tests/{test_s2_query_dataframe.py → test_s2_tools_query_dataframe.py} +5 -15
- aiagents4pharma/talk2scholars/tests/{test_paper_downloader.py → test_tools_paper_downloader.py} +25 -63
- aiagents4pharma/talk2scholars/tests/{test_question_and_answer_tool.py → test_tools_question_and_answer_tool.py} +2 -6
- aiagents4pharma/talk2scholars/tests/{test_s2_multi.py → test_tools_s2_multi.py} +5 -5
- aiagents4pharma/talk2scholars/tests/{test_s2_retrieve.py → test_tools_s2_retrieve.py} +2 -1
- aiagents4pharma/talk2scholars/tests/{test_s2_search.py → test_tools_s2_search.py} +5 -5
- aiagents4pharma/talk2scholars/tests/{test_s2_single.py → test_tools_s2_single.py} +5 -5
- aiagents4pharma/talk2scholars/tests/{test_arxiv_downloader.py → test_utils_arxiv_downloader.py} +16 -25
- aiagents4pharma/talk2scholars/tests/{test_base_paper_downloader.py → test_utils_base_paper_downloader.py} +25 -47
- aiagents4pharma/talk2scholars/tests/{test_biorxiv_downloader.py → test_utils_biorxiv_downloader.py} +14 -42
- aiagents4pharma/talk2scholars/tests/{test_medrxiv_downloader.py → test_utils_medrxiv_downloader.py} +15 -49
- aiagents4pharma/talk2scholars/tests/{test_nvidia_nim_reranker.py → test_utils_nvidia_nim_reranker.py} +6 -16
- aiagents4pharma/talk2scholars/tests/{test_pdf_answer_formatter.py → test_utils_pdf_answer_formatter.py} +1 -0
- aiagents4pharma/talk2scholars/tests/{test_pdf_batch_processor.py → test_utils_pdf_batch_processor.py} +6 -15
- aiagents4pharma/talk2scholars/tests/{test_pdf_collection_manager.py → test_utils_pdf_collection_manager.py} +34 -11
- aiagents4pharma/talk2scholars/tests/{test_pdf_document_processor.py → test_utils_pdf_document_processor.py} +2 -3
- aiagents4pharma/talk2scholars/tests/{test_pdf_generate_answer.py → test_utils_pdf_generate_answer.py} +3 -6
- aiagents4pharma/talk2scholars/tests/{test_pdf_gpu_detection.py → test_utils_pdf_gpu_detection.py} +5 -16
- aiagents4pharma/talk2scholars/tests/{test_pdf_rag_pipeline.py → test_utils_pdf_rag_pipeline.py} +7 -17
- aiagents4pharma/talk2scholars/tests/{test_pdf_retrieve_chunks.py → test_utils_pdf_retrieve_chunks.py} +4 -11
- aiagents4pharma/talk2scholars/tests/{test_pdf_singleton_manager.py → test_utils_pdf_singleton_manager.py} +26 -23
- aiagents4pharma/talk2scholars/tests/{test_pdf_vector_normalization.py → test_utils_pdf_vector_normalization.py} +1 -1
- aiagents4pharma/talk2scholars/tests/{test_pdf_vector_store.py → test_utils_pdf_vector_store.py} +27 -55
- aiagents4pharma/talk2scholars/tests/{test_pubmed_downloader.py → test_utils_pubmed_downloader.py} +31 -91
- aiagents4pharma/talk2scholars/tests/{test_read_helper_utils.py → test_utils_read_helper_utils.py} +2 -6
- aiagents4pharma/talk2scholars/tests/{test_s2_utils_ext_ids.py → test_utils_s2_utils_ext_ids.py} +5 -15
- aiagents4pharma/talk2scholars/tests/{test_zotero_human_in_the_loop.py → test_utils_zotero_human_in_the_loop.py} +6 -13
- aiagents4pharma/talk2scholars/tests/{test_zotero_path.py → test_utils_zotero_path.py} +53 -45
- aiagents4pharma/talk2scholars/tests/{test_zotero_read.py → test_utils_zotero_read.py} +30 -91
- aiagents4pharma/talk2scholars/tests/{test_zotero_write.py → test_utils_zotero_write.py} +6 -16
- aiagents4pharma/talk2scholars/tools/__init__.py +1 -4
- aiagents4pharma/talk2scholars/tools/paper_download/paper_downloader.py +20 -35
- aiagents4pharma/talk2scholars/tools/paper_download/utils/__init__.py +7 -5
- aiagents4pharma/talk2scholars/tools/paper_download/utils/arxiv_downloader.py +9 -11
- aiagents4pharma/talk2scholars/tools/paper_download/utils/base_paper_downloader.py +14 -21
- aiagents4pharma/talk2scholars/tools/paper_download/utils/biorxiv_downloader.py +14 -22
- aiagents4pharma/talk2scholars/tools/paper_download/utils/medrxiv_downloader.py +11 -13
- aiagents4pharma/talk2scholars/tools/paper_download/utils/pubmed_downloader.py +14 -28
- aiagents4pharma/talk2scholars/tools/pdf/question_and_answer.py +4 -8
- aiagents4pharma/talk2scholars/tools/pdf/utils/__init__.py +16 -14
- aiagents4pharma/talk2scholars/tools/pdf/utils/answer_formatter.py +4 -4
- aiagents4pharma/talk2scholars/tools/pdf/utils/batch_processor.py +15 -17
- aiagents4pharma/talk2scholars/tools/pdf/utils/collection_manager.py +2 -2
- aiagents4pharma/talk2scholars/tools/pdf/utils/document_processor.py +5 -5
- aiagents4pharma/talk2scholars/tools/pdf/utils/generate_answer.py +4 -4
- aiagents4pharma/talk2scholars/tools/pdf/utils/get_vectorstore.py +2 -6
- aiagents4pharma/talk2scholars/tools/pdf/utils/gpu_detection.py +5 -9
- aiagents4pharma/talk2scholars/tools/pdf/utils/nvidia_nim_reranker.py +4 -4
- aiagents4pharma/talk2scholars/tools/pdf/utils/paper_loader.py +2 -2
- aiagents4pharma/talk2scholars/tools/pdf/utils/rag_pipeline.py +6 -15
- aiagents4pharma/talk2scholars/tools/pdf/utils/retrieve_chunks.py +7 -15
- aiagents4pharma/talk2scholars/tools/pdf/utils/singleton_manager.py +2 -2
- aiagents4pharma/talk2scholars/tools/pdf/utils/tool_helper.py +3 -4
- aiagents4pharma/talk2scholars/tools/pdf/utils/vector_normalization.py +8 -17
- aiagents4pharma/talk2scholars/tools/pdf/utils/vector_store.py +17 -33
- aiagents4pharma/talk2scholars/tools/s2/__init__.py +8 -6
- aiagents4pharma/talk2scholars/tools/s2/display_dataframe.py +3 -7
- aiagents4pharma/talk2scholars/tools/s2/multi_paper_rec.py +7 -6
- aiagents4pharma/talk2scholars/tools/s2/query_dataframe.py +5 -12
- aiagents4pharma/talk2scholars/tools/s2/retrieve_semantic_scholar_paper_id.py +2 -4
- aiagents4pharma/talk2scholars/tools/s2/search.py +6 -6
- aiagents4pharma/talk2scholars/tools/s2/single_paper_rec.py +5 -3
- aiagents4pharma/talk2scholars/tools/s2/utils/__init__.py +1 -3
- aiagents4pharma/talk2scholars/tools/s2/utils/multi_helper.py +12 -18
- aiagents4pharma/talk2scholars/tools/s2/utils/search_helper.py +11 -18
- aiagents4pharma/talk2scholars/tools/s2/utils/single_helper.py +11 -16
- aiagents4pharma/talk2scholars/tools/zotero/__init__.py +1 -4
- aiagents4pharma/talk2scholars/tools/zotero/utils/__init__.py +1 -4
- aiagents4pharma/talk2scholars/tools/zotero/utils/read_helper.py +21 -39
- aiagents4pharma/talk2scholars/tools/zotero/utils/review_helper.py +2 -6
- aiagents4pharma/talk2scholars/tools/zotero/utils/write_helper.py +8 -11
- aiagents4pharma/talk2scholars/tools/zotero/utils/zotero_path.py +4 -12
- aiagents4pharma/talk2scholars/tools/zotero/utils/zotero_pdf_downloader.py +13 -27
- aiagents4pharma/talk2scholars/tools/zotero/zotero_read.py +4 -7
- aiagents4pharma/talk2scholars/tools/zotero/zotero_review.py +8 -10
- aiagents4pharma/talk2scholars/tools/zotero/zotero_write.py +3 -2
- {aiagents4pharma-1.44.0.dist-info → aiagents4pharma-1.45.1.dist-info}/METADATA +115 -51
- aiagents4pharma-1.45.1.dist-info/RECORD +324 -0
- {aiagents4pharma-1.44.0.dist-info → aiagents4pharma-1.45.1.dist-info}/WHEEL +1 -2
- aiagents4pharma-1.44.0.dist-info/RECORD +0 -293
- aiagents4pharma-1.44.0.dist-info/top_level.txt +0 -1
- /aiagents4pharma/talk2scholars/tests/{test_state.py → test_states_state.py} +0 -0
- /aiagents4pharma/talk2scholars/tests/{test_pdf_paper_loader.py → test_utils_pdf_paper_loader.py} +0 -0
- /aiagents4pharma/talk2scholars/tests/{test_tool_helper_utils.py → test_utils_tool_helper_utils.py} +0 -0
- /aiagents4pharma/talk2scholars/tests/{test_zotero_pdf_downloader_utils.py → test_utils_zotero_pdf_downloader_utils.py} +0 -0
- {aiagents4pharma-1.44.0.dist-info → aiagents4pharma-1.45.1.dist-info}/licenses/LICENSE +0 -0
@@ -4,7 +4,9 @@ Unit tests for Zotero path utility in zotero_path.py.
|
|
4
4
|
|
5
5
|
import unittest
|
6
6
|
from unittest.mock import MagicMock, patch
|
7
|
+
|
7
8
|
import pytest
|
9
|
+
|
8
10
|
from aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path import (
|
9
11
|
fetch_papers_for_save,
|
10
12
|
find_or_create_collection,
|
@@ -92,12 +94,8 @@ class TestFindOrCreateCollectionExtra(unittest.TestCase):
|
|
92
94
|
# Simulate no existing collections (so direct match fails)
|
93
95
|
self.fake_zot.collections.return_value = []
|
94
96
|
# Simulate create_collection returning a dict with a "success" key.
|
95
|
-
self.fake_zot.create_collection.return_value = {
|
96
|
-
|
97
|
-
}
|
98
|
-
result = find_or_create_collection(
|
99
|
-
self.fake_zot, "/NewCollection", create_missing=True
|
100
|
-
)
|
97
|
+
self.fake_zot.create_collection.return_value = {"success": {"0": "new_key_success"}}
|
98
|
+
result = find_or_create_collection(self.fake_zot, "/NewCollection", create_missing=True)
|
101
99
|
self.assertEqual(result, "new_key_success")
|
102
100
|
# Verify payload formatting: for a simple (non-nested) path, no parentCollection.
|
103
101
|
args, _ = self.fake_zot.create_collection.call_args
|
@@ -114,9 +112,7 @@ class TestFindOrCreateCollectionExtra(unittest.TestCase):
|
|
114
112
|
self.fake_zot.create_collection.return_value = {
|
115
113
|
"successful": {"0": {"data": {"key": "new_key_successful"}}}
|
116
114
|
}
|
117
|
-
result = find_or_create_collection(
|
118
|
-
self.fake_zot, "/NewCollection", create_missing=True
|
119
|
-
)
|
115
|
+
result = find_or_create_collection(self.fake_zot, "/NewCollection", create_missing=True)
|
120
116
|
self.assertEqual(result, "new_key_successful")
|
121
117
|
|
122
118
|
def test_create_collection_exception(self):
|
@@ -126,9 +122,7 @@ class TestFindOrCreateCollectionExtra(unittest.TestCase):
|
|
126
122
|
"""
|
127
123
|
self.fake_zot.collections.return_value = []
|
128
124
|
self.fake_zot.create_collection.side_effect = Exception("Creation error")
|
129
|
-
result = find_or_create_collection(
|
130
|
-
self.fake_zot, "/NewCollection", create_missing=True
|
131
|
-
)
|
125
|
+
result = find_or_create_collection(self.fake_zot, "/NewCollection", create_missing=True)
|
132
126
|
self.assertIsNone(result)
|
133
127
|
|
134
128
|
|
@@ -228,9 +222,7 @@ class TestZoteroPath:
|
|
228
222
|
mock_zotero.return_value = mock_zot
|
229
223
|
|
230
224
|
# Setup collections
|
231
|
-
collections = [
|
232
|
-
{"key": "abc123", "data": {"name": "Curiosity", "parentCollection": None}}
|
233
|
-
]
|
225
|
+
collections = [{"key": "abc123", "data": {"name": "Curiosity", "parentCollection": None}}]
|
234
226
|
mock_zot.collections.return_value = collections
|
235
227
|
|
236
228
|
# Setup create_collection response
|
@@ -249,9 +241,7 @@ class TestZoteroPath:
|
|
249
241
|
|
250
242
|
# Test creating nested "Curiosity/Curiosity2"
|
251
243
|
mock_zot.create_collection.reset_mock()
|
252
|
-
result = find_or_create_collection(
|
253
|
-
mock_zot, "/Curiosity/Curiosity2", create_missing=True
|
254
|
-
)
|
244
|
+
result = find_or_create_collection(mock_zot, "/Curiosity/Curiosity2", create_missing=True)
|
255
245
|
assert result == "new_key"
|
256
246
|
# Check that the call includes parentCollection
|
257
247
|
mock_zot.create_collection.assert_called_once()
|
@@ -314,11 +304,24 @@ class TestZoteroWrite:
|
|
314
304
|
mock_zot_class.return_value = mock_zot
|
315
305
|
yield mock_zot
|
316
306
|
|
317
|
-
@patch(
|
318
|
-
|
319
|
-
)
|
320
|
-
|
307
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.write_helper.fetch_papers_for_save")
|
308
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.write_helper.hydra.initialize")
|
309
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.write_helper.hydra.compose")
|
310
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.write_helper.zotero.Zotero")
|
311
|
+
def test_zotero_write_no_papers(self, mock_zotero_class, mock_compose, _, mock_fetch):
|
321
312
|
"""When no papers exist (even after approval), the function raises a ValueError."""
|
313
|
+
# Mock hydra configuration
|
314
|
+
cfg = MagicMock()
|
315
|
+
cfg.user_id = "test_user"
|
316
|
+
cfg.library_type = "user"
|
317
|
+
cfg.api_key = "test_key"
|
318
|
+
mock_compose.return_value = MagicMock()
|
319
|
+
mock_compose.return_value.tools.zotero_write = cfg
|
320
|
+
|
321
|
+
# Mock Zotero client
|
322
|
+
mock_zot = MagicMock()
|
323
|
+
mock_zotero_class.return_value = mock_zot
|
324
|
+
|
322
325
|
mock_fetch.return_value = None
|
323
326
|
|
324
327
|
state = {
|
@@ -338,22 +341,37 @@ class TestZoteroWrite:
|
|
338
341
|
)
|
339
342
|
assert "No fetched papers were found to save" in str(excinfo.value)
|
340
343
|
|
341
|
-
@patch(
|
342
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.write_helper.fetch_papers_for_save"
|
343
|
-
)
|
344
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.write_helper.fetch_papers_for_save")
|
344
345
|
@patch(
|
345
346
|
"aiagents4pharma.talk2scholars.tools.zotero.utils.write_helper.find_or_create_collection"
|
346
347
|
)
|
347
|
-
|
348
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.write_helper.hydra.initialize")
|
349
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.write_helper.hydra.compose")
|
350
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.write_helper.zotero.Zotero")
|
351
|
+
def test_zotero_write_invalid_collection(
|
352
|
+
self, mock_zotero_class, mock_compose, _, mock_find, mock_fetch
|
353
|
+
):
|
348
354
|
"""Saving to a nonexistent Zotero collection returns an error Command."""
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
355
|
+
# Mock hydra configuration
|
356
|
+
cfg = MagicMock()
|
357
|
+
cfg.user_id = "test_user"
|
358
|
+
cfg.library_type = "user"
|
359
|
+
cfg.api_key = "test_key"
|
360
|
+
mock_compose.return_value = MagicMock()
|
361
|
+
mock_compose.return_value.tools.zotero_write = cfg
|
362
|
+
|
363
|
+
# Mock Zotero client
|
364
|
+
mock_zot = MagicMock()
|
365
|
+
mock_zotero_class.return_value = mock_zot
|
366
|
+
mock_zot.collections.return_value = [
|
353
367
|
{"key": "k1", "data": {"name": "Curiosity"}},
|
354
368
|
{"key": "k2", "data": {"name": "Random"}},
|
355
369
|
]
|
356
370
|
|
371
|
+
sample = {"paper1": {"Title": "Test Paper"}}
|
372
|
+
mock_fetch.return_value = sample
|
373
|
+
mock_find.return_value = None
|
374
|
+
|
357
375
|
state = {
|
358
376
|
"zotero_write_approval_status": {
|
359
377
|
"approved": True,
|
@@ -375,9 +393,7 @@ class TestZoteroWrite:
|
|
375
393
|
assert "does not exist in Zotero" in msg
|
376
394
|
assert "Curiosity, Random" in msg
|
377
395
|
|
378
|
-
@patch(
|
379
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.write_helper.fetch_papers_for_save"
|
380
|
-
)
|
396
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.write_helper.fetch_papers_for_save")
|
381
397
|
@patch(
|
382
398
|
"aiagents4pharma.talk2scholars.tools.zotero.utils.write_helper.find_or_create_collection"
|
383
399
|
)
|
@@ -386,12 +402,8 @@ class TestZoteroWrite:
|
|
386
402
|
sample = {"paper1": {"Title": "Test Paper", "Authors": ["Test Author"]}}
|
387
403
|
mock_fetch.return_value = sample
|
388
404
|
mock_find.return_value = "abc123"
|
389
|
-
mock_zotero.collections.return_value = [
|
390
|
-
|
391
|
-
]
|
392
|
-
mock_zotero.create_items.return_value = {
|
393
|
-
"successful": {"0": {"key": "item123"}}
|
394
|
-
}
|
405
|
+
mock_zotero.collections.return_value = [{"key": "abc123", "data": {"name": "radiation"}}]
|
406
|
+
mock_zotero.create_items.return_value = {"successful": {"0": {"key": "item123"}}}
|
395
407
|
mock_hydra.tools.zotero_write.zotero.max_limit = 50
|
396
408
|
|
397
409
|
state = {
|
@@ -423,9 +435,7 @@ class TestZoteroRead:
|
|
423
435
|
def mock_hydra(self):
|
424
436
|
"""Fixture to mock hydra configuration."""
|
425
437
|
with (
|
426
|
-
patch(
|
427
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.write_helper.hydra.initialize"
|
428
|
-
),
|
438
|
+
patch("aiagents4pharma.talk2scholars.tools.zotero.utils.write_helper.hydra.initialize"),
|
429
439
|
patch(
|
430
440
|
"aiagents4pharma.talk2scholars.tools.zotero.utils.write_helper.hydra.compose"
|
431
441
|
) as mock_compose,
|
@@ -453,9 +463,7 @@ class TestZoteroRead:
|
|
453
463
|
mock_zot_class.return_value = mock_zot
|
454
464
|
yield mock_zot
|
455
465
|
|
456
|
-
@patch(
|
457
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections"
|
458
|
-
)
|
466
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections")
|
459
467
|
def test_zotero_read_item_collections_error(
|
460
468
|
self, mock_get_collections, mock_hydra, mock_zotero
|
461
469
|
):
|
@@ -17,7 +17,6 @@ from aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_pdf_downloader impo
|
|
17
17
|
)
|
18
18
|
from aiagents4pharma.talk2scholars.tools.zotero.zotero_read import zotero_read
|
19
19
|
|
20
|
-
|
21
20
|
# Dummy Hydra configuration to be used in tests
|
22
21
|
dummy_zotero_read_config = SimpleNamespace(
|
23
22
|
user_id="dummy_user",
|
@@ -34,14 +33,10 @@ dummy_cfg = SimpleNamespace(tools=SimpleNamespace(zotero_read=dummy_zotero_read_
|
|
34
33
|
class TestZoteroSearchTool(unittest.TestCase):
|
35
34
|
"""Tests for Zotero search tool."""
|
36
35
|
|
37
|
-
@patch(
|
38
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections"
|
39
|
-
)
|
36
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections")
|
40
37
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.zotero.Zotero")
|
41
38
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.compose")
|
42
|
-
@patch(
|
43
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize"
|
44
|
-
)
|
39
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize")
|
45
40
|
def test_valid_query(
|
46
41
|
self,
|
47
42
|
mock_hydra_init,
|
@@ -111,14 +106,10 @@ class TestZoteroSearchTool(unittest.TestCase):
|
|
111
106
|
self.assertIn("Query: test", message_content)
|
112
107
|
self.assertIn("Number of papers found: 2", message_content)
|
113
108
|
|
114
|
-
@patch(
|
115
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections"
|
116
|
-
)
|
109
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections")
|
117
110
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.zotero.Zotero")
|
118
111
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.compose")
|
119
|
-
@patch(
|
120
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize"
|
121
|
-
)
|
112
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize")
|
122
113
|
def test_empty_query_fetch_all_items(
|
123
114
|
self,
|
124
115
|
mock_hydra_init,
|
@@ -159,18 +150,12 @@ class TestZoteroSearchTool(unittest.TestCase):
|
|
159
150
|
update = result.update
|
160
151
|
filtered_papers = update["article_data"]
|
161
152
|
self.assertIn("paper1", filtered_papers)
|
162
|
-
fake_zot.items.assert_called_with(
|
163
|
-
limit=dummy_cfg.tools.zotero_read.zotero.max_limit
|
164
|
-
)
|
153
|
+
fake_zot.items.assert_called_with(limit=dummy_cfg.tools.zotero_read.zotero.max_limit)
|
165
154
|
|
166
|
-
@patch(
|
167
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections"
|
168
|
-
)
|
155
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections")
|
169
156
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.zotero.Zotero")
|
170
157
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.compose")
|
171
|
-
@patch(
|
172
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize"
|
173
|
-
)
|
158
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize")
|
174
159
|
def test_no_items_returned(
|
175
160
|
self,
|
176
161
|
mock_hydra_init,
|
@@ -198,17 +183,11 @@ class TestZoteroSearchTool(unittest.TestCase):
|
|
198
183
|
zotero_read.run(tool_input)
|
199
184
|
self.assertIn("No items returned from Zotero", str(context.exception))
|
200
185
|
|
201
|
-
@patch(
|
202
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections"
|
203
|
-
)
|
186
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections")
|
204
187
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.zotero.Zotero")
|
205
188
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.compose")
|
206
|
-
@patch(
|
207
|
-
|
208
|
-
)
|
209
|
-
@patch(
|
210
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.download_pdfs_in_parallel"
|
211
|
-
)
|
189
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize")
|
190
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.download_pdfs_in_parallel")
|
212
191
|
def test_filtering_no_matching_papers(self, *mocks):
|
213
192
|
"""Testing filtering when no paper matching"""
|
214
193
|
(
|
@@ -274,14 +253,10 @@ class TestZoteroSearchTool(unittest.TestCase):
|
|
274
253
|
self.assertEqual(filtered_papers["paper1"]["pdf_url"], "/tmp/fake_path.pdf")
|
275
254
|
self.assertEqual(filtered_papers["paper1"]["source"], "zotero")
|
276
255
|
|
277
|
-
@patch(
|
278
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections"
|
279
|
-
)
|
256
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections")
|
280
257
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.zotero.Zotero")
|
281
258
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.compose")
|
282
|
-
@patch(
|
283
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize"
|
284
|
-
)
|
259
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize")
|
285
260
|
def test_items_api_exception(
|
286
261
|
self,
|
287
262
|
mock_hydra_init,
|
@@ -309,14 +284,10 @@ class TestZoteroSearchTool(unittest.TestCase):
|
|
309
284
|
zotero_read.run(tool_input)
|
310
285
|
self.assertIn("Failed to fetch items from Zotero", str(context.exception))
|
311
286
|
|
312
|
-
@patch(
|
313
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections"
|
314
|
-
)
|
287
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections")
|
315
288
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.zotero.Zotero")
|
316
289
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.compose")
|
317
|
-
@patch(
|
318
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize"
|
319
|
-
)
|
290
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize")
|
320
291
|
def test_missing_key_in_item(
|
321
292
|
self,
|
322
293
|
mock_hydra_init,
|
@@ -370,14 +341,10 @@ class TestZoteroSearchTool(unittest.TestCase):
|
|
370
341
|
self.assertIn("paper_valid", filtered_papers)
|
371
342
|
self.assertEqual(len(filtered_papers), 1)
|
372
343
|
|
373
|
-
@patch(
|
374
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections"
|
375
|
-
)
|
344
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections")
|
376
345
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.zotero.Zotero")
|
377
346
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.compose")
|
378
|
-
@patch(
|
379
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize"
|
380
|
-
)
|
347
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize")
|
381
348
|
def test_item_not_dict(
|
382
349
|
self,
|
383
350
|
mock_hydra_init,
|
@@ -410,14 +377,10 @@ class TestZoteroSearchTool(unittest.TestCase):
|
|
410
377
|
zotero_read.run(tool_input)
|
411
378
|
self.assertIn("No matching papers returned from Zotero", str(context.exception))
|
412
379
|
|
413
|
-
@patch(
|
414
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections"
|
415
|
-
)
|
380
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections")
|
416
381
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.zotero.Zotero")
|
417
382
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.compose")
|
418
|
-
@patch(
|
419
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize"
|
420
|
-
)
|
383
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize")
|
421
384
|
def test_data_not_dict(
|
422
385
|
self,
|
423
386
|
mock_hydra_init,
|
@@ -447,17 +410,11 @@ class TestZoteroSearchTool(unittest.TestCase):
|
|
447
410
|
zotero_read.run(tool_input)
|
448
411
|
self.assertIn("No matching papers returned from Zotero", str(context.exception))
|
449
412
|
|
450
|
-
@patch(
|
451
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections"
|
452
|
-
)
|
413
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections")
|
453
414
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.zotero.Zotero")
|
454
415
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.compose")
|
455
|
-
@patch(
|
456
|
-
|
457
|
-
)
|
458
|
-
@patch(
|
459
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.requests.Session.get"
|
460
|
-
)
|
416
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize")
|
417
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.requests.Session.get")
|
461
418
|
def test_pdf_attachment_success(self, *mocks):
|
462
419
|
"""Test for pdf attachment success"""
|
463
420
|
(
|
@@ -506,9 +463,7 @@ class TestZoteroSearchTool(unittest.TestCase):
|
|
506
463
|
mock_response = MagicMock()
|
507
464
|
mock_response.status_code = 200
|
508
465
|
mock_response.iter_content = lambda chunk_size: [b"fake pdf content"]
|
509
|
-
mock_response.headers = {
|
510
|
-
"Content-Disposition": 'attachment; filename="file1.pdf"'
|
511
|
-
}
|
466
|
+
mock_response.headers = {"Content-Disposition": 'attachment; filename="file1.pdf"'}
|
512
467
|
mock_response.raise_for_status = lambda: None
|
513
468
|
mock_session_get.return_value = mock_response
|
514
469
|
|
@@ -528,14 +483,10 @@ class TestZoteroSearchTool(unittest.TestCase):
|
|
528
483
|
self.assertEqual(paper["filename"], "file1.pdf")
|
529
484
|
self.assertEqual(paper["attachment_key"], "attachment1")
|
530
485
|
|
531
|
-
@patch(
|
532
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections"
|
533
|
-
)
|
486
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections")
|
534
487
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.zotero.Zotero")
|
535
488
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.compose")
|
536
|
-
@patch(
|
537
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize"
|
538
|
-
)
|
489
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize")
|
539
490
|
def test_pdf_attachment_children_exception(
|
540
491
|
self,
|
541
492
|
mock_hydra_init,
|
@@ -590,14 +541,10 @@ class TestZoteroSearchTool(unittest.TestCase):
|
|
590
541
|
self.assertNotIn("filename", filtered_papers["paper1"])
|
591
542
|
self.assertNotIn("attachment_key", filtered_papers["paper1"])
|
592
543
|
|
593
|
-
@patch(
|
594
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections"
|
595
|
-
)
|
544
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections")
|
596
545
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.zotero.Zotero")
|
597
546
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.compose")
|
598
|
-
@patch(
|
599
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize"
|
600
|
-
)
|
547
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize")
|
601
548
|
def test_pdf_attachment_missing_key(
|
602
549
|
self,
|
603
550
|
mock_hydra_init,
|
@@ -653,14 +600,10 @@ class TestZoteroSearchTool(unittest.TestCase):
|
|
653
600
|
self.assertNotIn("pdf_url", paper)
|
654
601
|
self.assertNotIn("attachment_key", paper)
|
655
602
|
|
656
|
-
@patch(
|
657
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections"
|
658
|
-
)
|
603
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections")
|
659
604
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.zotero.Zotero")
|
660
605
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.compose")
|
661
|
-
@patch(
|
662
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize"
|
663
|
-
)
|
606
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize")
|
664
607
|
def test_pdf_attachment_outer_exception(
|
665
608
|
self,
|
666
609
|
mock_hydra_init,
|
@@ -739,14 +682,10 @@ class TestZoteroSearchTool(unittest.TestCase):
|
|
739
682
|
# Should return None on failure
|
740
683
|
self.assertIsNone(result)
|
741
684
|
|
742
|
-
@patch(
|
743
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections"
|
744
|
-
)
|
685
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.zotero_path.get_item_collections")
|
745
686
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.zotero.Zotero")
|
746
687
|
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.compose")
|
747
|
-
@patch(
|
748
|
-
"aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize"
|
749
|
-
)
|
688
|
+
@patch("aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize")
|
750
689
|
def test_download_pdf_exception_logging(
|
751
690
|
self,
|
752
691
|
mock_hydra_init,
|
@@ -4,16 +4,12 @@ Unit tests for Zotero write tool in zotero_write.py.
|
|
4
4
|
|
5
5
|
import unittest
|
6
6
|
from types import SimpleNamespace
|
7
|
-
from unittest.mock import
|
7
|
+
from unittest.mock import MagicMock, patch
|
8
8
|
|
9
9
|
from aiagents4pharma.talk2scholars.tools.zotero.zotero_write import zotero_write
|
10
10
|
|
11
|
-
dummy_zotero_write_config = SimpleNamespace(
|
12
|
-
|
13
|
-
)
|
14
|
-
dummy_cfg = SimpleNamespace(
|
15
|
-
tools=SimpleNamespace(zotero_write=dummy_zotero_write_config)
|
16
|
-
)
|
11
|
+
dummy_zotero_write_config = SimpleNamespace(user_id="dummy", library_type="user", api_key="dummy")
|
12
|
+
dummy_cfg = SimpleNamespace(tools=SimpleNamespace(zotero_write=dummy_zotero_write_config))
|
17
13
|
|
18
14
|
|
19
15
|
class TestZoteroSaveTool(unittest.TestCase):
|
@@ -49,9 +45,7 @@ class TestZoteroSaveTool(unittest.TestCase):
|
|
49
45
|
}
|
50
46
|
if papers is not None:
|
51
47
|
# When papers is provided as dict, use it directly.
|
52
|
-
state["last_displayed_papers"] = (
|
53
|
-
papers if isinstance(papers, dict) else "papers"
|
54
|
-
)
|
48
|
+
state["last_displayed_papers"] = papers if isinstance(papers, dict) else "papers"
|
55
49
|
if isinstance(papers, dict):
|
56
50
|
state["papers"] = papers
|
57
51
|
return state
|
@@ -83,9 +77,7 @@ class TestZoteroSaveTool(unittest.TestCase):
|
|
83
77
|
)
|
84
78
|
def test_invalid_collection(self, mock_find, mock_fetch):
|
85
79
|
"""Test when collection path is invalid"""
|
86
|
-
self.fake_zot.collections.return_value = [
|
87
|
-
{"key": "k1", "data": {"name": "Existing"}}
|
88
|
-
]
|
80
|
+
self.fake_zot.collections.return_value = [{"key": "k1", "data": {"name": "Existing"}}]
|
89
81
|
# Provide a valid papers dict so we don't hit the no-papers error.
|
90
82
|
state = self.make_state({"p1": {"Title": "X"}}, True)
|
91
83
|
result = zotero_write.run(
|
@@ -143,9 +135,7 @@ class TestZoteroSaveTool(unittest.TestCase):
|
|
143
135
|
self.fake_zot.collections.return_value = [
|
144
136
|
{"key": "colKey", "data": {"name": "Test Collection"}}
|
145
137
|
]
|
146
|
-
self.fake_zot.create_items.return_value = {
|
147
|
-
"successful": {"0": {"key": "item1"}}
|
148
|
-
}
|
138
|
+
self.fake_zot.create_items.return_value = {"successful": {"0": {"key": "item1"}}}
|
149
139
|
mock_fetch.return_value = {"p1": {"Title": "X"}}
|
150
140
|
mock_find.return_value = "colKey"
|
151
141
|
|
@@ -6,16 +6,17 @@ Supports downloading papers from arXiv, medRxiv, bioRxiv, and PubMed through a s
|
|
6
6
|
|
7
7
|
import logging
|
8
8
|
import threading
|
9
|
-
from typing import Annotated, Any,
|
9
|
+
from typing import Annotated, Any, Literal
|
10
10
|
|
11
11
|
import hydra
|
12
12
|
from hydra.core.global_hydra import GlobalHydra
|
13
|
-
from omegaconf import OmegaConf
|
14
13
|
from langchain_core.messages import ToolMessage
|
15
14
|
from langchain_core.tools import tool
|
16
15
|
from langchain_core.tools.base import InjectedToolCallId
|
17
16
|
from langgraph.types import Command
|
17
|
+
from omegaconf import OmegaConf
|
18
18
|
from pydantic import BaseModel, Field
|
19
|
+
|
19
20
|
from .utils.arxiv_downloader import ArxivDownloader
|
20
21
|
from .utils.base_paper_downloader import BasePaperDownloader
|
21
22
|
from .utils.biorxiv_downloader import BiorxivDownloader
|
@@ -30,14 +31,14 @@ logger = logging.getLogger(__name__)
|
|
30
31
|
class UnifiedPaperDownloadInput(BaseModel):
|
31
32
|
"""Input schema for the unified paper download tool."""
|
32
33
|
|
33
|
-
service:
|
34
|
+
service: Literal["arxiv", "medrxiv", "biorxiv", "pubmed"] | None = Field(
|
34
35
|
default=None,
|
35
36
|
description=(
|
36
37
|
"Paper service to download from: 'arxiv', 'medrxiv', 'biorxiv', or 'pubmed'. "
|
37
38
|
"If not specified, uses the configured default service."
|
38
39
|
),
|
39
40
|
)
|
40
|
-
identifiers:
|
41
|
+
identifiers: list[str] = Field(
|
41
42
|
description=(
|
42
43
|
"List of paper identifiers. Format depends on service:\n"
|
43
44
|
"- arxiv: arXiv IDs (e.g., ['1234.5678', '2301.12345'])\n"
|
@@ -140,12 +141,9 @@ class PaperDownloaderFactory:
|
|
140
141
|
return PaperDownloaderFactory._cached_config
|
141
142
|
|
142
143
|
try:
|
143
|
-
|
144
144
|
# Clear if already initialized
|
145
145
|
if GlobalHydra().is_initialized():
|
146
|
-
logger.info(
|
147
|
-
"GlobalHydra already initialized, clearing for config load"
|
148
|
-
)
|
146
|
+
logger.info("GlobalHydra already initialized, clearing for config load")
|
149
147
|
GlobalHydra.instance().clear()
|
150
148
|
|
151
149
|
# Load configuration
|
@@ -156,16 +154,12 @@ class PaperDownloaderFactory:
|
|
156
154
|
|
157
155
|
# Cache the configuration
|
158
156
|
PaperDownloaderFactory._cached_config = cfg.tools.paper_download
|
159
|
-
logger.info(
|
160
|
-
"Successfully loaded and cached paper download configuration"
|
161
|
-
)
|
157
|
+
logger.info("Successfully loaded and cached paper download configuration")
|
162
158
|
|
163
159
|
return PaperDownloaderFactory._cached_config
|
164
160
|
|
165
161
|
except Exception as e:
|
166
|
-
logger.error(
|
167
|
-
"Failed to load unified paper download configuration: %s", e
|
168
|
-
)
|
162
|
+
logger.error("Failed to load unified paper download configuration: %s", e)
|
169
163
|
raise RuntimeError(f"Configuration loading failed: {e}") from e
|
170
164
|
|
171
165
|
@staticmethod
|
@@ -181,10 +175,7 @@ class PaperDownloaderFactory:
|
|
181
175
|
Returns:
|
182
176
|
Service-specific configuration object
|
183
177
|
"""
|
184
|
-
if (
|
185
|
-
not hasattr(unified_config, "services")
|
186
|
-
or service not in unified_config.services
|
187
|
-
):
|
178
|
+
if not hasattr(unified_config, "services") or service not in unified_config.services:
|
188
179
|
raise ValueError(f"Service '{service}' not found in configuration")
|
189
180
|
|
190
181
|
# Create a simple config object that combines common and service-specific settings
|
@@ -202,14 +193,10 @@ class PaperDownloaderFactory:
|
|
202
193
|
config_obj = ServiceConfig()
|
203
194
|
|
204
195
|
# Handle common config (using helper method to reduce branches)
|
205
|
-
PaperDownloaderFactory._apply_config(
|
206
|
-
config_obj, unified_config.common, "common"
|
207
|
-
)
|
196
|
+
PaperDownloaderFactory._apply_config(config_obj, unified_config.common, "common")
|
208
197
|
|
209
198
|
# Handle service-specific config (using helper method to reduce branches)
|
210
|
-
PaperDownloaderFactory._apply_config(
|
211
|
-
config_obj, unified_config.services[service], service
|
212
|
-
)
|
199
|
+
PaperDownloaderFactory._apply_config(config_obj, unified_config.services[service], service)
|
213
200
|
|
214
201
|
return config_obj
|
215
202
|
|
@@ -239,9 +226,7 @@ class PaperDownloaderFactory:
|
|
239
226
|
|
240
227
|
# Method 2: Try direct attribute access
|
241
228
|
if hasattr(source_config, "__dict__"):
|
242
|
-
PaperDownloaderFactory._extract_from_dict(
|
243
|
-
config_obj, source_config.__dict__
|
244
|
-
)
|
229
|
+
PaperDownloaderFactory._extract_from_dict(config_obj, source_config.__dict__)
|
245
230
|
return
|
246
231
|
|
247
232
|
# Method 3: Try items() method
|
@@ -290,8 +275,8 @@ class PaperDownloaderFactory:
|
|
290
275
|
parse_docstring=True,
|
291
276
|
)
|
292
277
|
def download_papers(
|
293
|
-
service:
|
294
|
-
identifiers:
|
278
|
+
service: Literal["arxiv", "medrxiv", "biorxiv", "pubmed"] | None,
|
279
|
+
identifiers: list[str],
|
295
280
|
tool_call_id: Annotated[str, InjectedToolCallId],
|
296
281
|
) -> Command[Any]:
|
297
282
|
"""
|
@@ -334,36 +319,36 @@ def download_papers(
|
|
334
319
|
# Convenience functions for backward compatibility (optional)
|
335
320
|
# These functions explicitly specify the service, bypassing the default service config
|
336
321
|
def download_arxiv_papers(
|
337
|
-
arxiv_ids:
|
322
|
+
arxiv_ids: list[str], tool_call_id: Annotated[str, InjectedToolCallId]
|
338
323
|
) -> Command[Any]:
|
339
324
|
"""Convenience function for downloading arXiv papers (explicitly uses arXiv service)."""
|
340
325
|
return _download_papers_impl("arxiv", arxiv_ids, tool_call_id)
|
341
326
|
|
342
327
|
|
343
328
|
def download_medrxiv_papers(
|
344
|
-
dois:
|
329
|
+
dois: list[str], tool_call_id: Annotated[str, InjectedToolCallId]
|
345
330
|
) -> Command[Any]:
|
346
331
|
"""Convenience function for downloading medRxiv papers (explicitly uses medRxiv service)."""
|
347
332
|
return _download_papers_impl("medrxiv", dois, tool_call_id)
|
348
333
|
|
349
334
|
|
350
335
|
def download_biorxiv_papers(
|
351
|
-
dois:
|
336
|
+
dois: list[str], tool_call_id: Annotated[str, InjectedToolCallId]
|
352
337
|
) -> Command[Any]:
|
353
338
|
"""Convenience function for downloading bioRxiv papers (explicitly uses bioRxiv service)."""
|
354
339
|
return _download_papers_impl("biorxiv", dois, tool_call_id)
|
355
340
|
|
356
341
|
|
357
342
|
def download_pubmed_papers(
|
358
|
-
pmids:
|
343
|
+
pmids: list[str], tool_call_id: Annotated[str, InjectedToolCallId]
|
359
344
|
) -> Command[Any]:
|
360
345
|
"""Convenience function for downloading PubMed papers (explicitly uses PubMed service)."""
|
361
346
|
return _download_papers_impl("pubmed", pmids, tool_call_id)
|
362
347
|
|
363
348
|
|
364
349
|
def _download_papers_impl(
|
365
|
-
service:
|
366
|
-
identifiers:
|
350
|
+
service: Literal["arxiv", "medrxiv", "biorxiv", "pubmed"] | None,
|
351
|
+
identifiers: list[str],
|
367
352
|
tool_call_id: str,
|
368
353
|
) -> Command[Any]:
|
369
354
|
"""
|