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
@@ -5,7 +5,7 @@ Utility for zotero read tool.
|
|
5
5
|
"""
|
6
6
|
|
7
7
|
import logging
|
8
|
-
from typing import Any
|
8
|
+
from typing import Any
|
9
9
|
|
10
10
|
import hydra
|
11
11
|
import requests
|
@@ -51,7 +51,7 @@ class ZoteroSearchData:
|
|
51
51
|
self._filter_and_format_papers(items)
|
52
52
|
self._create_content()
|
53
53
|
|
54
|
-
def get_search_results(self) ->
|
54
|
+
def get_search_results(self) -> dict[str, Any]:
|
55
55
|
"""Get the search results and content."""
|
56
56
|
return {
|
57
57
|
"article_data": self.article_data,
|
@@ -61,9 +61,7 @@ class ZoteroSearchData:
|
|
61
61
|
def _load_config(self) -> Any:
|
62
62
|
"""Load hydra configuration."""
|
63
63
|
with hydra.initialize(version_base=None, config_path="../../../configs"):
|
64
|
-
cfg = hydra.compose(
|
65
|
-
config_name="config", overrides=["tools/zotero_read=default"]
|
66
|
-
)
|
64
|
+
cfg = hydra.compose(config_name="config", overrides=["tools/zotero_read=default"])
|
67
65
|
logger.info("Loaded configuration for Zotero search tool")
|
68
66
|
return cfg.tools.zotero_read
|
69
67
|
|
@@ -77,7 +75,7 @@ class ZoteroSearchData:
|
|
77
75
|
)
|
78
76
|
return zotero.Zotero(self.cfg.user_id, self.cfg.library_type, self.cfg.api_key)
|
79
77
|
|
80
|
-
def _fetch_items(self) ->
|
78
|
+
def _fetch_items(self) -> list[dict[str, Any]]:
|
81
79
|
"""Fetch items from Zotero."""
|
82
80
|
try:
|
83
81
|
if self.query.strip() == "":
|
@@ -100,15 +98,13 @@ class ZoteroSearchData:
|
|
100
98
|
|
101
99
|
if not items:
|
102
100
|
logger.error("No items returned from Zotero for query: '%s'", self.query)
|
103
|
-
raise RuntimeError(
|
104
|
-
"No items returned from Zotero. Please retry the same query."
|
105
|
-
)
|
101
|
+
raise RuntimeError("No items returned from Zotero. Please retry the same query.")
|
106
102
|
|
107
103
|
return items
|
108
104
|
|
109
|
-
def _collect_item_attachments(self) ->
|
105
|
+
def _collect_item_attachments(self) -> dict[str, str]:
|
110
106
|
"""Collect PDF attachment keys for non-orphan items."""
|
111
|
-
item_attachments:
|
107
|
+
item_attachments: dict[str, str] = {}
|
112
108
|
for item_key, item_data in self.article_data.items():
|
113
109
|
if item_data.get("Type") == "orphan_attachment":
|
114
110
|
continue
|
@@ -127,7 +123,7 @@ class ZoteroSearchData:
|
|
127
123
|
logger.error("Failed to get attachments for item %s: %s", item_key, e)
|
128
124
|
return item_attachments
|
129
125
|
|
130
|
-
def _process_orphaned_pdfs(self, orphaned_pdfs:
|
126
|
+
def _process_orphaned_pdfs(self, orphaned_pdfs: dict[str, str]) -> None:
|
131
127
|
"""Download or record orphaned PDF attachments."""
|
132
128
|
if self.download_pdfs:
|
133
129
|
logger.info("Downloading %d orphaned PDFs in parallel", len(orphaned_pdfs))
|
@@ -147,16 +143,14 @@ class ZoteroSearchData:
|
|
147
143
|
logger.info("Skipping orphaned PDF downloads (download_pdfs=False)")
|
148
144
|
for attachment_key in orphaned_pdfs:
|
149
145
|
self.article_data[attachment_key]["attachment_key"] = attachment_key
|
150
|
-
self.article_data[attachment_key]["filename"] =
|
151
|
-
|
152
|
-
)
|
146
|
+
self.article_data[attachment_key]["filename"] = self.article_data[
|
147
|
+
attachment_key
|
148
|
+
].get("Title", attachment_key)
|
153
149
|
|
154
|
-
def _process_item_pdfs(self, item_attachments:
|
150
|
+
def _process_item_pdfs(self, item_attachments: dict[str, str]) -> None:
|
155
151
|
"""Download or record regular item PDF attachments."""
|
156
152
|
if self.download_pdfs:
|
157
|
-
logger.info(
|
158
|
-
"Downloading %d regular item PDFs in parallel", len(item_attachments)
|
159
|
-
)
|
153
|
+
logger.info("Downloading %d regular item PDFs in parallel", len(item_attachments))
|
160
154
|
results = download_pdfs_in_parallel(
|
161
155
|
self.session,
|
162
156
|
self.cfg.user_id,
|
@@ -175,15 +169,13 @@ class ZoteroSearchData:
|
|
175
169
|
self.article_data[item_key]["attachment_key"] = attachment_key
|
176
170
|
logger.info("Downloaded Zotero PDF to: %s", file_path)
|
177
171
|
|
178
|
-
def _filter_and_format_papers(self, items:
|
172
|
+
def _filter_and_format_papers(self, items: list[dict[str, Any]]) -> None:
|
179
173
|
"""Filter and format papers from Zotero items, including standalone PDFs."""
|
180
|
-
filter_item_types =
|
181
|
-
self.cfg.zotero.filter_item_types if self.only_articles else []
|
182
|
-
)
|
174
|
+
filter_item_types = self.cfg.zotero.filter_item_types if self.only_articles else []
|
183
175
|
logger.debug("Filtering item types: %s", filter_item_types)
|
184
176
|
|
185
177
|
# Maps to track attachments for batch processing
|
186
|
-
orphaned_pdfs:
|
178
|
+
orphaned_pdfs: dict[str, str] = {} # attachment_key -> item key (same for orphans)
|
187
179
|
|
188
180
|
# First pass: process all items without downloading PDFs
|
189
181
|
for item in items:
|
@@ -214,17 +206,14 @@ class ZoteroSearchData:
|
|
214
206
|
"Authors": [
|
215
207
|
f"{creator.get('firstName', '')} {creator.get('lastName', '')}".strip()
|
216
208
|
for creator in data.get("creators", [])
|
217
|
-
if isinstance(creator, dict)
|
218
|
-
and creator.get("creatorType") == "author"
|
209
|
+
if isinstance(creator, dict) and creator.get("creatorType") == "author"
|
219
210
|
],
|
220
211
|
"source": "zotero",
|
221
212
|
}
|
222
213
|
# We'll collect attachment info in second pass
|
223
214
|
|
224
215
|
# CASE 2: Standalone orphaned PDF attachment
|
225
|
-
elif data.get("contentType") == "application/pdf" and not data.get(
|
226
|
-
"parentItem"
|
227
|
-
):
|
216
|
+
elif data.get("contentType") == "application/pdf" and not data.get("parentItem"):
|
228
217
|
attachment_key = key
|
229
218
|
filename = data.get("filename", "unknown.pdf")
|
230
219
|
|
@@ -260,25 +249,18 @@ class ZoteroSearchData:
|
|
260
249
|
|
261
250
|
# Ensure we have some results
|
262
251
|
if not self.article_data:
|
263
|
-
logger.error(
|
264
|
-
"No matching papers returned from Zotero for query: '%s'", self.query
|
265
|
-
)
|
252
|
+
logger.error("No matching papers returned from Zotero for query: '%s'", self.query)
|
266
253
|
raise RuntimeError(
|
267
254
|
"No matching papers returned from Zotero. Please retry the same query."
|
268
255
|
)
|
269
256
|
|
270
|
-
logger.info(
|
271
|
-
"Filtered %d items (including orphaned attachments)", len(self.article_data)
|
272
|
-
)
|
257
|
+
logger.info("Filtered %d items (including orphaned attachments)", len(self.article_data))
|
273
258
|
|
274
259
|
def _create_content(self) -> None:
|
275
260
|
"""Create the content message for the response."""
|
276
261
|
top_papers = list(self.article_data.values())[:2]
|
277
262
|
top_papers_info = "\n".join(
|
278
|
-
[
|
279
|
-
f"{i+1}. {paper['Title']} ({paper['Type']})"
|
280
|
-
for i, paper in enumerate(top_papers)
|
281
|
-
]
|
263
|
+
[f"{i + 1}. {paper['Title']} ({paper['Type']})" for i, paper in enumerate(top_papers)]
|
282
264
|
)
|
283
265
|
|
284
266
|
self.content = "Retrieval was successful. Papers are attached as an artifact."
|
@@ -5,7 +5,6 @@ Utility for reviewing papers and saving them to Zotero.
|
|
5
5
|
"""
|
6
6
|
|
7
7
|
import logging
|
8
|
-
from typing import List
|
9
8
|
|
10
9
|
# Configure logging
|
11
10
|
logging.basicConfig(level=logging.INFO)
|
@@ -40,12 +39,9 @@ class ReviewData:
|
|
40
39
|
|
41
40
|
def get_custom_path_approval_message(self, custom_path: str) -> str:
|
42
41
|
"""Get the formatted approval message for a custom collection path."""
|
43
|
-
return
|
44
|
-
f"Human approved saving papers to custom Zotero "
|
45
|
-
f"collection '{custom_path}'."
|
46
|
-
)
|
42
|
+
return f"Human approved saving papers to custom Zotero collection '{custom_path}'."
|
47
43
|
|
48
|
-
def _create_papers_summary(self) ->
|
44
|
+
def _create_papers_summary(self) -> list[str]:
|
49
45
|
"""Create a summary of papers for review."""
|
50
46
|
summary = []
|
51
47
|
for paper_id, paper in list(self.fetched_papers.items())[:5]:
|
@@ -5,15 +5,16 @@ Utility for zotero write tool.
|
|
5
5
|
"""
|
6
6
|
|
7
7
|
import logging
|
8
|
-
from typing import Any
|
8
|
+
from typing import Any
|
9
|
+
|
9
10
|
import hydra
|
10
11
|
from pyzotero import zotero
|
12
|
+
|
11
13
|
from .zotero_path import (
|
12
|
-
find_or_create_collection,
|
13
14
|
fetch_papers_for_save,
|
15
|
+
find_or_create_collection,
|
14
16
|
)
|
15
17
|
|
16
|
-
|
17
18
|
# Configure logging
|
18
19
|
logging.basicConfig(level=logging.INFO)
|
19
20
|
logger = logging.getLogger(__name__)
|
@@ -41,9 +42,7 @@ class ZoteroWriteData:
|
|
41
42
|
def _load_config(self) -> Any:
|
42
43
|
"""Load hydra configuration."""
|
43
44
|
with hydra.initialize(version_base=None, config_path="../../../configs"):
|
44
|
-
cfg = hydra.compose(
|
45
|
-
config_name="config", overrides=["tools/zotero_write=default"]
|
46
|
-
)
|
45
|
+
cfg = hydra.compose(config_name="config", overrides=["tools/zotero_write=default"])
|
47
46
|
logger.info("Loaded configuration for Zotero write tool")
|
48
47
|
return cfg.tools.zotero_write
|
49
48
|
|
@@ -107,9 +106,7 @@ class ZoteroWriteData:
|
|
107
106
|
if " " in name
|
108
107
|
else {"creatorType": "author", "lastName": name}
|
109
108
|
)
|
110
|
-
for name in [
|
111
|
-
author.split(" (ID: ")[0] for author in paper.get("Authors", [])
|
112
|
-
]
|
109
|
+
for name in [author.split(" (ID: ")[0] for author in paper.get("Authors", [])]
|
113
110
|
]
|
114
111
|
|
115
112
|
self.zotero_items.append(
|
@@ -152,13 +149,13 @@ class ZoteroWriteData:
|
|
152
149
|
top_papers = list(self.fetched_papers.values())[:2]
|
153
150
|
top_papers_info = "\n".join(
|
154
151
|
[
|
155
|
-
f"{i+1}. {paper.get('Title', 'N/A')} ({paper.get('URL', 'N/A')})"
|
152
|
+
f"{i + 1}. {paper.get('Title', 'N/A')} ({paper.get('URL', 'N/A')})"
|
156
153
|
for i, paper in enumerate(top_papers)
|
157
154
|
]
|
158
155
|
)
|
159
156
|
self.content += "Here are a few of these articles:\n" + top_papers_info
|
160
157
|
|
161
|
-
def process_write(self) ->
|
158
|
+
def process_write(self) -> dict[str, Any]:
|
162
159
|
"""Process the write operation and return results."""
|
163
160
|
self._validate_papers()
|
164
161
|
matched_collection_key = self._find_collection()
|
@@ -29,9 +29,7 @@ def get_item_collections(zot):
|
|
29
29
|
|
30
30
|
# Create mappings: collection key → name and collection key → parent key
|
31
31
|
collection_map = {col["key"]: col["data"]["name"] for col in collections}
|
32
|
-
parent_map = {
|
33
|
-
col["key"]: col["data"].get("parentCollection") for col in collections
|
34
|
-
}
|
32
|
+
parent_map = {col["key"]: col["data"].get("parentCollection") for col in collections}
|
35
33
|
|
36
34
|
# Build full paths for collections
|
37
35
|
def build_collection_path(col_key):
|
@@ -49,9 +47,7 @@ def get_item_collections(zot):
|
|
49
47
|
|
50
48
|
for collection in collections:
|
51
49
|
collection_key = collection["key"]
|
52
|
-
collection_items = zot.collection_items(
|
53
|
-
collection_key
|
54
|
-
) # Fetch items in the collection
|
50
|
+
collection_items = zot.collection_items(collection_key) # Fetch items in the collection
|
55
51
|
|
56
52
|
for item in collection_items:
|
57
53
|
item_key = item["data"]["key"]
|
@@ -67,9 +63,7 @@ def get_item_collections(zot):
|
|
67
63
|
|
68
64
|
def find_or_create_collection(zot, path, create_missing=False):
|
69
65
|
"""find collection or create if missing"""
|
70
|
-
logger.info(
|
71
|
-
"Finding collection for path: %s (create_missing=%s)", path, create_missing
|
72
|
-
)
|
66
|
+
logger.info("Finding collection for path: %s (create_missing=%s)", path, create_missing)
|
73
67
|
# Normalize path: remove leading/trailing slashes and convert to lowercase
|
74
68
|
normalized = path.strip("/").lower()
|
75
69
|
path_parts = normalized.split("/") if normalized else []
|
@@ -136,9 +130,7 @@ def get_all_collection_paths(zot):
|
|
136
130
|
|
137
131
|
# Create mappings: collection key → name and collection key → parent key
|
138
132
|
collection_map = {col["key"]: col["data"]["name"] for col in collections}
|
139
|
-
parent_map = {
|
140
|
-
col["key"]: col["data"].get("parentCollection") for col in collections
|
141
|
-
}
|
133
|
+
parent_map = {col["key"]: col["data"].get("parentCollection") for col in collections}
|
142
134
|
|
143
135
|
# Build full paths for collections
|
144
136
|
def build_collection_path(col_key):
|
@@ -3,10 +3,10 @@
|
|
3
3
|
Utility functions for downloading PDFs from Zotero.
|
4
4
|
"""
|
5
5
|
|
6
|
+
import concurrent.futures
|
6
7
|
import logging
|
7
8
|
import tempfile
|
8
|
-
|
9
|
-
import concurrent.futures
|
9
|
+
|
10
10
|
import requests
|
11
11
|
|
12
12
|
logger = logging.getLogger(__name__)
|
@@ -18,7 +18,7 @@ def download_zotero_pdf(
|
|
18
18
|
api_key: str,
|
19
19
|
attachment_key: str,
|
20
20
|
**kwargs,
|
21
|
-
) ->
|
21
|
+
) -> tuple[str, str] | None:
|
22
22
|
"""
|
23
23
|
Download a PDF from Zotero by attachment key.
|
24
24
|
|
@@ -40,18 +40,12 @@ def download_zotero_pdf(
|
|
40
40
|
# Log configured parameters for verification
|
41
41
|
logger.info("download_zotero_pdf params -> timeout=%s, chunk_size=%s", timeout, chunk_size)
|
42
42
|
# Log download start
|
43
|
-
logger.info(
|
44
|
-
|
45
|
-
)
|
46
|
-
zotero_pdf_url = (
|
47
|
-
f"https://api.zotero.org/users/{user_id}/items/" f"{attachment_key}/file"
|
48
|
-
)
|
43
|
+
logger.info("Downloading Zotero PDF for attachment %s from Zotero API", attachment_key)
|
44
|
+
zotero_pdf_url = f"https://api.zotero.org/users/{user_id}/items/{attachment_key}/file"
|
49
45
|
headers = {"Zotero-API-Key": api_key}
|
50
46
|
|
51
47
|
try:
|
52
|
-
response = session.get(
|
53
|
-
zotero_pdf_url, headers=headers, stream=True, timeout=timeout
|
54
|
-
)
|
48
|
+
response = session.get(zotero_pdf_url, headers=headers, stream=True, timeout=timeout)
|
55
49
|
response.raise_for_status()
|
56
50
|
|
57
51
|
# Download to a temporary file first
|
@@ -65,9 +59,7 @@ def download_zotero_pdf(
|
|
65
59
|
# Determine filename from Content-Disposition header or default
|
66
60
|
if "filename=" in response.headers.get("Content-Disposition", ""):
|
67
61
|
filename = (
|
68
|
-
response.headers.get("Content-Disposition", "")
|
69
|
-
.split("filename=")[-1]
|
70
|
-
.strip('"')
|
62
|
+
response.headers.get("Content-Disposition", "").split("filename=")[-1].strip('"')
|
71
63
|
)
|
72
64
|
else:
|
73
65
|
filename = "downloaded.pdf"
|
@@ -75,9 +67,7 @@ def download_zotero_pdf(
|
|
75
67
|
return temp_file_path, filename
|
76
68
|
|
77
69
|
except (requests.exceptions.RequestException, OSError) as e:
|
78
|
-
logger.error(
|
79
|
-
"Failed to download Zotero PDF for attachment %s: %s", attachment_key, e
|
80
|
-
)
|
70
|
+
logger.error("Failed to download Zotero PDF for attachment %s: %s", attachment_key, e)
|
81
71
|
return None
|
82
72
|
|
83
73
|
|
@@ -85,9 +75,9 @@ def download_pdfs_in_parallel(
|
|
85
75
|
session: requests.Session,
|
86
76
|
user_id: str,
|
87
77
|
api_key: str,
|
88
|
-
attachment_item_map:
|
78
|
+
attachment_item_map: dict[str, str],
|
89
79
|
**kwargs,
|
90
|
-
) ->
|
80
|
+
) -> dict[str, tuple[str, str, str]]:
|
91
81
|
"""
|
92
82
|
Download multiple PDFs in parallel using ThreadPoolExecutor.
|
93
83
|
|
@@ -108,20 +98,16 @@ def download_pdfs_in_parallel(
|
|
108
98
|
chunk_size = kwargs.get("chunk_size")
|
109
99
|
# Log configured parameters for verification
|
110
100
|
logger.info(
|
111
|
-
"download_pdfs_in_parallel params -> max_workers=%s, chunk_size=%s",
|
101
|
+
"download_pdfs_in_parallel params -> max_workers=%s, chunk_size=%s",
|
112
102
|
max_workers,
|
113
103
|
chunk_size,
|
114
104
|
)
|
115
|
-
results:
|
105
|
+
results: dict[str, tuple[str, str, str]] = {}
|
116
106
|
if not attachment_item_map:
|
117
107
|
return results
|
118
108
|
|
119
109
|
with concurrent.futures.ThreadPoolExecutor(
|
120
|
-
max_workers=(
|
121
|
-
max_workers
|
122
|
-
if max_workers is not None
|
123
|
-
else min(10, len(attachment_item_map))
|
124
|
-
)
|
110
|
+
max_workers=(max_workers if max_workers is not None else min(10, len(attachment_item_map)))
|
125
111
|
) as executor:
|
126
112
|
future_to_keys = {
|
127
113
|
executor.submit(
|
@@ -10,13 +10,14 @@ for each found item and makes the results available as an artifact.
|
|
10
10
|
|
11
11
|
import logging
|
12
12
|
from typing import Annotated, Any
|
13
|
+
|
13
14
|
from langchain_core.messages import ToolMessage
|
14
15
|
from langchain_core.tools import tool
|
15
16
|
from langchain_core.tools.base import InjectedToolCallId
|
16
17
|
from langgraph.types import Command
|
17
18
|
from pydantic import BaseModel, Field
|
18
|
-
from .utils.read_helper import ZoteroSearchData
|
19
19
|
|
20
|
+
from .utils.read_helper import ZoteroSearchData
|
20
21
|
|
21
22
|
# Configure logging
|
22
23
|
logging.basicConfig(level=logging.INFO)
|
@@ -34,16 +35,12 @@ class ZoteroSearchInput(BaseModel):
|
|
34
35
|
tool_call_id (str): Internal identifier for this tool invocation.
|
35
36
|
"""
|
36
37
|
|
37
|
-
query: str = Field(
|
38
|
-
description="Search query string to find papers in Zotero library."
|
39
|
-
)
|
38
|
+
query: str = Field(description="Search query string to find papers in Zotero library.")
|
40
39
|
only_articles: bool = Field(
|
41
40
|
default=True,
|
42
41
|
description="Whether to only search for journal articles/conference papers.",
|
43
42
|
)
|
44
|
-
limit: int = Field(
|
45
|
-
default=2, description="Maximum number of results to return", ge=1, le=100
|
46
|
-
)
|
43
|
+
limit: int = Field(default=2, description="Maximum number of results to return", ge=1, le=100)
|
47
44
|
download_pdfs: bool = Field(
|
48
45
|
default=False,
|
49
46
|
description="Whether to download PDF attachments immediately (default True).",
|
@@ -5,15 +5,17 @@ This tool implements human-in-the-loop review for Zotero write operations.
|
|
5
5
|
"""
|
6
6
|
|
7
7
|
import logging
|
8
|
-
from typing import Annotated, Any,
|
8
|
+
from typing import Annotated, Any, Literal
|
9
|
+
|
10
|
+
from langchain_core.messages import HumanMessage, ToolMessage
|
9
11
|
from langchain_core.tools import tool
|
10
|
-
from langchain_core.messages import ToolMessage, HumanMessage
|
11
12
|
from langchain_core.tools.base import InjectedToolCallId
|
12
13
|
from langgraph.prebuilt import InjectedState
|
13
14
|
from langgraph.types import Command, interrupt
|
14
15
|
from pydantic import BaseModel, Field
|
15
|
-
|
16
|
+
|
16
17
|
from .utils.review_helper import ReviewData
|
18
|
+
from .utils.zotero_path import fetch_papers_for_save
|
17
19
|
|
18
20
|
# Configure logging
|
19
21
|
logging.basicConfig(level=logging.INFO)
|
@@ -28,7 +30,7 @@ class ZoteroReviewDecision(BaseModel):
|
|
28
30
|
"""
|
29
31
|
|
30
32
|
decision: Literal["approve", "reject", "custom"]
|
31
|
-
custom_path:
|
33
|
+
custom_path: str | None = None
|
32
34
|
|
33
35
|
|
34
36
|
class ZoteroReviewInput(BaseModel):
|
@@ -83,9 +85,7 @@ def zotero_review(
|
|
83
85
|
raise ValueError("LLM model is not available in the state.")
|
84
86
|
structured_llm = llm_model.with_structured_output(ZoteroReviewDecision)
|
85
87
|
# Convert the raw human response to a message for structured parsing
|
86
|
-
decision_response = structured_llm.invoke(
|
87
|
-
[HumanMessage(content=str(human_review))]
|
88
|
-
)
|
88
|
+
decision_response = structured_llm.invoke([HumanMessage(content=str(human_review))])
|
89
89
|
|
90
90
|
# Process the structured response
|
91
91
|
if decision_response.decision == "approve":
|
@@ -105,9 +105,7 @@ def zotero_review(
|
|
105
105
|
}
|
106
106
|
)
|
107
107
|
if decision_response.decision == "custom" and decision_response.custom_path:
|
108
|
-
logger.info(
|
109
|
-
"User approved with custom path: %s", decision_response.custom_path
|
110
|
-
)
|
108
|
+
logger.info("User approved with custom path: %s", decision_response.custom_path)
|
111
109
|
return Command(
|
112
110
|
update={
|
113
111
|
"messages": [
|
@@ -6,14 +6,15 @@ This tool is used to save fetched papers to Zotero library after human approval.
|
|
6
6
|
|
7
7
|
import logging
|
8
8
|
from typing import Annotated, Any
|
9
|
+
|
9
10
|
from langchain_core.messages import ToolMessage
|
10
11
|
from langchain_core.tools import tool
|
11
12
|
from langchain_core.tools.base import InjectedToolCallId
|
12
|
-
from langgraph.types import Command
|
13
13
|
from langgraph.prebuilt import InjectedState
|
14
|
+
from langgraph.types import Command
|
14
15
|
from pydantic import BaseModel, Field
|
15
|
-
from .utils.write_helper import ZoteroWriteData
|
16
16
|
|
17
|
+
from .utils.write_helper import ZoteroWriteData
|
17
18
|
|
18
19
|
# Configure logging
|
19
20
|
logging.basicConfig(level=logging.INFO)
|