Spaces:
Sleeping
Sleeping
Create app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
import requests
|
| 3 |
+
import xml.etree.ElementTree as ET
|
| 4 |
+
import pandas as pd
|
| 5 |
+
from googletrans import Translator
|
| 6 |
+
|
| 7 |
+
# 语言翻译字典
|
| 8 |
+
translations = {
|
| 9 |
+
"en": {
|
| 10 |
+
"title": "PubMed Literature Search",
|
| 11 |
+
"search_placeholder": "Enter search query (e.g., cancer treatment)",
|
| 12 |
+
"search_button": "Search",
|
| 13 |
+
"language_option": "English",
|
| 14 |
+
"language_label": "Language",
|
| 15 |
+
"results_title": "Search Results",
|
| 16 |
+
"error_message": "An error occurred while fetching data from PubMed.",
|
| 17 |
+
"no_results": "No articles found for the given query.",
|
| 18 |
+
"col_index": "Index",
|
| 19 |
+
"col_title": "Title",
|
| 20 |
+
"col_abstract": "Abstract",
|
| 21 |
+
"col_authors": "Authors",
|
| 22 |
+
"col_link": "Link"
|
| 23 |
+
},
|
| 24 |
+
"zh": {
|
| 25 |
+
"title": "PubMed 文献检索",
|
| 26 |
+
"search_placeholder": "输入检索词(例如:cancer treatment)",
|
| 27 |
+
"search_button": "检索",
|
| 28 |
+
"language_option": "中文",
|
| 29 |
+
"language_label": "语言",
|
| 30 |
+
"results_title": "检索结果",
|
| 31 |
+
"error_message": "从 PubMed 获取数据时出错。",
|
| 32 |
+
"no_results": "未找到相关文献。",
|
| 33 |
+
"col_index": "序号",
|
| 34 |
+
"col_title": "文献标题",
|
| 35 |
+
"col_abstract": "文献摘要",
|
| 36 |
+
"col_authors": "文献作者",
|
| 37 |
+
"col_link": "文献链接"
|
| 38 |
+
}
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
def get_translation(lang, key):
|
| 42 |
+
return translations[lang][key]
|
| 43 |
+
|
| 44 |
+
def search_pubmed(query, retmax=200):
|
| 45 |
+
"""
|
| 46 |
+
使用PubMed API进行检索
|
| 47 |
+
"""
|
| 48 |
+
base_url = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/"
|
| 49 |
+
search_url = f"{base_url}esearch.fcgi?db=pubmed&term={query}&retmax={retmax}"
|
| 50 |
+
try:
|
| 51 |
+
search_response = requests.get(search_url)
|
| 52 |
+
search_response.raise_for_status()
|
| 53 |
+
search_root = ET.fromstring(search_response.content)
|
| 54 |
+
id_list = [id_elem.text for id_elem in search_root.findall(".//Id")]
|
| 55 |
+
return id_list
|
| 56 |
+
except requests.exceptions.RequestException as e:
|
| 57 |
+
st.error(f"Error during eSearch: {e}")
|
| 58 |
+
return []
|
| 59 |
+
|
| 60 |
+
def fetch_articles(id_list):
|
| 61 |
+
"""
|
| 62 |
+
根据ID列表获取文献详情
|
| 63 |
+
"""
|
| 64 |
+
base_url = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/"
|
| 65 |
+
ids = ",".join(id_list)
|
| 66 |
+
fetch_url = f"{base_url}efetch.fcgi?db=pubmed&id={ids}&rettype=xml"
|
| 67 |
+
try:
|
| 68 |
+
fetch_response = requests.get(fetch_url)
|
| 69 |
+
fetch_response.raise_for_status()
|
| 70 |
+
return fetch_response.content
|
| 71 |
+
except requests.exceptions.RequestException as e:
|
| 72 |
+
st.error(f"Error during eFetch: {e}")
|
| 73 |
+
return None
|
| 74 |
+
|
| 75 |
+
def parse_articles(xml_data):
|
| 76 |
+
"""
|
| 77 |
+
解析文献的XML数据
|
| 78 |
+
"""
|
| 79 |
+
articles = []
|
| 80 |
+
if xml_data:
|
| 81 |
+
root = ET.fromstring(xml_data)
|
| 82 |
+
for article in root.findall(".//PubmedArticle"):
|
| 83 |
+
title_elem = article.find(".//ArticleTitle")
|
| 84 |
+
title = title_elem.text if title_elem is not None else "No Title"
|
| 85 |
+
|
| 86 |
+
abstract_elem = article.find(".//AbstractText")
|
| 87 |
+
abstract = abstract_elem.text if abstract_elem is not None else "No Abstract"
|
| 88 |
+
|
| 89 |
+
author_list = article.findall(".//Author")
|
| 90 |
+
authors = ", ".join([
|
| 91 |
+
f"{author.find('LastName').text if author.find('LastName') is not None else ''} {author.find('ForeName').text if author.find('ForeName') is not None else ''}".strip()
|
| 92 |
+
for author in author_list
|
| 93 |
+
]) if author_list else "No Authors"
|
| 94 |
+
|
| 95 |
+
pmid_elem = article.find(".//PMID")
|
| 96 |
+
pmid = pmid_elem.text if pmid_elem is not None else ""
|
| 97 |
+
link = f"https://pubmed.ncbi.nlm.nih.gov/{pmid}/" if pmid else "No Link"
|
| 98 |
+
|
| 99 |
+
articles.append({
|
| 100 |
+
"Title": title,
|
| 101 |
+
"Abstract": abstract,
|
| 102 |
+
"Authors": authors,
|
| 103 |
+
"Link": link
|
| 104 |
+
})
|
| 105 |
+
return articles
|
| 106 |
+
|
| 107 |
+
def main():
|
| 108 |
+
st.set_page_config(layout="wide")
|
| 109 |
+
|
| 110 |
+
# 语言选择
|
| 111 |
+
lang = st.sidebar.radio(
|
| 112 |
+
"Language / 语言",
|
| 113 |
+
("en", "zh"),
|
| 114 |
+
format_func=lambda x: "English" if x == "en" else "中文"
|
| 115 |
+
)
|
| 116 |
+
|
| 117 |
+
st.title(get_translation(lang, "title"))
|
| 118 |
+
|
| 119 |
+
# 搜索框
|
| 120 |
+
search_query = st.text_input(get_translation(lang, "search_placeholder"))
|
| 121 |
+
|
| 122 |
+
if st.button(get_translation(lang, "search_button")):
|
| 123 |
+
if search_query:
|
| 124 |
+
with st.spinner('Searching...'):
|
| 125 |
+
id_list = search_pubmed(search_query)
|
| 126 |
+
if id_list:
|
| 127 |
+
xml_data = fetch_articles(id_list)
|
| 128 |
+
if xml_data:
|
| 129 |
+
articles = parse_articles(xml_data)
|
| 130 |
+
if articles:
|
| 131 |
+
st.subheader(get_translation(lang, "results_title"))
|
| 132 |
+
|
| 133 |
+
# 翻译标题和摘要
|
| 134 |
+
if lang == 'zh':
|
| 135 |
+
translator = Translator()
|
| 136 |
+
for article in articles:
|
| 137 |
+
try:
|
| 138 |
+
article['Title'] = translator.translate(article['Title'], dest='zh-cn').text
|
| 139 |
+
article['Abstract'] = translator.translate(article['Abstract'], dest='zh-cn').text
|
| 140 |
+
except Exception as e:
|
| 141 |
+
st.warning(f"翻译时出错: {e}")
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
df = pd.DataFrame(articles)
|
| 145 |
+
df.index = range(1, len(df) + 1)
|
| 146 |
+
df.rename(columns={
|
| 147 |
+
"Title": get_translation(lang, "col_title"),
|
| 148 |
+
"Abstract": get_translation(lang, "col_abstract"),
|
| 149 |
+
"Authors": get_translation(lang, "col_authors"),
|
| 150 |
+
"Link": get_translation(lang, "col_link")
|
| 151 |
+
}, inplace=True)
|
| 152 |
+
df.index.name = get_translation(lang, "col_index")
|
| 153 |
+
|
| 154 |
+
st.dataframe(df)
|
| 155 |
+
else:
|
| 156 |
+
st.warning(get_translation(lang, "no_results"))
|
| 157 |
+
else:
|
| 158 |
+
st.error(get_translation(lang, "error_message"))
|
| 159 |
+
else:
|
| 160 |
+
st.warning(get_translation(lang, "no_results"))
|
| 161 |
+
|
| 162 |
+
if __name__ == "__main__":
|
| 163 |
+
main()
|
| 164 |
+
|