Files
translator/translator/app.py

121 lines
4.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# app.py
#
# author: deng
# date : 20250604
import threading
import streamlit as st
from utils import parse_config
class TranslatorApp:
"""Streamlit App for Language Translation"""
def __init__(self, config_path: str = 'assets/config.toml'):
self._config = parse_config(config_path)
self._chain = None
# Start pre-warming imports and LLM client in a background thread
self._lock = threading.Lock()
threading.Thread(target=self.prepare_chain, daemon=True).start()
def prepare_chain(self) -> None:
"""Prepare the chain for translation.
Thread-safe: safe to call from both background thread and main thread.
"""
if self._chain is not None:
return
with self._lock:
if self._chain is not None:
return
from langchain.prompts import ChatPromptTemplate
system_template = (
'你是專業的翻譯人員,請判斷接下來句子的語言是否為{source_lang},若是的話則請將該句翻譯成{target_lang}'
'並且符合{description}(僅回傳翻譯結果即可),若非的話則請回傳一模一樣的句子。'
)
user_template = '{input_text}'
if self._config['app']['llm_mode'] == 'ollama':
from langchain_ollama import ChatOllama
llm = ChatOllama(
base_url=self._config['app']['ollama']['url'],
model=self._config['app']['ollama']['model_name'],
temperature=self._config['app']['ollama']['temperature'],
max_tokens=self._config['app']['ollama']['max_tokens'],
top_p=self._config['app']['ollama']['top_p'],
keep_alive=self._config['app']['ollama']['keep_alive'],
stop=None
)
elif self._config['app']['llm_mode'] == 'openai':
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model=self._config['app']['openai']['model_name'],
temperature=self._config['app']['openai']['temperature'],
max_tokens=self._config['app']['openai']['max_tokens'],
top_p=self._config['app']['openai']['top_p']
)
else:
raise ValueError(f"Unsupported llm model: {self._config['app']['llm_mode']}")
prompt = ChatPromptTemplate.from_messages([
('system', system_template),
('human', user_template)
])
self._chain = prompt | llm
def run(self) -> None:
""" Run the Streamlit app """
# Interface
st.set_page_config(
page_title=self._config['app']['page_title'],
page_icon=self._config['app']['page_favicon_path'],
)
st.title(body=self._config['app']['page_title'])
direction = st.radio(
label='語言',
options=list(self._config['app']['lang_directions'].keys()),
index=0,
key='lang_choice',
horizontal=True
)
input_text = st.text_area(
label='輸入',
placeholder='請輸入文字',
key='input_text'
)
translate_button = st.button('翻譯')
output_container = st.empty()
# Action
if input_text or translate_button:
if not input_text.strip():
st.warning('請輸入要翻譯的文字')
else:
self.prepare_chain()
with st.spinner('翻譯中...'):
result = self._chain.stream({
'input_text': input_text,
'source_lang': self._config['app']['lang_directions'][direction]['source_lang'],
'target_lang': self._config['app']['lang_directions'][direction]['target_lang'],
'description': self._config['app']['lang_directions'][direction]['description']
})
output_container.write_stream(
stream=result
)
@st.cache_resource(show_spinner=False, max_entries=1)
def get_app_instance() -> TranslatorApp:
return TranslatorApp()
if __name__ == '__main__':
app = get_app_instance()
app.run()