3a05chatgpt commited on
Commit
b11b466
·
verified ·
1 Parent(s): 40774bb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +219 -50
app.py CHANGED
@@ -1,76 +1,245 @@
1
  import openai
2
  import gradio as gr
3
  import fitz # PyMuPDF
4
- from openai import OpenAI # ✅ 新增正確 Client
 
 
 
5
 
 
6
  api_key = ""
7
- selected_model = ""
8
  summary_text = ""
9
-
10
- client = None # ✅ 全域 client 物件
11
 
12
  def set_api_key(user_api_key):
 
13
  global api_key, client
14
- api_key = user_api_key
15
- client = OpenAI(api_key=api_key) # ✅ 正確初始化新版 Client
16
- return "✅ API Key 已設定"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  def set_model(model_name):
 
19
  global selected_model
20
  selected_model = model_name
21
- return f"✅ 模型已選:{model_name}"
22
 
23
  def extract_pdf_text(file_path):
24
- doc = fitz.open(file_path)
25
- text = ""
26
- for page in doc:
27
- text += page.get_text()
28
- return text
 
 
 
 
 
 
 
 
29
 
30
  def generate_summary(pdf_file):
31
- global summary_text
32
- pdf_text = extract_pdf_text(pdf_file)
33
- if not pdf_text.strip():
34
- return "⚠️ 無法解析 PDF 文字,可能為純圖片 PDF。"
35
- response = client.chat.completions.create(
36
- model=selected_model,
37
- messages=[
38
- {"role": "system", "content": "請將以下 PDF 內容整理為條列式摘要重點。"},
39
- {"role": "user", "content": pdf_text[:4000]}
40
- ]
41
- )
42
- summary_text = response.choices[0].message.content
43
- return summary_text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
 
45
  def ask_question(user_question):
46
- response = client.chat.completions.create(
47
- model=selected_model,
48
- messages=[
49
- {"role": "system", "content": f"根據以下 PDF 摘要內容回答問題:\n{summary_text}"},
50
- {"role": "user", "content": user_question}
51
- ]
52
- )
53
- return response.choices[0].message.content
 
 
 
 
 
 
 
 
 
 
 
 
54
 
55
- with gr.Blocks() as demo:
56
- gr.Markdown("# 📄 PDF 摘要 & 問答助手 (Hugging Face 版)")
 
 
 
 
57
 
58
- api_key_input = gr.Textbox(label="輸入 OpenAI API Key", type="password")
59
- api_key_status = gr.Textbox(label="狀態", interactive=False)
60
- api_key_input.submit(set_api_key, inputs=api_key_input, outputs=api_key_status)
 
 
 
 
 
 
 
 
 
 
 
61
 
62
- model_choice = gr.Radio(["gpt-3.5-turbo", "gpt-4", "gpt-4o"], label="選擇模型")
63
- model_status = gr.Textbox(label="模型狀態", interactive=False)
64
- model_choice.change(set_model, inputs=model_choice, outputs=model_status)
 
 
 
65
 
66
- pdf_upload = gr.File(label="上傳 PDF")
67
- summary_output = gr.Textbox(label="PDF 摘要", lines=10)
68
- summary_btn = gr.Button("生成摘要")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  summary_btn.click(generate_summary, inputs=pdf_upload, outputs=summary_output)
70
-
71
- question_input = gr.Textbox(label="請輸入您的問題")
72
- answer_output = gr.Textbox(label="AI 回答", lines=5)
73
- question_btn = gr.Button("送出問題")
74
  question_btn.click(ask_question, inputs=question_input, outputs=answer_output)
 
 
75
 
76
- demo.launch()
 
 
 
 
 
 
1
  import openai
2
  import gradio as gr
3
  import fitz # PyMuPDF
4
+ from openai import OpenAI
5
+ import os
6
+ import tempfile
7
+ import traceback
8
 
9
+ # 全域變數
10
  api_key = ""
11
+ selected_model = "gpt-4"
12
  summary_text = ""
13
+ client = None
14
+ pdf_text = ""
15
 
16
  def set_api_key(user_api_key):
17
+ """設定 OpenAI API Key 並初始化客戶端"""
18
  global api_key, client
19
+ try:
20
+ api_key = user_api_key.strip()
21
+ if not api_key:
22
+ return "❌ API Key 不能為空"
23
+
24
+ client = OpenAI(api_key=api_key)
25
+
26
+ # 測試 API Key 是否有效
27
+ test_response = client.chat.completions.create(
28
+ model="gpt-4",
29
+ messages=[{"role": "user", "content": "你好"}],
30
+ max_tokens=5
31
+ )
32
+
33
+ return "✅ API Key 已設定並驗證成功"
34
+ except Exception as e:
35
+ return f"❌ API Key 設定失敗: {str(e)}"
36
 
37
  def set_model(model_name):
38
+ """設定選擇的模型"""
39
  global selected_model
40
  selected_model = model_name
41
+ return f"✅ 模型已選擇:{model_name}"
42
 
43
  def extract_pdf_text(file_path):
44
+ """從 PDF 文件中提取文字"""
45
+ try:
46
+ doc = fitz.open(file_path)
47
+ text = ""
48
+ for page_num, page in enumerate(doc):
49
+ page_text = page.get_text()
50
+ if page_text.strip(): # 只添加非空白頁面
51
+ text += f"\n--- 第 {page_num + 1} 頁 ---\n"
52
+ text += page_text
53
+ doc.close()
54
+ return text
55
+ except Exception as e:
56
+ return f"❌ PDF 解析錯誤: {str(e)}"
57
 
58
  def generate_summary(pdf_file):
59
+ """從 PDF 內容生成摘要"""
60
+ global summary_text, pdf_text
61
+
62
+ if not client:
63
+ return "❌ 請先設定 OpenAI API Key"
64
+
65
+ if not pdf_file:
66
+ return " 請先上傳 PDF 文件"
67
+
68
+ try:
69
+ # 從 PDF 提取文字
70
+ pdf_text = extract_pdf_text(pdf_file.name)
71
+
72
+ if not pdf_text.strip():
73
+ return "⚠️ 無法解析 PDF 文字,可能為純圖片 PDF 或空白文件。"
74
+
75
+ # 檢查文字長度,必要時截斷
76
+ max_chars = 8000 # 為系統提示留出空間
77
+ if len(pdf_text) > max_chars:
78
+ pdf_text_truncated = pdf_text[:max_chars] + "\n\n[文本已截斷,僅顯示前 8000 字符]"
79
+ else:
80
+ pdf_text_truncated = pdf_text
81
+
82
+ # 生成摘要
83
+ response = client.chat.completions.create(
84
+ model=selected_model,
85
+ messages=[
86
+ {
87
+ "role": "system",
88
+ "content": """你是一個專業的文檔摘要助手。請將以下 PDF 內容整理為結構化的摘要:
89
+
90
+ 1. 首先提供一個簡短的總體概述
91
+ 2. 然後按照重要性列出主要重點(使用項目符號)
92
+ 3. 如果有數據或統計信息,請特別標注
93
+ 4. 如果有結論或建議,請單獨列出
94
+
95
+ 請用繁體中文回答,保持專業且易於理解的語調。"""
96
+ },
97
+ {"role": "user", "content": pdf_text_truncated}
98
+ ],
99
+ temperature=0.3
100
+ )
101
+
102
+ summary_text = response.choices[0].message.content
103
+ return summary_text
104
+
105
+ except Exception as e:
106
+ error_msg = f"❌ 摘要生成失敗: {str(e)}"
107
+ print(f"錯誤詳情: {traceback.format_exc()}")
108
+ return error_msg
109
 
110
  def ask_question(user_question):
111
+ """基於 PDF 內容回答問題"""
112
+ if not client:
113
+ return "❌ 請先設定 OpenAI API Key"
114
+
115
+ if not summary_text and not pdf_text:
116
+ return "❌ 請先生成 PDF 摘要"
117
+
118
+ if not user_question.strip():
119
+ return "❌ 請輸入問題"
120
+
121
+ try:
122
+ # 使用��要和原始文本來提供更好的上下文
123
+ context = f"PDF 摘要:\n{summary_text}\n\n原始內容(部分):\n{pdf_text[:2000]}"
124
+
125
+ response = client.chat.completions.create(
126
+ model=selected_model,
127
+ messages=[
128
+ {
129
+ "role": "system",
130
+ "content": f"""你是一個專業的文檔問答助手。請基於提供的 PDF 內容回答用戶問題。
131
 
132
+ 規則:
133
+ 1. 只根據提供的文檔內容回答
134
+ 2. 如果文檔中沒有相關信息,請明確說明
135
+ 3. 引用具體的文檔內容來支持你的回答
136
+ 4. 用繁體中文回答
137
+ 5. 保持客觀和準確
138
 
139
+ 文檔內容:
140
+ {context}"""
141
+ },
142
+ {"role": "user", "content": user_question}
143
+ ],
144
+ temperature=0.2
145
+ )
146
+
147
+ return response.choices[0].message.content
148
+
149
+ except Exception as e:
150
+ error_msg = f"❌ 問答生成失敗: {str(e)}"
151
+ print(f"錯誤詳情: {traceback.format_exc()}")
152
+ return error_msg
153
 
154
+ def clear_all():
155
+ """清除所有資料"""
156
+ global summary_text, pdf_text
157
+ summary_text = ""
158
+ pdf_text = ""
159
+ return "", "", ""
160
 
161
+ # 創建 Gradio 介面
162
+ with gr.Blocks(theme=gr.themes.Soft(), title="PDF 摘要助手") as demo:
163
+ gr.Markdown("""
164
+ # 📄 PDF 摘要 & 問答助手
165
+
166
+ 這個工具可以幫助您:
167
+ - 📋 自動生成 PDF 文檔摘要
168
+ - 🤖 基於文檔內容回答問題
169
+ - 💡 快速理解長篇文檔的核心內容
170
+ """)
171
+
172
+ with gr.Tab("🔧 設定"):
173
+ with gr.Row():
174
+ with gr.Column():
175
+ api_key_input = gr.Textbox(
176
+ label="🔑 輸入 OpenAI API Key",
177
+ type="password",
178
+ placeholder="請輸入您的 OpenAI API Key"
179
+ )
180
+ api_key_status = gr.Textbox(
181
+ label="API 狀態",
182
+ interactive=False,
183
+ value="等待設定 API Key..."
184
+ )
185
+
186
+ with gr.Column():
187
+ model_choice = gr.Radio(
188
+ ["gpt-4", "gpt-4.1", "gpt-4.5"],
189
+ label="🤖 選擇模型",
190
+ value="gpt-4"
191
+ )
192
+ model_status = gr.Textbox(
193
+ label="模型狀態",
194
+ interactive=False,
195
+ value="✅ 模型已選擇:gpt-4"
196
+ )
197
+
198
+ with gr.Tab("📄 PDF 處理"):
199
+ with gr.Row():
200
+ with gr.Column():
201
+ pdf_upload = gr.File(
202
+ label="📁 上傳 PDF 文件",
203
+ file_types=[".pdf"]
204
+ )
205
+ with gr.Row():
206
+ summary_btn = gr.Button("🔄 生成摘要", variant="primary")
207
+ clear_btn = gr.Button("🗑️ 清除資料", variant="secondary")
208
+
209
+ with gr.Column():
210
+ summary_output = gr.Textbox(
211
+ label="📋 PDF 摘要",
212
+ lines=15,
213
+ placeholder="上傳 PDF 文件並點擊 '生成摘要' 按鈕"
214
+ )
215
+
216
+ with gr.Tab("❓ 問答"):
217
+ with gr.Row():
218
+ with gr.Column():
219
+ question_input = gr.Textbox(
220
+ label="💬 請輸入您的問題",
221
+ placeholder="例如:這份文件的主要結論是什麼?"
222
+ )
223
+ question_btn = gr.Button("📤 送出問題", variant="primary")
224
+
225
+ with gr.Column():
226
+ answer_output = gr.Textbox(
227
+ label="🤖 AI 回答",
228
+ lines=10,
229
+ placeholder="AI 回答將顯示在這裡"
230
+ )
231
+
232
+ # 事件處理器
233
+ api_key_input.submit(set_api_key, inputs=api_key_input, outputs=api_key_status)
234
+ model_choice.change(set_model, inputs=model_choice, outputs=model_status)
235
  summary_btn.click(generate_summary, inputs=pdf_upload, outputs=summary_output)
 
 
 
 
236
  question_btn.click(ask_question, inputs=question_input, outputs=answer_output)
237
+ question_input.submit(ask_question, inputs=question_input, outputs=answer_output)
238
+ clear_btn.click(clear_all, outputs=[summary_output, question_input, answer_output])
239
 
240
+ if __name__ == "__main__":
241
+ demo.launch(
242
+ server_name="0.0.0.0",
243
+ server_port=7860,
244
+ show_api=False
245
+ )