mabuseif commited on
Commit
690cf25
Β·
verified Β·
1 Parent(s): d40a75c

Upload 3 files

Browse files
Files changed (3) hide show
  1. README.md +109 -19
  2. app.py +480 -0
  3. requirements.txt +3 -2
README.md CHANGED
@@ -1,19 +1,109 @@
1
- ---
2
- title: SCC
3
- emoji: πŸš€
4
- colorFrom: red
5
- colorTo: red
6
- sdk: docker
7
- app_port: 8501
8
- tags:
9
- - streamlit
10
- pinned: false
11
- short_description: Smart Context Citation Tool
12
- ---
13
-
14
- # Welcome to Streamlit!
15
-
16
- Edit `/src/streamlit_app.py` to customize this app to your heart's desire. :heart:
17
-
18
- If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
19
- forums](https://discuss.streamlit.io).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Smart Context Citation (SCC) Tool
2
+
3
+ A Python-based tool designed for Hugging Face Spaces that automates the implementation of the Smart Context Citation (SCC) referencing style.
4
+
5
+ ## Overview
6
+
7
+ The Smart Context Citation (SCC) style is a next-generation digital referencing system designed to address the evolving landscape of academic writing in the age of Generative AI (GenAI) and online information dependency. It redefines citation practices by embedding citation context directly in the document, eliminating the need for traditional reference lists, and using cryptographic hash signatures to ensure citation integrity.
8
+
9
+ ## Features
10
+
11
+ ### Citation Generator Tab
12
+ - Input fields for username, task name, author name, publication year, source URL, and cited text
13
+ - Automatic date and time display (Melbourne, Australia timezone)
14
+ - Generation of SCC-compliant citations in HTML and plaintext formats
15
+ - SHA-256 hash generation for citation integrity
16
+ - Copy-to-clipboard functionality for all outputs
17
+ - Warning system for URLs that already contain text fragments
18
+ - Comprehensive SCC style documentation and instructions
19
+
20
+ ### Verify Citation Tab
21
+ - Hash verification system to check citation authenticity
22
+ - Table display of verification history
23
+ - Download verification history as CSV file
24
+ - Support for multiple hash verification
25
+
26
+ ## SCC Style Benefits
27
+
28
+ - **Integrity**: Prevents citation manipulation or fabrication
29
+ - **Transparency**: Readers see exactly what was cited
30
+ - **Efficiency**: Eliminates duplication in reference lists
31
+ - **Digital Fluency**: Reflects real-world web-based research behavior
32
+ - **AI-Resistant**: Makes it difficult for GenAI tools to generate fake or superficial citations
33
+
34
+ ## Installation and Setup
35
+
36
+ ### For Hugging Face Spaces
37
+
38
+ 1. Create a new Space on Hugging Face
39
+ 2. Upload the following files:
40
+ - `app.py` (main application)
41
+ - `requirements.txt` (dependencies)
42
+ - `README.md` (this file)
43
+ 3. Set the Space SDK to "Streamlit"
44
+ 4. The app will automatically deploy
45
+
46
+ ### For Local Development
47
+
48
+ 1. Clone or download the repository
49
+ 2. Install dependencies:
50
+ ```bash
51
+ pip install -r requirements.txt
52
+ ```
53
+ 3. Run the application:
54
+ ```bash
55
+ streamlit run app.py
56
+ ```
57
+
58
+ ## Usage Examples
59
+
60
+ ### Example Citation Generation
61
+
62
+ **Input:**
63
+ - Author: `Abuseif et al.`
64
+ - Year: `2025`
65
+ - URL: `https://www.sciencedirect.com/science/article/pii/S2772411523000046`
66
+ - Text: `A proposed design framework for green roof settings in general and trees on buildings`
67
+
68
+ **Output (HTML):**
69
+ ```html
70
+ <a href="https://www.sciencedirect.com/science/article/pii/S2772411523000046#:~:text=A%20proposed%20design%20framework%20for%20green%20roof%20settings%20in%20general%20and%20trees%20on%20buildings" data-hash="[GENERATED_HASH]">(Abuseif et al., 2025)</a>
71
+ ```
72
+
73
+ **Output (Plaintext):**
74
+ ```
75
+ (Abuseif et al., 2025) [hash: a78c45f91e2d...]
76
+ ```
77
+
78
+ ## Technical Details
79
+
80
+ ### Hash Generation
81
+ The SHA-256 hash is generated from the concatenated string:
82
+ ```
83
+ Author, Year | URL | Fragment text | Cited text | username | task name | date | time
84
+ ```
85
+
86
+ ### Text Fragment Support
87
+ The tool uses the Text Fragments WICG specification to create URLs that highlight specific text passages in modern browsers using the `#:~:text=` syntax.
88
+
89
+ ## Dependencies
90
+
91
+ - `streamlit`: Web application framework
92
+ - `pytz`: Timezone handling for Melbourne, Australia timezone
93
+ - `pandas`: Data manipulation for verification history
94
+
95
+ ## Creator
96
+
97
+ Developed by: Dr Majed Abuseif
98
+ School of Architecture and Built Environment
99
+ Deakin University
100
+ Β© 2025
101
+
102
+ ## Technical Legitimacy
103
+
104
+ This tool references the [Text Fragments WICG specification](https://wicg.github.io/scroll-to-text-fragment/) to reinforce the technical legitimacy of the approach.
105
+
106
+ ## License
107
+
108
+ Β© 2025 Dr Majed Abuseif, Deakin University. All rights reserved.
109
+
app.py ADDED
@@ -0,0 +1,480 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import streamlit as st
3
+ import hashlib
4
+ import urllib.parse
5
+ from datetime import datetime
6
+ import pytz
7
+ import pandas as pd
8
+ import json
9
+
10
+ # --- Constants ---
11
+ MELBOURNE_TIMEZONE = 'Australia/Melbourne'
12
+
13
+ # --- Custom CSS for enhanced UI ---
14
+ def load_css():
15
+ st.markdown("""
16
+ <style>
17
+ .main-header {
18
+ background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
19
+ padding: 2rem;
20
+ border-radius: 10px;
21
+ color: white;
22
+ text-align: center;
23
+ margin-bottom: 2rem;
24
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
25
+ }
26
+
27
+ .citation-output {
28
+ background: #f8f9fa;
29
+ border: 2px solid #e9ecef;
30
+ border-radius: 8px;
31
+ padding: 1rem;
32
+ margin: 1rem 0;
33
+ font-family: 'Courier New', monospace;
34
+ position: relative;
35
+ }
36
+
37
+ .copy-button {
38
+ background: #28a745;
39
+ color: white;
40
+ border: none;
41
+ padding: 0.5rem 1rem;
42
+ border-radius: 5px;
43
+ cursor: pointer;
44
+ font-size: 0.9rem;
45
+ margin-top: 0.5rem;
46
+ transition: background-color 0.3s;
47
+ }
48
+
49
+ .copy-button:hover {
50
+ background: #218838;
51
+ }
52
+
53
+ .warning-box {
54
+ background: #fff3cd;
55
+ border: 1px solid #ffeaa7;
56
+ border-radius: 8px;
57
+ padding: 1rem;
58
+ margin: 1rem 0;
59
+ color: #856404;
60
+ }
61
+
62
+ .success-box {
63
+ background: #d4edda;
64
+ border: 1px solid #c3e6cb;
65
+ border-radius: 8px;
66
+ padding: 1rem;
67
+ margin: 1rem 0;
68
+ color: #155724;
69
+ }
70
+
71
+ .info-card {
72
+ background: white;
73
+ border-radius: 10px;
74
+ padding: 1.5rem;
75
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
76
+ margin: 1rem 0;
77
+ border-left: 4px solid #667eea;
78
+ }
79
+
80
+ .creator-info {
81
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
82
+ color: white;
83
+ padding: 1rem;
84
+ border-radius: 8px;
85
+ text-align: center;
86
+ margin: 2rem 0;
87
+ font-size: 0.9rem;
88
+ }
89
+
90
+ .hash-display {
91
+ background: #f1f3f4;
92
+ border: 1px solid #dadce0;
93
+ border-radius: 6px;
94
+ padding: 1rem;
95
+ font-family: 'Courier New', monospace;
96
+ font-size: 0.85rem;
97
+ word-break: break-all;
98
+ margin: 0.5rem 0;
99
+ }
100
+
101
+ .tab-content {
102
+ padding: 2rem 0;
103
+ }
104
+
105
+ .form-section {
106
+ background: white;
107
+ padding: 2rem;
108
+ border-radius: 10px;
109
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
110
+ margin: 1rem 0;
111
+ }
112
+
113
+ .datetime-display {
114
+ background: #e3f2fd;
115
+ border-radius: 6px;
116
+ padding: 0.8rem;
117
+ margin: 0.5rem 0;
118
+ border-left: 4px solid #2196f3;
119
+ }
120
+
121
+ .verification-table {
122
+ margin: 1rem 0;
123
+ border-radius: 8px;
124
+ overflow: hidden;
125
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
126
+ }
127
+ </style>
128
+ """, unsafe_allow_html=True)
129
+
130
+ # --- Helper Functions ---
131
+ def generate_citation_hash(author, year, url, fragment_text, cited_text, username, task_name, current_date, current_time):
132
+ data = f"{author}, {year} | {url} | {fragment_text} | {cited_text} | {username} | {task_name} | {current_date} | {current_time}"
133
+ return hashlib.sha256(data.encode('utf-8')).hexdigest()
134
+
135
+ def format_citation_html(url, fragment_text, author, year, scc_hash):
136
+ encoded_fragment = urllib.parse.quote(fragment_text)
137
+ full_url = f"{url}#:~:text={encoded_fragment}"
138
+ return f'<a href="{full_url}" data-hash="{scc_hash}">({author}, {year})</a>'
139
+
140
+ def format_citation_plaintext(author, year, scc_hash):
141
+ return f'({author}, {year}) [hash: {scc_hash[:12]}...]'
142
+
143
+ def check_for_fragment(url):
144
+ return '#:~:text=' in url
145
+
146
+ def copy_to_clipboard_js(text, button_id):
147
+ """Generate JavaScript for copying text to clipboard"""
148
+ return f"""
149
+ <script>
150
+ function copyToClipboard_{button_id}() {{
151
+ navigator.clipboard.writeText(`{text}`).then(function() {{
152
+ document.getElementById('copy_status_{button_id}').innerHTML = 'βœ… Copied!';
153
+ setTimeout(function() {{
154
+ document.getElementById('copy_status_{button_id}').innerHTML = '';
155
+ }}, 2000);
156
+ }}, function(err) {{
157
+ document.getElementById('copy_status_{button_id}').innerHTML = '❌ Copy failed';
158
+ console.error('Could not copy text: ', err);
159
+ }});
160
+ }}
161
+ </script>
162
+ <button onclick="copyToClipboard_{button_id}()" class="copy-button">πŸ“‹ Copy to Clipboard</button>
163
+ <span id="copy_status_{button_id}" style="margin-left: 10px; color: green; font-weight: bold;"></span>
164
+ """
165
+
166
+ # --- Streamlit App ---
167
+ st.set_page_config(layout="wide", page_title="Smart Context Citation Tool", page_icon="πŸ“š")
168
+
169
+ # Load custom CSS
170
+ load_css()
171
+
172
+ # Main header
173
+ st.markdown("""
174
+ <div class="main-header">
175
+ <h1>πŸ“š Smart Context Citation (SCC) Tool</h1>
176
+ <p>Next-generation digital referencing system for the age of Generative AI</p>
177
+ </div>
178
+ """, unsafe_allow_html=True)
179
+
180
+ # Creator information
181
+ st.markdown("""
182
+ <div class="creator-info">
183
+ <strong>Developed by:</strong> Dr Majed Abuseif<br>
184
+ School of Architecture and Built Environment<br>
185
+ Deakin University<br>
186
+ Β© 2025
187
+ </div>
188
+ """, unsafe_allow_html=True)
189
+
190
+ st.sidebar.header("πŸ“– About SCC")
191
+ st.sidebar.markdown("""
192
+ <div class="info-card">
193
+ The Smart Context Citation (SCC) style is a next-generation digital referencing system designed for the age of Generative AI. It embeds citation context directly in the document, uses cryptographic hash signatures for integrity, and eliminates traditional reference lists.
194
+
195
+ <strong>🎯 Purpose:</strong> Transparency, integrity, and digital fluency in citations.
196
+
197
+ <strong>πŸ—οΈ Structure:</strong>
198
+ β€’ Inline general author name and date style citation
199
+ β€’ Hyperlinked URL with text fragment (#:~:text=)
200
+ β€’ SHA-256 hash for verification
201
+
202
+ <strong>✨ Benefits:</strong> Enhances fairness, integrates with source contexts, promotes digital fluency, prevents fabrication, and eliminates traditional reference lists.
203
+
204
+ <strong>πŸ”— Technical Legitimacy:</strong> Referencing the <a href="https://wicg.github.io/scroll-to-text-fragment/" target="_blank">Text Fragments WICG specification</a> for technical legitimacy.
205
+ </div>
206
+ """, unsafe_allow_html=True)
207
+
208
+ st.sidebar.header("πŸ’‘ Example Citation")
209
+ st.sidebar.markdown("""
210
+ <div class="info-card">
211
+ <strong>πŸ“ Input:</strong><br>
212
+ β€’ Author: <code>Abuseif et al.</code><br>
213
+ β€’ Year: <code>2025</code><br>
214
+ β€’ URL: <code>https://www.sciencedirect.com/science/article/pii/S2772411523000046</code><br>
215
+ β€’ Text: <code>A proposed design framework for green roof settings in general and trees on buildings</code>
216
+
217
+ <strong>πŸ“€ Output (HTML - example hash):</strong><br>
218
+ <div class="hash-display">
219
+ &lt;a href="https://www.sciencedirect.com/science/article/pii/S2772411523000046#:~:text=A%20proposed%20design%20framework%20for%20green%20roof%20settings%20in%20general%20and%20trees%20on%20buildings" data-hash="[GENERATED_HASH]"&gt;(Abuseif et al., 2025)&lt;/a&gt;
220
+ </div>
221
+ </div>
222
+ """, unsafe_allow_html=True)
223
+
224
+ tabs = st.tabs(["πŸ”§ Citation Generator", "βœ… Verify Citation"])
225
+
226
+ with tabs[0]:
227
+ st.markdown('<div class="tab-content">', unsafe_allow_html=True)
228
+ st.header("πŸ”§ Generate New Citation")
229
+
230
+ with st.container():
231
+ st.markdown('<div class="form-section">', unsafe_allow_html=True)
232
+
233
+ col1, col2 = st.columns(2)
234
+
235
+ with col1:
236
+ username = st.text_input("πŸ‘€ Username", help="Your username for tracking purposes", placeholder="e.g., john_doe")
237
+ task_name = st.text_input("πŸ“‹ Task Name", help="The name of the task or project", placeholder="e.g., Literature Review Assignment")
238
+ author_name = st.text_input("✍️ Author Name", help="The author(s) of the source", placeholder="e.g., Smith or Smith et al.")
239
+
240
+ with col2:
241
+ publication_year = st.text_input("πŸ“… Publication Year", help="The year of publication", placeholder="e.g., 2023")
242
+ source_url = st.text_input("πŸ”— Source URL", help="The full URL of the source", placeholder="https://example.com/article")
243
+
244
+ cited_text = st.text_area("πŸ“ Quoted or Paraphrased Text",
245
+ help="The exact text quoted or paraphrased from the source",
246
+ placeholder="e.g., Thermal comfort thresholds are exceeded frequently in Australian schools",
247
+ height=100)
248
+
249
+ # Get current date and time in Melbourne timezone
250
+ melbourne_tz = pytz.timezone(MELBOURNE_TIMEZONE)
251
+ current_datetime_melbourne = datetime.now(melbourne_tz)
252
+ current_date = current_datetime_melbourne.strftime("%Y-%m-%d")
253
+ current_time = current_datetime_melbourne.strftime("%H:%M:%S")
254
+
255
+ st.markdown(f"""
256
+ <div class="datetime-display">
257
+ <strong>πŸ• Current Date & Time (Melbourne, Australia):</strong><br>
258
+ πŸ“… Date: {current_date}<br>
259
+ ⏰ Time: {current_time}
260
+ </div>
261
+ """, unsafe_allow_html=True)
262
+
263
+ generate_button = st.button("πŸš€ Generate Citation", type="primary", use_container_width=True)
264
+
265
+ st.markdown('</div>', unsafe_allow_html=True)
266
+
267
+ if generate_button:
268
+ if not all([username, task_name, author_name, publication_year, source_url, cited_text]):
269
+ st.error("⚠️ Please fill in all fields before generating a citation.")
270
+ elif check_for_fragment(source_url):
271
+ st.markdown("""
272
+ <div class="warning-box">
273
+ <strong>⚠️ Warning:</strong> It seems like your URL already contains a text fragment (<code>#:~:text=</code>).
274
+ This suggests you may have used AI assistance in generating this link. Please go back to the original source,
275
+ read the context carefully, and copy the source link again without any existing fragment.
276
+ </div>
277
+ """, unsafe_allow_html=True)
278
+ else:
279
+ scc_hash = generate_citation_hash(author_name, publication_year, source_url, cited_text, cited_text, username, task_name, current_date, current_time)
280
+
281
+ st.markdown("## πŸŽ‰ Generated Citations")
282
+
283
+ # HTML Citation - Start of text
284
+ st.markdown("### πŸ“ HTML Citation (Start of Text)")
285
+ html_citation_start = f'"{cited_text}" ' + format_citation_html(source_url, cited_text, author_name, publication_year, scc_hash)
286
+
287
+ st.markdown('<div class="citation-output">', unsafe_allow_html=True)
288
+ st.code(html_citation_start, language='html')
289
+ st.markdown(copy_to_clipboard_js(html_citation_start.replace('`', '\\`'), "html_start"), unsafe_allow_html=True)
290
+ st.markdown('</div>', unsafe_allow_html=True)
291
+
292
+ # HTML Citation - End of text
293
+ st.markdown("### πŸ“ HTML Citation (End of Text)")
294
+ html_citation_end = format_citation_html(source_url, cited_text, author_name, publication_year, scc_hash) + f' "{cited_text}"'
295
+
296
+ st.markdown('<div class="citation-output">', unsafe_allow_html=True)
297
+ st.code(html_citation_end, language='html')
298
+ st.markdown(copy_to_clipboard_js(html_citation_end.replace('`', '\\`'), "html_end"), unsafe_allow_html=True)
299
+ st.markdown('</div>', unsafe_allow_html=True)
300
+
301
+ # Plaintext Citation
302
+ st.markdown("### πŸ“„ Plaintext Citation")
303
+ plaintext_citation = format_citation_plaintext(author_name, publication_year, scc_hash)
304
+
305
+ st.markdown('<div class="citation-output">', unsafe_allow_html=True)
306
+ st.code(plaintext_citation)
307
+ st.markdown(copy_to_clipboard_js(plaintext_citation, "plaintext"), unsafe_allow_html=True)
308
+ st.markdown('</div>', unsafe_allow_html=True)
309
+
310
+ # Citation Hash Details
311
+ st.markdown("### πŸ” Citation Hash Details (for Verification)")
312
+ hash_details = {
313
+ "author": author_name,
314
+ "year": publication_year,
315
+ "url": source_url,
316
+ "fragment_text": cited_text,
317
+ "cited_text": cited_text,
318
+ "username": username,
319
+ "task_name": task_name,
320
+ "date": current_date,
321
+ "time": current_time,
322
+ "hash": scc_hash
323
+ }
324
+
325
+ st.markdown('<div class="hash-display">', unsafe_allow_html=True)
326
+ st.json(hash_details)
327
+ st.markdown('</div>', unsafe_allow_html=True)
328
+
329
+ # Instructions section
330
+ st.markdown("## πŸ“‹ Instructions for Copying to Word")
331
+ st.markdown("""
332
+ <div class="info-card">
333
+ <strong>To use the generated HTML citation in Microsoft Word:</strong><br><br>
334
+ 1. πŸ“‹ Copy the desired HTML citation (Start or End of Text) using the 'Copy to Clipboard' button<br>
335
+ 2. πŸ“„ In Word, go to the 'Insert' tab<br>
336
+ 3. πŸ”— Click on 'Object' β†’ 'Text from File...'<br>
337
+ 4. πŸ“ Select 'HTML Document' from the file type dropdown<br>
338
+ 5. πŸ’Ύ Paste the copied HTML into a new text file (e.g., using Notepad) and save it with a <code>.html</code> extension<br>
339
+ 6. βœ… Select this <code>.html</code> file in the 'Text from File...' dialog<br><br>
340
+
341
+ <strong>Alternative method:</strong> You might be able to paste directly into Word and then right-click and choose 'Keep Source Formatting' or 'Merge Formatting' if available, but the 'Text from File' method is more reliable for preserving hyperlinks and data attributes.
342
+ </div>
343
+ """, unsafe_allow_html=True)
344
+
345
+ st.markdown("## πŸ” Guidance on Verifying Citations")
346
+ st.markdown("""
347
+ <div class="info-card">
348
+ To verify a citation, you can recompute the hash using the original input data and compare it to the embedded hash.
349
+ The <strong>'Verify Citation'</strong> tab allows you to do this easily.
350
+ </div>
351
+ """, unsafe_allow_html=True)
352
+
353
+ st.markdown('</div>', unsafe_allow_html=True)
354
+
355
+ with tabs[1]:
356
+ st.markdown('<div class="tab-content">', unsafe_allow_html=True)
357
+ st.header("βœ… Verify Citation")
358
+ st.markdown("""
359
+ <div class="info-card">
360
+ Enter the citation details below to recompute and verify the hash. This ensures the citation hasn't been tampered with or fabricated.
361
+ </div>
362
+ """, unsafe_allow_html=True)
363
+
364
+ # Initialize session state for storing verified hashes
365
+ if 'verified_hashes' not in st.session_state:
366
+ st.session_state.verified_hashes = []
367
+
368
+ with st.container():
369
+ st.markdown('<div class="form-section">', unsafe_allow_html=True)
370
+
371
+ col1, col2 = st.columns(2)
372
+
373
+ with col1:
374
+ verify_username = st.text_input("πŸ‘€ Username (for verification)", placeholder="e.g., john_doe")
375
+ verify_task_name = st.text_input("πŸ“‹ Task Name (for verification)", placeholder="e.g., Literature Review Assignment")
376
+ verify_author_name = st.text_input("✍️ Author Name (for verification)", placeholder="e.g., Smith or Smith et al.")
377
+ verify_publication_year = st.text_input("πŸ“… Publication Year (for verification)", placeholder="e.g., 2023")
378
+
379
+ with col2:
380
+ verify_source_url = st.text_input("πŸ”— Source URL (for verification)", placeholder="https://example.com/article")
381
+ verify_date = st.text_input("πŸ“… Date (YYYY-MM-DD) (for verification)", placeholder="e.g., 2025-01-08")
382
+ verify_time = st.text_input("⏰ Time (HH:MM:SS) (for verification)", placeholder="e.g., 14:30:25")
383
+ expected_hash = st.text_input("πŸ” Expected Hash (from the citation)", placeholder="Enter the full hash from the citation")
384
+
385
+ verify_cited_text = st.text_area("πŸ“ Quoted or Paraphrased Text (for verification)",
386
+ placeholder="e.g., Thermal comfort thresholds are exceeded frequently in Australian schools",
387
+ height=100)
388
+
389
+ verify_button = st.button("πŸ” Verify Hash", type="primary", use_container_width=True)
390
+
391
+ st.markdown('</div>', unsafe_allow_html=True)
392
+
393
+ if verify_button:
394
+ if not all([verify_username, verify_task_name, verify_author_name, verify_publication_year,
395
+ verify_source_url, verify_cited_text, verify_date, verify_time, expected_hash]):
396
+ st.error("⚠️ Please fill in all fields before verifying the hash.")
397
+ else:
398
+ recomputed_hash = generate_citation_hash(
399
+ verify_author_name, verify_publication_year, verify_source_url,
400
+ verify_cited_text, verify_cited_text, verify_username, verify_task_name,
401
+ verify_date, verify_time
402
+ )
403
+
404
+ if recomputed_hash == expected_hash:
405
+ st.markdown("""
406
+ <div class="success-box">
407
+ <strong>βœ… Hash verified successfully!</strong> The citation is authentic and hasn't been tampered with.
408
+ </div>
409
+ """, unsafe_allow_html=True)
410
+
411
+ st.session_state.verified_hashes.append({
412
+ "Author": verify_author_name,
413
+ "Year": verify_publication_year,
414
+ "URL": verify_source_url,
415
+ "Fragment text": verify_cited_text,
416
+ "Cited text": verify_cited_text,
417
+ "Username": verify_username,
418
+ "Task name": verify_task_name,
419
+ "Date": verify_date,
420
+ "Time": verify_time,
421
+ "Original Hash": expected_hash,
422
+ "Recomputed Hash": recomputed_hash,
423
+ "Status": "βœ… Verified"
424
+ })
425
+ else:
426
+ st.markdown("""
427
+ <div class="warning-box">
428
+ <strong>❌ Hash verification failed!</strong> The citation may have been altered or is not authentic.
429
+ </div>
430
+ """, unsafe_allow_html=True)
431
+
432
+ st.session_state.verified_hashes.append({
433
+ "Author": verify_author_name,
434
+ "Year": verify_publication_year,
435
+ "URL": verify_source_url,
436
+ "Fragment text": verify_cited_text,
437
+ "Cited text": verify_cited_text,
438
+ "Username": verify_username,
439
+ "Task name": verify_task_name,
440
+ "Date": verify_date,
441
+ "Time": verify_time,
442
+ "Original Hash": expected_hash,
443
+ "Recomputed Hash": recomputed_hash,
444
+ "Status": "❌ Failed"
445
+ })
446
+
447
+ if st.session_state.verified_hashes:
448
+ st.markdown("## πŸ“Š Verification History")
449
+ df = pd.DataFrame(st.session_state.verified_hashes)
450
+
451
+ st.markdown('<div class="verification-table">', unsafe_allow_html=True)
452
+ st.dataframe(df, use_container_width=True)
453
+ st.markdown('</div>', unsafe_allow_html=True)
454
+
455
+ # Download as CSV
456
+ @st.cache_data
457
+ def convert_df_to_csv(df):
458
+ return df.to_csv(index=False).encode('utf-8')
459
+
460
+ csv = convert_df_to_csv(df)
461
+
462
+ st.download_button(
463
+ label="πŸ“₯ Download Verification History as CSV",
464
+ data=csv,
465
+ file_name="scc_verification_history.csv",
466
+ mime="text/csv",
467
+ use_container_width=True
468
+ )
469
+
470
+ # Clear history button
471
+ if st.button("πŸ—‘οΈ Clear Verification History", type="secondary"):
472
+ st.session_state.verified_hashes = []
473
+ st.experimental_rerun()
474
+
475
+ st.markdown('</div>', unsafe_allow_html=True)
476
+
477
+
478
+
479
+
480
+
requirements.txt CHANGED
@@ -1,3 +1,4 @@
1
- altair
 
2
  pandas
3
- streamlit
 
1
+ streamlit
2
+ pytz
3
  pandas
4
+