File size: 19,430 Bytes
690cf25
4a1af2e
690cf25
 
 
 
 
 
 
 
 
 
b2b9458
690cf25
 
 
 
 
 
 
 
 
 
b2b9458
 
 
690cf25
 
 
 
 
 
b2b9458
 
690cf25
 
ea6bf79
690cf25
 
 
 
 
 
b2b9458
690cf25
 
 
b2b9458
 
 
690cf25
 
 
 
 
b2b9458
 
 
690cf25
 
 
 
 
 
b2b9458
690cf25
 
b2b9458
690cf25
 
b2b9458
690cf25
b2b9458
 
 
690cf25
 
 
 
b2b9458
 
 
690cf25
 
 
 
 
 
 
 
 
 
 
 
b2b9458
 
690cf25
 
b2b9458
690cf25
 
 
 
b2b9458
690cf25
 
 
 
 
 
 
 
 
 
 
 
 
ea6bf79
690cf25
 
 
 
 
 
 
 
 
 
b2b9458
690cf25
 
 
 
b2b9458
690cf25
 
 
 
b2b9458
 
690cf25
 
ea1a78f
 
 
 
 
 
 
 
 
 
 
e50b8c7
 
ea1a78f
 
 
 
 
 
 
 
 
 
4a1af2e
 
 
 
ea1a78f
 
 
 
 
 
690cf25
b2b9458
690cf25
 
 
 
 
 
 
b2b9458
690cf25
 
 
 
b2b9458
 
 
 
 
 
690cf25
b2b9458
690cf25
b2b9458
 
 
 
690cf25
b2b9458
690cf25
b2b9458
 
 
 
 
 
 
 
 
ea6bf79
b2b9458
ea6bf79
b2b9458
ea6bf79
b2b9458
 
 
690cf25
b2b9458
690cf25
 
 
b2b9458
690cf25
44c2693
 
b2b9458
 
 
 
44c2693
 
 
 
 
 
 
 
b2b9458
 
44c2693
 
 
 
 
b2b9458
ea1a78f
e50b8c7
4a1af2e
ea1a78f
 
b2b9458
 
 
 
 
 
 
 
44c2693
b2b9458
 
 
 
 
 
 
 
 
 
44c2693
b2b9458
 
ea6bf79
b2b9458
ea6bf79
 
 
 
 
 
 
 
 
b2b9458
ea6bf79
 
 
 
 
 
 
 
 
b2b9458
 
 
 
 
 
 
44c2693
 
b2b9458
 
 
 
 
 
 
 
 
 
690cf25
 
b2b9458
690cf25
 
 
b2b9458
 
 
 
 
 
690cf25
 
 
 
 
b2b9458
690cf25
 
 
 
 
 
 
 
 
 
 
b2b9458
690cf25
 
 
 
 
 
 
 
 
 
44c2693
 
b2b9458
 
 
44c2693
b2b9458
44c2693
 
 
 
 
 
 
b2b9458
 
44c2693
 
b2b9458
44c2693
 
 
 
 
b2b9458
44c2693
b2b9458
 
44c2693
b2b9458
 
 
 
 
44c2693
b2b9458
 
 
 
44c2693
b2b9458
 
 
 
 
 
 
 
 
 
 
 
 
 
44c2693
4a1af2e
b2b9458
 
 
 
 
 
 
 
690cf25
b2b9458
 
 
 
 
 
 
 
 
 
44c2693
 
b2b9458
 
 
 
 
 
 
 
690cf25
 
b2b9458
690cf25
 
 
 
 
 
 
 
 
 
 
 
 
 
b2b9458
690cf25
 
 
 
 
 
 
b2b9458
690cf25
 
 
b2b9458
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
import streamlit as st
import streamlit.components.v1 as components
import hashlib
import urllib.parse
from datetime import datetime
import pytz
import pandas as pd
import json

# --- Constants ---
MELBOURNE_TIMEZONE = 'Australia/Melbourne'

# --- Custom CSS for simplified UI ---
def load_css():
    st.markdown("""
    <style>
    .main-header {
        padding: 2rem;
        text-align: center;
        margin-bottom: 2rem;
    }
    
    .citation-output {
        background: #f8f8f8;
        border: 1px solid #e0e0e0;
        border-radius: 4px;
        padding: 1rem;
        margin: 1rem 0;
        font-family: 'Courier New', monospace;
    }
    
    .copy-button {
        background: #e0e0e0;
        color: black;
        border: none;
        padding: 0.5rem 1rem;
        border-radius: 4px;
        cursor: pointer;
        font-size: 0.9rem;
        margin-top: 0.5rem;
    }
    
    .copy-button:hover {
        background: #d0d0d0;
    }
    
    .warning-box {
        background: #f8f8f8;
        border: 1px solid #e0e0e0;
        border-radius: 4px;
        padding: 1rem;
        margin: 1rem 0;
    }
    
    .success-box {
        background: #f8f8f8;
        border: 1px solid #e0e0e0;
        border-radius: 4px;
        padding: 1rem;
        margin: 1rem 0;
    }
    
    .info-card {
        background: white;
        border-radius: 4px;
        padding: 1.5rem;
        margin: 1rem 0;
        border-left: 1px solid #e0e0e0;
    }
    
    .footer {
        text-align: center;
        padding: 2rem;
        margin-top: 2rem;
        border-top: 1px solid #e0e0e0;
        font-size: 0.9rem;
    }
    
    .hash-display {
        background: #f8f8f8;
        border: 1px solid #e0e0e0;
        border-radius: 4px;
        padding: 1rem;
        font-family: 'Courier New', monospace;
        font-size: 0.85rem;
        word-break: break-all;
        margin: 0.5rem 0;
    }
    
    .tab-content {
        padding: 2rem 0;
    }
    
    .datetime-display {
        background: #f8f8f8;
        border-radius: 4px;
        padding: 0.8rem;
        margin: 0.5rem 0;
        border-left: 1px solid #e0e0e0;
    }
    
    .verification-table {
        margin: 1rem 0;
        border-radius: 4px;
        overflow: hidden;
    }
    </style>
    """, unsafe_allow_html=True)

# --- Helper Functions ---
def generate_citation_hash(author, year, url, fragment_text, cited_text, username, task_name, current_date, current_time):
    data = f"{author}, {year} | {url} | {fragment_text} | {cited_text} | {username} | {task_name} | {current_date} | {current_time}"
    return hashlib.sha256(data.encode('utf-8')).hexdigest()

def format_citation_html(url, fragment_text, author, year, scc_hash):
    encoded_fragment = urllib.parse.quote(fragment_text)
    full_url = f"{url}#:~:text={encoded_fragment}"
    return f'<a href="{full_url}" data-hash="{scc_hash}">{author}, {year}</a>'

def check_for_fragment(url):
    return '#:~:text=' in url

def copy_to_clipboard_js(text, button_id):
    """Generate JavaScript for copying text to clipboard"""
    return f"""
    <script>
    function copyToClipboard_{button_id}() {{
        navigator.clipboard.writeText(`{text}`).then(function() {{
            document.getElementById('copy_status_{button_id}').innerHTML = 'Copied!';
            setTimeout(function() {{
                document.getElementById('copy_status_{button_id}').innerHTML = '';
            }}, 2000);
        }}, function(err) {{
            document.getElementById('copy_status_{button_id}').innerHTML = 'Copy failed';
            console.error('Could not copy text: ', err);
        }});
    }}
    </script>
    <button onclick="copyToClipboard_{button_id}()" class="copy-button">Copy to Clipboard</button>
    <span id="copy_status_{button_id}" style="margin-left: 10px; font-weight: bold;"></span>
    """

# --- Live Clock JavaScript ---
def live_clock():
    return """
    <div class="datetime-display">
        <span id="live_datetime"></span>
    </div>
    <script>
        function updateClock() {
            const options = {
                timeZone: 'Australia/Melbourne',
                year: 'numeric',
                month: '2-digit',
                day: '2-digit',
                hour: '2-digit',
                minute: '2-digit',
                second: '2-digit',
                hour12: false
            };
            const formatter = new Intl.DateTimeFormat('en-AU', options);
            const now = new Date();
            const parts = formatter.formatToParts(now);
            const date = `${parts[4].value}-${parts[2].value}-${parts[0].value}`;
            const time = `${parts[6].value}:${parts[8].value}:${parts[10].value}`;
            const datetimeElement = document.getElementById('live_datetime');
            if (datetimeElement) {
                datetimeElement.innerText = `${date} ${time}`;
            }
        }
        updateClock();
        setInterval(updateClock, 1000);
    </script>
    """

# --- Streamlit App ---
st.set_page_config(layout="wide", page_title="Smart Context Citation Tool")

# Load custom CSS
load_css()

# Main header
st.markdown("""
<div class="main-header">
    <h1>Smart Context Citation (SCC) Tool</h1>
    <p>Next-generation digital referencing system for the age of Generative AI</p>
</div>
""", unsafe_allow_html=True)

# Expandable section for About and Example
with st.expander("About SCC and Example Citation"):
    st.markdown("""
    <div class="info-card">
    <h3>About SCC</h3>
    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.

    <strong>Purpose:</strong> Transparency, integrity, and digital fluency in citations.

    <strong>Structure:</strong>
    - Inline general author name and date style citation
    - Hyperlinked URL with text fragment (#:~:text=)
    - SHA-256 hash for verification

    <strong>Benefits:</strong> Enhances fairness, integrates with source contexts, promotes digital fluency, prevents fabrication, and eliminates traditional reference lists.

    <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.
    </div>
    
    <div class="info-card">
    <h3>Example Citation</h3>
    <strong>Input:</strong><br>
    - Author: <code>Abuseif et al.</code><br>
    - Year: <code>2025</code><br>
    - URL: <code>https://www.sciencedirect.com/science/article/pii/S2772411523000046</code><br>
    - Text: <code>A proposed design framework for green roof settings in general and trees on buildings</code><br>

    <strong>Output (HTML):</strong><br>
    <div class="hash-display">
    &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;
    </div>
    </div>
    """, unsafe_allow_html=True)

tabs = st.tabs(["Citation Generator", "Verify Citation"])

with tabs[0]:
    st.markdown('<div class="tab-content">', unsafe_allow_html=True)
    st.header("Generate New Citation")

    # User Information Section
    st.subheader("User Information")
    col1, col2 = st.columns(2)
    with col1:
        username = st.text_input("Username", help="Your username for tracking purposes", placeholder="e.g., john_doe")
    with col2:
        task_name = st.text_input("Task Name", help="The name of the task or project", placeholder="e.g., Literature Review Assignment")

    # Citation Info Section
    st.subheader("Citation Info")
    col3, col4 = st.columns(2)
    with col3:
        author_name = st.text_input("Author(s) Name", help="The author(s) of the source", placeholder="e.g., Smith or Smith et al.")
    with col4:
        publication_year = st.text_input("Publication Year", help="The year of publication", placeholder="e.g., 2023")
    
    col5, col6 = st.columns(2)
    with col5:
        source_url = st.text_input("Source URL", help="The full URL of the source", placeholder="https://example.com/article")
    with col6:
        annotated_text = st.text_input("Annotated Text", help="The text quoted or paraphrased from the source", placeholder="e.g., Thermal comfort thresholds...")

    # Live date and time display
    st.markdown("### Current Date and Time")
    components.html(live_clock(), height=50)

    # Get current date and time in Melbourne timezone for hash generation
    melbourne_tz = pytz.timezone(MELBOURNE_TIMEZONE)
    current_datetime_melbourne = datetime.now(melbourne_tz)
    current_date = current_datetime_melbourne.strftime("%Y-%m-%d")
    current_time = current_datetime_melbourne.strftime("%H:%M:%S")

    generate_button = st.button("Generate Citation", type="primary", use_container_width=True)

    if generate_button:
        if not all([username, task_name, author_name, publication_year, source_url, annotated_text]):
            st.error("Please fill in all fields before generating a citation.")
        elif check_for_fragment(source_url):
            st.markdown("""
            <div class="warning-box">
                <strong>Warning:</strong> It seems like your URL already contains a text fragment (<code>#:~:text=</code>). 
                This suggests you may have used AI assistance in generating this link. Please go back to the original source, 
                read the context carefully, and copy the source link again without any existing fragment.
            </div>
            """, unsafe_allow_html=True)
        else:
            scc_hash = generate_citation_hash(author_name, publication_year, source_url, annotated_text, annotated_text, username, task_name, current_date, current_time)

            st.markdown("## Generated Citations")
            col_html1, col_html2 = st.columns(2)

            # HTML Citation - Start of Text
            with col_html1:
                st.markdown("### HTML Citation (Start of Text)")
                html_citation_start = f'"{annotated_text}" (<a href="{source_url}#:~:text={urllib.parse.quote(annotated_text)}" data-hash="{scc_hash}">{author_name}, {publication_year}</a>)'
                
                st.markdown('<div class="citation-output">', unsafe_allow_html=True)
                st.code(html_citation_start, language='html')
                st.markdown(copy_to_clipboard_js(html_citation_start.replace('`', '\\`'), "html_start"), unsafe_allow_html=True)
                st.markdown('</div>', unsafe_allow_html=True)

            # HTML Citation - End of Text
            with col_html2:
                st.markdown("### HTML Citation (End of Text)")
                html_citation_end = f'(<a href="{source_url}#:~:text={urllib.parse.quote(annotated_text)}" data-hash="{scc_hash}">{author_name}, {publication_year}</a>) "{annotated_text}"'
                
                st.markdown('<div class="citation-output">', unsafe_allow_html=True)
                st.code(html_citation_end, language='html')
                st.markdown(copy_to_clipboard_js(html_citation_end.replace('`', '\\`'), "html_end"), unsafe_allow_html=True)
                st.markdown('</div>', unsafe_allow_html=True)

            # Citation Hash Details
            st.markdown("### Citation Hash Details (for Verification)")
            hash_details = {
                "author": author_name,
                "year": publication_year,
                "url": source_url,
                "fragment_text": annotated_text,
                "cited_text": annotated_text,
                "username": username,
                "task_name": task_name,
                "date": current_date,
                "time": current_time,
                "hash": scc_hash
            }
            
            st.markdown('<div class="hash-display">', unsafe_allow_html=True)
            st.json(hash_details)
            st.markdown('</div>', unsafe_allow_html=True)

    # Instructions section
    st.markdown("## Instructions for Copying to Word")
    st.markdown("""
    <div class="info-card">
    <strong>To use the generated HTML citation in Microsoft Word:</strong><br><br>
    1. Copy the desired HTML citation (Start or End of Text) using the 'Copy to Clipboard' button<br>
    2. In Word, go to the 'Insert' tab<br>
    3. Click on 'Object' → 'Text from File...'<br>
    4. Select 'HTML Document' from the file type dropdown<br>
    5. Paste the copied HTML into a new text file (e.g., using Notepad) and save it with a <code>.html</code> extension<br>
    6. Select this <code>.html</code> file in the 'Text from File...' dialog<br><br>
    
    <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.
    </div>
    """, unsafe_allow_html=True)

    st.markdown("## Guidance on Verifying Citations")
    st.markdown("""
    <div class="info-card">
    To verify a citation, you can recompute the hash using the original input data and compare it to the embedded hash. 
    The <strong>'Verify Citation'</strong> tab allows you to do this easily.
    </div>
    """, unsafe_allow_html=True)
    
    st.markdown('</div>', unsafe_allow_html=True)

with tabs[1]:
    st.markdown('<div class="tab-content">', unsafe_allow_html=True)
    st.header("Verify Citation")
    st.markdown("""
    <div class="info-card">
    Enter the citation details below to recompute and verify the hash. This ensures the citation hasn't been tampered with or fabricated.
    </div>
    """, unsafe_allow_html=True)

    # Initialize session state for storing verified hashes
    if 'verified_hashes' not in st.session_state:
        st.session_state.verified_hashes = []

    # User Information Section
    st.subheader("User Information")
    col1, col2 = st.columns(2)
    with col1:
        verify_username = st.text_input("Username (for verification)", placeholder="e.g., john_doe")
    with col2:
        verify_task_name = st.text_input("Task Name (for verification)", placeholder="e.g., Literature Review Assignment")

    # Citation Info Section
    st.subheader("Citation Info")
    col3, col4 = st.columns(2)
    with col3:
        verify_author_name = st.text_input("Author(s) Name (for verification)", placeholder="e.g., Smith or Smith et al.")
    with col4:
        verify_publication_year = st.text_input("Publication Year (for verification)", placeholder="e.g., 2023")
    
    col5, col6 = st.columns(2)
    with col5:
        verify_source_url = st.text_input("Source URL (for verification)", placeholder="https://example.com/article")
    with col6:
        verify_annotated_text = st.text_input("Annotated Text (for verification)", placeholder="e.g., Thermal comfort thresholds...")
    
    col7, col8 = st.columns(2)
    with col7:
        verify_date = st.text_input("Date (YYYY-MM-DD) (for verification)", placeholder="e.g., 2025-01-08")
    with col8:
        verify_time = st.text_input("Time (HH:MM:SS) (for verification)", placeholder="e.g., 14:30:25")
    
    expected_hash = st.text_input("Expected Hash (from the citation)", placeholder="Enter the full hash from the citation")

    verify_button = st.button("Verify Hash", type="primary", use_container_width=True)

    if verify_button:
        if not all([verify_username, verify_task_name, verify_author_name, verify_publication_year, 
                   verify_source_url, verify_annotated_text, verify_date, verify_time, expected_hash]):
            st.error("Please fill in all fields before verifying the hash.")
        else:
            recomputed_hash = generate_citation_hash(
                verify_author_name, verify_publication_year, verify_source_url,
                verify_annotated_text, verify_annotated_text, verify_username, verify_task_name,
                verify_date, verify_time
            )

            if recomputed_hash == expected_hash:
                st.markdown("""
                <div class="success-box">
                    <strong>Hash verified successfully!</strong> The citation is authentic and hasn't been tampered with.
                </div>
                """, unsafe_allow_html=True)
                
                st.session_state.verified_hashes.append({
                    "Author": verify_author_name,
                    "Year": verify_publication_year,
                    "URL": verify_source_url,
                    "Fragment text": verify_annotated_text,
                    "Outlined text": verify_annotated_text,
                    "Username": verify_username,
                    "Task name": verify_task_name,
                    "Date": verify_date,
                    "Time": verify_time,
                    "Original Hash": expected_hash,
                    "Recomputed Hash": recomputed_hash,
                    "Status": "Verified"
                })
            else:
                st.markdown("""
                <div class="warning-box">
                    <strong>Hash verification failed!</strong> The citation may have been altered or is not authentic.
                </div>
                """, unsafe_allow_html=True)
                
                st.session_state.verified_hashes.append({
                    "Author": verify_author_name,
                    "Year": verify_publication_year,
                    "URL": verify_source_url,
                    "Fragment text": verify_annotated_text,
                    "Cited text": verify_annotated_text,
                    "Username": verify_username,
                    "Task name": verify_task_name,
                    "Date": verify_date,
                    "Time": verify_time,
                    "Original Hash": expected_hash,
                    "Recomputed Hash": recomputed_hash,
                    "Status": "Failed"
                })

    if st.session_state.verified_hashes:
        st.markdown("## Verification History")
        df = pd.DataFrame(st.session_state.verified_hashes)
        
        st.markdown('<div class="verification-table">', unsafe_allow_html=True)
        st.dataframe(df, use_container_width=True)
        st.markdown('</div>', unsafe_allow_html=True)

        # Download as CSV
        @st.cache_data
        def convert_df_to_csv(df):
            return df.to_csv(index=False).encode('utf-8')

        csv = convert_df_to_csv(df)

        st.download_button(
            label="Download Verification History as CSV",
            data=csv,
            file_name="scc_verification_history.csv",
            mime="text/csv",
            use_container_width=True
        )
        
        # Clear history button
        if st.button("Clear Verification History", type="secondary"):
            st.session_state.verified_hashes = []
            st.experimental_rerun()
    
    st.markdown('</div>', unsafe_allow_html=True)

# Footer
st.markdown("""
<div class="footer">
    Developed by: Dr Majed Abuseif<br>
    School of Architecture and Built Environment<br>
    Deakin University<br>
    © 2025
</div>
""", unsafe_allow_html=True)