Upload app.py
Browse files
app.py
CHANGED
@@ -2,14 +2,9 @@ import gradio as gr
|
|
2 |
import re
|
3 |
from docx import Document
|
4 |
from docx.shared import Cm, Pt
|
5 |
-
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
|
6 |
-
from docx.enum.style import WD_STYLE_TYPE
|
7 |
-
from docx.oxml.ns import qn
|
8 |
-
from docx.oxml import OxmlElement
|
9 |
import tempfile
|
10 |
import os
|
11 |
|
12 |
-
|
13 |
def format_docx(file, chapter_keywords):
|
14 |
"""
|
15 |
處理上傳的 Word 文件
|
@@ -21,13 +16,17 @@ def format_docx(file, chapter_keywords):
|
|
21 |
return None, "請輸入章節分段方式(例如:章,節,話)"
|
22 |
|
23 |
try:
|
24 |
-
from docx import Document
|
25 |
-
from docx.shared import Cm, Pt
|
26 |
-
import re
|
27 |
-
import tempfile
|
28 |
-
|
29 |
doc = Document(file.name)
|
30 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
# 解析章節關鍵字
|
32 |
keywords = [keyword.strip() for keyword in chapter_keywords.split(',')]
|
33 |
|
@@ -86,10 +85,6 @@ def format_docx(file, chapter_keywords):
|
|
86 |
return None, f"❌ 處理失敗:{str(e)}"
|
87 |
|
88 |
def create_interface():
|
89 |
-
|
90 |
-
"""
|
91 |
-
建立 Gradio 介面
|
92 |
-
"""
|
93 |
with gr.Blocks(title="Word 文件格式化工具", theme=gr.themes.Soft()) as demo:
|
94 |
gr.HTML("""
|
95 |
<div style="text-align: center; margin-bottom: 20px;">
|
@@ -97,44 +92,33 @@ def create_interface():
|
|
97 |
<p>自動格式化您的 Word 文件,設定章節樣式和分頁</p>
|
98 |
</div>
|
99 |
""")
|
100 |
-
|
101 |
with gr.Row():
|
102 |
with gr.Column(scale=1):
|
103 |
-
# 檔案上傳
|
104 |
file_input = gr.File(
|
105 |
label="上傳 Word 文件 (.docx)",
|
106 |
file_types=[".docx"],
|
107 |
file_count="single"
|
108 |
)
|
109 |
-
|
110 |
-
# 章節關鍵字輸入
|
111 |
chapter_input = gr.Textbox(
|
112 |
label="章節分段方式",
|
113 |
placeholder="章,節,話",
|
114 |
info="請輸入章節關鍵字,用逗號分隔(例如:章,節,話)",
|
115 |
value="章,節,話"
|
116 |
)
|
117 |
-
|
118 |
-
# 處理按鈕
|
119 |
process_btn = gr.Button("🔄 開始處理", variant="primary", size="lg")
|
120 |
-
|
121 |
with gr.Column(scale=1):
|
122 |
-
# 狀態顯示
|
123 |
status_output = gr.Textbox(
|
124 |
label="處理狀態",
|
125 |
interactive=False,
|
126 |
lines=3
|
127 |
)
|
128 |
-
|
129 |
-
# 下載連結
|
130 |
download_output = gr.File(
|
131 |
label="下載處理後的文件",
|
132 |
interactive=False
|
133 |
)
|
134 |
-
|
135 |
-
#
|
136 |
-
gr.HTML("""
|
137 |
-
<div style="margin-top: 30px; padding: 20px; background-color: #f8f9fa; border-radius: 10px;">
|
138 |
<h3>🛠️ 處理功能說明</h3>
|
139 |
<ul>
|
140 |
<li><strong>樣式調整:</strong>將所有段落設定為無間距樣式</li>
|
@@ -144,12 +128,9 @@ def create_interface():
|
|
144 |
<li><strong>標題格式:</strong>章節標題設定為粗體標題 1 樣式(無縮排)</li>
|
145 |
<li><strong>分頁設定:</strong>每個章節前自動分頁</li>
|
146 |
</ul>
|
147 |
-
</div>
|
148 |
-
|
149 |
-
|
150 |
-
# 使用範例
|
151 |
-
gr.HTML("""
|
152 |
-
<div style="margin-top: 20px; padding: 20px; background-color: #e8f4f8; border-radius: 10px;">
|
153 |
<h3>💡 使用範例</h3>
|
154 |
<p><strong>章節關鍵字設定:</strong></p>
|
155 |
<ul>
|
@@ -167,23 +148,16 @@ def create_interface():
|
|
167 |
<li>第I章、第II章、第III章...</li>
|
168 |
<li>第二十三章、第三十四節...</li>
|
169 |
</ul>
|
170 |
-
</div>
|
171 |
-
|
172 |
-
|
173 |
-
# 綁定事件
|
174 |
process_btn.click(
|
175 |
fn=format_docx,
|
176 |
inputs=[file_input, chapter_input],
|
177 |
outputs=[download_output, status_output]
|
178 |
)
|
179 |
-
|
180 |
return demo
|
181 |
|
182 |
-
# 建立並啟動介面
|
183 |
if __name__ == "__main__":
|
184 |
demo = create_interface()
|
185 |
-
demo.launch(
|
186 |
-
server_name="0.0.0.0",
|
187 |
-
server_port=7860,
|
188 |
-
share=True
|
189 |
-
)
|
|
|
2 |
import re
|
3 |
from docx import Document
|
4 |
from docx.shared import Cm, Pt
|
|
|
|
|
|
|
|
|
5 |
import tempfile
|
6 |
import os
|
7 |
|
|
|
8 |
def format_docx(file, chapter_keywords):
|
9 |
"""
|
10 |
處理上傳的 Word 文件
|
|
|
16 |
return None, "請輸入章節分段方式(例如:章,節,話)"
|
17 |
|
18 |
try:
|
|
|
|
|
|
|
|
|
|
|
19 |
doc = Document(file.name)
|
20 |
|
21 |
+
# 確保有 Heading 1 樣式
|
22 |
+
from docx.enum.style import WD_STYLE_TYPE
|
23 |
+
styles = doc.styles
|
24 |
+
if 'Heading 1' not in styles:
|
25 |
+
heading_style = styles.add_style('Heading 1', WD_STYLE_TYPE.PARAGRAPH)
|
26 |
+
heading_style.base_style = styles['Normal']
|
27 |
+
heading_style.font.bold = True
|
28 |
+
heading_style.font.size = Pt(16)
|
29 |
+
|
30 |
# 解析章節關鍵字
|
31 |
keywords = [keyword.strip() for keyword in chapter_keywords.split(',')]
|
32 |
|
|
|
85 |
return None, f"❌ 處理失敗:{str(e)}"
|
86 |
|
87 |
def create_interface():
|
|
|
|
|
|
|
|
|
88 |
with gr.Blocks(title="Word 文件格式化工具", theme=gr.themes.Soft()) as demo:
|
89 |
gr.HTML("""
|
90 |
<div style="text-align: center; margin-bottom: 20px;">
|
|
|
92 |
<p>自動格式化您的 Word 文件,設定章節樣式和分頁</p>
|
93 |
</div>
|
94 |
""")
|
95 |
+
|
96 |
with gr.Row():
|
97 |
with gr.Column(scale=1):
|
|
|
98 |
file_input = gr.File(
|
99 |
label="上傳 Word 文件 (.docx)",
|
100 |
file_types=[".docx"],
|
101 |
file_count="single"
|
102 |
)
|
|
|
|
|
103 |
chapter_input = gr.Textbox(
|
104 |
label="章節分段方式",
|
105 |
placeholder="章,節,話",
|
106 |
info="請輸入章節關鍵字,用逗號分隔(例如:章,節,話)",
|
107 |
value="章,節,話"
|
108 |
)
|
|
|
|
|
109 |
process_btn = gr.Button("🔄 開始處理", variant="primary", size="lg")
|
|
|
110 |
with gr.Column(scale=1):
|
|
|
111 |
status_output = gr.Textbox(
|
112 |
label="處理狀態",
|
113 |
interactive=False,
|
114 |
lines=3
|
115 |
)
|
|
|
|
|
116 |
download_output = gr.File(
|
117 |
label="下載處理後的文件",
|
118 |
interactive=False
|
119 |
)
|
120 |
+
|
121 |
+
gr.HTML("""<div style="margin-top: 30px; padding: 20px; background-color: #f8f9fa; border-radius: 10px;">
|
|
|
|
|
122 |
<h3>🛠️ 處理功能說明</h3>
|
123 |
<ul>
|
124 |
<li><strong>樣式調整:</strong>將所有段落設定為無間距樣式</li>
|
|
|
128 |
<li><strong>標題格式:</strong>章節標題設定為粗體標題 1 樣式(無縮排)</li>
|
129 |
<li><strong>分頁設定:</strong>每個章節前自動分頁</li>
|
130 |
</ul>
|
131 |
+
</div>""")
|
132 |
+
|
133 |
+
gr.HTML("""<div style="margin-top: 20px; padding: 20px; background-color: #e8f4f8; border-radius: 10px;">
|
|
|
|
|
|
|
134 |
<h3>💡 使用範例</h3>
|
135 |
<p><strong>章節關鍵字設定:</strong></p>
|
136 |
<ul>
|
|
|
148 |
<li>第I章、第II章、第III章...</li>
|
149 |
<li>第二十三章、第三十四節...</li>
|
150 |
</ul>
|
151 |
+
</div>""")
|
152 |
+
|
|
|
|
|
153 |
process_btn.click(
|
154 |
fn=format_docx,
|
155 |
inputs=[file_input, chapter_input],
|
156 |
outputs=[download_output, status_output]
|
157 |
)
|
158 |
+
|
159 |
return demo
|
160 |
|
|
|
161 |
if __name__ == "__main__":
|
162 |
demo = create_interface()
|
163 |
+
demo.launch(server_name="0.0.0.0", server_port=7860, share=True)
|
|
|
|
|
|
|
|