Spaces:
Runtime error
Runtime error
root
commited on
Commit
•
5c5c629
1
Parent(s):
92bcd1d
abstractfunctionadded
Browse files- README.md +8 -6
- README_en.md +70 -0
- app.py +75 -41
- applocal.py +75 -41
- config.ini +2 -2
- huixiangdou/service/findarticles.py +29 -0
- huixiangdou/service/retriever.py +1 -1
README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
---
|
2 |
-
title: 文献综述助手
|
3 |
emoji: 📚
|
4 |
colorFrom: blue
|
5 |
colorTo: indigo
|
@@ -9,11 +9,13 @@ sdk_version: "4.25.0"
|
|
9 |
app_file: app.py
|
10 |
pinned: false
|
11 |
---
|
12 |
-
|
|
|
13 |
## 项目概述
|
14 |
-
-
|
15 |
-
-
|
16 |
-
-
|
|
|
17 |
- [huggingface 体验链接](https://huggingface.co/spaces/Yijun-Yang/ReadReview/), zeroGPUs 比较吝啬 我把本地推理给阉割了 不要用本地模型哈 用API 用本地模型会报错
|
18 |
|
19 |
## 流程图
|
@@ -97,7 +99,7 @@ huggingface-cli download maidalun1020/bce-reranker-base_v1 --local-dir /root/mod
|
|
97 |
```bash
|
98 |
conda activate ReviewAgent
|
99 |
cd MedicalReviewAgent
|
100 |
-
python3
|
101 |
python3 app.py # 如果不打算用本地/root/models储存的模型 这是hf的spaces的构建配置
|
102 |
```
|
103 |
gradio在本地7860端口运行
|
|
|
1 |
---
|
2 |
+
title: 文献综述助手
|
3 |
emoji: 📚
|
4 |
colorFrom: blue
|
5 |
colorTo: indigo
|
|
|
9 |
app_file: app.py
|
10 |
pinned: false
|
11 |
---
|
12 |
+
[English](README_en.md) | 中文
|
13 |
+
# MedicalReviewAgent
|
14 |
## 项目概述
|
15 |
+
- 一个基于RAG技术和Agent流程的医学文献综述辅助工具。他允许用户配置本地或远程的大语言模型,通过关键词或PMID搜索PubMed以获取文献,上传PDF文件,以及创建和管理文献数据库。用户可以通过设置不同的参数来生成数据库,用于不同的需求。
|
16 |
+
- 其中文本分块的聚类和标注功能作为一个创新点,目标是通过聚类算法对大量的文本分块进行聚类,这样大模型只需要阅读少量代表性分块并对聚类进行标注就可以输出对数据库内容的整体认识。
|
17 |
+
- 最后写综述功能可以基于用户提问输出一段完整带有相关参考文献的综述文本。
|
18 |
+
- 总体来说这个小工具旨在帮助科研人员高效检索,管理,阅读和总结文献。
|
19 |
- [huggingface 体验链接](https://huggingface.co/spaces/Yijun-Yang/ReadReview/), zeroGPUs 比较吝啬 我把本地推理给阉割了 不要用本地模型哈 用API 用本地模型会报错
|
20 |
|
21 |
## 流程图
|
|
|
99 |
```bash
|
100 |
conda activate ReviewAgent
|
101 |
cd MedicalReviewAgent
|
102 |
+
python3 applocal.py --model_downloaded True # 如果已经在/root/models下载了模型 这个参数会换一个配置文件,里面的modelpath是本地路径不是hf的仓库路径 自己显卡跑跑用这个
|
103 |
python3 app.py # 如果不打算用本地/root/models储存的模型 这是hf的spaces的构建配置
|
104 |
```
|
105 |
gradio在本地7860端口运行
|
README_en.md
ADDED
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
English | [中文](README.md)
|
2 |
+
# MedicalReviewAgent:
|
3 |
+
|
4 |
+
## Project Overview
|
5 |
+
|
6 |
+
- MedicalReviewAgent is a medical literature review assistance tool based on RAG technology and agent workflows. It enables users to configure local or remote large language models to search PubMed via keywords or PMIDs, upload PDF files, and create and manage literature databases. Users can generate databases with different settings for various needs.
|
7 |
+
- The tool innovatively includes text block clustering and tagging to manage large volumes of text efficiently. By clustering text blocks, the large model only needs to read a few representative blocks and annotate clusters to summarize the database content comprehensively.
|
8 |
+
- The "write review" feature allows generating complete review text with references based on user queries.
|
9 |
+
- Overall, this tool is designed to help researchers efficiently retrieve, manage, read, and summarize literature.
|
10 |
+
- [Hugging Face Experience Link](https://huggingface.co/spaces/Yijun-Yang/ReadReview/). Note: ZeroGPUs are limited, so avoid using the local model as it may result in errors.
|
11 |
+
|
12 |
+
## Workflow Diagrams
|
13 |
+
|
14 |
+
### Literature and Knowledge Base Construction
|
15 |
+
![Literature and Knowledge Base Construction Diagram](https://github.com/jabberwockyang/MedicalReviewAgent/assets/52541128/d70a2ec1-7a20-4b5b-a91c-bf649f657319)
|
16 |
+
|
17 |
+
### Human-Computer Collaborative Writing
|
18 |
+
![Human-Computer Collaborative Writing Diagram](https://github.com/jabberwockyang/MedicalReviewAgent/assets/52541128/fc394d8b-1668-4349-9adc-1c4c0a7e0a8b)
|
19 |
+
|
20 |
+
## Features
|
21 |
+
|
22 |
+
1. **Model Service Configuration**
|
23 |
+
- **Remote Model Selection**: Allows users to choose between remote or local large models from various providers like Kimi, Deepseek, Zhipuai, and GPT.
|
24 |
+
|
25 |
+
2. **Literature Search + Database Creation**
|
26 |
+
- **Literature Search**: Users can enter keywords, set the search quantity, and conduct PubMed PMC literature searches.
|
27 |
+
- **Literature Database Management**: Supports deleting existing literature databases and provides real-time updates on the library's overview.
|
28 |
+
- **Database Creation**: Users can set block size and cluster numbers for text clustering.
|
29 |
+
- **Database Management**: Supports creating new databases, deleting existing ones, and viewing database overviews.
|
30 |
+
|
31 |
+
3. **Writing Reviews**
|
32 |
+
- **Sampling Annotated Article Clusters**: Users can choose block size and cluster numbers, set the sampling annotation ratio, and start the annotation process.
|
33 |
+
- **Inspiration Generation**: Based on annotated article clusters, the large model provides inspiration to help generate the framework of questions needed for the review.
|
34 |
+
- **Review Generation**: Users can input the content or topic they wish to write about, click the generate review button, and the system will automatically generate review text with references.
|
35 |
+
|
36 |
+
## Highlights
|
37 |
+
|
38 |
+
1. **Efficient Literature Search and Management**: Quickly find related literature by keywords and supports uploading existing PDF literature for easy library construction and management.
|
39 |
+
2. **Flexible Database Generation**: Provides flexible parameters for database generation, supports multiple generations and updates to ensure timeliness and accuracy.
|
40 |
+
3. **Intelligent Review Generation**: Utilizes advanced large model technology for automated article cluster annotation and inspiration generation, helping users quickly produce high-quality review text.
|
41 |
+
4. **User-Friendly Interface**: Intuitive interface and detailed usage instructions make it easy for users to start and use all features.
|
42 |
+
5. **Remote and Local Model Support**: Supports a variety of large model providers to meet different user needs. Whether using local or remote models, configurations can be flexibly adjusted.
|
43 |
+
|
44 |
+
## Installation and Running
|
45 |
+
|
46 |
+
Create a new conda environment:
|
47 |
+
```bash
|
48 |
+
conda create --name ReviewAgent python=3.10.14
|
49 |
+
conda activate ReviewAgent
|
50 |
+
```
|
51 |
+
Clone the GitHub repository:
|
52 |
+
```bash
|
53 |
+
git clone https://github.com/jabberwockyang/MedicalReviewAgent.git
|
54 |
+
cd MedicalReviewAgent
|
55 |
+
pip install -r requirements.txt
|
56 |
+
```
|
57 |
+
Download models with huggingface-cli (optional, HF will download on first call, but there might be firewall issues):
|
58 |
+
```bash
|
59 |
+
cd /root && mkdir models
|
60 |
+
cd /root/models
|
61 |
+
# login required
|
62 |
+
huggingface-cli download Qwen/Qwen1.5-7B-Chat --local-dir /root/models/Qwen1.5-7B-Chat
|
63 |
+
huggingface-cli download maidalun1020/bce-embedding-base_v1 --local-dir /root/models/bce-embedding-base_v1
|
64 |
+
huggingface-cli download maidalun1020/bce-reranker-base_v1 --local-dir /root/models/bce-reranker-base_v1
|
65 |
+
```
|
66 |
+
Start the service:
|
67 |
+
```bash
|
68 |
+
conda activate ReviewAgent
|
69 |
+
cd MedicalReviewAgent
|
70 |
+
python3 app.py --model_downloaded True # Use this if models
|
app.py
CHANGED
@@ -82,7 +82,7 @@ def udate_model_dropdown(remote_company):
|
|
82 |
'kimi': ['moonshot-v1-128k'],
|
83 |
'deepseek': ['deepseek-chat'],
|
84 |
'zhipuai': ['glm-4'],
|
85 |
-
'gpt': ['gpt-4-32k-0613','gpt-3.5-turbo']
|
86 |
}
|
87 |
return gr.Dropdown(choices= model_choices[remote_company])
|
88 |
|
@@ -107,7 +107,7 @@ def update_remote_config(remote_ornot,remote_company = None,api = None,baseurl =
|
|
107 |
return gr.Button("配置已保存")
|
108 |
|
109 |
# @spaces.GPU(duration=120)
|
110 |
-
def get_ready(query:str,chunksize=None,k=None):
|
111 |
|
112 |
with open(CONFIG_PATH, encoding='utf8') as f:
|
113 |
config = pytoml.load(f)
|
@@ -124,6 +124,8 @@ def get_ready(query:str,chunksize=None,k=None):
|
|
124 |
except:
|
125 |
pass
|
126 |
|
|
|
|
|
127 |
if query == 'annotation':
|
128 |
if not chunksize or not k:
|
129 |
raise ValueError('chunksize or k not provided')
|
@@ -182,9 +184,11 @@ def update_repo_info():
|
|
182 |
pmc_success = repo_info['pmc_success_d']
|
183 |
scihub_success = repo_info['scihub_success_d']
|
184 |
failed_download = repo_info['failed_download']
|
|
|
|
|
185 |
|
186 |
number_of_upload = number_of_pdf-scihub_success
|
187 |
-
return keywords, retmax, search_len, import_len, failed_pmid_len, pmc_success, scihub_success,
|
188 |
else:
|
189 |
return None,None,None,None,None,None,None,None,None,number_of_pdf
|
190 |
else:
|
@@ -223,33 +227,39 @@ def delete_articles_repo():
|
|
223 |
repodir, workdir, _ = get_ready('repo_work')
|
224 |
if os.path.exists(repodir):
|
225 |
shutil.rmtree(repodir)
|
|
|
226 |
if os.path.exists(workdir):
|
227 |
shutil.rmtree(workdir)
|
|
|
228 |
|
229 |
return gr.Textbox(label="文献库概况",lines =3,
|
230 |
value = '文献库和相关数据库已删除',
|
231 |
visible = True)
|
232 |
|
233 |
def update_repo():
|
234 |
-
|
|
|
|
|
235 |
newinfo = ""
|
236 |
if keys == None:
|
237 |
newinfo += '无关键词搜索相关信息\n'
|
238 |
newinfo += '无导入的PMID\n'
|
239 |
-
if
|
240 |
-
newinfo += f'上传的PDF数量: {
|
241 |
else:
|
242 |
newinfo += '无上传的PDF\n'
|
243 |
else:
|
244 |
newinfo += f'关键词搜索:'
|
245 |
-
newinfo += f'
|
246 |
-
newinfo += f'
|
247 |
-
newinfo += f'
|
248 |
newinfo += f'导入的PMID数量: {import_len}\n'
|
249 |
-
newinfo += f'成功获取PMC全文数量: {pmc_success}\n'
|
250 |
-
newinfo += f'成功获取SciHub全文数量: {scihub_success}\n'
|
251 |
-
newinfo += f"下载失败的ID: {failed}\n"
|
252 |
-
newinfo += f
|
|
|
|
|
253 |
|
254 |
return gr.Textbox(label="文献库概况",lines =1,
|
255 |
value = newinfo,
|
@@ -259,26 +269,35 @@ def update_database_info():
|
|
259 |
with open(CONFIG_PATH, encoding='utf8') as f:
|
260 |
config = pytoml.load(f)
|
261 |
workdir = config['feature_store']['work_dir']
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
272 |
|
273 |
-
|
274 |
-
|
|
|
275 |
|
276 |
-
return
|
277 |
|
278 |
@spaces.GPU(duration=120)
|
279 |
def generate_database(chunksize:int,nclusters:str|list[str]):
|
280 |
# 在这里运行生成数据库的函数
|
281 |
repodir, workdir, _ = get_ready('repo_work')
|
|
|
|
|
282 |
if not os.path.exists(repodir):
|
283 |
return gr.Textbox(label="数据库已生成",value = '请先生成文献库',visible = True)
|
284 |
nclusters = [int(i) for i in nclusters]
|
@@ -295,12 +314,17 @@ def generate_database(chunksize:int,nclusters:str|list[str]):
|
|
295 |
chunk_size=chunksize,
|
296 |
n_clusters=nclusters,
|
297 |
config_path=CONFIG_PATH)
|
|
|
298 |
|
299 |
# walk all files in repo dir
|
300 |
-
file_opr = FileOperation()
|
301 |
files = file_opr.scan_dir(repo_dir=repodir)
|
302 |
fs_init.initialize(files=files, work_dir=workdir,file_opr=file_opr)
|
303 |
file_opr.summarize(files)
|
|
|
|
|
|
|
|
|
|
|
304 |
del fs_init
|
305 |
cache.pop('default')
|
306 |
texts, _ = update_database_info()
|
@@ -310,6 +334,7 @@ def delete_database():
|
|
310 |
_, workdir, _ = get_ready('repo_work')
|
311 |
if os.path.exists(workdir):
|
312 |
shutil.rmtree(workdir)
|
|
|
313 |
return gr.Textbox(label="数据库概况",lines =3,value = '数据库已删除',visible = True)
|
314 |
|
315 |
def update_database_textbox():
|
@@ -319,17 +344,24 @@ def update_database_textbox():
|
|
319 |
else:
|
320 |
return gr.Textbox(label="数据库概况",value = '\n'.join(texts),visible = True)
|
321 |
|
322 |
-
def update_chunksize_dropdown():
|
323 |
_, jsonobj = update_database_info()
|
324 |
-
|
|
|
|
|
|
|
|
|
325 |
|
326 |
-
def update_ncluster_dropdown(chunksize:int):
|
327 |
_, jsonobj = update_database_info()
|
328 |
-
|
|
|
|
|
|
|
329 |
return gr.Dropdown(choices= nclusters)
|
330 |
|
331 |
# @spaces.GPU(duration=120)
|
332 |
-
def annotation(n,chunksize:int,nclusters:int,remote_ornot:bool):
|
333 |
'''
|
334 |
use llm to annotate cluster
|
335 |
n: percentage of clusters to annotate
|
@@ -340,7 +372,7 @@ def annotation(n,chunksize:int,nclusters:int,remote_ornot:bool):
|
|
340 |
else:
|
341 |
backend = 'local'
|
342 |
|
343 |
-
clusterdir, samples, assistant, theme = get_ready('annotation',chunksize,nclusters)
|
344 |
new_obj_list = []
|
345 |
n = round(n * len(samples.keys()))
|
346 |
for cluster_no in random.sample(samples.keys(), n):
|
@@ -369,14 +401,14 @@ def annotation(n,chunksize:int,nclusters:int,remote_ornot:bool):
|
|
369 |
return '\n\n'.join([obj['annotation'] for obj in new_obj_list])
|
370 |
|
371 |
# @spaces.GPU(duration=120)
|
372 |
-
def inspiration(annotation:str,chunksize:int,nclusters:int,remote_ornot:bool):
|
373 |
query = 'inspiration'
|
374 |
if remote_ornot:
|
375 |
backend = 'remote'
|
376 |
else:
|
377 |
backend = 'local'
|
378 |
|
379 |
-
clusterdir, annoresult, assistant, theme = get_ready('inspiration',chunksize,nclusters)
|
380 |
new_obj_list = []
|
381 |
|
382 |
if annotation is not None: # if the user wants to get inspiration from specific clusters only
|
@@ -418,13 +450,13 @@ def getpmcurls(references):
|
|
418 |
return urls
|
419 |
|
420 |
@spaces.GPU(duration=120)
|
421 |
-
def summarize_text(query,chunksize:int,remote_ornot:bool):
|
422 |
if remote_ornot:
|
423 |
backend = 'remote'
|
424 |
else:
|
425 |
backend = 'local'
|
426 |
|
427 |
-
assistant,_ = get_ready('summarize',chunksize=chunksize,k=None)
|
428 |
code, reply, references = assistant.generate(query=query,
|
429 |
history=[],
|
430 |
groupname='',backend = backend)
|
@@ -611,6 +643,7 @@ def main_interface():
|
|
611 |
with gr.Accordion("聚类标注相关参数", open=True):
|
612 |
with gr.Row():
|
613 |
update_options = gr.Button("更新数据库情况", scale=0)
|
|
|
614 |
chunksize = gr.Dropdown([], label="选择块大小", scale=0)
|
615 |
nclusters = gr.Dropdown([], label="选择聚类数", scale=0)
|
616 |
ntoread = gr.Slider(
|
@@ -637,22 +670,23 @@ def main_interface():
|
|
637 |
output_references = gr.Markdown(label="参考文献")
|
638 |
|
639 |
update_options.click(update_chunksize_dropdown,
|
|
|
640 |
outputs=[chunksize])
|
641 |
|
642 |
chunksize.change(update_ncluster_dropdown,
|
643 |
-
inputs=[chunksize],
|
644 |
outputs= [nclusters])
|
645 |
|
646 |
annotation_button.click(annotation,
|
647 |
-
inputs = [ntoread, chunksize, nclusters,remote_ornot],
|
648 |
outputs=[annotation_output])
|
649 |
|
650 |
inspiration_button.click(inspiration,
|
651 |
-
inputs= [annotation_output, chunksize, nclusters,remote_ornot],
|
652 |
outputs=[inspiration_output])
|
653 |
|
654 |
write_button.click(summarize_text,
|
655 |
-
inputs=[query, chunksize,remote_ornot],
|
656 |
outputs =[output_text,output_references])
|
657 |
|
658 |
demo.launch(share=False, server_name='0.0.0.0', debug=True,show_error=True,allowed_paths=['img_0.jpg'])
|
|
|
82 |
'kimi': ['moonshot-v1-128k'],
|
83 |
'deepseek': ['deepseek-chat'],
|
84 |
'zhipuai': ['glm-4'],
|
85 |
+
'gpt': ['gpt-4-32k-0613','gpt-3.5-turbo','gpt-4']
|
86 |
}
|
87 |
return gr.Dropdown(choices= model_choices[remote_company])
|
88 |
|
|
|
107 |
return gr.Button("配置已保存")
|
108 |
|
109 |
# @spaces.GPU(duration=120)
|
110 |
+
def get_ready(query:str,chunksize=None,k=None,use_abstract=False):
|
111 |
|
112 |
with open(CONFIG_PATH, encoding='utf8') as f:
|
113 |
config = pytoml.load(f)
|
|
|
124 |
except:
|
125 |
pass
|
126 |
|
127 |
+
if use_abstract:
|
128 |
+
workdir = workdir + '_ab'
|
129 |
if query == 'annotation':
|
130 |
if not chunksize or not k:
|
131 |
raise ValueError('chunksize or k not provided')
|
|
|
184 |
pmc_success = repo_info['pmc_success_d']
|
185 |
scihub_success = repo_info['scihub_success_d']
|
186 |
failed_download = repo_info['failed_download']
|
187 |
+
abstract_success = repo_info['abstract_success']
|
188 |
+
failed_abstract = repo_info['failed_abstract']
|
189 |
|
190 |
number_of_upload = number_of_pdf-scihub_success
|
191 |
+
return keywords, retmax, search_len, import_len, failed_pmid_len, pmc_success, scihub_success, failed_download, abstract_success, failed_abstract, number_of_upload
|
192 |
else:
|
193 |
return None,None,None,None,None,None,None,None,None,number_of_pdf
|
194 |
else:
|
|
|
227 |
repodir, workdir, _ = get_ready('repo_work')
|
228 |
if os.path.exists(repodir):
|
229 |
shutil.rmtree(repodir)
|
230 |
+
shutil.rmtree(repodir + '_ab')
|
231 |
if os.path.exists(workdir):
|
232 |
shutil.rmtree(workdir)
|
233 |
+
shutil.rmtree(workdir + '_ab')
|
234 |
|
235 |
return gr.Textbox(label="文献库概况",lines =3,
|
236 |
value = '文献库和相关数据库已删除',
|
237 |
visible = True)
|
238 |
|
239 |
def update_repo():
|
240 |
+
# keywords, retmax, search_len, import_len, failed_pmid_len, pmc_success, scihub_success, failed_download, abstract_success, failed_abstract, number_of_upload
|
241 |
+
# None,None,None,None,None,None,None,None,None,number_of_pdf
|
242 |
+
keys, retmax, search_len, import_len, _, pmc_success, scihub_success, failed, abstract_success, failed_abstract, pdfuplo = update_repo_info()
|
243 |
newinfo = ""
|
244 |
if keys == None:
|
245 |
newinfo += '无关键词搜索相关信息\n'
|
246 |
newinfo += '无导入的PMID\n'
|
247 |
+
if pdfuplo:
|
248 |
+
newinfo += f'上传的PDF数量: {pdfuplo}\n'
|
249 |
else:
|
250 |
newinfo += '无上传的PDF\n'
|
251 |
else:
|
252 |
newinfo += f'关键词搜索:'
|
253 |
+
newinfo += f' 关键词: {keys}\n'
|
254 |
+
newinfo += f' 搜索上限: {retmax}\n'
|
255 |
+
newinfo += f' 搜索到的PMID数量: {search_len}\n'
|
256 |
newinfo += f'导入的PMID数量: {import_len}\n'
|
257 |
+
newinfo += f' 成功获取PMC全文数量: {pmc_success}\n'
|
258 |
+
newinfo += f' 成功获取SciHub全文数量: {scihub_success}\n'
|
259 |
+
newinfo += f" 下载失败的ID: {failed}\n"
|
260 |
+
newinfo += f" 成功获取摘要的数量: {abstract_success}\n"
|
261 |
+
newinfo += f" 获取摘要失败的数量: {failed_abstract}\n"
|
262 |
+
newinfo += f'上传的PDF数量: {pdfuplo}\n'
|
263 |
|
264 |
return gr.Textbox(label="文献库概况",lines =1,
|
265 |
value = newinfo,
|
|
|
269 |
with open(CONFIG_PATH, encoding='utf8') as f:
|
270 |
config = pytoml.load(f)
|
271 |
workdir = config['feature_store']['work_dir']
|
272 |
+
abworkdir = workdir + '_ab'
|
273 |
+
options = []
|
274 |
+
total_json_obj = {}
|
275 |
+
for dir in [workdir,abworkdir]:
|
276 |
+
tag = 'FullText' if '_ab' not in dir else 'Abstract'
|
277 |
+
|
278 |
+
chunkdirs = glob.glob(os.path.join(dir, 'chunksize_*'))
|
279 |
+
chunkdirs.sort()
|
280 |
+
list_of_chunksize = [int(chunkdir.split('_')[-1]) for chunkdir in chunkdirs]
|
281 |
+
# print(list_of_chunksize)
|
282 |
+
jsonobj = {}
|
283 |
+
for chunkdir in chunkdirs:
|
284 |
+
k_dir = glob.glob(os.path.join(chunkdir, 'cluster_features','cluster_features_*'))
|
285 |
+
k_dir.sort()
|
286 |
+
list_of_k = [int(k.split('_')[-1]) for k in k_dir]
|
287 |
+
jsonobj[int(chunkdir.split('_')[-1])] = list_of_k
|
288 |
|
289 |
+
total_json_obj[tag] = jsonobj
|
290 |
+
newoptions = [f"{tag}, chunksize:{chunksize}, k:{k}" for chunksize in list_of_chunksize for k in jsonobj[chunksize]]
|
291 |
+
options.extend(newoptions)
|
292 |
|
293 |
+
return options, total_json_obj
|
294 |
|
295 |
@spaces.GPU(duration=120)
|
296 |
def generate_database(chunksize:int,nclusters:str|list[str]):
|
297 |
# 在这里运行生成数据库的函数
|
298 |
repodir, workdir, _ = get_ready('repo_work')
|
299 |
+
abrepodir = repodir + '_ab'
|
300 |
+
abworkdir = workdir + '_ab'
|
301 |
if not os.path.exists(repodir):
|
302 |
return gr.Textbox(label="数据库已生成",value = '请先生成文献库',visible = True)
|
303 |
nclusters = [int(i) for i in nclusters]
|
|
|
314 |
chunk_size=chunksize,
|
315 |
n_clusters=nclusters,
|
316 |
config_path=CONFIG_PATH)
|
317 |
+
file_opr = FileOperation()
|
318 |
|
319 |
# walk all files in repo dir
|
|
|
320 |
files = file_opr.scan_dir(repo_dir=repodir)
|
321 |
fs_init.initialize(files=files, work_dir=workdir,file_opr=file_opr)
|
322 |
file_opr.summarize(files)
|
323 |
+
|
324 |
+
files = file_opr.scan_dir(repo_dir=abrepodir)
|
325 |
+
fs_init.initialize(files=files, work_dir=abworkdir,file_opr=file_opr)
|
326 |
+
file_opr.summarize(files)
|
327 |
+
|
328 |
del fs_init
|
329 |
cache.pop('default')
|
330 |
texts, _ = update_database_info()
|
|
|
334 |
_, workdir, _ = get_ready('repo_work')
|
335 |
if os.path.exists(workdir):
|
336 |
shutil.rmtree(workdir)
|
337 |
+
shutil.rmtree(workdir+'_ab')
|
338 |
return gr.Textbox(label="数据库概况",lines =3,value = '数据库已删除',visible = True)
|
339 |
|
340 |
def update_database_textbox():
|
|
|
344 |
else:
|
345 |
return gr.Textbox(label="数据库概况",value = '\n'.join(texts),visible = True)
|
346 |
|
347 |
+
def update_chunksize_dropdown(use_abstract):
|
348 |
_, jsonobj = update_database_info()
|
349 |
+
if use_abstract:
|
350 |
+
choices = jsonobj['Abstract'].keys()
|
351 |
+
else:
|
352 |
+
choices = jsonobj['FullText'].keys()
|
353 |
+
return gr.Dropdown(choices= choices)
|
354 |
|
355 |
+
def update_ncluster_dropdown(chunksize:int,use_abstract:bool):
|
356 |
_, jsonobj = update_database_info()
|
357 |
+
if use_abstract:
|
358 |
+
nclusters = jsonobj['Abstract'][chunksize]
|
359 |
+
else:
|
360 |
+
nclusters = jsonobj['FullText'][chunksize]
|
361 |
return gr.Dropdown(choices= nclusters)
|
362 |
|
363 |
# @spaces.GPU(duration=120)
|
364 |
+
def annotation(n,chunksize:int,nclusters:int,remote_ornot:bool,use_abstract:bool):
|
365 |
'''
|
366 |
use llm to annotate cluster
|
367 |
n: percentage of clusters to annotate
|
|
|
372 |
else:
|
373 |
backend = 'local'
|
374 |
|
375 |
+
clusterdir, samples, assistant, theme = get_ready('annotation',chunksize,nclusters,use_abstract)
|
376 |
new_obj_list = []
|
377 |
n = round(n * len(samples.keys()))
|
378 |
for cluster_no in random.sample(samples.keys(), n):
|
|
|
401 |
return '\n\n'.join([obj['annotation'] for obj in new_obj_list])
|
402 |
|
403 |
# @spaces.GPU(duration=120)
|
404 |
+
def inspiration(annotation:str,chunksize:int,nclusters:int,remote_ornot:bool,use_abstract:bool):
|
405 |
query = 'inspiration'
|
406 |
if remote_ornot:
|
407 |
backend = 'remote'
|
408 |
else:
|
409 |
backend = 'local'
|
410 |
|
411 |
+
clusterdir, annoresult, assistant, theme = get_ready('inspiration',chunksize,nclusters,use_abstract)
|
412 |
new_obj_list = []
|
413 |
|
414 |
if annotation is not None: # if the user wants to get inspiration from specific clusters only
|
|
|
450 |
return urls
|
451 |
|
452 |
@spaces.GPU(duration=120)
|
453 |
+
def summarize_text(query,chunksize:int,remote_ornot:bool,use_abstract:bool):
|
454 |
if remote_ornot:
|
455 |
backend = 'remote'
|
456 |
else:
|
457 |
backend = 'local'
|
458 |
|
459 |
+
assistant,_ = get_ready('summarize',chunksize=chunksize,k=None,use_abstract=use_abstract)
|
460 |
code, reply, references = assistant.generate(query=query,
|
461 |
history=[],
|
462 |
groupname='',backend = backend)
|
|
|
643 |
with gr.Accordion("聚类标注相关参数", open=True):
|
644 |
with gr.Row():
|
645 |
update_options = gr.Button("更新数据库情况", scale=0)
|
646 |
+
use_abstract = gr.Checkbox(label="是否仅使用摘要",scale=0)
|
647 |
chunksize = gr.Dropdown([], label="选择块大小", scale=0)
|
648 |
nclusters = gr.Dropdown([], label="选择聚类数", scale=0)
|
649 |
ntoread = gr.Slider(
|
|
|
670 |
output_references = gr.Markdown(label="参考文献")
|
671 |
|
672 |
update_options.click(update_chunksize_dropdown,
|
673 |
+
inputs=[use_abstract],
|
674 |
outputs=[chunksize])
|
675 |
|
676 |
chunksize.change(update_ncluster_dropdown,
|
677 |
+
inputs=[chunksize,use_abstract],
|
678 |
outputs= [nclusters])
|
679 |
|
680 |
annotation_button.click(annotation,
|
681 |
+
inputs = [ntoread, chunksize, nclusters,remote_ornot,use_abstract],
|
682 |
outputs=[annotation_output])
|
683 |
|
684 |
inspiration_button.click(inspiration,
|
685 |
+
inputs= [annotation_output, chunksize, nclusters,remote_ornot,use_abstract],
|
686 |
outputs=[inspiration_output])
|
687 |
|
688 |
write_button.click(summarize_text,
|
689 |
+
inputs=[query, chunksize,remote_ornot,use_abstract],
|
690 |
outputs =[output_text,output_references])
|
691 |
|
692 |
demo.launch(share=False, server_name='0.0.0.0', debug=True,show_error=True,allowed_paths=['img_0.jpg'])
|
applocal.py
CHANGED
@@ -82,7 +82,7 @@ def udate_model_dropdown(remote_company):
|
|
82 |
'kimi': ['moonshot-v1-128k'],
|
83 |
'deepseek': ['deepseek-chat'],
|
84 |
'zhipuai': ['glm-4'],
|
85 |
-
'gpt': ['gpt-4-32k-0613','gpt-3.5-turbo']
|
86 |
}
|
87 |
return gr.Dropdown(choices= model_choices[remote_company])
|
88 |
|
@@ -107,7 +107,7 @@ def update_remote_config(remote_ornot,remote_company = None,api = None,baseurl =
|
|
107 |
return gr.Button("配置已保存")
|
108 |
|
109 |
# @spaces.GPU(duration=360)
|
110 |
-
def get_ready(query:str,chunksize=None,k=None):
|
111 |
|
112 |
with open(CONFIG_PATH, encoding='utf8') as f:
|
113 |
config = pytoml.load(f)
|
@@ -124,6 +124,8 @@ def get_ready(query:str,chunksize=None,k=None):
|
|
124 |
except:
|
125 |
pass
|
126 |
|
|
|
|
|
127 |
if query == 'annotation':
|
128 |
if not chunksize or not k:
|
129 |
raise ValueError('chunksize or k not provided')
|
@@ -182,9 +184,11 @@ def update_repo_info():
|
|
182 |
pmc_success = repo_info['pmc_success_d']
|
183 |
scihub_success = repo_info['scihub_success_d']
|
184 |
failed_download = repo_info['failed_download']
|
|
|
|
|
185 |
|
186 |
number_of_upload = number_of_pdf-scihub_success
|
187 |
-
return keywords, retmax, search_len, import_len, failed_pmid_len, pmc_success, scihub_success,
|
188 |
else:
|
189 |
return None,None,None,None,None,None,None,None,None,number_of_pdf
|
190 |
else:
|
@@ -223,33 +227,39 @@ def delete_articles_repo():
|
|
223 |
repodir, workdir, _ = get_ready('repo_work')
|
224 |
if os.path.exists(repodir):
|
225 |
shutil.rmtree(repodir)
|
|
|
226 |
if os.path.exists(workdir):
|
227 |
shutil.rmtree(workdir)
|
|
|
228 |
|
229 |
return gr.Textbox(label="文献库概况",lines =3,
|
230 |
value = '文献库和相关数据库已删除',
|
231 |
visible = True)
|
232 |
|
233 |
def update_repo():
|
234 |
-
|
|
|
|
|
235 |
newinfo = ""
|
236 |
if keys == None:
|
237 |
newinfo += '无关键词搜索相关信息\n'
|
238 |
newinfo += '无导入的PMID\n'
|
239 |
-
if
|
240 |
-
newinfo += f'上传的PDF数量: {
|
241 |
else:
|
242 |
newinfo += '无上传的PDF\n'
|
243 |
else:
|
244 |
newinfo += f'关键词搜索:'
|
245 |
-
newinfo += f'
|
246 |
-
newinfo += f'
|
247 |
-
newinfo += f'
|
248 |
newinfo += f'导入的PMID数量: {import_len}\n'
|
249 |
-
newinfo += f'成功获取PMC全文数量: {pmc_success}\n'
|
250 |
-
newinfo += f'成功获取SciHub全文数量: {scihub_success}\n'
|
251 |
-
newinfo += f"下载失败的ID: {failed}\n"
|
252 |
-
newinfo += f
|
|
|
|
|
253 |
|
254 |
return gr.Textbox(label="文献库概况",lines =1,
|
255 |
value = newinfo,
|
@@ -259,26 +269,35 @@ def update_database_info():
|
|
259 |
with open(CONFIG_PATH, encoding='utf8') as f:
|
260 |
config = pytoml.load(f)
|
261 |
workdir = config['feature_store']['work_dir']
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
272 |
|
273 |
-
|
274 |
-
|
|
|
275 |
|
276 |
-
return
|
277 |
|
278 |
# @spaces.GPU(duration=360)
|
279 |
def generate_database(chunksize:int,nclusters:str|list[str]):
|
280 |
# 在这里运行生成数据库的函数
|
281 |
repodir, workdir, _ = get_ready('repo_work')
|
|
|
|
|
282 |
if not os.path.exists(repodir):
|
283 |
return gr.Textbox(label="数据库已生成",value = '请先生成文献库',visible = True)
|
284 |
nclusters = [int(i) for i in nclusters]
|
@@ -295,12 +314,17 @@ def generate_database(chunksize:int,nclusters:str|list[str]):
|
|
295 |
chunk_size=chunksize,
|
296 |
n_clusters=nclusters,
|
297 |
config_path=CONFIG_PATH)
|
|
|
298 |
|
299 |
# walk all files in repo dir
|
300 |
-
file_opr = FileOperation()
|
301 |
files = file_opr.scan_dir(repo_dir=repodir)
|
302 |
fs_init.initialize(files=files, work_dir=workdir,file_opr=file_opr)
|
303 |
file_opr.summarize(files)
|
|
|
|
|
|
|
|
|
|
|
304 |
del fs_init
|
305 |
cache.pop('default')
|
306 |
texts, _ = update_database_info()
|
@@ -310,6 +334,7 @@ def delete_database():
|
|
310 |
_, workdir, _ = get_ready('repo_work')
|
311 |
if os.path.exists(workdir):
|
312 |
shutil.rmtree(workdir)
|
|
|
313 |
return gr.Textbox(label="数据库概况",lines =3,value = '数据库已删除',visible = True)
|
314 |
|
315 |
def update_database_textbox():
|
@@ -319,17 +344,24 @@ def update_database_textbox():
|
|
319 |
else:
|
320 |
return gr.Textbox(label="数据库概况",value = '\n'.join(texts),visible = True)
|
321 |
|
322 |
-
def update_chunksize_dropdown():
|
323 |
_, jsonobj = update_database_info()
|
324 |
-
|
|
|
|
|
|
|
|
|
325 |
|
326 |
-
def update_ncluster_dropdown(chunksize:int):
|
327 |
_, jsonobj = update_database_info()
|
328 |
-
|
|
|
|
|
|
|
329 |
return gr.Dropdown(choices= nclusters)
|
330 |
|
331 |
# @spaces.GPU(duration=360)
|
332 |
-
def annotation(n,chunksize:int,nclusters:int,remote_ornot:bool):
|
333 |
'''
|
334 |
use llm to annotate cluster
|
335 |
n: percentage of clusters to annotate
|
@@ -340,7 +372,7 @@ def annotation(n,chunksize:int,nclusters:int,remote_ornot:bool):
|
|
340 |
else:
|
341 |
backend = 'local'
|
342 |
|
343 |
-
clusterdir, samples, assistant, theme = get_ready('annotation',chunksize,nclusters)
|
344 |
new_obj_list = []
|
345 |
n = round(n * len(samples.keys()))
|
346 |
for cluster_no in random.sample(samples.keys(), n):
|
@@ -369,14 +401,14 @@ def annotation(n,chunksize:int,nclusters:int,remote_ornot:bool):
|
|
369 |
return '\n\n'.join([obj['annotation'] for obj in new_obj_list])
|
370 |
|
371 |
# @spaces.GPU(duration=360)
|
372 |
-
def inspiration(annotation:str,chunksize:int,nclusters:int,remote_ornot:bool):
|
373 |
query = 'inspiration'
|
374 |
if remote_ornot:
|
375 |
backend = 'remote'
|
376 |
else:
|
377 |
backend = 'local'
|
378 |
|
379 |
-
clusterdir, annoresult, assistant, theme = get_ready('inspiration',chunksize,nclusters)
|
380 |
new_obj_list = []
|
381 |
|
382 |
if annotation is not None: # if the user wants to get inspiration from specific clusters only
|
@@ -418,13 +450,13 @@ def getpmcurls(references):
|
|
418 |
return urls
|
419 |
|
420 |
# @spaces.GPU(duration=360)
|
421 |
-
def summarize_text(query,chunksize:int,remote_ornot:bool):
|
422 |
if remote_ornot:
|
423 |
backend = 'remote'
|
424 |
else:
|
425 |
backend = 'local'
|
426 |
|
427 |
-
assistant,_ = get_ready('summarize',chunksize=chunksize,k=None)
|
428 |
code, reply, references = assistant.generate(query=query,
|
429 |
history=[],
|
430 |
groupname='',backend = backend)
|
@@ -611,6 +643,7 @@ def main_interface():
|
|
611 |
with gr.Accordion("聚类标注相关参数", open=True):
|
612 |
with gr.Row():
|
613 |
update_options = gr.Button("更新数据库情况", scale=0)
|
|
|
614 |
chunksize = gr.Dropdown([], label="选择块大小", scale=0)
|
615 |
nclusters = gr.Dropdown([], label="选择聚类数", scale=0)
|
616 |
ntoread = gr.Slider(
|
@@ -637,22 +670,23 @@ def main_interface():
|
|
637 |
output_references = gr.Markdown(label="参考文献")
|
638 |
|
639 |
update_options.click(update_chunksize_dropdown,
|
|
|
640 |
outputs=[chunksize])
|
641 |
|
642 |
chunksize.change(update_ncluster_dropdown,
|
643 |
-
inputs=[chunksize],
|
644 |
outputs= [nclusters])
|
645 |
|
646 |
annotation_button.click(annotation,
|
647 |
-
inputs = [ntoread, chunksize, nclusters,remote_ornot],
|
648 |
outputs=[annotation_output])
|
649 |
|
650 |
inspiration_button.click(inspiration,
|
651 |
-
inputs= [annotation_output, chunksize, nclusters,remote_ornot],
|
652 |
outputs=[inspiration_output])
|
653 |
|
654 |
write_button.click(summarize_text,
|
655 |
-
inputs=[query, chunksize,remote_ornot],
|
656 |
outputs =[output_text,output_references])
|
657 |
|
658 |
demo.launch(share=False, server_name='0.0.0.0', debug=True,show_error=True,allowed_paths=['img_0.jpg'])
|
|
|
82 |
'kimi': ['moonshot-v1-128k'],
|
83 |
'deepseek': ['deepseek-chat'],
|
84 |
'zhipuai': ['glm-4'],
|
85 |
+
'gpt': ['gpt-4-32k-0613','gpt-3.5-turbo','gpt-4']
|
86 |
}
|
87 |
return gr.Dropdown(choices= model_choices[remote_company])
|
88 |
|
|
|
107 |
return gr.Button("配置已保存")
|
108 |
|
109 |
# @spaces.GPU(duration=360)
|
110 |
+
def get_ready(query:str,chunksize=None,k=None,use_abstract=False):
|
111 |
|
112 |
with open(CONFIG_PATH, encoding='utf8') as f:
|
113 |
config = pytoml.load(f)
|
|
|
124 |
except:
|
125 |
pass
|
126 |
|
127 |
+
if use_abstract:
|
128 |
+
workdir = workdir + '_ab'
|
129 |
if query == 'annotation':
|
130 |
if not chunksize or not k:
|
131 |
raise ValueError('chunksize or k not provided')
|
|
|
184 |
pmc_success = repo_info['pmc_success_d']
|
185 |
scihub_success = repo_info['scihub_success_d']
|
186 |
failed_download = repo_info['failed_download']
|
187 |
+
abstract_success = repo_info['abstract_success']
|
188 |
+
failed_abstract = repo_info['failed_abstract']
|
189 |
|
190 |
number_of_upload = number_of_pdf-scihub_success
|
191 |
+
return keywords, retmax, search_len, import_len, failed_pmid_len, pmc_success, scihub_success, failed_download, abstract_success, failed_abstract, number_of_upload
|
192 |
else:
|
193 |
return None,None,None,None,None,None,None,None,None,number_of_pdf
|
194 |
else:
|
|
|
227 |
repodir, workdir, _ = get_ready('repo_work')
|
228 |
if os.path.exists(repodir):
|
229 |
shutil.rmtree(repodir)
|
230 |
+
shutil.rmtree(repodir + '_ab')
|
231 |
if os.path.exists(workdir):
|
232 |
shutil.rmtree(workdir)
|
233 |
+
shutil.rmtree(workdir + '_ab')
|
234 |
|
235 |
return gr.Textbox(label="文献库概况",lines =3,
|
236 |
value = '文献库和相关数据库已删除',
|
237 |
visible = True)
|
238 |
|
239 |
def update_repo():
|
240 |
+
# keywords, retmax, search_len, import_len, failed_pmid_len, pmc_success, scihub_success, failed_download, abstract_success, failed_abstract, number_of_upload
|
241 |
+
# None,None,None,None,None,None,None,None,None,number_of_pdf
|
242 |
+
keys, retmax, search_len, import_len, _, pmc_success, scihub_success, failed, abstract_success, failed_abstract, pdfuplo = update_repo_info()
|
243 |
newinfo = ""
|
244 |
if keys == None:
|
245 |
newinfo += '无关键词搜索相关信息\n'
|
246 |
newinfo += '无导入的PMID\n'
|
247 |
+
if pdfuplo:
|
248 |
+
newinfo += f'上传的PDF数量: {pdfuplo}\n'
|
249 |
else:
|
250 |
newinfo += '无上传的PDF\n'
|
251 |
else:
|
252 |
newinfo += f'关键词搜索:'
|
253 |
+
newinfo += f' 关键词: {keys}\n'
|
254 |
+
newinfo += f' 搜索上限: {retmax}\n'
|
255 |
+
newinfo += f' 搜索到的PMID数量: {search_len}\n'
|
256 |
newinfo += f'导入的PMID数量: {import_len}\n'
|
257 |
+
newinfo += f' 成功获取PMC全文数量: {pmc_success}\n'
|
258 |
+
newinfo += f' 成功获取SciHub全文数量: {scihub_success}\n'
|
259 |
+
newinfo += f" 下载失败的ID: {failed}\n"
|
260 |
+
newinfo += f" 成功获取摘要的数量: {abstract_success}\n"
|
261 |
+
newinfo += f" 获取摘要失败的数量: {failed_abstract}\n"
|
262 |
+
newinfo += f'上传的PDF数量: {pdfuplo}\n'
|
263 |
|
264 |
return gr.Textbox(label="文献库概况",lines =1,
|
265 |
value = newinfo,
|
|
|
269 |
with open(CONFIG_PATH, encoding='utf8') as f:
|
270 |
config = pytoml.load(f)
|
271 |
workdir = config['feature_store']['work_dir']
|
272 |
+
abworkdir = workdir + '_ab'
|
273 |
+
options = []
|
274 |
+
total_json_obj = {}
|
275 |
+
for dir in [workdir,abworkdir]:
|
276 |
+
tag = 'FullText' if '_ab' not in dir else 'Abstract'
|
277 |
+
|
278 |
+
chunkdirs = glob.glob(os.path.join(dir, 'chunksize_*'))
|
279 |
+
chunkdirs.sort()
|
280 |
+
list_of_chunksize = [int(chunkdir.split('_')[-1]) for chunkdir in chunkdirs]
|
281 |
+
# print(list_of_chunksize)
|
282 |
+
jsonobj = {}
|
283 |
+
for chunkdir in chunkdirs:
|
284 |
+
k_dir = glob.glob(os.path.join(chunkdir, 'cluster_features','cluster_features_*'))
|
285 |
+
k_dir.sort()
|
286 |
+
list_of_k = [int(k.split('_')[-1]) for k in k_dir]
|
287 |
+
jsonobj[int(chunkdir.split('_')[-1])] = list_of_k
|
288 |
|
289 |
+
total_json_obj[tag] = jsonobj
|
290 |
+
newoptions = [f"{tag}, chunksize:{chunksize}, k:{k}" for chunksize in list_of_chunksize for k in jsonobj[chunksize]]
|
291 |
+
options.extend(newoptions)
|
292 |
|
293 |
+
return options, total_json_obj
|
294 |
|
295 |
# @spaces.GPU(duration=360)
|
296 |
def generate_database(chunksize:int,nclusters:str|list[str]):
|
297 |
# 在这里运行生成数据库的函数
|
298 |
repodir, workdir, _ = get_ready('repo_work')
|
299 |
+
abrepodir = repodir + '_ab'
|
300 |
+
abworkdir = workdir + '_ab'
|
301 |
if not os.path.exists(repodir):
|
302 |
return gr.Textbox(label="数据库已生成",value = '请先生成文献库',visible = True)
|
303 |
nclusters = [int(i) for i in nclusters]
|
|
|
314 |
chunk_size=chunksize,
|
315 |
n_clusters=nclusters,
|
316 |
config_path=CONFIG_PATH)
|
317 |
+
file_opr = FileOperation()
|
318 |
|
319 |
# walk all files in repo dir
|
|
|
320 |
files = file_opr.scan_dir(repo_dir=repodir)
|
321 |
fs_init.initialize(files=files, work_dir=workdir,file_opr=file_opr)
|
322 |
file_opr.summarize(files)
|
323 |
+
|
324 |
+
files = file_opr.scan_dir(repo_dir=abrepodir)
|
325 |
+
fs_init.initialize(files=files, work_dir=abworkdir,file_opr=file_opr)
|
326 |
+
file_opr.summarize(files)
|
327 |
+
|
328 |
del fs_init
|
329 |
cache.pop('default')
|
330 |
texts, _ = update_database_info()
|
|
|
334 |
_, workdir, _ = get_ready('repo_work')
|
335 |
if os.path.exists(workdir):
|
336 |
shutil.rmtree(workdir)
|
337 |
+
shutil.rmtree(workdir+'_ab')
|
338 |
return gr.Textbox(label="数据库概况",lines =3,value = '数据库已删除',visible = True)
|
339 |
|
340 |
def update_database_textbox():
|
|
|
344 |
else:
|
345 |
return gr.Textbox(label="数据库概况",value = '\n'.join(texts),visible = True)
|
346 |
|
347 |
+
def update_chunksize_dropdown(use_abstract):
|
348 |
_, jsonobj = update_database_info()
|
349 |
+
if use_abstract:
|
350 |
+
choices = jsonobj['Abstract'].keys()
|
351 |
+
else:
|
352 |
+
choices = jsonobj['FullText'].keys()
|
353 |
+
return gr.Dropdown(choices= choices)
|
354 |
|
355 |
+
def update_ncluster_dropdown(chunksize:int,use_abstract:bool):
|
356 |
_, jsonobj = update_database_info()
|
357 |
+
if use_abstract:
|
358 |
+
nclusters = jsonobj['Abstract'][chunksize]
|
359 |
+
else:
|
360 |
+
nclusters = jsonobj['FullText'][chunksize]
|
361 |
return gr.Dropdown(choices= nclusters)
|
362 |
|
363 |
# @spaces.GPU(duration=360)
|
364 |
+
def annotation(n,chunksize:int,nclusters:int,remote_ornot:bool,use_abstract:bool):
|
365 |
'''
|
366 |
use llm to annotate cluster
|
367 |
n: percentage of clusters to annotate
|
|
|
372 |
else:
|
373 |
backend = 'local'
|
374 |
|
375 |
+
clusterdir, samples, assistant, theme = get_ready('annotation',chunksize,nclusters,use_abstract)
|
376 |
new_obj_list = []
|
377 |
n = round(n * len(samples.keys()))
|
378 |
for cluster_no in random.sample(samples.keys(), n):
|
|
|
401 |
return '\n\n'.join([obj['annotation'] for obj in new_obj_list])
|
402 |
|
403 |
# @spaces.GPU(duration=360)
|
404 |
+
def inspiration(annotation:str,chunksize:int,nclusters:int,remote_ornot:bool,use_abstract:bool):
|
405 |
query = 'inspiration'
|
406 |
if remote_ornot:
|
407 |
backend = 'remote'
|
408 |
else:
|
409 |
backend = 'local'
|
410 |
|
411 |
+
clusterdir, annoresult, assistant, theme = get_ready('inspiration',chunksize,nclusters,use_abstract)
|
412 |
new_obj_list = []
|
413 |
|
414 |
if annotation is not None: # if the user wants to get inspiration from specific clusters only
|
|
|
450 |
return urls
|
451 |
|
452 |
# @spaces.GPU(duration=360)
|
453 |
+
def summarize_text(query,chunksize:int,remote_ornot:bool,use_abstract:bool):
|
454 |
if remote_ornot:
|
455 |
backend = 'remote'
|
456 |
else:
|
457 |
backend = 'local'
|
458 |
|
459 |
+
assistant,_ = get_ready('summarize',chunksize=chunksize,k=None,use_abstract=use_abstract)
|
460 |
code, reply, references = assistant.generate(query=query,
|
461 |
history=[],
|
462 |
groupname='',backend = backend)
|
|
|
643 |
with gr.Accordion("聚类标注相关参数", open=True):
|
644 |
with gr.Row():
|
645 |
update_options = gr.Button("更新数据库情况", scale=0)
|
646 |
+
use_abstract = gr.Checkbox(label="是否仅使用摘要",scale=0)
|
647 |
chunksize = gr.Dropdown([], label="选择块大小", scale=0)
|
648 |
nclusters = gr.Dropdown([], label="选择聚类数", scale=0)
|
649 |
ntoread = gr.Slider(
|
|
|
670 |
output_references = gr.Markdown(label="参考文献")
|
671 |
|
672 |
update_options.click(update_chunksize_dropdown,
|
673 |
+
inputs=[use_abstract],
|
674 |
outputs=[chunksize])
|
675 |
|
676 |
chunksize.change(update_ncluster_dropdown,
|
677 |
+
inputs=[chunksize,use_abstract],
|
678 |
outputs= [nclusters])
|
679 |
|
680 |
annotation_button.click(annotation,
|
681 |
+
inputs = [ntoread, chunksize, nclusters,remote_ornot,use_abstract],
|
682 |
outputs=[annotation_output])
|
683 |
|
684 |
inspiration_button.click(inspiration,
|
685 |
+
inputs= [annotation_output, chunksize, nclusters,remote_ornot,use_abstract],
|
686 |
outputs=[inspiration_output])
|
687 |
|
688 |
write_button.click(summarize_text,
|
689 |
+
inputs=[query, chunksize,remote_ornot,use_abstract],
|
690 |
outputs =[output_text,output_references])
|
691 |
|
692 |
demo.launch(share=False, server_name='0.0.0.0', debug=True,show_error=True,allowed_paths=['img_0.jpg'])
|
config.ini
CHANGED
@@ -4,8 +4,8 @@ embedding_model_path = "/root/models/bce-embedding-base_v1"
|
|
4 |
reranker_model_path = "/root/models/bce-reranker-base_v1"
|
5 |
repo_dir = "repodir"
|
6 |
work_dir = "workdir"
|
7 |
-
n_clusters = [10
|
8 |
-
chunk_size =
|
9 |
|
10 |
[web_search]
|
11 |
x_api_key = "${YOUR-API-KEY}"
|
|
|
4 |
reranker_model_path = "/root/models/bce-reranker-base_v1"
|
5 |
repo_dir = "repodir"
|
6 |
work_dir = "workdir"
|
7 |
+
n_clusters = [10]
|
8 |
+
chunk_size = 2482
|
9 |
|
10 |
[web_search]
|
11 |
x_api_key = "${YOUR-API-KEY}"
|
huixiangdou/service/findarticles.py
CHANGED
@@ -88,6 +88,7 @@ class ArticleRetrieval:
|
|
88 |
for docsum in root.findall('DocSum'):
|
89 |
pmcid = None
|
90 |
doi = None
|
|
|
91 |
id_value = docsum.find('Id').text
|
92 |
for item in docsum.findall('.//Item[@Name="doi"]'):
|
93 |
doi = item.text
|
@@ -155,11 +156,16 @@ class ArticleRetrieval:
|
|
155 |
def fetch_full_text(self):
|
156 |
if not os.path.exists(self.repo_dir):
|
157 |
os.makedirs(self.repo_dir)
|
|
|
|
|
158 |
print(f"Saving articles to {self.repo_dir}.")
|
159 |
self.pmc_success = 0
|
160 |
self.scihub_success = 0
|
|
|
161 |
self.failed_download = []
|
|
|
162 |
downloaded = os.listdir(self.repo_dir)
|
|
|
163 |
for id in tqdm(self.pmc_ids, desc="Fetching full texts", unit="article"):
|
164 |
# check if file already downloaded
|
165 |
if f"{id}.txt" in downloaded:
|
@@ -194,6 +200,27 @@ class ArticleRetrieval:
|
|
194 |
self.scihub_success += 1
|
195 |
else:
|
196 |
self.failed_download.append(doi)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
197 |
|
198 |
def save_config(self):
|
199 |
config = {
|
@@ -213,6 +240,8 @@ class ArticleRetrieval:
|
|
213 |
"pmc_success_d": self.pmc_success,
|
214 |
"scihub_success_d": self.scihub_success,
|
215 |
"failed_download": self.failed_download,
|
|
|
|
|
216 |
|
217 |
}
|
218 |
with open(os.path.join(self.repo_dir, 'info.json'), 'w') as f:
|
|
|
88 |
for docsum in root.findall('DocSum'):
|
89 |
pmcid = None
|
90 |
doi = None
|
91 |
+
abstract = None
|
92 |
id_value = docsum.find('Id').text
|
93 |
for item in docsum.findall('.//Item[@Name="doi"]'):
|
94 |
doi = item.text
|
|
|
156 |
def fetch_full_text(self):
|
157 |
if not os.path.exists(self.repo_dir):
|
158 |
os.makedirs(self.repo_dir)
|
159 |
+
os.makedirs(self.repo_dir + '_ab')
|
160 |
+
|
161 |
print(f"Saving articles to {self.repo_dir}.")
|
162 |
self.pmc_success = 0
|
163 |
self.scihub_success = 0
|
164 |
+
self.abstract_success = 0
|
165 |
self.failed_download = []
|
166 |
+
self.failed_abstract = []
|
167 |
downloaded = os.listdir(self.repo_dir)
|
168 |
+
downloaded_ab = os.listdir(self.repo_dir + '_ab')
|
169 |
for id in tqdm(self.pmc_ids, desc="Fetching full texts", unit="article"):
|
170 |
# check if file already downloaded
|
171 |
if f"{id}.txt" in downloaded:
|
|
|
200 |
self.scihub_success += 1
|
201 |
else:
|
202 |
self.failed_download.append(doi)
|
203 |
+
for pmid in tqdm(self.pmids, desc="Fetching abstract texts", unit="article"):
|
204 |
+
# check if file already downloaded
|
205 |
+
if f"{pmid}.txt" in downloaded_ab:
|
206 |
+
print(f"File already downloaded: {pmid}")
|
207 |
+
self.scihub_success += 1
|
208 |
+
continue
|
209 |
+
base_url = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi"
|
210 |
+
params = {
|
211 |
+
"db": "pubmed",
|
212 |
+
"id": pmid,
|
213 |
+
}
|
214 |
+
|
215 |
+
response = requests.get(base_url, params=params)
|
216 |
+
root = ET.fromstring(response.content)
|
217 |
+
abstract = root.find('.//AbstractText')
|
218 |
+
if abstract is not None:
|
219 |
+
with open(os.path.join(self.repo_dir + '_ab',f'{pmid}.txt'), 'w') as f:
|
220 |
+
f.write(abstract.text)
|
221 |
+
self.abstract_success += 1
|
222 |
+
else:
|
223 |
+
self.failed_abstract.append(pmid)
|
224 |
|
225 |
def save_config(self):
|
226 |
config = {
|
|
|
240 |
"pmc_success_d": self.pmc_success,
|
241 |
"scihub_success_d": self.scihub_success,
|
242 |
"failed_download": self.failed_download,
|
243 |
+
"abstract_success": self.abstract_success,
|
244 |
+
"failed_abstract": self.failed_abstract
|
245 |
|
246 |
}
|
247 |
with open(os.path.join(self.repo_dir, 'info.json'), 'w') as f:
|
huixiangdou/service/retriever.py
CHANGED
@@ -40,7 +40,7 @@ class Retriever:
|
|
40 |
search_type='similarity',
|
41 |
search_kwargs={
|
42 |
'score_threshold': 0.15,
|
43 |
-
'k':
|
44 |
})
|
45 |
|
46 |
self.reordering = LongContextReorder()
|
|
|
40 |
search_type='similarity',
|
41 |
search_kwargs={
|
42 |
'score_threshold': 0.15,
|
43 |
+
'k': 10
|
44 |
})
|
45 |
|
46 |
self.reordering = LongContextReorder()
|