job2023 commited on
Commit
fbdb5d7
·
verified ·
1 Parent(s): 298c50f

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +290 -0
app.py ADDED
@@ -0,0 +1,290 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import requests
3
+ import gradio as gr
4
+ from openai import OpenAI
5
+ from bs4 import BeautifulSoup
6
+ from dotenv import load_dotenv
7
+
8
+ # Load environment variables from .env file (for local development)
9
+ load_dotenv()
10
+
11
+ # Get API key from environment variable
12
+ TYPHOON_API_KEY = os.environ.get("TYPHOON_API_KEY")
13
+ if not TYPHOON_API_KEY:
14
+ print("Warning: TYPHOON_API_KEY not found in environment variables.")
15
+ print("Please set it in your .env file or in your Cloudflare environment variables.")
16
+
17
+ class URLSummarizer:
18
+ """A class to summarize web content and output summaries in Thai with Markdown formatting."""
19
+
20
+ def __init__(self):
21
+ """Initialize the summarizer with API key from environment."""
22
+ # Initialize the OpenAI client with the API key from environment
23
+ self.client = OpenAI(
24
+ api_key=TYPHOON_API_KEY,
25
+ base_url='https://api.opentyphoon.ai/v1'
26
+ )
27
+ self.message_counter = 1
28
+
29
+ def load_from_url(self, url):
30
+ """Load content from a URL using BeautifulSoup for better text extraction."""
31
+ try:
32
+ response = requests.get(url, timeout=30)
33
+ response.raise_for_status()
34
+
35
+ # Parse the HTML with BeautifulSoup
36
+ soup = BeautifulSoup(response.text, 'html.parser')
37
+
38
+ # Remove script and style elements
39
+ for script in soup(["script", "style"]):
40
+ script.extract()
41
+
42
+ # Get text
43
+ text = soup.get_text(separator=' ', strip=True)
44
+
45
+ # Break into lines and remove leading/trailing space
46
+ lines = (line.strip() for line in text.splitlines())
47
+ # Break multi-headlines into a line each
48
+ chunks = (phrase.strip() for line in lines for phrase in line.split(" "))
49
+ # Remove blank lines
50
+ text = '\n'.join(chunk for chunk in chunks if chunk)
51
+
52
+ return text
53
+ except Exception as e:
54
+ return f"Error: {str(e)}"
55
+
56
+ def chunk_text(self, text, chunk_size=10000):
57
+ """Split text into manageable chunks."""
58
+ words = text.split()
59
+ chunks = []
60
+ current_chunk = []
61
+ current_size = 0
62
+
63
+ for word in words:
64
+ if current_size + len(word) + 1 > chunk_size:
65
+ chunks.append(' '.join(current_chunk))
66
+ current_chunk = [word]
67
+ current_size = len(word)
68
+ else:
69
+ current_chunk.append(word)
70
+ current_size += len(word) + 1
71
+
72
+ if current_chunk:
73
+ chunks.append(' '.join(current_chunk))
74
+
75
+ return chunks
76
+
77
+ def summarize_chunk(self, content, is_chunk=False, chunk_num=0, total_chunks=1):
78
+ """Summarize a single chunk of content with Markdown formatting."""
79
+ if not self.client:
80
+ return "## ⚠️ ข้อผิดพลาด\nAPI key ไม่ถูกกำหนด"
81
+
82
+ try:
83
+ # Create message with appropriate context
84
+ chunk_context = ""
85
+ if is_chunk:
86
+ chunk_context = f"This is part {chunk_num} of {total_chunks} of the full content. "
87
+
88
+ messages = [
89
+ {"role": "system", "content": "You are a professional summarizer. Create a comprehensive summary in Thai language using Markdown formatting for better readability."},
90
+ {"role": "user", "content": f"""{chunk_context}Please summarize the following content according to these guidelines:
91
+
92
+ 1. Focus on key points, main concepts, and important details
93
+ 2. Use clear section headings with markdown (## for headings)
94
+ 3. Use **bold** for emphasis on important terms
95
+ 4. Use *italics* for names, titles, and secondary emphasis
96
+ 5. Use bullet points or numbered lists where appropriate
97
+ 6. Use markdown block quotes (>) for quotations or highlighted text
98
+ 7. Format for easy reading with paragraph breaks
99
+ 8. {'' if is_chunk else f"End with [End of Summary, Message #{self.message_counter}]"}
100
+
101
+ CONTENT TO SUMMARIZE:
102
+ {content}
103
+ """}
104
+ ]
105
+
106
+ # Make API call
107
+ response = self.client.chat.completions.create(
108
+ model="typhoon-v2-70b-instruct",
109
+ messages=messages,
110
+ max_tokens=2000,
111
+ temperature=0.3
112
+ )
113
+
114
+ return response.choices[0].message.content
115
+ except Exception as e:
116
+ return f"## ⚠️ ข้อผิดพลาด\nเกิดปัญหาในการสรุปส่วนที่ {chunk_num}: {str(e)}"
117
+
118
+ def combine_summaries(self, summaries):
119
+ """Combine multiple chunk summaries into one coherent summary with Markdown."""
120
+ if not self.client:
121
+ return "## ⚠️ ข้อผิดพลาด\nAPI key ไม่ถูกกำหนด"
122
+
123
+ combined_text = "\n\n".join(summaries)
124
+
125
+ try:
126
+ messages = [
127
+ {"role": "system", "content": "You are a professional summarizer. Create a comprehensive summary in Thai language using Markdown formatting for better readability."},
128
+ {"role": "user", "content": f"""Please combine these summaries into one coherent summary according to these guidelines:
129
+
130
+ 1. Ensure the summary flows naturally as one complete text
131
+ 2. Remove any redundancies or repetitions
132
+ 3. Ensure all key information is preserved
133
+ 4. Use markdown formatting to enhance readability:
134
+ - ## for section headings
135
+ - **bold** for important terms
136
+ - *italics* for names and titles
137
+ - Bullet points or numbered lists where appropriate
138
+ - > blockquotes for important quotes
139
+ 5. Add a # main title at the top
140
+ 6. End with [End of Summary, Message #{self.message_counter}]
141
+
142
+ SUMMARIES TO COMBINE:
143
+ {combined_text}
144
+ """}
145
+ ]
146
+
147
+ # Make API call
148
+ response = self.client.chat.completions.create(
149
+ model="typhoon-v2-70b-instruct",
150
+ messages=messages,
151
+ max_tokens=2000,
152
+ temperature=0.3
153
+ )
154
+
155
+ self.message_counter += 1
156
+ return response.choices[0].message.content
157
+ except Exception as e:
158
+ return f"## ⚠️ ข้อผิดพลาด\nเกิดปัญหาในการรวมบทสรุป: {str(e)}"
159
+
160
+ def summarize_url(self, url, progress=gr.Progress()):
161
+ """Process a URL and generate a summary with Markdown formatting."""
162
+ # Check if API client is initialized
163
+ if not TYPHOON_API_KEY:
164
+ return "## ⚠️ ข้อผิดพลาด\nไม่พบ API key ในการตั้งค่าสภาพแวดล้อม กรุณาตั้งค่า TYPHOON_API_KEY"
165
+
166
+ # Progress indicator
167
+ progress(0, desc="กำลังโหลดข้อมูลจาก URL...")
168
+
169
+ # Validate URL
170
+ if not url:
171
+ return "## ⚠️ ข้อผิดพลาด\nกรุณากรอก URL"
172
+
173
+ # Add https:// if missing
174
+ if not url.startswith(('http://', 'https://')):
175
+ url = 'https://' + url
176
+
177
+ # Load content from URL
178
+ content = self.load_from_url(url)
179
+
180
+ if not content or content.startswith("Error:"):
181
+ return content if content else "## ⚠️ ข้อผิดพลาด\nไม่สามารถดึงข้อมูลจาก URL ได้"
182
+
183
+ # Check if content is empty
184
+ if not content.strip():
185
+ return "## ⚠️ ข้อผิดพลาด\nไม่พบเนื้อหาจาก URL ที่ระบุ"
186
+
187
+ # Split into chunks if needed
188
+ chunks = self.chunk_text(content)
189
+ progress(0.2, desc="โหลดข้อมูลสำเร็จ")
190
+
191
+ summary = None
192
+
193
+ if len(chunks) == 1:
194
+ # Only one chunk, process directly
195
+ progress(0.4, desc="กำลังสรุปเนื้อหา...")
196
+ summary = self.summarize_chunk(chunks[0])
197
+ progress(0.9, desc="สรุปเนื้อหาเสร็จสิ้น!")
198
+ else:
199
+ # Multiple chunks, process each and then combine
200
+ progress(0.3, desc=f"เนื้อหายาวเกินไป แบ่งออกเป็น {len(chunks)} ส่วน")
201
+
202
+ chunk_summaries = []
203
+ for i, chunk in enumerate(chunks):
204
+ progress_val = 0.3 + (0.5 * (i / len(chunks)))
205
+ progress(progress_val, desc=f"กำลังสรุปส่วนที่ {i+1}/{len(chunks)}...")
206
+ summary = self.summarize_chunk(chunk, True, i+1, len(chunks))
207
+ if summary and not summary.startswith("## ⚠️ ข้อผิดพลาด"):
208
+ chunk_summaries.append(summary)
209
+
210
+ if not chunk_summaries:
211
+ return "## ⚠️ ข้อผิดพลาด\nไม่สามารถสรุปเนื้อหาได้"
212
+
213
+ if len(chunk_summaries) == 1:
214
+ summary = chunk_summaries[0]
215
+ else:
216
+ # Combine all summaries
217
+ progress(0.8, desc="กำลังรวมบทสรุปทั้งหมด...")
218
+ summary = self.combine_summaries(chunk_summaries)
219
+
220
+ progress(1.0, desc="สรุปเนื้อหาเสร็จสิ้น!")
221
+
222
+ if summary and not summary.startswith("## ⚠️ ข้อผิดพลาด"):
223
+ return summary
224
+ else:
225
+ return summary if summary else "## ⚠️ ข้อผิดพลาด\nไม่สามารถสรุปเนื้อหาได้"
226
+
227
+
228
+ # Set up Gradio interface
229
+ def create_interface():
230
+ summarizer = URLSummarizer()
231
+
232
+ with gr.Blocks(title="Thai URL Summarizer", theme=gr.themes.Soft()) as interface:
233
+ gr.Markdown("# 🇹🇭 Typhoon2 สรุปเนื้อหาจากเว็บไซต์ by เพจ ตื่นมาโค้ดpython")
234
+ gr.Markdown("ป้อน URL และรับบทสรุปที่ครอบคลุมเป็นภาษาไทย")
235
+
236
+ with gr.Row():
237
+ url_input = gr.Textbox(
238
+ label="URL",
239
+ placeholder="ใส่ URL เว็บไซต์ที่นี่ (เช่น https://example.com)",
240
+ lines=1
241
+ )
242
+
243
+ with gr.Row():
244
+ submit_btn = gr.Button("สร้างบทสรุป", variant="primary")
245
+
246
+ with gr.Row():
247
+ output = gr.Markdown(
248
+ label="บทสรุป (ภาษาไทย)",
249
+ value="บทสรุปจะปรากฏที่นี่"
250
+ )
251
+
252
+ with gr.Accordion("เกี่ยวกับเครื่องมือนี้", open=False):
253
+ gr.Markdown("""
254
+ ## เกี่ยวกับเครื่องมือนี้
255
+
256
+ เครื่องมือนี้ใช้โมเดล Typhoon v2-70b-instruct เพื่อสร้างบทสรุปที่ครอบคลุมของเนื้อหาเว็บในภาษาไทย พร้อมการจัดรูปแบบ Markdown เพื่อความอ่านง่าย
257
+
258
+ ### คุณสมบัติ:
259
+ - ประมวลผลเนื้อหาเว็บเพจใดก็ได้
260
+ - รองรับบทความยาวโดยการแบ่งออกเป็นส่วนย่อยและรวมบทสรุปเข้าด้วยกัน
261
+ - สร้างบทสรุปภาษาไทยที่มีโครงสร้างดีด้วยการจัดรูปแบบที่เหมาะสม
262
+ - รักษาข้อมูลสำคัญจากเนื้อหาต้นฉบับ
263
+
264
+ ### ข้อกำหนด:
265
+ - ต้องมีการเชื่อมต่ออินเทอร์เน็ตเพื่อเข้าถึงเนื้อหา URL
266
+
267
+ ### ประกาศความเป็นส่วนตัว:
268
+ - เนื้อหา URL จะถูกประมวลผลชั่วคราวและไม่ถูกจัดเก็บอย่างถาวร
269
+ """)
270
+
271
+ gr.Markdown("""
272
+ ### ตัวอย่างการใช้งาน
273
+ ลองใส่ URL ของเว็บไซต์ที่มีเนื้อหาภาษาไทย เช่น บทความข่าว, บล็อก, หรือเพจสินค้า แล้วคลิก "สร้างบทสรุป"
274
+
275
+ บทสรุปที่ได้จะรวมเนื้อหาสำคัญจากหน้าเว็บและนำเสนอในรูปแบบ Markdown พร้อมหัวข้อและการจัดรูปแบบที่อ่านง่าย
276
+ """)
277
+
278
+ # Set up the submission action
279
+ submit_btn.click(
280
+ fn=summarizer.summarize_url,
281
+ inputs=[url_input],
282
+ outputs=output
283
+ )
284
+
285
+ return interface
286
+
287
+ # Launch the Gradio app
288
+ if __name__ == "__main__":
289
+ app = create_interface()
290
+ app.launch(share=True)