Spaces:
Running
Running
increased max_errors in details_sheet_watcher and removed new feature banner
Browse files
app.py
CHANGED
|
@@ -862,62 +862,77 @@ def auto_refresh_worker():
|
|
| 862 |
time.sleep(3600)
|
| 863 |
|
| 864 |
def details_sheet_watcher():
|
| 865 |
-
"""Background watcher: checks every 30 seconds (drift-free, IST logs) if 'POINTS LAST UPDATED' changed"""
|
| 866 |
import time
|
| 867 |
from datetime import datetime
|
| 868 |
|
| 869 |
last_seen_update = None
|
| 870 |
consecutive_errors = 0
|
| 871 |
-
max_errors =
|
| 872 |
|
| 873 |
watcher_client = None
|
| 874 |
watcher_spreadsheet = None
|
| 875 |
watcher_sheet = None
|
| 876 |
last_connection_time = None
|
| 877 |
-
connection_duration =
|
| 878 |
-
|
| 879 |
-
# Specific cell coordinates for "POINTS LAST UPDATED"
|
| 880 |
-
TARGET_ROW = 16
|
| 881 |
-
TARGET_COL = 2
|
| 882 |
-
CELL_RANGE = f"R{TARGET_ROW}C{TARGET_COL}" # Row 16, Column 2
|
| 883 |
-
|
| 884 |
check_interval = 30 # seconds
|
| 885 |
next_check = time.time()
|
| 886 |
|
| 887 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 888 |
|
| 889 |
while True:
|
| 890 |
-
start_time = time.time()
|
| 891 |
try:
|
| 892 |
if data_cache["is_loading"]:
|
| 893 |
print("⏳ Watcher: Skipping check – data loading in progress")
|
| 894 |
else:
|
| 895 |
current_time = datetime.now()
|
| 896 |
-
|
| 897 |
-
|
| 898 |
-
|
| 899 |
-
|
| 900 |
-
|
| 901 |
-
|
| 902 |
-
|
| 903 |
-
|
| 904 |
-
|
| 905 |
-
|
| 906 |
-
|
| 907 |
-
|
| 908 |
-
|
| 909 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 910 |
try:
|
| 911 |
-
#
|
| 912 |
cell_value = watcher_sheet.cell(TARGET_ROW, TARGET_COL).value
|
| 913 |
current_update = str(cell_value).strip() if cell_value else ""
|
| 914 |
-
|
| 915 |
now_ist = datetime.now(ist).strftime("%Y-%m-%d %H:%M:%S")
|
| 916 |
|
| 917 |
if last_seen_update is None:
|
| 918 |
last_seen_update = current_update
|
| 919 |
-
print(f"🕒 Watcher
|
| 920 |
-
print(f" Target
|
| 921 |
elif current_update != last_seen_update:
|
| 922 |
print(f"🔄 CHANGE DETECTED! ({now_ist})")
|
| 923 |
print(f" Old: {last_seen_update[:60]}...")
|
|
@@ -931,34 +946,34 @@ def details_sheet_watcher():
|
|
| 931 |
else:
|
| 932 |
print(f"⏳ Data already loading, skipping reload ({now_ist})")
|
| 933 |
else:
|
| 934 |
-
# Log heartbeat every 5 minutes in IST
|
| 935 |
current_ist = datetime.now(ist)
|
| 936 |
if current_ist.minute % 5 == 0 and current_ist.second < check_interval:
|
| 937 |
print(f"✅ Watcher: No changes detected in R{TARGET_ROW}C{TARGET_COL} ({current_ist.strftime('%H:%M:%S')})")
|
| 938 |
-
|
| 939 |
except Exception as cell_error:
|
| 940 |
-
print(f"⚠️ Error reading cell R{TARGET_ROW}C{TARGET_COL}: {str(cell_error)[:
|
| 941 |
consecutive_errors += 1
|
| 942 |
|
| 943 |
-
|
|
|
|
| 944 |
print(f"✅ Watcher: Connection restored (cleared {consecutive_errors} errors)")
|
| 945 |
consecutive_errors = 0
|
| 946 |
|
| 947 |
except Exception as e:
|
| 948 |
consecutive_errors += 1
|
| 949 |
-
print(f"⚠️ Watcher error #{consecutive_errors}: {str(e)[:
|
| 950 |
watcher_client = None
|
| 951 |
watcher_spreadsheet = None
|
| 952 |
watcher_sheet = None
|
|
|
|
| 953 |
if consecutive_errors >= max_errors:
|
| 954 |
print("❌ Too many watcher errors, waiting 5 minutes before retry...")
|
| 955 |
time.sleep(300)
|
| 956 |
consecutive_errors = 0
|
| 957 |
|
| 958 |
-
# Drift-free
|
| 959 |
next_check += check_interval
|
| 960 |
-
|
| 961 |
-
time.sleep(sleep_time)
|
| 962 |
|
| 963 |
|
| 964 |
def get_detailed_student_points(roll_no, studentwise_data):
|
|
@@ -1371,42 +1386,15 @@ with gr.Blocks(
|
|
| 1371 |
title="Student Reward Points Check",
|
| 1372 |
theme=gr.themes.Soft(),
|
| 1373 |
) as app:
|
| 1374 |
-
gr.HTML(
|
| 1375 |
-
"""
|
| 1376 |
-
<style>
|
| 1377 |
-
@keyframes fadeOut {
|
| 1378 |
-
0% { opacity: 1; }
|
| 1379 |
-
90% { opacity: 1; }
|
| 1380 |
-
100% { opacity: 0; display: none; }
|
| 1381 |
-
}
|
| 1382 |
-
|
| 1383 |
-
.auto-hide-banner {
|
| 1384 |
-
animation: fadeOut 10s forwards;
|
| 1385 |
-
}
|
| 1386 |
-
</style>
|
| 1387 |
-
|
| 1388 |
-
<div class="auto-hide-banner" style='background-color:#FFF3CD;
|
| 1389 |
-
padding:12px;
|
| 1390 |
-
border-radius:10px;
|
| 1391 |
-
text-align:center;
|
| 1392 |
-
font-size:16px;
|
| 1393 |
-
color:#856404;
|
| 1394 |
-
font-weight:500;
|
| 1395 |
-
margin-bottom:10px;'>
|
| 1396 |
-
🆕 <b>New Feature Added!</b> Check out the new <b>📚 Innovative Practice (IP) Details</b> tab to view subject-wise IP points and marks instantly!<br>
|
| 1397 |
-
Check out by clicking the 3 dots and select the Innovative Practice (IP) Details Tab and Enter your roll no 🚀
|
| 1398 |
-
</div>
|
| 1399 |
-
"""
|
| 1400 |
-
)
|
| 1401 |
gr.Markdown("## 🎓 Student Reward Points Checker")
|
| 1402 |
gr.Markdown("##### Search for Student Details such as Reward Points, Redemption Dates and Innovative Practice (IP) Details")
|
| 1403 |
gr.Markdown("##### எல்லா புகழும் இறைவனுக்கே ✝ 🕉 ☪")
|
| 1404 |
-
|
| 1405 |
-
|
| 1406 |
-
|
| 1407 |
-
|
| 1408 |
-
|
| 1409 |
-
|
| 1410 |
gr.Markdown("💻 **Mode**: Use Desktop Mode in browser for Good UI and UX")
|
| 1411 |
gr.Markdown("🕒 **Auto-Updates**: Data automatically refreshes when there is a change in Reward Points Sheet")
|
| 1412 |
gr.Markdown("📝 **Issue/Feedback Form** : [Issue/Feedback Form](https://docs.google.com/forms/d/e/1FAIpQLScnl0udcN2pUDENHl45HIj5HZbvDuwZ0g2eepBbp8tJYg-NvQ/viewform)")
|
|
|
|
| 862 |
time.sleep(3600)
|
| 863 |
|
| 864 |
def details_sheet_watcher():
|
| 865 |
+
"""Background watcher: checks every 30 seconds (drift-free, IST logs) if 'POINTS LAST UPDATED' changed safely"""
|
| 866 |
import time
|
| 867 |
from datetime import datetime
|
| 868 |
|
| 869 |
last_seen_update = None
|
| 870 |
consecutive_errors = 0
|
| 871 |
+
max_errors = 10
|
| 872 |
|
| 873 |
watcher_client = None
|
| 874 |
watcher_spreadsheet = None
|
| 875 |
watcher_sheet = None
|
| 876 |
last_connection_time = None
|
| 877 |
+
connection_duration = 3600 # 1 hour
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 878 |
check_interval = 30 # seconds
|
| 879 |
next_check = time.time()
|
| 880 |
|
| 881 |
+
TARGET_ROW, TARGET_COL = 16, 2
|
| 882 |
+
|
| 883 |
+
print(f"👀 Starting optimized details sheet watcher (R{TARGET_ROW}C{TARGET_COL}, every {check_interval}s)...")
|
| 884 |
+
|
| 885 |
+
global last_auth_refresh
|
| 886 |
+
last_auth_refresh = 0
|
| 887 |
|
| 888 |
while True:
|
|
|
|
| 889 |
try:
|
| 890 |
if data_cache["is_loading"]:
|
| 891 |
print("⏳ Watcher: Skipping check – data loading in progress")
|
| 892 |
else:
|
| 893 |
current_time = datetime.now()
|
| 894 |
+
|
| 895 |
+
# Refresh only if 24 hours passed or connection lost
|
| 896 |
+
should_refresh = (
|
| 897 |
+
watcher_client is None
|
| 898 |
+
or watcher_sheet is None
|
| 899 |
+
or last_connection_time is None
|
| 900 |
+
or (current_time - last_connection_time).total_seconds() > connection_duration
|
| 901 |
+
)
|
| 902 |
+
|
| 903 |
+
if should_refresh:
|
| 904 |
+
# Enforce 5-min cooldown between authorizations
|
| 905 |
+
if time.time() - last_auth_refresh < 300:
|
| 906 |
+
print("⏳ Skipping token refresh — recently done.")
|
| 907 |
+
else:
|
| 908 |
+
print("🔄 Watcher: Refreshing connection...")
|
| 909 |
+
try:
|
| 910 |
+
watcher_client = authorize()
|
| 911 |
+
watcher_spreadsheet = watcher_client.open_by_key(os.getenv("GOOGLE_SHEET_ID"))
|
| 912 |
+
watcher_sheet = watcher_spreadsheet.get_worksheet_by_id(847680829)
|
| 913 |
+
last_connection_time = current_time
|
| 914 |
+
last_auth_refresh = time.time()
|
| 915 |
+
print(f"✅ Watcher: Connection refreshed (monitoring cell R{TARGET_ROW}C{TARGET_COL})")
|
| 916 |
+
except Exception as e:
|
| 917 |
+
print(f"⚠️ Watcher: Failed to refresh connection — {str(e)[:100]}")
|
| 918 |
+
time.sleep(60)
|
| 919 |
+
continue
|
| 920 |
+
|
| 921 |
+
# Skip check if no valid sheet
|
| 922 |
+
if not watcher_sheet:
|
| 923 |
+
time.sleep(check_interval)
|
| 924 |
+
continue
|
| 925 |
+
|
| 926 |
try:
|
| 927 |
+
# Fetch only specific cell value
|
| 928 |
cell_value = watcher_sheet.cell(TARGET_ROW, TARGET_COL).value
|
| 929 |
current_update = str(cell_value).strip() if cell_value else ""
|
|
|
|
| 930 |
now_ist = datetime.now(ist).strftime("%Y-%m-%d %H:%M:%S")
|
| 931 |
|
| 932 |
if last_seen_update is None:
|
| 933 |
last_seen_update = current_update
|
| 934 |
+
print(f"🕒 Watcher started at {now_ist}")
|
| 935 |
+
print(f" Target R{TARGET_ROW}C{TARGET_COL}: {current_update[:80]}...")
|
| 936 |
elif current_update != last_seen_update:
|
| 937 |
print(f"🔄 CHANGE DETECTED! ({now_ist})")
|
| 938 |
print(f" Old: {last_seen_update[:60]}...")
|
|
|
|
| 946 |
else:
|
| 947 |
print(f"⏳ Data already loading, skipping reload ({now_ist})")
|
| 948 |
else:
|
|
|
|
| 949 |
current_ist = datetime.now(ist)
|
| 950 |
if current_ist.minute % 5 == 0 and current_ist.second < check_interval:
|
| 951 |
print(f"✅ Watcher: No changes detected in R{TARGET_ROW}C{TARGET_COL} ({current_ist.strftime('%H:%M:%S')})")
|
| 952 |
+
|
| 953 |
except Exception as cell_error:
|
| 954 |
+
print(f"⚠️ Error reading cell R{TARGET_ROW}C{TARGET_COL}: {str(cell_error)[:200]}")
|
| 955 |
consecutive_errors += 1
|
| 956 |
|
| 957 |
+
# Reset error counter if stable
|
| 958 |
+
if consecutive_errors > 0:
|
| 959 |
print(f"✅ Watcher: Connection restored (cleared {consecutive_errors} errors)")
|
| 960 |
consecutive_errors = 0
|
| 961 |
|
| 962 |
except Exception as e:
|
| 963 |
consecutive_errors += 1
|
| 964 |
+
print(f"⚠️ Watcher error #{consecutive_errors}: {str(e)[:200]}")
|
| 965 |
watcher_client = None
|
| 966 |
watcher_spreadsheet = None
|
| 967 |
watcher_sheet = None
|
| 968 |
+
|
| 969 |
if consecutive_errors >= max_errors:
|
| 970 |
print("❌ Too many watcher errors, waiting 5 minutes before retry...")
|
| 971 |
time.sleep(300)
|
| 972 |
consecutive_errors = 0
|
| 973 |
|
| 974 |
+
# Drift-free sleep to maintain 30s sync
|
| 975 |
next_check += check_interval
|
| 976 |
+
time.sleep(max(0, next_check - time.time()))
|
|
|
|
| 977 |
|
| 978 |
|
| 979 |
def get_detailed_student_points(roll_no, studentwise_data):
|
|
|
|
| 1386 |
title="Student Reward Points Check",
|
| 1387 |
theme=gr.themes.Soft(),
|
| 1388 |
) as app:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1389 |
gr.Markdown("## 🎓 Student Reward Points Checker")
|
| 1390 |
gr.Markdown("##### Search for Student Details such as Reward Points, Redemption Dates and Innovative Practice (IP) Details")
|
| 1391 |
gr.Markdown("##### எல்லா புகழும் இறைவனுக்கே ✝ 🕉 ☪")
|
| 1392 |
+
gr.Markdown("""
|
| 1393 |
+
***Available Features*** :
|
| 1394 |
+
**🔍 Student Search Tab**,
|
| 1395 |
+
**📚 IP Details Tab**,
|
| 1396 |
+
**ℹ️ System Info Tab**
|
| 1397 |
+
""")
|
| 1398 |
gr.Markdown("💻 **Mode**: Use Desktop Mode in browser for Good UI and UX")
|
| 1399 |
gr.Markdown("🕒 **Auto-Updates**: Data automatically refreshes when there is a change in Reward Points Sheet")
|
| 1400 |
gr.Markdown("📝 **Issue/Feedback Form** : [Issue/Feedback Form](https://docs.google.com/forms/d/e/1FAIpQLScnl0udcN2pUDENHl45HIj5HZbvDuwZ0g2eepBbp8tJYg-NvQ/viewform)")
|