Jiangxz commited on
Commit
ab4dc27
·
verified ·
1 Parent(s): 1906b83

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +261 -0
  2. requirements.txt +3 -0
app.py ADDED
@@ -0,0 +1,261 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+ # 財政部財政資訊中心 江信宗
3
+
4
+ import gradio as gr
5
+ import os
6
+ from openai import OpenAI
7
+ import resend
8
+ import time
9
+ import html
10
+ import tempfile
11
+ import re
12
+
13
+ custom_css = """
14
+ .center-aligned {
15
+ text-align: center !important;
16
+ color: #ff4081;
17
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
18
+ margin-bottom: 0px !important;
19
+ }
20
+ .input-background {
21
+ background-color: #B7E0FF !important;
22
+ padding: 15px !important;
23
+ border-radius: 10px !important;
24
+ margin: 0 !important;
25
+ height: auto;
26
+ }
27
+ .input-background textarea {
28
+ font-size: 18px !important;
29
+ background-color: #ffffff;
30
+ border: 1px solid #f0f8ff;
31
+ border-radius: 8px !important;
32
+ }
33
+ .script-background {
34
+ background-color: #FEF9D9 !important;
35
+ padding: 15px !important;
36
+ border-radius: 10px !important;
37
+ margin: 0 !important;
38
+ }
39
+ .api-background {
40
+ background-color: #FFCFB3 !important;
41
+ padding: 15px !important;
42
+ border-radius: 10px !important;
43
+ }
44
+ .text-background {
45
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Helvetica', 'Arial', sans-serif;
46
+ font-size: 18px !important;
47
+ line-height: 1.6 !important;
48
+ padding: 30px !important;
49
+ border-radius: 20px !important;
50
+ background-color: #FFFED3 !important;
51
+ margin: 0 !important;
52
+ transition: all 0.3s ease;
53
+ position: relative;
54
+ z-index: 1;
55
+ overflow: hidden;
56
+ }
57
+ .translation-header {
58
+ font-size: 24px;
59
+ font-weight: 600;
60
+ color: #1d1d1f;
61
+ margin-bottom: 20px;
62
+ text-align: center;
63
+ }
64
+ .translation-content {
65
+ color: #000000;
66
+ font-size: 20px;
67
+ text-align: justify;
68
+ hyphens: auto;
69
+ word-wrap: break-word;
70
+ overflow-wrap: break-word;
71
+ }
72
+ .translation-content p {
73
+ margin-bottom: 15px;
74
+ }
75
+ @media (max-width: 768px) {
76
+ .text-background {
77
+ font-size: 16px !important;
78
+ padding: 0px !important;
79
+ }
80
+
81
+ .translation-header {
82
+ font-size: 20px;
83
+ }
84
+ }
85
+ .submit-btn {
86
+ border-radius: 10px !important;
87
+ border: none !important;
88
+ background-color: #ff4081 !important;
89
+ color: white !important;
90
+ font-weight: bold !important;
91
+ transition: all 0.3s ease !important;
92
+ margin: 0 !important;
93
+ }
94
+ .submit-btn:hover {
95
+ background-color: #f50057 !important;
96
+ transform: scale(1.05);
97
+ }
98
+ .clear-button {
99
+ border-radius: 10px !important;
100
+ border: none !important;
101
+ background-color: #333333 !important;
102
+ color: white !important;
103
+ font-weight: bold !important;
104
+ transition: all 0.3s ease !important;
105
+ }
106
+ .clear-button:hover {
107
+ background-color: #000000 !important;
108
+ transform: scale(1.05);
109
+ }
110
+ """
111
+
112
+ def translate(content_text, language, api_key):
113
+ start_time = time.time()
114
+ language_dict = {"繁體中文": "English", "English": "繁體中文"}
115
+ corr_language = language_dict[language]
116
+ if not api_key:
117
+ resend.api_key = os.environ["YOUR_API_TOKEN"]
118
+ params: resend.Emails.SendParams = {
119
+ "from": "Trans_API <onboarding@resend.dev>",
120
+ "to": ["antivir7@gmail.com"],
121
+ "subject": "精緻翻譯",
122
+ "html": f"""
123
+ <strong>翻譯文章</strong><br>
124
+ 文章:{content_text}
125
+ """,
126
+ }
127
+ try:
128
+ email_response = resend.Emails.send(params)
129
+ print(f"Email sent successfully. Response:{email_response}")
130
+ api_key = os.getenv("YOUR_API_KEY")
131
+ except Exception as e:
132
+ gr.Warning(f"請輸入正確的API Key!!")
133
+ return "請輸入正確的API Key!!"
134
+ client = OpenAI(
135
+ api_key=api_key,
136
+ base_url="https://api.chatanywhere.org/v1",
137
+ )
138
+ system_prompt = f"""你是一位精通繁體中文與英文的專業翻譯,具有40年翻譯經驗且擁有豐富的跨學術專業知識,深度參與《The New York Times》及《Bloomberg》的中文版翻譯工作,對於時事新聞和論文的翻譯有深入的理解。我希望你能幫我將以下{corr_language}全文內容翻譯成{language},風格與上述雜誌的中文版本相似。
139
+
140
+ Remember: 翻譯規則:
141
+ # 翻譯時要準確傳達{corr_language}原文內容的事實和背景。
142
+ # 保留特定的英文術語、數字或名字,並在其前後加上空格,例如:"中 UN 文","不超過 10 秒"。
143
+ # 依據步驟來翻譯原文,並且列印每一次的輸出結果:
144
+ ## 根據{corr_language}全文內容直譯,旨在忠實呈現原文,不要遺漏任何訊息,並保持原文的專業性和精準性。
145
+ ## 根據直譯的結果重新意譯(意譯稿),遵守{corr_language}原意的前提下讓內容更通俗易懂,提高文字的文學美感,符合《The Wall Street Journal》與《The Economist》中網的中文表達習慣
146
+ ## 根據重新意譯的結果反向翻譯成{corr_language}(回譯稿)。
147
+ ## 校對回譯稿及{corr_language}原稿中的區別,重點檢查回譯稿與{corr_language}原稿有表達歧義的部分,並確保您的回應客觀且避免使用刻板印象。
148
+ ## 根據上一步校對意見,修改意譯稿產生翻譯終稿。
149
+ # 每輪翻譯後,都要重新比對{corr_language}原文,找到扭曲原意或遺漏的內容,然後再補充到下一輪的翻譯當中。
150
+ # 針對翻譯為繁體中文的翻譯終稿,請依照臺灣用詞對照表:["人工智能":"人工智慧","計算機":"電腦","訪問":"存取","設置":"設定","數據":"資料","社交媒體":"社群媒體","私人帳戶":"個人帳號","帳戶":"帳號","博客":"部落格","谷歌":"Google","用戶":"使用者","信息":"訊息","視頻":"影片","軟件":"軟體","硬盤":"硬碟","攝影機":"攝像頭","渠道":"管道","多維":"多元","宇航員":"太空人","短信":"簡訊","查體":"體檢","台球":"撞球","塔樓":"大廈","包間":"包廂","出租車":"計程車","公安局":"警察局","充值卡":"儲值卡","塑料":"塑膠","城鐵":"捷運","鼠標":"滑鼠","網絡":"網路","互聯網":"網際網路","U盤":"隨身碟","燃氣灶":"瓦斯爐","晶體管":"半導體","屏幕":"螢幕","電飯煲":"電鍋","洗面奶":"洗面乳","移動電話":"行動電話","菠蘿":"鳳梨","頭腦風暴":"腦力激盪"]進行修正文字。
151
+
152
+ 你理解翻譯規則後,user將會給你發送完整{corr_language}內容,收到後請按照上面的翻譯規則和下面的格式輸出翻譯結果及摘要,回傳格式如下,"{{{{xxx}}}}"表示預留位置:
153
+
154
+ ### 第一階段:直譯
155
+ {{{{直譯結果}}}}
156
+
157
+ ### 第二階段:意譯初稿
158
+ {{{{意譯初稿}}}}
159
+
160
+ ### 第三階段:回譯稿
161
+ {{{{回譯稿}}}}
162
+
163
+ ### 第四階段:校對意見
164
+
165
+ 以下是在{language}翻譯中缺失的部分:
166
+
167
+ {{{{重複以下列表,直到列出所有缺失的內容}}}}
168
+ - 對比原文缺失或表達歧義部分{{1...n}}:
169
+ - 原文:"{language}"
170
+ - 譯文:"{corr_language}"
171
+ - 建議:{{{{新增翻譯 or 修改翻譯}}}}
172
+
173
+ ### 第五階段:翻譯終稿
174
+ {{{{翻譯終稿}}}}
175
+ """
176
+ try:
177
+ gr.Info("Stepwise翻譯中....")
178
+ response = client.chat.completions.create(
179
+ model="gpt-4o-mini",
180
+ messages=[
181
+ {"role": "system", "content": system_prompt},
182
+ {"role": "user", "content": content_text}
183
+ ],
184
+ temperature=0.7
185
+ )
186
+ result = response.choices[0].message.content.strip()
187
+ final_translation = result.split("### 第五階段:翻譯終稿")[-1].strip()
188
+ try:
189
+ with tempfile.NamedTemporaryFile(mode='w+', encoding='utf-8', suffix='.txt', delete=False) as temp_file:
190
+ temp_file.write(f"【原稿({language_dict[language]})】\n\n{content_text}\n\n")
191
+ temp_file.write(f"\n\n【翻譯稿({language})】\n\n{final_translation}")
192
+ temp_file_path = temp_file.name
193
+ except Exception as e:
194
+ gr.Info(f"翻譯完成,執行時間: {(time.time() - start_time):.2f} 秒。")
195
+ return final_translation, None
196
+ gr.Info(f"翻譯完成並提供翻譯結果下載,執行時間: {(time.time() - start_time):.2f} 秒。")
197
+ return final_translation, temp_file_path
198
+ except Exception as e:
199
+ return f"Error: {e}", None
200
+
201
+ with gr.Blocks(theme=gr.themes.Monochrome(), css=custom_css) as iface:
202
+ gr.Markdown("""
203
+ # 文章解碼重構 - 財政部財政資訊中心
204
+ > ### **※ 學習 Chain-of-Thought 思維,逐步探索字詞的深意,細心揣摩原文的情感,重構出忠實且動人心弦的作品。系統部署:江信宗,LLM:GPT-4o-mini。**
205
+ """, elem_classes="center-aligned")
206
+ content = gr.Textbox(
207
+ label="輸入您的文章",
208
+ placeholder="Enter your text here",
209
+ interactive=True,
210
+ autofocus=True,
211
+ max_lines=10,
212
+ elem_classes="input-background"
213
+ )
214
+ with gr.Row():
215
+ Language = gr.Dropdown(
216
+ choices = ["繁體中文","English"],
217
+ value="繁體中文",
218
+ label="翻譯成...語言",
219
+ interactive=True,
220
+ elem_classes="script-background"
221
+ )
222
+ file_output = gr.File(label="下載翻譯結果", elem_classes="script-background", visible=False)
223
+ api_key_input = gr.Textbox(label="輸入您的 API Key", type="password", placeholder="API authentication key", scale=1, elem_classes="api-background")
224
+ with gr.Row():
225
+ submit_btn = gr.Button("傳送", variant="primary", scale=2, elem_classes="submit-btn")
226
+ clear_button = gr.Button("清除", variant="secondary", scale=1, elem_classes="clear-button")
227
+ translate_result = gr.HTML(elem_classes="text-background", visible=False)
228
+
229
+ def on_submit(content_text, language, api_key):
230
+ result, file_path = translate(content_text, language, api_key)
231
+ formatted_result = (
232
+ '<div class="translation-header">※ 解碼重構結果 ※</div>'
233
+ '<div class="translation-content">'
234
+ '{}'
235
+ '</div>'
236
+ ).format(html.escape(result).replace('\n', '</p><p>'))
237
+ return gr.update(
238
+ value=formatted_result,
239
+ visible=True
240
+ ), gr.update(value=file_path, visible=True)
241
+
242
+ submit_btn.click(
243
+ fn=on_submit,
244
+ inputs=[content, Language, api_key_input],
245
+ outputs=[translate_result, file_output]
246
+ )
247
+
248
+ def clear_inputs():
249
+ return "", "繁體中文", "", gr.update(value="", visible=False), gr.update(value=None, visible=False)
250
+
251
+ clear_button.click(
252
+ fn=clear_inputs,
253
+ inputs=[],
254
+ outputs=[content, Language, api_key_input, translate_result, file_output]
255
+ )
256
+
257
+ if __name__ == "__main__":
258
+ if "SPACE_ID" in os.environ:
259
+ iface.launch()
260
+ else:
261
+ iface.launch(share=True, show_api=False)
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ gradio
2
+ openai
3
+ resend