aiagents4pharma 1.43.0__py3-none-any.whl → 1.45.0__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.
Files changed (290) hide show
  1. aiagents4pharma/__init__.py +2 -2
  2. aiagents4pharma/talk2aiagents4pharma/.dockerignore +13 -0
  3. aiagents4pharma/talk2aiagents4pharma/Dockerfile +105 -0
  4. aiagents4pharma/talk2aiagents4pharma/README.md +1 -0
  5. aiagents4pharma/talk2aiagents4pharma/__init__.py +4 -5
  6. aiagents4pharma/talk2aiagents4pharma/agents/__init__.py +3 -2
  7. aiagents4pharma/talk2aiagents4pharma/agents/main_agent.py +24 -23
  8. aiagents4pharma/talk2aiagents4pharma/configs/__init__.py +2 -2
  9. aiagents4pharma/talk2aiagents4pharma/configs/agents/__init__.py +2 -2
  10. aiagents4pharma/talk2aiagents4pharma/configs/agents/main_agent/default.yaml +2 -2
  11. aiagents4pharma/talk2aiagents4pharma/configs/config.yaml +1 -1
  12. aiagents4pharma/talk2aiagents4pharma/docker-compose/cpu/.env.example +23 -0
  13. aiagents4pharma/talk2aiagents4pharma/docker-compose/cpu/docker-compose.yml +93 -0
  14. aiagents4pharma/talk2aiagents4pharma/docker-compose/gpu/.env.example +23 -0
  15. aiagents4pharma/talk2aiagents4pharma/docker-compose/gpu/docker-compose.yml +108 -0
  16. aiagents4pharma/talk2aiagents4pharma/install.md +127 -0
  17. aiagents4pharma/talk2aiagents4pharma/states/__init__.py +3 -2
  18. aiagents4pharma/talk2aiagents4pharma/states/state_talk2aiagents4pharma.py +5 -3
  19. aiagents4pharma/talk2aiagents4pharma/tests/__init__.py +2 -2
  20. aiagents4pharma/talk2aiagents4pharma/tests/test_main_agent.py +72 -50
  21. aiagents4pharma/talk2biomodels/.dockerignore +13 -0
  22. aiagents4pharma/talk2biomodels/Dockerfile +104 -0
  23. aiagents4pharma/talk2biomodels/README.md +1 -0
  24. aiagents4pharma/talk2biomodels/__init__.py +4 -8
  25. aiagents4pharma/talk2biomodels/agents/__init__.py +3 -2
  26. aiagents4pharma/talk2biomodels/agents/t2b_agent.py +47 -42
  27. aiagents4pharma/talk2biomodels/api/__init__.py +4 -5
  28. aiagents4pharma/talk2biomodels/api/kegg.py +14 -10
  29. aiagents4pharma/talk2biomodels/api/ols.py +13 -10
  30. aiagents4pharma/talk2biomodels/api/uniprot.py +7 -6
  31. aiagents4pharma/talk2biomodels/configs/__init__.py +3 -4
  32. aiagents4pharma/talk2biomodels/configs/agents/__init__.py +2 -2
  33. aiagents4pharma/talk2biomodels/configs/agents/t2b_agent/__init__.py +2 -2
  34. aiagents4pharma/talk2biomodels/configs/agents/t2b_agent/default.yaml +1 -1
  35. aiagents4pharma/talk2biomodels/configs/config.yaml +1 -1
  36. aiagents4pharma/talk2biomodels/configs/tools/__init__.py +4 -5
  37. aiagents4pharma/talk2biomodels/configs/tools/ask_question/__init__.py +2 -2
  38. aiagents4pharma/talk2biomodels/configs/tools/ask_question/default.yaml +1 -2
  39. aiagents4pharma/talk2biomodels/configs/tools/custom_plotter/__init__.py +2 -2
  40. aiagents4pharma/talk2biomodels/configs/tools/custom_plotter/default.yaml +1 -1
  41. aiagents4pharma/talk2biomodels/configs/tools/get_annotation/__init__.py +2 -2
  42. aiagents4pharma/talk2biomodels/configs/tools/get_annotation/default.yaml +1 -1
  43. aiagents4pharma/talk2biomodels/install.md +63 -0
  44. aiagents4pharma/talk2biomodels/models/__init__.py +4 -4
  45. aiagents4pharma/talk2biomodels/models/basico_model.py +36 -28
  46. aiagents4pharma/talk2biomodels/models/sys_bio_model.py +13 -10
  47. aiagents4pharma/talk2biomodels/states/__init__.py +3 -2
  48. aiagents4pharma/talk2biomodels/states/state_talk2biomodels.py +12 -8
  49. aiagents4pharma/talk2biomodels/tests/BIOMD0000000449_url.xml +1585 -0
  50. aiagents4pharma/talk2biomodels/tests/__init__.py +2 -2
  51. aiagents4pharma/talk2biomodels/tests/article_on_model_537.pdf +0 -0
  52. aiagents4pharma/talk2biomodels/tests/test_api.py +18 -14
  53. aiagents4pharma/talk2biomodels/tests/test_ask_question.py +8 -9
  54. aiagents4pharma/talk2biomodels/tests/test_basico_model.py +15 -9
  55. aiagents4pharma/talk2biomodels/tests/test_get_annotation.py +54 -55
  56. aiagents4pharma/talk2biomodels/tests/test_getmodelinfo.py +28 -27
  57. aiagents4pharma/talk2biomodels/tests/test_integration.py +21 -33
  58. aiagents4pharma/talk2biomodels/tests/test_load_biomodel.py +14 -11
  59. aiagents4pharma/talk2biomodels/tests/test_param_scan.py +21 -20
  60. aiagents4pharma/talk2biomodels/tests/test_query_article.py +129 -29
  61. aiagents4pharma/talk2biomodels/tests/test_search_models.py +9 -13
  62. aiagents4pharma/talk2biomodels/tests/test_simulate_model.py +16 -15
  63. aiagents4pharma/talk2biomodels/tests/test_steady_state.py +12 -22
  64. aiagents4pharma/talk2biomodels/tests/test_sys_bio_model.py +33 -29
  65. aiagents4pharma/talk2biomodels/tools/__init__.py +15 -12
  66. aiagents4pharma/talk2biomodels/tools/ask_question.py +42 -32
  67. aiagents4pharma/talk2biomodels/tools/custom_plotter.py +51 -43
  68. aiagents4pharma/talk2biomodels/tools/get_annotation.py +99 -75
  69. aiagents4pharma/talk2biomodels/tools/get_modelinfo.py +57 -51
  70. aiagents4pharma/talk2biomodels/tools/load_arguments.py +52 -32
  71. aiagents4pharma/talk2biomodels/tools/load_biomodel.py +8 -2
  72. aiagents4pharma/talk2biomodels/tools/parameter_scan.py +107 -90
  73. aiagents4pharma/talk2biomodels/tools/query_article.py +14 -13
  74. aiagents4pharma/talk2biomodels/tools/search_models.py +37 -26
  75. aiagents4pharma/talk2biomodels/tools/simulate_model.py +47 -37
  76. aiagents4pharma/talk2biomodels/tools/steady_state.py +76 -58
  77. aiagents4pharma/talk2biomodels/tools/utils.py +4 -3
  78. aiagents4pharma/talk2cells/README.md +1 -0
  79. aiagents4pharma/talk2cells/__init__.py +4 -5
  80. aiagents4pharma/talk2cells/agents/__init__.py +3 -2
  81. aiagents4pharma/talk2cells/agents/scp_agent.py +21 -19
  82. aiagents4pharma/talk2cells/states/__init__.py +3 -2
  83. aiagents4pharma/talk2cells/states/state_talk2cells.py +4 -2
  84. aiagents4pharma/talk2cells/tests/scp_agent/test_scp_agent.py +8 -9
  85. aiagents4pharma/talk2cells/tools/__init__.py +3 -2
  86. aiagents4pharma/talk2cells/tools/scp_agent/__init__.py +4 -4
  87. aiagents4pharma/talk2cells/tools/scp_agent/display_studies.py +5 -3
  88. aiagents4pharma/talk2cells/tools/scp_agent/search_studies.py +21 -22
  89. aiagents4pharma/talk2knowledgegraphs/.dockerignore +13 -0
  90. aiagents4pharma/talk2knowledgegraphs/Dockerfile +103 -0
  91. aiagents4pharma/talk2knowledgegraphs/README.md +1 -0
  92. aiagents4pharma/talk2knowledgegraphs/__init__.py +4 -7
  93. aiagents4pharma/talk2knowledgegraphs/agents/__init__.py +3 -2
  94. aiagents4pharma/talk2knowledgegraphs/agents/t2kg_agent.py +40 -30
  95. aiagents4pharma/talk2knowledgegraphs/configs/__init__.py +3 -6
  96. aiagents4pharma/talk2knowledgegraphs/configs/agents/t2kg_agent/__init__.py +2 -2
  97. aiagents4pharma/talk2knowledgegraphs/configs/agents/t2kg_agent/default.yaml +8 -8
  98. aiagents4pharma/talk2knowledgegraphs/configs/app/__init__.py +3 -2
  99. aiagents4pharma/talk2knowledgegraphs/configs/app/frontend/__init__.py +2 -2
  100. aiagents4pharma/talk2knowledgegraphs/configs/app/frontend/default.yaml +1 -1
  101. aiagents4pharma/talk2knowledgegraphs/configs/config.yaml +1 -1
  102. aiagents4pharma/talk2knowledgegraphs/configs/tools/__init__.py +4 -5
  103. aiagents4pharma/talk2knowledgegraphs/configs/tools/graphrag_reasoning/__init__.py +2 -2
  104. aiagents4pharma/talk2knowledgegraphs/configs/tools/graphrag_reasoning/default.yaml +1 -1
  105. aiagents4pharma/talk2knowledgegraphs/configs/tools/multimodal_subgraph_extraction/default.yaml +17 -2
  106. aiagents4pharma/talk2knowledgegraphs/configs/tools/subgraph_extraction/__init__.py +2 -2
  107. aiagents4pharma/talk2knowledgegraphs/configs/tools/subgraph_extraction/default.yaml +1 -1
  108. aiagents4pharma/talk2knowledgegraphs/configs/tools/subgraph_summarization/__init__.py +2 -2
  109. aiagents4pharma/talk2knowledgegraphs/configs/tools/subgraph_summarization/default.yaml +1 -1
  110. aiagents4pharma/talk2knowledgegraphs/configs/utils/enrichments/ols_terms/default.yaml +1 -1
  111. aiagents4pharma/talk2knowledgegraphs/configs/utils/enrichments/reactome_pathways/default.yaml +1 -1
  112. aiagents4pharma/talk2knowledgegraphs/configs/utils/enrichments/uniprot_proteins/default.yaml +1 -1
  113. aiagents4pharma/talk2knowledgegraphs/configs/utils/pubchem_utils/default.yaml +1 -1
  114. aiagents4pharma/talk2knowledgegraphs/datasets/__init__.py +4 -6
  115. aiagents4pharma/talk2knowledgegraphs/datasets/biobridge_primekg.py +115 -67
  116. aiagents4pharma/talk2knowledgegraphs/datasets/dataset.py +2 -0
  117. aiagents4pharma/talk2knowledgegraphs/datasets/primekg.py +35 -24
  118. aiagents4pharma/talk2knowledgegraphs/datasets/starkqa_primekg.py +29 -21
  119. aiagents4pharma/talk2knowledgegraphs/docker-compose/cpu/.env.example +23 -0
  120. aiagents4pharma/talk2knowledgegraphs/docker-compose/cpu/docker-compose.yml +93 -0
  121. aiagents4pharma/talk2knowledgegraphs/docker-compose/gpu/.env.example +23 -0
  122. aiagents4pharma/talk2knowledgegraphs/docker-compose/gpu/docker-compose.yml +108 -0
  123. aiagents4pharma/talk2knowledgegraphs/entrypoint.sh +190 -0
  124. aiagents4pharma/talk2knowledgegraphs/install.md +140 -0
  125. aiagents4pharma/talk2knowledgegraphs/milvus_data_dump.py +31 -65
  126. aiagents4pharma/talk2knowledgegraphs/states/__init__.py +3 -2
  127. aiagents4pharma/talk2knowledgegraphs/states/state_talk2knowledgegraphs.py +1 -0
  128. aiagents4pharma/talk2knowledgegraphs/tests/test_agents_t2kg_agent.py +65 -40
  129. aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_biobridge_primekg.py +54 -48
  130. aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_dataset.py +4 -0
  131. aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_primekg.py +17 -4
  132. aiagents4pharma/talk2knowledgegraphs/tests/test_datasets_starkqa_primekg.py +33 -24
  133. aiagents4pharma/talk2knowledgegraphs/tests/test_tools_graphrag_reasoning.py +116 -69
  134. aiagents4pharma/talk2knowledgegraphs/tests/test_tools_milvus_multimodal_subgraph_extraction.py +736 -413
  135. aiagents4pharma/talk2knowledgegraphs/tests/test_tools_multimodal_subgraph_extraction.py +22 -15
  136. aiagents4pharma/talk2knowledgegraphs/tests/test_tools_subgraph_extraction.py +19 -12
  137. aiagents4pharma/talk2knowledgegraphs/tests/test_tools_subgraph_summarization.py +95 -48
  138. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_embeddings.py +4 -0
  139. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_huggingface.py +5 -0
  140. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_nim_molmim.py +13 -18
  141. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_embeddings_ollama.py +10 -3
  142. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_enrichments.py +4 -3
  143. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_ollama.py +3 -2
  144. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_ols.py +1 -0
  145. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_pubchem.py +9 -4
  146. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_reactome.py +6 -6
  147. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_enrichments_uniprot.py +4 -0
  148. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_extractions_milvus_multimodal_pcst.py +442 -42
  149. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_kg_utils.py +3 -4
  150. aiagents4pharma/talk2knowledgegraphs/tests/test_utils_pubchem_utils.py +10 -6
  151. aiagents4pharma/talk2knowledgegraphs/tools/__init__.py +10 -7
  152. aiagents4pharma/talk2knowledgegraphs/tools/graphrag_reasoning.py +15 -20
  153. aiagents4pharma/talk2knowledgegraphs/tools/milvus_multimodal_subgraph_extraction.py +245 -205
  154. aiagents4pharma/talk2knowledgegraphs/tools/multimodal_subgraph_extraction.py +92 -90
  155. aiagents4pharma/talk2knowledgegraphs/tools/subgraph_extraction.py +25 -37
  156. aiagents4pharma/talk2knowledgegraphs/tools/subgraph_summarization.py +10 -13
  157. aiagents4pharma/talk2knowledgegraphs/utils/__init__.py +4 -7
  158. aiagents4pharma/talk2knowledgegraphs/utils/embeddings/__init__.py +4 -7
  159. aiagents4pharma/talk2knowledgegraphs/utils/embeddings/embeddings.py +4 -0
  160. aiagents4pharma/talk2knowledgegraphs/utils/embeddings/huggingface.py +11 -14
  161. aiagents4pharma/talk2knowledgegraphs/utils/embeddings/nim_molmim.py +7 -7
  162. aiagents4pharma/talk2knowledgegraphs/utils/embeddings/ollama.py +12 -6
  163. aiagents4pharma/talk2knowledgegraphs/utils/embeddings/sentence_transformer.py +8 -6
  164. aiagents4pharma/talk2knowledgegraphs/utils/enrichments/__init__.py +9 -6
  165. aiagents4pharma/talk2knowledgegraphs/utils/enrichments/enrichments.py +1 -0
  166. aiagents4pharma/talk2knowledgegraphs/utils/enrichments/ollama.py +15 -9
  167. aiagents4pharma/talk2knowledgegraphs/utils/enrichments/ols_terms.py +23 -20
  168. aiagents4pharma/talk2knowledgegraphs/utils/enrichments/pubchem_strings.py +12 -10
  169. aiagents4pharma/talk2knowledgegraphs/utils/enrichments/reactome_pathways.py +16 -10
  170. aiagents4pharma/talk2knowledgegraphs/utils/enrichments/uniprot_proteins.py +26 -18
  171. aiagents4pharma/talk2knowledgegraphs/utils/extractions/__init__.py +4 -5
  172. aiagents4pharma/talk2knowledgegraphs/utils/extractions/milvus_multimodal_pcst.py +218 -81
  173. aiagents4pharma/talk2knowledgegraphs/utils/extractions/multimodal_pcst.py +53 -47
  174. aiagents4pharma/talk2knowledgegraphs/utils/extractions/pcst.py +18 -14
  175. aiagents4pharma/talk2knowledgegraphs/utils/kg_utils.py +22 -23
  176. aiagents4pharma/talk2knowledgegraphs/utils/pubchem_utils.py +11 -10
  177. aiagents4pharma/talk2scholars/.dockerignore +13 -0
  178. aiagents4pharma/talk2scholars/Dockerfile +104 -0
  179. aiagents4pharma/talk2scholars/README.md +1 -0
  180. aiagents4pharma/talk2scholars/agents/__init__.py +1 -5
  181. aiagents4pharma/talk2scholars/agents/main_agent.py +6 -4
  182. aiagents4pharma/talk2scholars/agents/paper_download_agent.py +5 -4
  183. aiagents4pharma/talk2scholars/agents/pdf_agent.py +4 -2
  184. aiagents4pharma/talk2scholars/agents/s2_agent.py +2 -2
  185. aiagents4pharma/talk2scholars/agents/zotero_agent.py +10 -11
  186. aiagents4pharma/talk2scholars/configs/__init__.py +1 -3
  187. aiagents4pharma/talk2scholars/configs/agents/talk2scholars/__init__.py +1 -4
  188. aiagents4pharma/talk2scholars/configs/agents/talk2scholars/main_agent/default.yaml +1 -1
  189. aiagents4pharma/talk2scholars/configs/agents/talk2scholars/pdf_agent/default.yaml +1 -1
  190. aiagents4pharma/talk2scholars/configs/agents/talk2scholars/s2_agent/default.yaml +8 -8
  191. aiagents4pharma/talk2scholars/configs/agents/talk2scholars/zotero_agent/default.yaml +7 -7
  192. aiagents4pharma/talk2scholars/configs/tools/__init__.py +8 -6
  193. aiagents4pharma/talk2scholars/docker-compose/cpu/.env.example +21 -0
  194. aiagents4pharma/talk2scholars/docker-compose/cpu/docker-compose.yml +90 -0
  195. aiagents4pharma/talk2scholars/docker-compose/gpu/.env.example +21 -0
  196. aiagents4pharma/talk2scholars/docker-compose/gpu/docker-compose.yml +105 -0
  197. aiagents4pharma/talk2scholars/install.md +122 -0
  198. aiagents4pharma/talk2scholars/state/state_talk2scholars.py +8 -8
  199. aiagents4pharma/talk2scholars/tests/{test_main_agent.py → test_agents_main_agent.py} +41 -23
  200. aiagents4pharma/talk2scholars/tests/{test_paper_download_agent.py → test_agents_paper_agents_download_agent.py} +10 -16
  201. aiagents4pharma/talk2scholars/tests/{test_pdf_agent.py → test_agents_pdf_agent.py} +6 -10
  202. aiagents4pharma/talk2scholars/tests/{test_s2_agent.py → test_agents_s2_agent.py} +8 -16
  203. aiagents4pharma/talk2scholars/tests/{test_zotero_agent.py → test_agents_zotero_agent.py} +5 -7
  204. aiagents4pharma/talk2scholars/tests/{test_s2_display_dataframe.py → test_s2_tools_display_dataframe.py} +6 -7
  205. aiagents4pharma/talk2scholars/tests/{test_s2_query_dataframe.py → test_s2_tools_query_dataframe.py} +5 -15
  206. aiagents4pharma/talk2scholars/tests/{test_paper_downloader.py → test_tools_paper_downloader.py} +25 -63
  207. aiagents4pharma/talk2scholars/tests/{test_question_and_answer_tool.py → test_tools_question_and_answer_tool.py} +2 -6
  208. aiagents4pharma/talk2scholars/tests/{test_s2_multi.py → test_tools_s2_multi.py} +5 -5
  209. aiagents4pharma/talk2scholars/tests/{test_s2_retrieve.py → test_tools_s2_retrieve.py} +2 -1
  210. aiagents4pharma/talk2scholars/tests/{test_s2_search.py → test_tools_s2_search.py} +5 -5
  211. aiagents4pharma/talk2scholars/tests/{test_s2_single.py → test_tools_s2_single.py} +5 -5
  212. aiagents4pharma/talk2scholars/tests/{test_arxiv_downloader.py → test_utils_arxiv_downloader.py} +16 -25
  213. aiagents4pharma/talk2scholars/tests/{test_base_paper_downloader.py → test_utils_base_paper_downloader.py} +25 -47
  214. aiagents4pharma/talk2scholars/tests/{test_biorxiv_downloader.py → test_utils_biorxiv_downloader.py} +14 -42
  215. aiagents4pharma/talk2scholars/tests/{test_medrxiv_downloader.py → test_utils_medrxiv_downloader.py} +15 -49
  216. aiagents4pharma/talk2scholars/tests/{test_nvidia_nim_reranker.py → test_utils_nvidia_nim_reranker.py} +6 -16
  217. aiagents4pharma/talk2scholars/tests/{test_pdf_answer_formatter.py → test_utils_pdf_answer_formatter.py} +1 -0
  218. aiagents4pharma/talk2scholars/tests/{test_pdf_batch_processor.py → test_utils_pdf_batch_processor.py} +6 -15
  219. aiagents4pharma/talk2scholars/tests/{test_pdf_collection_manager.py → test_utils_pdf_collection_manager.py} +34 -11
  220. aiagents4pharma/talk2scholars/tests/{test_pdf_document_processor.py → test_utils_pdf_document_processor.py} +2 -3
  221. aiagents4pharma/talk2scholars/tests/{test_pdf_generate_answer.py → test_utils_pdf_generate_answer.py} +3 -6
  222. aiagents4pharma/talk2scholars/tests/{test_pdf_gpu_detection.py → test_utils_pdf_gpu_detection.py} +5 -16
  223. aiagents4pharma/talk2scholars/tests/{test_pdf_rag_pipeline.py → test_utils_pdf_rag_pipeline.py} +7 -17
  224. aiagents4pharma/talk2scholars/tests/{test_pdf_retrieve_chunks.py → test_utils_pdf_retrieve_chunks.py} +4 -11
  225. aiagents4pharma/talk2scholars/tests/{test_pdf_singleton_manager.py → test_utils_pdf_singleton_manager.py} +26 -23
  226. aiagents4pharma/talk2scholars/tests/{test_pdf_vector_normalization.py → test_utils_pdf_vector_normalization.py} +1 -1
  227. aiagents4pharma/talk2scholars/tests/{test_pdf_vector_store.py → test_utils_pdf_vector_store.py} +27 -55
  228. aiagents4pharma/talk2scholars/tests/{test_pubmed_downloader.py → test_utils_pubmed_downloader.py} +31 -91
  229. aiagents4pharma/talk2scholars/tests/{test_read_helper_utils.py → test_utils_read_helper_utils.py} +2 -6
  230. aiagents4pharma/talk2scholars/tests/{test_s2_utils_ext_ids.py → test_utils_s2_utils_ext_ids.py} +5 -15
  231. aiagents4pharma/talk2scholars/tests/{test_zotero_human_in_the_loop.py → test_utils_zotero_human_in_the_loop.py} +6 -13
  232. aiagents4pharma/talk2scholars/tests/{test_zotero_path.py → test_utils_zotero_path.py} +53 -45
  233. aiagents4pharma/talk2scholars/tests/{test_zotero_read.py → test_utils_zotero_read.py} +30 -91
  234. aiagents4pharma/talk2scholars/tests/{test_zotero_write.py → test_utils_zotero_write.py} +6 -16
  235. aiagents4pharma/talk2scholars/tools/__init__.py +1 -4
  236. aiagents4pharma/talk2scholars/tools/paper_download/paper_downloader.py +20 -35
  237. aiagents4pharma/talk2scholars/tools/paper_download/utils/__init__.py +7 -5
  238. aiagents4pharma/talk2scholars/tools/paper_download/utils/arxiv_downloader.py +9 -11
  239. aiagents4pharma/talk2scholars/tools/paper_download/utils/base_paper_downloader.py +14 -21
  240. aiagents4pharma/talk2scholars/tools/paper_download/utils/biorxiv_downloader.py +14 -22
  241. aiagents4pharma/talk2scholars/tools/paper_download/utils/medrxiv_downloader.py +11 -13
  242. aiagents4pharma/talk2scholars/tools/paper_download/utils/pubmed_downloader.py +14 -28
  243. aiagents4pharma/talk2scholars/tools/pdf/question_and_answer.py +4 -8
  244. aiagents4pharma/talk2scholars/tools/pdf/utils/__init__.py +16 -14
  245. aiagents4pharma/talk2scholars/tools/pdf/utils/answer_formatter.py +4 -4
  246. aiagents4pharma/talk2scholars/tools/pdf/utils/batch_processor.py +15 -17
  247. aiagents4pharma/talk2scholars/tools/pdf/utils/collection_manager.py +2 -2
  248. aiagents4pharma/talk2scholars/tools/pdf/utils/document_processor.py +5 -5
  249. aiagents4pharma/talk2scholars/tools/pdf/utils/generate_answer.py +4 -4
  250. aiagents4pharma/talk2scholars/tools/pdf/utils/get_vectorstore.py +2 -6
  251. aiagents4pharma/talk2scholars/tools/pdf/utils/gpu_detection.py +5 -9
  252. aiagents4pharma/talk2scholars/tools/pdf/utils/nvidia_nim_reranker.py +4 -4
  253. aiagents4pharma/talk2scholars/tools/pdf/utils/paper_loader.py +2 -2
  254. aiagents4pharma/talk2scholars/tools/pdf/utils/rag_pipeline.py +6 -15
  255. aiagents4pharma/talk2scholars/tools/pdf/utils/retrieve_chunks.py +7 -15
  256. aiagents4pharma/talk2scholars/tools/pdf/utils/singleton_manager.py +2 -2
  257. aiagents4pharma/talk2scholars/tools/pdf/utils/tool_helper.py +3 -4
  258. aiagents4pharma/talk2scholars/tools/pdf/utils/vector_normalization.py +8 -17
  259. aiagents4pharma/talk2scholars/tools/pdf/utils/vector_store.py +17 -33
  260. aiagents4pharma/talk2scholars/tools/s2/__init__.py +8 -6
  261. aiagents4pharma/talk2scholars/tools/s2/display_dataframe.py +3 -7
  262. aiagents4pharma/talk2scholars/tools/s2/multi_paper_rec.py +7 -6
  263. aiagents4pharma/talk2scholars/tools/s2/query_dataframe.py +5 -12
  264. aiagents4pharma/talk2scholars/tools/s2/retrieve_semantic_scholar_paper_id.py +2 -4
  265. aiagents4pharma/talk2scholars/tools/s2/search.py +6 -6
  266. aiagents4pharma/talk2scholars/tools/s2/single_paper_rec.py +5 -3
  267. aiagents4pharma/talk2scholars/tools/s2/utils/__init__.py +1 -3
  268. aiagents4pharma/talk2scholars/tools/s2/utils/multi_helper.py +12 -18
  269. aiagents4pharma/talk2scholars/tools/s2/utils/search_helper.py +11 -18
  270. aiagents4pharma/talk2scholars/tools/s2/utils/single_helper.py +11 -16
  271. aiagents4pharma/talk2scholars/tools/zotero/__init__.py +1 -4
  272. aiagents4pharma/talk2scholars/tools/zotero/utils/__init__.py +1 -4
  273. aiagents4pharma/talk2scholars/tools/zotero/utils/read_helper.py +21 -39
  274. aiagents4pharma/talk2scholars/tools/zotero/utils/review_helper.py +2 -6
  275. aiagents4pharma/talk2scholars/tools/zotero/utils/write_helper.py +8 -11
  276. aiagents4pharma/talk2scholars/tools/zotero/utils/zotero_path.py +4 -12
  277. aiagents4pharma/talk2scholars/tools/zotero/utils/zotero_pdf_downloader.py +13 -27
  278. aiagents4pharma/talk2scholars/tools/zotero/zotero_read.py +4 -7
  279. aiagents4pharma/talk2scholars/tools/zotero/zotero_review.py +8 -10
  280. aiagents4pharma/talk2scholars/tools/zotero/zotero_write.py +3 -2
  281. {aiagents4pharma-1.43.0.dist-info → aiagents4pharma-1.45.0.dist-info}/METADATA +115 -50
  282. aiagents4pharma-1.45.0.dist-info/RECORD +324 -0
  283. {aiagents4pharma-1.43.0.dist-info → aiagents4pharma-1.45.0.dist-info}/WHEEL +1 -2
  284. aiagents4pharma-1.43.0.dist-info/RECORD +0 -293
  285. aiagents4pharma-1.43.0.dist-info/top_level.txt +0 -1
  286. /aiagents4pharma/talk2scholars/tests/{test_state.py → test_states_state.py} +0 -0
  287. /aiagents4pharma/talk2scholars/tests/{test_pdf_paper_loader.py → test_utils_pdf_paper_loader.py} +0 -0
  288. /aiagents4pharma/talk2scholars/tests/{test_tool_helper_utils.py → test_utils_tool_helper_utils.py} +0 -0
  289. /aiagents4pharma/talk2scholars/tests/{test_zotero_pdf_downloader_utils.py → test_utils_zotero_pdf_downloader_utils.py} +0 -0
  290. {aiagents4pharma-1.43.0.dist-info → aiagents4pharma-1.45.0.dist-info}/licenses/LICENSE +0 -0
@@ -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
- "aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize"
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
- "aiagents4pharma.talk2scholars.tools.zotero.utils.read_helper.hydra.initialize"
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 patch, MagicMock
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
- user_id="dummy", library_type="user", api_key="dummy"
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
 
@@ -4,9 +4,6 @@
4
4
  Import statements
5
5
  """
6
6
 
7
- from . import s2
8
- from . import pdf
9
- from . import zotero
10
- from . import paper_download
7
+ from . import paper_download, pdf, s2, zotero
11
8
 
12
9
  __all__ = ["s2", "pdf", "zotero", "paper_download"]
@@ -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, List, Literal, Optional
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: Optional[Literal["arxiv", "medrxiv", "biorxiv", "pubmed"]] = Field(
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: List[str] = Field(
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: Optional[Literal["arxiv", "medrxiv", "biorxiv", "pubmed"]],
294
- identifiers: List[str],
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: List[str], tool_call_id: Annotated[str, InjectedToolCallId]
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: List[str], tool_call_id: Annotated[str, InjectedToolCallId]
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: List[str], tool_call_id: Annotated[str, InjectedToolCallId]
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: List[str], tool_call_id: Annotated[str, InjectedToolCallId]
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: Optional[Literal["arxiv", "medrxiv", "biorxiv", "pubmed"]],
366
- identifiers: List[str],
350
+ service: Literal["arxiv", "medrxiv", "biorxiv", "pubmed"] | None,
351
+ identifiers: list[str],
367
352
  tool_call_id: str,
368
353
  ) -> Command[Any]:
369
354
  """
@@ -5,11 +5,13 @@ biorxiv and medrxiv.
5
5
  """
6
6
 
7
7
  # Import modules
8
- from . import arxiv_downloader
9
- from . import base_paper_downloader
10
- from . import biorxiv_downloader
11
- from . import medrxiv_downloader
12
- from . import pubmed_downloader
8
+ from . import (
9
+ arxiv_downloader,
10
+ base_paper_downloader,
11
+ biorxiv_downloader,
12
+ medrxiv_downloader,
13
+ pubmed_downloader,
14
+ )
13
15
 
14
16
  __all__ = [
15
17
  "arxiv_downloader",
@@ -5,7 +5,7 @@ ArXiv paper downloader implementation.
5
5
 
6
6
  import logging
7
7
  import xml.etree.ElementTree as ET
8
- from typing import Any, Dict, Optional, Tuple
8
+ from typing import Any
9
9
 
10
10
  import requests
11
11
 
@@ -92,8 +92,8 @@ class ArxivDownloader(BasePaperDownloader):
92
92
  self,
93
93
  metadata: ET.Element,
94
94
  identifier: str,
95
- pdf_result: Optional[Tuple[str, str]],
96
- ) -> Dict[str, Any]:
95
+ pdf_result: tuple[str, str] | None,
96
+ ) -> dict[str, Any]:
97
97
  """
98
98
  Extract structured metadata from arXiv API response.
99
99
 
@@ -124,7 +124,7 @@ class ArxivDownloader(BasePaperDownloader):
124
124
  "arxiv_id": identifier,
125
125
  }
126
126
 
127
- def _extract_basic_metadata(self, entry: ET.Element, ns: dict) -> Dict[str, Any]:
127
+ def _extract_basic_metadata(self, entry: ET.Element, ns: dict) -> dict[str, Any]:
128
128
  """Extract basic metadata (title, authors, abstract, date) from entry."""
129
129
  title = self._extract_title(entry, ns)
130
130
  authors = self._extract_authors(entry, ns)
@@ -160,13 +160,11 @@ class ArxivDownloader(BasePaperDownloader):
160
160
  def _extract_publication_date(self, entry: ET.Element, ns: dict) -> str:
161
161
  """Extract publication date from entry."""
162
162
  published_elem = entry.find("atom:published", ns)
163
- return (
164
- (published_elem.text or "").strip() if published_elem is not None else "N/A"
165
- )
163
+ return (published_elem.text or "").strip() if published_elem is not None else "N/A"
166
164
 
167
165
  def _extract_pdf_metadata(
168
- self, pdf_result: Optional[Tuple[str, str]], identifier: str
169
- ) -> Dict[str, Any]:
166
+ self, pdf_result: tuple[str, str] | None, identifier: str
167
+ ) -> dict[str, Any]:
170
168
  """Extract PDF-related metadata."""
171
169
  if pdf_result:
172
170
  temp_file_path, filename = pdf_result
@@ -198,12 +196,12 @@ class ArxivDownloader(BasePaperDownloader):
198
196
  """Generate default filename for arXiv paper."""
199
197
  return f"{identifier}.pdf"
200
198
 
201
- def _get_paper_identifier_info(self, paper: Dict[str, Any]) -> str:
199
+ def _get_paper_identifier_info(self, paper: dict[str, Any]) -> str:
202
200
  """Get arXiv-specific identifier info for paper summary."""
203
201
  arxiv_id = paper.get("arxiv_id", "N/A")
204
202
  pub_date = paper.get("Publication Date", "N/A")
205
203
  return f" (arXiv:{arxiv_id}, {pub_date})"
206
204
 
207
- def _add_service_identifier(self, entry: Dict[str, Any], identifier: str) -> None:
205
+ def _add_service_identifier(self, entry: dict[str, Any], identifier: str) -> None:
208
206
  """Add arXiv ID field to entry."""
209
207
  entry["arxiv_id"] = identifier