danielhjerresen commited on
Commit
4656a03
·
verified ·
1 Parent(s): e421562

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +252 -38
src/streamlit_app.py CHANGED
@@ -1,40 +1,254 @@
1
- import altair as alt
2
- import numpy as np
3
- import pandas as pd
4
  import streamlit as st
 
5
 
6
- """
7
- # Welcome to Streamlit!
8
-
9
- Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
10
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
11
- forums](https://discuss.streamlit.io).
12
-
13
- In the meantime, below is an example of what you can do with just a few lines of code:
14
- """
15
-
16
- num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
17
- num_turns = st.slider("Number of turns in spiral", 1, 300, 31)
18
-
19
- indices = np.linspace(0, 1, num_points)
20
- theta = 2 * np.pi * num_turns * indices
21
- radius = indices
22
-
23
- x = radius * np.cos(theta)
24
- y = radius * np.sin(theta)
25
-
26
- df = pd.DataFrame({
27
- "x": x,
28
- "y": y,
29
- "idx": indices,
30
- "rand": np.random.randn(num_points),
31
- })
32
-
33
- st.altair_chart(alt.Chart(df, height=700, width=700)
34
- .mark_point(filled=True)
35
- .encode(
36
- x=alt.X("x", axis=None),
37
- y=alt.Y("y", axis=None),
38
- color=alt.Color("idx", legend=None, scale=alt.Scale()),
39
- size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
40
- ))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
+ import fitz
3
 
4
+ from pdf_counter import count_characters
5
+
6
+
7
+ # ============================================================
8
+ # PAGE CONFIGURATION
9
+ # ============================================================
10
+ # Sets the browser tab title and makes the app use the full
11
+ # available screen width.
12
+
13
+ st.set_page_config(
14
+ page_title="PDF Character Counter",
15
+ layout="wide",
16
+ )
17
+
18
+
19
+ # ============================================================
20
+ # APP TITLE AND DESCRIPTION
21
+ # ============================================================
22
+ # Displays the main heading and short explanation of the app.
23
+
24
+ st.title("PDF Character Counter")
25
+ st.write(
26
+ "Counts characters including spaces and can automatically remove headers, footers, and page numbers."
27
+ )
28
+
29
+
30
+ # ============================================================
31
+ # PDF UPLOAD
32
+ # ============================================================
33
+ # Allows the user to upload a PDF file.
34
+
35
+ uploaded_file = st.file_uploader(
36
+ "Upload PDF",
37
+ type=["pdf"],
38
+ )
39
+
40
+
41
+ # ============================================================
42
+ # MAIN APP LOGIC
43
+ # ============================================================
44
+ # Runs only after the user has uploaded a PDF.
45
+
46
+ if uploaded_file:
47
+
48
+ # Read the uploaded PDF as bytes.
49
+ pdf_bytes = uploaded_file.read()
50
+
51
+ # Open the PDF with PyMuPDF so we can count the pages.
52
+ doc = fitz.open(
53
+ stream=pdf_bytes,
54
+ filetype="pdf",
55
+ )
56
+
57
+ page_count = len(doc)
58
+
59
+ # --------------------------------------------------------
60
+ # SETTINGS SECTION
61
+ # --------------------------------------------------------
62
+ # Lets the user choose pages to exclude and whether headers,
63
+ # footers, and page numbers should be removed.
64
+
65
+ st.subheader("Settings")
66
+
67
+ excluded_pages = st.multiselect(
68
+ "Exclude pages",
69
+ options=list(range(1, page_count + 1)),
70
+ default=[],
71
+ )
72
+
73
+ col1, col2, col3 = st.columns(3)
74
+
75
+ with col1:
76
+ remove_headers = st.checkbox(
77
+ "Remove headers",
78
+ value=True,
79
+ )
80
+
81
+ with col2:
82
+ remove_footers = st.checkbox(
83
+ "Remove footers",
84
+ value=True,
85
+ )
86
+
87
+ with col3:
88
+ remove_page_numbers = st.checkbox(
89
+ "Remove page numbers",
90
+ value=True,
91
+ )
92
+
93
+ # --------------------------------------------------------
94
+ # CHARACTER COUNTING
95
+ # --------------------------------------------------------
96
+ # Sends the uploaded PDF and selected settings to the
97
+ # counting function in pdf_counter.py.
98
+
99
+ result = count_characters(
100
+ pdf_bytes=pdf_bytes,
101
+ excluded_pages=set(excluded_pages),
102
+ remove_headers=remove_headers,
103
+ remove_footers=remove_footers,
104
+ remove_page_numbers=remove_page_numbers,
105
+ )
106
+
107
+ st.divider()
108
+
109
+ # --------------------------------------------------------
110
+ # TOTAL CHARACTER COUNT
111
+ # --------------------------------------------------------
112
+ # Displays the total number of characters counted.
113
+
114
+ st.metric(
115
+ "Characters including spaces",
116
+ f"{result['total_characters']:,}".replace(",", "."),
117
+ )
118
+
119
+ st.divider()
120
+
121
+ # --------------------------------------------------------
122
+ # REMOVED ELEMENTS SUMMARY
123
+ # --------------------------------------------------------
124
+ # Splits removed elements into headers, footers, and
125
+ # page numbers so they can be shown separately.
126
+
127
+ st.subheader("Elements removed from the count")
128
+
129
+ removed_items = result["removed_items"]
130
+
131
+ removed_headers = [
132
+ item
133
+ for item in removed_items
134
+ if item["Type"] in ["Sidehoved", "Løbende sidehoved"]
135
+ ]
136
+
137
+ removed_footers = [
138
+ item
139
+ for item in removed_items
140
+ if item["Type"] == "Sidefod"
141
+ ]
142
+
143
+ removed_page_numbers = [
144
+ item
145
+ for item in removed_items
146
+ if item["Type"] == "Sidetal"
147
+ ]
148
+
149
+ col1, col2, col3 = st.columns(3)
150
+
151
+ with col1:
152
+ st.metric(
153
+ "Headers removed",
154
+ len(removed_headers),
155
+ )
156
+
157
+ with col2:
158
+ st.metric(
159
+ "Footers removed",
160
+ len(removed_footers),
161
+ )
162
+
163
+ with col3:
164
+ st.metric(
165
+ "Page numbers removed",
166
+ len(removed_page_numbers),
167
+ )
168
+
169
+ # --------------------------------------------------------
170
+ # REMOVED HEADERS TABLE
171
+ # --------------------------------------------------------
172
+ # Shows the specific header elements that were removed.
173
+
174
+ with st.expander("Show removed headers"):
175
+
176
+ if removed_headers:
177
+ st.dataframe(
178
+ removed_headers,
179
+ use_container_width=True,
180
+ )
181
+ else:
182
+ st.info("No headers were removed.")
183
+
184
+ # --------------------------------------------------------
185
+ # REMOVED FOOTERS TABLE
186
+ # --------------------------------------------------------
187
+ # Shows the specific footer elements that were removed.
188
+
189
+ with st.expander("Show removed footers"):
190
+
191
+ if removed_footers:
192
+ st.dataframe(
193
+ removed_footers,
194
+ use_container_width=True,
195
+ )
196
+ else:
197
+ st.info("No footers were removed.")
198
+
199
+ # --------------------------------------------------------
200
+ # REMOVED PAGE NUMBERS TABLE
201
+ # --------------------------------------------------------
202
+ # Shows the specific page numbers that were removed.
203
+
204
+ with st.expander("Show removed page numbers"):
205
+
206
+ if removed_page_numbers:
207
+ st.dataframe(
208
+ removed_page_numbers,
209
+ use_container_width=True,
210
+ )
211
+ else:
212
+ st.info("No page numbers were removed.")
213
+
214
+ st.divider()
215
+
216
+ # --------------------------------------------------------
217
+ # PAGE-BY-PAGE RESULTS
218
+ # --------------------------------------------------------
219
+ # Displays the character count for each page.
220
+
221
+ st.subheader("Result per page")
222
+
223
+ st.dataframe(
224
+ result["page_results"],
225
+ use_container_width=True,
226
+ )
227
+
228
+ st.divider()
229
+
230
+ # --------------------------------------------------------
231
+ # INCLUDED TEXT PREVIEW
232
+ # --------------------------------------------------------
233
+ # Lets the user inspect the exact text that was included
234
+ # in the final character count.
235
+
236
+ with st.expander("View text included in the count"):
237
+
238
+ st.text_area(
239
+ "Text",
240
+ result["included_text"],
241
+ height=400,
242
+ )
243
+
244
+ # --------------------------------------------------------
245
+ # TEXT DOWNLOAD
246
+ # --------------------------------------------------------
247
+ # Allows the user to download the counted text as a TXT file.
248
+
249
+ st.download_button(
250
+ label="Download text as TXT",
251
+ data=result["included_text"],
252
+ file_name="counted_text.txt",
253
+ mime="text/plain",
254
+ )