Aye10032 commited on
Commit ·
529e208
1
Parent(s): 02fb4e4
update
Browse files- .gitignore +1 -0
- .streamlit/config.toml +6 -0
- App.py +23 -0
- README.md +1 -1
- pages/Reference.py +196 -0
- pages/Reformat.py +65 -0
- pages/TextToImage.py +92 -0
- pages/Translate.py +137 -0
- requirements.txt +6 -0
- ui/Component.py +13 -0
- utils/Decorator.py +41 -0
- utils/__init__.py +0 -0
.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
/config.yaml
|
.streamlit/config.toml
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[browser]
|
| 2 |
+
gatherUsageStats = false
|
| 3 |
+
|
| 4 |
+
[client]
|
| 5 |
+
showSidebarNavigation = false
|
| 6 |
+
toolbarMode = "auto"
|
App.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
|
| 3 |
+
from ui.Component import side_bar_links
|
| 4 |
+
|
| 5 |
+
st.set_page_config(
|
| 6 |
+
page_title='工具箱',
|
| 7 |
+
page_icon='🔨',
|
| 8 |
+
)
|
| 9 |
+
|
| 10 |
+
with st.sidebar:
|
| 11 |
+
side_bar_links()
|
| 12 |
+
|
| 13 |
+
st.markdown("""
|
| 14 |
+
# 自用小工具
|
| 15 |
+
|
| 16 |
+
## 文本格式化
|
| 17 |
+
|
| 18 |
+
将PDF中直接复制的文本中的换行符去除,并将引用转化为markdown格式。
|
| 19 |
+
|
| 20 |
+
## 引用文献生成
|
| 21 |
+
|
| 22 |
+
处理PUBMED的NLM格式的引用文献,并转化为yaml格式,方便存储在markdown文件中
|
| 23 |
+
""")
|
README.md
CHANGED
|
@@ -5,7 +5,7 @@ colorFrom: red
|
|
| 5 |
colorTo: yellow
|
| 6 |
sdk: streamlit
|
| 7 |
sdk_version: 1.34.0
|
| 8 |
-
app_file:
|
| 9 |
pinned: false
|
| 10 |
license: gpl-3.0
|
| 11 |
---
|
|
|
|
| 5 |
colorTo: yellow
|
| 6 |
sdk: streamlit
|
| 7 |
sdk_version: 1.34.0
|
| 8 |
+
app_file: App.py
|
| 9 |
pinned: false
|
| 10 |
license: gpl-3.0
|
| 11 |
---
|
pages/Reference.py
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import random
|
| 2 |
+
from typing import Dict, Any
|
| 3 |
+
|
| 4 |
+
import requests
|
| 5 |
+
import streamlit as st
|
| 6 |
+
import yaml
|
| 7 |
+
from loguru import logger
|
| 8 |
+
|
| 9 |
+
from ui.Component import side_bar_links
|
| 10 |
+
from bs4 import BeautifulSoup
|
| 11 |
+
|
| 12 |
+
from utils.Decorator import retry
|
| 13 |
+
|
| 14 |
+
st.set_page_config(
|
| 15 |
+
page_title='工具箱',
|
| 16 |
+
page_icon='🔨',
|
| 17 |
+
layout='wide',
|
| 18 |
+
)
|
| 19 |
+
|
| 20 |
+
with st.sidebar:
|
| 21 |
+
side_bar_links()
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
def add():
|
| 25 |
+
ref_list: list = st.session_state.get('reference_list')
|
| 26 |
+
|
| 27 |
+
_data = {
|
| 28 |
+
'title': st.session_state.get('title'),
|
| 29 |
+
'pmid': st.session_state.get('pmid').replace('PMID:', '').replace(' ', ''),
|
| 30 |
+
'pmc': st.session_state.get('pmc').replace('PMCID:', '').replace(' ', ''),
|
| 31 |
+
'doi': st.session_state.get('doi').replace('DOI:', '').replace(' ', ''),
|
| 32 |
+
}
|
| 33 |
+
if _data in ref_list:
|
| 34 |
+
st.toast('already exist')
|
| 35 |
+
else:
|
| 36 |
+
ref_list.append(_data)
|
| 37 |
+
st.session_state.reference_list = ref_list
|
| 38 |
+
yaml_str = yaml.dump(ref_list)
|
| 39 |
+
st.session_state.reference_text = yaml_str
|
| 40 |
+
|
| 41 |
+
st.session_state['title'] = ''
|
| 42 |
+
st.session_state['pmid'] = ''
|
| 43 |
+
st.session_state['pmc'] = ''
|
| 44 |
+
st.session_state['doi'] = ''
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def reset():
|
| 48 |
+
st.session_state.reference_list = []
|
| 49 |
+
st.session_state.reference_text = ''
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
# def anal_ml():
|
| 53 |
+
# nlm_str: str = st.session_state.get('nlm_text')
|
| 54 |
+
# nlm_list = nlm_str.split('.', 4)
|
| 55 |
+
# title = nlm_list[1]
|
| 56 |
+
# id_list = nlm_list[-1].split('; ')
|
| 57 |
+
# if len(id_list) > 1:
|
| 58 |
+
# pmc = id_list[-1]
|
| 59 |
+
# else:
|
| 60 |
+
# pmc = ''
|
| 61 |
+
# base_list = id_list[0].split('. ')
|
| 62 |
+
# doi = base_list[0]
|
| 63 |
+
# pmid = base_list[1]
|
| 64 |
+
#
|
| 65 |
+
# _data = {
|
| 66 |
+
# 'title': title[1:] if title.startswith(' ') else title,
|
| 67 |
+
# 'pmid': pmid.replace('PMID:', '').replace(' ', ''),
|
| 68 |
+
# 'pmc': pmc.replace('PMCID:', '').replace(' ', '').replace('.', ''),
|
| 69 |
+
# 'doi': doi.replace('doi:', '').replace(' ', ''),
|
| 70 |
+
# }
|
| 71 |
+
#
|
| 72 |
+
# ref_list: list = st.session_state.get('reference_list')
|
| 73 |
+
#
|
| 74 |
+
# if _data in ref_list:
|
| 75 |
+
# st.toast('already exist')
|
| 76 |
+
# else:
|
| 77 |
+
# ref_list.append(_data)
|
| 78 |
+
# st.session_state.reference_list = ref_list
|
| 79 |
+
# yaml_str = yaml.dump(ref_list)
|
| 80 |
+
# st.session_state.reference_text = yaml_str
|
| 81 |
+
#
|
| 82 |
+
# st.session_state['nlm_text'] = ''
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
def get_data():
|
| 86 |
+
term: str = st.session_state.get('term_text')
|
| 87 |
+
term = term.replace('\r', ' ').replace('\n', '')
|
| 88 |
+
_data = __get_info(term)
|
| 89 |
+
|
| 90 |
+
ref_list: list = st.session_state.get('reference_list')
|
| 91 |
+
|
| 92 |
+
if _data in ref_list:
|
| 93 |
+
st.toast('already exist')
|
| 94 |
+
else:
|
| 95 |
+
ref_list.append(_data)
|
| 96 |
+
st.session_state.reference_list = ref_list
|
| 97 |
+
yaml_str = yaml.dump(ref_list, width=999)
|
| 98 |
+
st.session_state.reference_text = yaml_str
|
| 99 |
+
|
| 100 |
+
st.session_state['term_text'] = ''
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
@retry(delay=random.uniform(2.0, 5.0))
|
| 104 |
+
def __get_info(pmid: str) -> Dict[str, Any]:
|
| 105 |
+
url = f'https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&id={pmid}&retmode=xml'
|
| 106 |
+
|
| 107 |
+
headers = {
|
| 108 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
response = requests.request("GET", url, headers=headers, timeout=10)
|
| 112 |
+
|
| 113 |
+
if response.status_code == 200:
|
| 114 |
+
soup = BeautifulSoup(response.text, 'xml')
|
| 115 |
+
|
| 116 |
+
title = soup.find('Article').find('ArticleTitle').text if soup.find('Article') else None
|
| 117 |
+
|
| 118 |
+
doi_block = soup.find('ArticleIdList').find('ArticleId', {'IdType': 'doi'})
|
| 119 |
+
if doi_block:
|
| 120 |
+
doi = doi_block.text
|
| 121 |
+
else:
|
| 122 |
+
doi = ''
|
| 123 |
+
logger.warning('DOI not found')
|
| 124 |
+
|
| 125 |
+
pmc_block = soup.find('ArticleIdList').find('ArticleId', {'IdType': 'pmc'})
|
| 126 |
+
if pmc_block:
|
| 127 |
+
pmc = pmc_block.text.replace('PMC', '')
|
| 128 |
+
else:
|
| 129 |
+
pmc = ''
|
| 130 |
+
|
| 131 |
+
return {
|
| 132 |
+
'title': title,
|
| 133 |
+
'pmid': pmid,
|
| 134 |
+
'pmc': pmc,
|
| 135 |
+
'doi': doi
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
def del_item():
|
| 140 |
+
index: int = st.session_state.get('delete_id')
|
| 141 |
+
ref_list: list = st.session_state.get('reference_list')
|
| 142 |
+
|
| 143 |
+
ref_list.pop(index)
|
| 144 |
+
|
| 145 |
+
yaml_str = yaml.dump(ref_list, width=999)
|
| 146 |
+
st.session_state.reference_text = yaml_str
|
| 147 |
+
st.session_state.reference_list = ref_list
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
st.title("引用格式化")
|
| 151 |
+
|
| 152 |
+
col1, col2 = st.columns([1, 1], gap="medium")
|
| 153 |
+
|
| 154 |
+
if 'reference_list' not in st.session_state:
|
| 155 |
+
st.session_state.reference_list = []
|
| 156 |
+
|
| 157 |
+
if 'reference_text' not in st.session_state:
|
| 158 |
+
st.session_state.reference_text = ''
|
| 159 |
+
|
| 160 |
+
with col1:
|
| 161 |
+
with st.expander('manual'):
|
| 162 |
+
st.text_input('title', key='title')
|
| 163 |
+
|
| 164 |
+
col1_1, col1_2 = st.columns([1, 1], gap="small")
|
| 165 |
+
col1_1.text_input('pmid', key='pmid')
|
| 166 |
+
col1_2.text_input('pmc', key='pmc')
|
| 167 |
+
|
| 168 |
+
st.text_input('doi', key='doi')
|
| 169 |
+
|
| 170 |
+
col2_1, col2_2 = st.columns([1, 1], gap="small")
|
| 171 |
+
col2_1.button('add', use_container_width=True, type='primary', on_click=add)
|
| 172 |
+
col2_2.button('reset', use_container_width=True, on_click=reset)
|
| 173 |
+
|
| 174 |
+
st.text_input('Search', key='term_text')
|
| 175 |
+
st.button('add', use_container_width=True, on_click=get_data)
|
| 176 |
+
|
| 177 |
+
if len(st.session_state.get('reference_list')) > 0:
|
| 178 |
+
st.divider()
|
| 179 |
+
|
| 180 |
+
st.write('共有', len(st.session_state.get('reference_list')), '条引用')
|
| 181 |
+
|
| 182 |
+
col3_1, col3_2 = st.columns([2, 1], gap='small')
|
| 183 |
+
col3_1.number_input(
|
| 184 |
+
'id',
|
| 185 |
+
min_value=0,
|
| 186 |
+
max_value=len(st.session_state.get('reference_list')) - 1,
|
| 187 |
+
key='delete_id',
|
| 188 |
+
label_visibility='collapsed'
|
| 189 |
+
)
|
| 190 |
+
col3_2.button('delete', type='primary', on_click=del_item)
|
| 191 |
+
|
| 192 |
+
with col2:
|
| 193 |
+
with st.container(height=486, border=True):
|
| 194 |
+
st.write(st.session_state.get('reference_list'))
|
| 195 |
+
|
| 196 |
+
st.code(st.session_state.get('reference_text'), language='yaml')
|
pages/Reformat.py
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import re
|
| 2 |
+
|
| 3 |
+
import streamlit as st
|
| 4 |
+
|
| 5 |
+
from ui.Component import side_bar_links
|
| 6 |
+
|
| 7 |
+
st.set_page_config(
|
| 8 |
+
page_title='工具箱',
|
| 9 |
+
page_icon='🔨',
|
| 10 |
+
layout='wide',
|
| 11 |
+
)
|
| 12 |
+
|
| 13 |
+
with st.sidebar:
|
| 14 |
+
side_bar_links()
|
| 15 |
+
|
| 16 |
+
st.title("格式化工具")
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
def re_format(origin_str: str) -> str:
|
| 20 |
+
new_str = origin_str.replace('\r', '').replace('\n', '')
|
| 21 |
+
|
| 22 |
+
matches = re.findall(r'\[\s*\d+(?:,\s*\d+)*]', new_str)
|
| 23 |
+
|
| 24 |
+
for match in matches:
|
| 25 |
+
match_str: str = match
|
| 26 |
+
new_ref = ''.join([
|
| 27 |
+
f"[^{ind.replace(' ', '')}]"
|
| 28 |
+
for ind in match_str.replace('[', '').replace(']', '').split(',')
|
| 29 |
+
])
|
| 30 |
+
new_str = new_str.replace(match, new_ref)
|
| 31 |
+
|
| 32 |
+
matches = re.findall(r'\[\s*\d+(?:-\s*\d+)*]', new_str)
|
| 33 |
+
|
| 34 |
+
for match in matches:
|
| 35 |
+
match_str: str = match
|
| 36 |
+
match_str = match_str.replace('[', '').replace(']', '')
|
| 37 |
+
a = int(match_str.split('-')[0].strip())
|
| 38 |
+
b = int(match_str.split('-')[-1].strip())
|
| 39 |
+
|
| 40 |
+
new_ref = ''.join([
|
| 41 |
+
f'[^{i}]'
|
| 42 |
+
for i in range(a, b + 1)
|
| 43 |
+
])
|
| 44 |
+
new_str = new_str.replace(match, new_ref)
|
| 45 |
+
|
| 46 |
+
return new_str
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
col1, col2 = st.columns([1, 1], gap="medium")
|
| 50 |
+
|
| 51 |
+
if 'markdown_text' not in st.session_state:
|
| 52 |
+
st.session_state.markdown_text = ''
|
| 53 |
+
|
| 54 |
+
with col1.container(height=520, border=True):
|
| 55 |
+
st.markdown(st.session_state.markdown_text)
|
| 56 |
+
|
| 57 |
+
with col2:
|
| 58 |
+
st.code(st.session_state.markdown_text, language='markdown')
|
| 59 |
+
|
| 60 |
+
if prompt := st.chat_input():
|
| 61 |
+
response = re_format(prompt)
|
| 62 |
+
|
| 63 |
+
st.session_state.markdown_text = response
|
| 64 |
+
|
| 65 |
+
st.rerun()
|
pages/TextToImage.py
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
|
| 3 |
+
import requests
|
| 4 |
+
import urllib3
|
| 5 |
+
|
| 6 |
+
import streamlit as st
|
| 7 |
+
from loguru import logger
|
| 8 |
+
|
| 9 |
+
from ui.Component import side_bar_links
|
| 10 |
+
|
| 11 |
+
st.set_page_config(
|
| 12 |
+
page_title='工具箱',
|
| 13 |
+
page_icon='🔨',
|
| 14 |
+
layout='wide',
|
| 15 |
+
)
|
| 16 |
+
|
| 17 |
+
with st.sidebar:
|
| 18 |
+
side_bar_links()
|
| 19 |
+
|
| 20 |
+
st.text_input('Api_key', type='password', key='api_key')
|
| 21 |
+
|
| 22 |
+
st.title('CogView 文生图')
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
def generate_image_url(prompt: str) -> str:
|
| 26 |
+
from zhipuai import ZhipuAI
|
| 27 |
+
|
| 28 |
+
api = st.session_state.get('api_key')
|
| 29 |
+
if api != '':
|
| 30 |
+
client = ZhipuAI(api_key=api) # 请填写您自己的APIKey
|
| 31 |
+
|
| 32 |
+
response = client.images.generations(
|
| 33 |
+
model="cogview-3",
|
| 34 |
+
prompt=prompt,
|
| 35 |
+
)
|
| 36 |
+
|
| 37 |
+
return response.data[0].url
|
| 38 |
+
else:
|
| 39 |
+
st.error('请先输入API!')
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
def download_img(img_url: str) -> str:
|
| 43 |
+
r = requests.get(img_url, stream=True)
|
| 44 |
+
if r.status_code == 200:
|
| 45 |
+
filename = img_url.split('/')[-1]
|
| 46 |
+
filepath = f'/home/aye/Service/MyTools/image/{filename}'
|
| 47 |
+
open(filepath, 'wb').write(r.content)
|
| 48 |
+
del r
|
| 49 |
+
return filepath
|
| 50 |
+
else:
|
| 51 |
+
st.error('download fail')
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
if 'filepath' not in st.session_state:
|
| 55 |
+
st.session_state['filepath'] = ''
|
| 56 |
+
|
| 57 |
+
if os.path.exists(st.session_state.get('filepath')):
|
| 58 |
+
with st.chat_message('user'):
|
| 59 |
+
st.write(st.session_state.get('image_prompt'))
|
| 60 |
+
with st.chat_message('ai'):
|
| 61 |
+
path: str = st.session_state.get('filepath')
|
| 62 |
+
st.image(path)
|
| 63 |
+
with open(path, "rb") as file:
|
| 64 |
+
btn = st.download_button(
|
| 65 |
+
label="下载",
|
| 66 |
+
data=file,
|
| 67 |
+
file_name=path.split('/')[-1],
|
| 68 |
+
mime="image/png"
|
| 69 |
+
)
|
| 70 |
+
|
| 71 |
+
if image_prompt := st.chat_input(key='image_prompt'):
|
| 72 |
+
with st.chat_message('user'):
|
| 73 |
+
logger.info(image_prompt)
|
| 74 |
+
st.write(image_prompt)
|
| 75 |
+
|
| 76 |
+
with st.spinner('正在生成图片...'):
|
| 77 |
+
url = generate_image_url(image_prompt)
|
| 78 |
+
logger.info(url)
|
| 79 |
+
|
| 80 |
+
with st.spinner('正在下载图片...'):
|
| 81 |
+
path = download_img(url)
|
| 82 |
+
st.session_state['filepath'] = path
|
| 83 |
+
|
| 84 |
+
with st.chat_message('ai'):
|
| 85 |
+
st.image(path)
|
| 86 |
+
with open(path, "rb") as file:
|
| 87 |
+
btn = st.download_button(
|
| 88 |
+
label="下载",
|
| 89 |
+
data=file,
|
| 90 |
+
file_name=url.split('/')[-1],
|
| 91 |
+
mime="image/png"
|
| 92 |
+
)
|
pages/Translate.py
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
|
| 3 |
+
import httpx
|
| 4 |
+
import streamlit as st
|
| 5 |
+
import yaml
|
| 6 |
+
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage
|
| 7 |
+
from langchain_core.prompts import ChatPromptTemplate
|
| 8 |
+
from langchain_openai import ChatOpenAI
|
| 9 |
+
from loguru import logger
|
| 10 |
+
|
| 11 |
+
from ui.Component import side_bar_links
|
| 12 |
+
|
| 13 |
+
st.set_page_config(
|
| 14 |
+
page_title='工具箱',
|
| 15 |
+
page_icon='🔨',
|
| 16 |
+
layout='wide',
|
| 17 |
+
)
|
| 18 |
+
|
| 19 |
+
st.title("一键生成翻译总结")
|
| 20 |
+
|
| 21 |
+
with st.sidebar:
|
| 22 |
+
side_bar_links()
|
| 23 |
+
|
| 24 |
+
st.toggle('去除换行', key='trans_reformat')
|
| 25 |
+
st.toggle('总结', key='trans_conclusion')
|
| 26 |
+
|
| 27 |
+
st.toggle('输出格式', key='trans_text_mode')
|
| 28 |
+
if st.session_state.get('trans_text_mode'):
|
| 29 |
+
st.caption('markdown')
|
| 30 |
+
else:
|
| 31 |
+
st.caption('latex')
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def get_translate_and_conclude(question: str, step: int):
|
| 35 |
+
if step == 0:
|
| 36 |
+
_prompt = ChatPromptTemplate.from_messages(
|
| 37 |
+
[
|
| 38 |
+
SystemMessage("You are an AI academic assistant and should answer user questions rigorously."),
|
| 39 |
+
("human",
|
| 40 |
+
"你将收到一个论文的片段。首先,将这段文本以学术风格**翻译为中文**,不要漏句。对于所有的特殊符号和latex代码,请保持原样不要改变。"
|
| 41 |
+
"对于文中一些显得与上下文突兀的数字,很大可能是引用文献,请使用latex语法将它们表示为一个上标,并使用美元符号包围,如$^2$。这是你要翻译的文献片段:\n{question}"),
|
| 42 |
+
]
|
| 43 |
+
)
|
| 44 |
+
elif step == 1:
|
| 45 |
+
_prompt = ChatPromptTemplate.from_messages(
|
| 46 |
+
[
|
| 47 |
+
SystemMessage(content="You are an AI academic assistant and should answer user questions rigorously."),
|
| 48 |
+
HumanMessage(
|
| 49 |
+
content=f"""首先,将这段文本**翻译为中文**,不要漏句。对于所有的特殊符号和latex代码,请保持原样不要改变:
|
| 50 |
+
{st.session_state.translate_messages[-3]}"""
|
| 51 |
+
),
|
| 52 |
+
AIMessage(content=str(st.session_state.translate_messages[-2])),
|
| 53 |
+
HumanMessage(content=question),
|
| 54 |
+
]
|
| 55 |
+
)
|
| 56 |
+
else:
|
| 57 |
+
raise Exception("Wrong step value")
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
llm = ChatOpenAI(
|
| 61 |
+
model_name="gpt-3.5-turbo",
|
| 62 |
+
temperature=0,
|
| 63 |
+
openai_api_key=st.secrets['gpt_key'],
|
| 64 |
+
streaming=True
|
| 65 |
+
)
|
| 66 |
+
|
| 67 |
+
chain = _prompt | llm
|
| 68 |
+
|
| 69 |
+
if step == 0:
|
| 70 |
+
llm_result = chain.stream({"question": question})
|
| 71 |
+
else:
|
| 72 |
+
llm_result = chain.stream({"question": question})
|
| 73 |
+
|
| 74 |
+
return llm_result
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
col1, col2 = st.columns([1, 1], gap="medium")
|
| 78 |
+
|
| 79 |
+
if 'translate_messages' not in st.session_state:
|
| 80 |
+
st.session_state.translate_messages = []
|
| 81 |
+
|
| 82 |
+
if 'markdown_text' not in st.session_state:
|
| 83 |
+
st.session_state.markdown_text = ''
|
| 84 |
+
|
| 85 |
+
chat_container = col1.container(height=610, border=False)
|
| 86 |
+
|
| 87 |
+
with chat_container:
|
| 88 |
+
for message in st.session_state.translate_messages:
|
| 89 |
+
icon = 'logo.png' if message['role'] != 'user' else None
|
| 90 |
+
with st.chat_message(message['role']):
|
| 91 |
+
st.markdown(message['content'])
|
| 92 |
+
|
| 93 |
+
with col2:
|
| 94 |
+
if st.session_state.markdown_text != '':
|
| 95 |
+
with st.container(height=520, border=True):
|
| 96 |
+
st.markdown(st.session_state.markdown_text)
|
| 97 |
+
if st.session_state.get('trans_text_mode'):
|
| 98 |
+
st.code(st.session_state.markdown_text, language='markdown')
|
| 99 |
+
else:
|
| 100 |
+
st.code(st.session_state.markdown_text, language='latex')
|
| 101 |
+
|
| 102 |
+
if prompt := st.chat_input():
|
| 103 |
+
st.session_state.translate_messages = []
|
| 104 |
+
if st.session_state.get('trans_reformat'):
|
| 105 |
+
prompt = prompt.replace("\n", " ").replace("\r", "")
|
| 106 |
+
|
| 107 |
+
logger.info(f'[translate]: {prompt}')
|
| 108 |
+
prompt = prompt.replace('$', r'\$')
|
| 109 |
+
|
| 110 |
+
chat_container.chat_message("human").write(prompt)
|
| 111 |
+
st.session_state.translate_messages.append({'role': 'user', 'content': prompt})
|
| 112 |
+
|
| 113 |
+
response = get_translate_and_conclude(prompt, 0)
|
| 114 |
+
translate_result = chat_container.chat_message("ai").write_stream(response)
|
| 115 |
+
st.session_state.translate_messages.append({'role': 'assistant', 'content': translate_result})
|
| 116 |
+
|
| 117 |
+
if st.session_state.get('trans_conclusion'):
|
| 118 |
+
query = "接下来,请用两到四句话总结一下这段文本的内容"
|
| 119 |
+
chat_container.chat_message("human").write(query)
|
| 120 |
+
st.session_state.translate_messages.append({'role': 'user', 'content': query})
|
| 121 |
+
|
| 122 |
+
response = get_translate_and_conclude(query, 1)
|
| 123 |
+
conclusion_result = chat_container.chat_message("ai").write_stream(response)
|
| 124 |
+
logger.info(f"(conclude): {conclusion_result}")
|
| 125 |
+
st.session_state.translate_messages.append({'role': 'assistant', 'content': conclusion_result})
|
| 126 |
+
|
| 127 |
+
if st.session_state.get('trans_text_mode'):
|
| 128 |
+
markdown_text = f"""{prompt}\t\r\n{translate_result}\t\r\n> {conclusion_result}"""
|
| 129 |
+
else:
|
| 130 |
+
markdown_text = f"""{prompt}\n\n{translate_result}\n\n\\tbox{{ {conclusion_result} }}"""
|
| 131 |
+
markdown_text = markdown_text.replace('%', r'\%')
|
| 132 |
+
st.session_state.markdown_text = markdown_text
|
| 133 |
+
else:
|
| 134 |
+
markdown_text = f"""{prompt}\t\r\n{translate_result}"""
|
| 135 |
+
st.session_state.markdown_text = markdown_text
|
| 136 |
+
|
| 137 |
+
st.rerun()
|
requirements.txt
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
loguru
|
| 2 |
+
bs4
|
| 3 |
+
PyYAML
|
| 4 |
+
langchain
|
| 5 |
+
langchain_openai
|
| 6 |
+
lxml
|
ui/Component.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def side_bar_links():
|
| 5 |
+
st.header('工具箱')
|
| 6 |
+
|
| 7 |
+
st.page_link('App.py', label='Home', icon='🏠')
|
| 8 |
+
st.page_link('pages/Reformat.py', label='文本格式化', icon='📖')
|
| 9 |
+
st.page_link('pages/Reference.py', label='引用文献生成', icon='📙')
|
| 10 |
+
st.page_link('pages/Translate.py', label='翻译总结工具', icon='🌐')
|
| 11 |
+
st.page_link('pages/TextToImage.py', label='文生图', icon='🎨')
|
| 12 |
+
|
| 13 |
+
st.divider()
|
utils/Decorator.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import time
|
| 2 |
+
from functools import wraps
|
| 3 |
+
from typing import Callable, Any
|
| 4 |
+
from loguru import logger
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
def retry(retries: int = 3, delay: float = 1) -> Callable:
|
| 8 |
+
"""
|
| 9 |
+
为函数提供重试逻辑的装饰器。
|
| 10 |
+
|
| 11 |
+
参数:
|
| 12 |
+
retries (int): 最大重试次数,默认为3。
|
| 13 |
+
delay (float): 两次重试之间的延迟时间(秒),默认为1。
|
| 14 |
+
|
| 15 |
+
返回:
|
| 16 |
+
Callable: 被装饰的函数。
|
| 17 |
+
|
| 18 |
+
异常:
|
| 19 |
+
ValueError: 如果retries小于1或delay小于等于0,则抛出此异常。
|
| 20 |
+
"""
|
| 21 |
+
if retries < 1 or delay <= 0:
|
| 22 |
+
raise ValueError('Wrong param')
|
| 23 |
+
|
| 24 |
+
def decorator(func: Callable) -> Callable:
|
| 25 |
+
@wraps(func)
|
| 26 |
+
def wrapper(*args, **kwargs) -> Any:
|
| 27 |
+
for i in range(1, retries + 1):
|
| 28 |
+
try:
|
| 29 |
+
return func(*args, **kwargs)
|
| 30 |
+
except Exception as e:
|
| 31 |
+
if i == retries:
|
| 32 |
+
logger.error(f'Error: {repr(e)}.')
|
| 33 |
+
logger.error(f'"{func.__name__}()" failed after {retries} retries.')
|
| 34 |
+
break
|
| 35 |
+
else:
|
| 36 |
+
logger.debug(f'Error: {repr(e)} -> Retrying...')
|
| 37 |
+
time.sleep(delay)
|
| 38 |
+
|
| 39 |
+
return wrapper
|
| 40 |
+
|
| 41 |
+
return decorator
|
utils/__init__.py
ADDED
|
File without changes
|