File size: 9,318 Bytes
783b316
3b88694
 
 
 
 
 
 
 
f44bd77
 
3b88694
 
 
 
 
 
 
216d7ff
3b88694
 
 
 
 
 
 
 
 
79e289d
 
 
 
 
 
 
3b88694
 
 
 
216d7ff
 
 
 
 
 
 
 
 
 
 
3b88694
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f44bd77
3b88694
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
aa3ebce
 
81c447a
aa3ebce
 
 
 
 
 
 
 
79e289d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3b88694
 
783b316
3b88694
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216d7ff
 
 
 
 
 
 
3b88694
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79e289d
 
aa3ebce
3b88694
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79e289d
 
aa3ebce
3b88694
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
import streamlit as st
import PyPDF2
import pandas as pd
import os
import google.generativeai as genai
from datetime import datetime
import logging
import sys
from io import BytesIO
from pathlib import Path

# 設定頁面配置
st.set_page_config(
    page_title="PDF 處理與翻譯工具",
    page_icon="📄",
    layout="wide"
)

# 使用 Streamlit 的記錄方式,避免檔案權限問題
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.StreamHandler(sys.stdout)
    ]
)
logger = logging.getLogger(__name__)

# 檢查是否有openpyxl套件,用於Excel匯出
try:
    import openpyxl
    EXCEL_SUPPORT = True
except ImportError:
    EXCEL_SUPPORT = False

# 應用標題
st.title("PDF 內容處理與翻譯工具")
st.markdown("使用 Gemini API 來處理和翻譯 PDF 文件內容")

# 嘗試讀取CSV示例
try:
    csv_path = Path(__file__).parent / "data.csv"
    if csv_path.exists():
        df = pd.read_csv(csv_path)
        st.sidebar.subheader("範例數據")
        st.sidebar.dataframe(df)
except Exception as e:
    # 靜默處理CSV讀取錯誤,不顯示給用戶
    pass

# 側邊欄設置
with st.sidebar:
    st.header("設置")
    api_key = st.text_input("輸入 Gemini API Key", type="password")
    target_language = st.selectbox(
        "選擇目標語言", 
        ["繁體中文", "簡體中文", "英文", "日文", "韓文", "法文", "德文", "西班牙文"]
    )
    
    st.markdown("---")
    st.markdown("### 關於")
    st.markdown("此應用程序使用 Streamlit 和 Gemini API 處理 PDF 文件內容。")

# 主功能
def setup_gemini_api(api_key):
    """設置 Gemini API"""
    try:
        os.environ["GEMINI_API_KEY"] = api_key
        genai.configure(api_key=api_key)
        return genai.GenerativeModel("gemini-1.5-flash")
    except Exception as e:
        logger.error(f"Gemini API 設置失敗: {e}")
        st.error(f"Gemini API 設置失敗: {e}")
        return None

def extract_text_from_pdf(pdf_file):
    """從PDF文件中提取所有文本內容,以頁面為單位返回文本列表"""
    try:
        reader = PyPDF2.PdfReader(pdf_file)
        total_pages = len(reader.pages)
        logger.info(f"PDF共有 {total_pages} 頁")
        
        pages_text = []
        for page_num in range(total_pages):
            with st.spinner(f"提取第 {page_num+1} 頁..."):
                page_text = reader.pages[page_num].extract_text()
                pages_text.append(page_text)
        
        return pages_text, total_pages
    except Exception as e:
        logger.error(f"PDF文本提取錯誤: {e}")
        st.error(f"PDF文本提取錯誤: {e}")
        return [], 0

def translate_with_gemini(model, text, target_language):
    """使用Gemini將文本翻譯成目標語言"""
    try:
        prompt = f"""
        請將以下文本翻譯成{target_language},保持專業和準確性:
        
        {text}
        
        只需要返回翻譯後的文本,不要加入其他解釋或備註。
        """
        
        response = model.generate_content(prompt)
        return response.text.strip()
    except Exception as e:
        logger.error(f"Gemini翻譯失敗: {e}")
        return f"翻譯失敗: {str(e)}"

def process_with_gemini(model, text, instruction="請解釋以下內容"):
    """使用Gemini處理文本"""
    try:
        prompt = f"{instruction}:\n\n{text}"
        response = model.generate_content(prompt)
        return response.text.strip()
    except Exception as e:
        logger.error(f"Gemini處理失敗: {e}")
        return f"處理失敗: {str(e)}"

def provide_download_options(result_df):
    """提供下載選項,確保CSV中文不會出現亂碼"""
    
    # 使用UTF-8-SIG編碼保證中文在CSV中不會出現亂碼
    csv_data = result_df.to_csv(index=False, encoding='utf-8-sig')
    st.download_button(
        label="下載結果為CSV",
        data=csv_data,
        file_name=f"pdf_process_result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv",
        mime="text/csv; charset=utf-8-sig",  # 指定MIME類型包含編碼
    )
    
    # 如果支援Excel格式,也提供Excel下載選項
    if EXCEL_SUPPORT:
        excel_buffer = BytesIO()
        result_df.to_excel(excel_buffer, index=False, engine='openpyxl')
        excel_data = excel_buffer.getvalue()
        
        st.download_button(
            label="下載結果為Excel",
            data=excel_data,
            file_name=f"pdf_process_result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx",
            mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            key="excel_download"  # 添加唯一key避免與CSV下載按鈕衝突
        )

# 上傳PDF文件
uploaded_file = st.file_uploader("上傳PDF文件", type="pdf")

if uploaded_file is not None:
    # 顯示上傳成功訊息
    st.success(f"文件 '{uploaded_file.name}' 上傳成功!")
    
    # 檢查API Key是否已提供
    if not api_key:
        st.warning("請先在側邊欄輸入 Gemini API Key")
    else:
        # 初始化Gemini模型
        with st.spinner("初始化 Gemini API..."):
            model = setup_gemini_api(api_key)
        
        if model:
            # 處理PDF檔案
            with st.spinner("正在提取PDF內容..."):
                try:
                    # 直接從記憶體讀取PDF內容,避免寫入臨時文件
                    pdf_bytes = BytesIO(uploaded_file.getvalue())
                    pages_text, total_pages = extract_text_from_pdf(pdf_bytes)
                except Exception as e:
                    st.error(f"處理PDF文件時發生錯誤: {e}")
                    pages_text, total_pages = [], 0
            
            if pages_text:
                # 創建一個選擇頁面的選項
                page_to_process = st.selectbox(
                    "選擇要處理的頁面", 
                    range(1, total_pages + 1),
                    format_func=lambda x: f"第 {x} 頁"
                )
                
                # 顯示選定頁面的內容預覽
                st.subheader(f"第 {page_to_process} 頁內容預覽")
                selected_page_content = pages_text[page_to_process - 1]
                st.text_area("原始內容", selected_page_content, height=200)
                
                # 處理選項
                process_method = st.radio(
                    "選擇處理方式",
                    ["翻譯原始內容", "先解釋後翻譯"]
                )
                
                if st.button("開始處理"):
                    with st.spinner("處理中..."):
                        if process_method == "翻譯原始內容":
                            # 直接翻譯
                            translation = translate_with_gemini(model, selected_page_content, target_language)
                            
                            # 顯示結果
                            st.subheader("翻譯結果")
                            st.write(translation)
                            
                            # 準備下載結果
                            result_df = pd.DataFrame({
                                "時間戳記": [datetime.now().isoformat()],
                                "原始內容": [selected_page_content],
                                f"{target_language}翻譯": [translation]
                            })
                            
                            # 提供下載選項
                            provide_download_options(result_df)
                        else:
                            # 先解釋後翻譯
                            with st.spinner("解釋內容..."):
                                explanation = process_with_gemini(
                                    model, 
                                    selected_page_content, 
                                    "請詳細解釋以下內容的主要要點和重要信息"
                                )
                            
                            with st.spinner("翻譯解釋..."):
                                translation = translate_with_gemini(model, explanation, target_language)
                            
                            # 顯示結果
                            st.subheader("內容解釋")
                            st.write(explanation)
                            
                            st.subheader(f"{target_language}翻譯")
                            st.write(translation)
                            
                            # 準備下載結果
                            result_df = pd.DataFrame({
                                "時間戳記": [datetime.now().isoformat()],
                                "原始內容": [selected_page_content],
                                "內容解釋": [explanation],
                                f"{target_language}翻譯": [translation]
                            })
                            
                            # 提供下載選項
                            provide_download_options(result_df)
            else:
                st.error("無法提取PDF內容,請檢查文件格式是否正確。")