Spaces:
Sleeping
Sleeping
Update ui.py
Browse files
ui.py
CHANGED
|
@@ -4,6 +4,7 @@ import pandas as pd
|
|
| 4 |
import asyncio
|
| 5 |
from datetime import datetime
|
| 6 |
import pytz
|
|
|
|
| 7 |
from config import APP_TITLE, EXAMPLE_QUERIES
|
| 8 |
from database import get_sample_data
|
| 9 |
|
|
@@ -12,24 +13,34 @@ def format_timestamp_to_cet(iso_timestamp):
|
|
| 12 |
try:
|
| 13 |
if not iso_timestamp or iso_timestamp == '':
|
| 14 |
return 'N/A'
|
| 15 |
-
|
| 16 |
# Handle different ISO timestamp formats
|
| 17 |
timestamp_str = str(iso_timestamp)
|
| 18 |
-
|
| 19 |
# Replace 'Z' with '+00:00' for proper ISO format
|
| 20 |
if timestamp_str.endswith('Z'):
|
| 21 |
timestamp_str = timestamp_str[:-1] + '+00:00'
|
| 22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
# Parse ISO timestamp
|
| 24 |
dt = datetime.fromisoformat(timestamp_str)
|
| 25 |
-
|
| 26 |
# Convert to CET timezone
|
| 27 |
cet = pytz.timezone('CET')
|
| 28 |
dt_cet = dt.astimezone(cet)
|
| 29 |
-
|
| 30 |
# Format as readable string: "2025-09-13 14:30 CET"
|
| 31 |
return dt_cet.strftime('%Y-%m-%d %H:%M CET')
|
| 32 |
-
|
| 33 |
except (ValueError, AttributeError, TypeError) as e:
|
| 34 |
# Fallback to original timestamp if parsing fails
|
| 35 |
print(f"[DEBUG] Failed to format timestamp '{iso_timestamp}': {e}")
|
|
@@ -526,6 +537,15 @@ def create_interface(agent):
|
|
| 526 |
font-size: 13px !important;
|
| 527 |
padding: 12px 16px !important;
|
| 528 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 529 |
}
|
| 530 |
|
| 531 |
@media (max-width: 480px) {
|
|
@@ -627,24 +647,28 @@ def create_interface(agent):
|
|
| 627 |
### Simulated Email History
|
| 628 |
All emails shown here are **mock emails** generated for demonstration purposes.
|
| 629 |
""")
|
| 630 |
-
|
| 631 |
-
|
| 632 |
-
|
| 633 |
-
|
| 634 |
-
|
| 635 |
-
|
| 636 |
-
|
| 637 |
-
|
| 638 |
-
|
| 639 |
-
|
| 640 |
-
|
| 641 |
-
|
| 642 |
-
|
| 643 |
-
|
| 644 |
-
|
| 645 |
-
|
| 646 |
-
|
| 647 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 648 |
|
| 649 |
# Database Explorer Tab
|
| 650 |
with gr.Tab("π Database Explorer"):
|
|
|
|
| 4 |
import asyncio
|
| 5 |
from datetime import datetime
|
| 6 |
import pytz
|
| 7 |
+
import re
|
| 8 |
from config import APP_TITLE, EXAMPLE_QUERIES
|
| 9 |
from database import get_sample_data
|
| 10 |
|
|
|
|
| 13 |
try:
|
| 14 |
if not iso_timestamp or iso_timestamp == '':
|
| 15 |
return 'N/A'
|
| 16 |
+
|
| 17 |
# Handle different ISO timestamp formats
|
| 18 |
timestamp_str = str(iso_timestamp)
|
| 19 |
+
|
| 20 |
# Replace 'Z' with '+00:00' for proper ISO format
|
| 21 |
if timestamp_str.endswith('Z'):
|
| 22 |
timestamp_str = timestamp_str[:-1] + '+00:00'
|
| 23 |
+
|
| 24 |
+
# Handle timestamps with more than 6 microsecond digits
|
| 25 |
+
# Python's fromisoformat() only supports up to 6 digits
|
| 26 |
+
# Match pattern: YYYY-MM-DDTHH:MM:SS.microseconds+timezone
|
| 27 |
+
match = re.match(r'(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2})\.(\d+)(.*)', timestamp_str)
|
| 28 |
+
if match:
|
| 29 |
+
date_time_part, microseconds, timezone_part = match.groups()
|
| 30 |
+
# Truncate microseconds to 6 digits max
|
| 31 |
+
microseconds = microseconds[:6]
|
| 32 |
+
timestamp_str = f"{date_time_part}.{microseconds}{timezone_part}"
|
| 33 |
+
|
| 34 |
# Parse ISO timestamp
|
| 35 |
dt = datetime.fromisoformat(timestamp_str)
|
| 36 |
+
|
| 37 |
# Convert to CET timezone
|
| 38 |
cet = pytz.timezone('CET')
|
| 39 |
dt_cet = dt.astimezone(cet)
|
| 40 |
+
|
| 41 |
# Format as readable string: "2025-09-13 14:30 CET"
|
| 42 |
return dt_cet.strftime('%Y-%m-%d %H:%M CET')
|
| 43 |
+
|
| 44 |
except (ValueError, AttributeError, TypeError) as e:
|
| 45 |
# Fallback to original timestamp if parsing fails
|
| 46 |
print(f"[DEBUG] Failed to format timestamp '{iso_timestamp}': {e}")
|
|
|
|
| 537 |
font-size: 13px !important;
|
| 538 |
padding: 12px 16px !important;
|
| 539 |
}
|
| 540 |
+
|
| 541 |
+
/* Email Activity tab: stack columns vertically on mobile */
|
| 542 |
+
.email-activity-row {
|
| 543 |
+
flex-direction: column !important;
|
| 544 |
+
}
|
| 545 |
+
|
| 546 |
+
.email-activity-row .gradio-column {
|
| 547 |
+
width: 100% !important;
|
| 548 |
+
}
|
| 549 |
}
|
| 550 |
|
| 551 |
@media (max-width: 480px) {
|
|
|
|
| 647 |
### Simulated Email History
|
| 648 |
All emails shown here are **mock emails** generated for demonstration purposes.
|
| 649 |
""")
|
| 650 |
+
|
| 651 |
+
with gr.Row(elem_classes=["email-activity-row"]):
|
| 652 |
+
# Left side - Email log
|
| 653 |
+
with gr.Column(scale=1):
|
| 654 |
+
email_log = gr.DataFrame(
|
| 655 |
+
headers=["Timestamp", "Recipient", "Subject", "Status", "Invoice ID"],
|
| 656 |
+
label="Mock Emails Generated (Not Sent)",
|
| 657 |
+
wrap=True
|
| 658 |
+
)
|
| 659 |
+
|
| 660 |
+
with gr.Row():
|
| 661 |
+
refresh_email_btn = gr.Button("π Refresh Log", scale=1)
|
| 662 |
+
export_btn = gr.Button("π₯ Export to CSV", scale=1)
|
| 663 |
+
|
| 664 |
+
# Right side - Email preview
|
| 665 |
+
with gr.Column(scale=1):
|
| 666 |
+
email_preview = gr.Textbox(
|
| 667 |
+
label="Email Preview (Click on a row to view)",
|
| 668 |
+
lines=15,
|
| 669 |
+
max_lines=25,
|
| 670 |
+
interactive=False
|
| 671 |
+
)
|
| 672 |
|
| 673 |
# Database Explorer Tab
|
| 674 |
with gr.Tab("π Database Explorer"):
|