Spaces:
Runtime error
Runtime error
SNET Onboarding Setup
Browse files- pag/monitor.py +38 -6
- tokens.txt +0 -0
- tokens_expired.txt +0 -6
- utils.py +71 -12
pag/monitor.py
CHANGED
|
@@ -321,24 +321,56 @@ def monitor_fields():
|
|
| 321 |
if field_name != "Select Field":
|
| 322 |
st.title(":orange[Field Health Forecast]")
|
| 323 |
st.write(f"Press the button below to predict {metric} for the next 30 weeks")
|
| 324 |
-
if
|
|
|
|
|
|
|
| 325 |
st.session_state['api_token'] = ''
|
| 326 |
st.session_state['api_token_confirmed'] = False
|
|
|
|
|
|
|
| 327 |
if not st.session_state['api_token_confirmed']:
|
| 328 |
st.warning("No Valid API Token Found")
|
| 329 |
-
st.
|
| 330 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 331 |
api_token = st.text_input("API Token", key="api_token_input", help="Enter the API Token From SNET")
|
| 332 |
if st.button("submit API Token", key="confirm_api_token"):
|
| 333 |
-
if utils.confirm_api_token(api_token):
|
| 334 |
st.session_state['api_token'] = api_token
|
| 335 |
st.session_state['api_token_confirmed'] = True
|
| 336 |
st.session_state['valid_until'] = utils.load_token_expiration(api_token).strftime('%Y-%m-%d %H:%M:%S')
|
| 337 |
st.rerun()
|
| 338 |
else:
|
| 339 |
-
st.error("Invalid API Token")
|
| 340 |
else:
|
| 341 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 342 |
lookback_days = st.slider("Select Lookback Days", 10, 360, 30, step=10,key="lookback_days", help="Large lookback days may take longer to load")
|
| 343 |
subcol1, subcol2, subcol3 = st.columns(3)
|
| 344 |
|
|
|
|
| 321 |
if field_name != "Select Field":
|
| 322 |
st.title(":orange[Field Health Forecast]")
|
| 323 |
st.write(f"Press the button below to predict {metric} for the next 30 weeks")
|
| 324 |
+
# Reset session state if any of the required keys are missing
|
| 325 |
+
required_keys = ['api_token', 'api_token_confirmed', 'valid_until']
|
| 326 |
+
if any(key not in st.session_state for key in required_keys):
|
| 327 |
st.session_state['api_token'] = ''
|
| 328 |
st.session_state['api_token_confirmed'] = False
|
| 329 |
+
st.session_state['valid_until'] = ''
|
| 330 |
+
|
| 331 |
if not st.session_state['api_token_confirmed']:
|
| 332 |
st.warning("No Valid API Token Found")
|
| 333 |
+
with st.expander("Need a new API Token?", expanded=True):
|
| 334 |
+
st.markdown(utils.NEW_TOKEN_INSTRUCTIONS, unsafe_allow_html=True)
|
| 335 |
+
with st.expander("Token Usage history", expanded=False):
|
| 336 |
+
filename = f'{current_user}_tokens.csv'
|
| 337 |
+
if os.path.exists(filename):
|
| 338 |
+
token_usage = pd.read_csv(filename)
|
| 339 |
+
token_usage['is_expired'] = token_usage['valid_until'].apply(lambda x: 'Yes' if datetime.strptime(x, '%Y-%m-%d %H:%M:%S') < datetime.now() else 'No')
|
| 340 |
+
st.write(token_usage)
|
| 341 |
+
else:
|
| 342 |
+
st.write("No Token Usage History Found")
|
| 343 |
api_token = st.text_input("API Token", key="api_token_input", help="Enter the API Token From SNET")
|
| 344 |
if st.button("submit API Token", key="confirm_api_token"):
|
| 345 |
+
if utils.confirm_api_token(api_token)['valid']:
|
| 346 |
st.session_state['api_token'] = api_token
|
| 347 |
st.session_state['api_token_confirmed'] = True
|
| 348 |
st.session_state['valid_until'] = utils.load_token_expiration(api_token).strftime('%Y-%m-%d %H:%M:%S')
|
| 349 |
st.rerun()
|
| 350 |
else:
|
| 351 |
+
st.error(f"Invalid API Token; {utils.confirm_api_token(api_token)['message']}")
|
| 352 |
else:
|
| 353 |
+
now = datetime.now()
|
| 354 |
+
valid_until = datetime.strptime(st.session_state['valid_until'], '%Y-%m-%d %H:%M:%S')
|
| 355 |
+
time_remaining = valid_until - now
|
| 356 |
+
minutes_remaining = int(time_remaining.total_seconds() // 60)
|
| 357 |
+
seconds_remaining = int(time_remaining.total_seconds() % 60)
|
| 358 |
+
time_left_column, clear_token_column = st.columns([1,1])
|
| 359 |
+
with time_left_column:
|
| 360 |
+
st.success(f"API Token Confirmed. Token valid for {minutes_remaining} minutes and {seconds_remaining} seconds")
|
| 361 |
+
with clear_token_column:
|
| 362 |
+
if st.button("Clear API Token", key="clear_api_token"):
|
| 363 |
+
st.session_state['api_token'] = ''
|
| 364 |
+
st.session_state['api_token_confirmed'] = False
|
| 365 |
+
st.session_state['valid_until'] = ''
|
| 366 |
+
st.rerun()
|
| 367 |
+
with st.expander("Need a new API Token?", expanded=False):
|
| 368 |
+
st.markdown(utils.NEW_TOKEN_INSTRUCTIONS, unsafe_allow_html=True)
|
| 369 |
+
with st.expander("Token Usage history", expanded=False):
|
| 370 |
+
token_usage = utils.manage_user_tokens(current_user, st.session_state['api_token'], valid_until.strftime('%Y-%m-%d %H:%M:%S'))
|
| 371 |
+
token_usage['is_expired'] = token_usage['valid_until'].apply(lambda x: 'Yes' if datetime.strptime(x, '%Y-%m-%d %H:%M:%S') < datetime.now() else 'No')
|
| 372 |
+
st.write(token_usage)
|
| 373 |
+
|
| 374 |
lookback_days = st.slider("Select Lookback Days", 10, 360, 30, step=10,key="lookback_days", help="Large lookback days may take longer to load")
|
| 375 |
subcol1, subcol2, subcol3 = st.columns(3)
|
| 376 |
|
tokens.txt
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
tokens_expired.txt
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
9mfg7acflhkbif70bnrn2lq3ult5t7l5,2024-07-26T20:38:48.882401
|
| 2 |
-
3swbgq8p1x6wo4kt8vn9apus3y1trlii,2024-07-26T20:08:55.102588
|
| 3 |
-
9mfg7acflhkbif70bnrn2lq3ult5t7l5,2024-07-26T20:09:19.569408
|
| 4 |
-
9mfg7acflhkbif70bnrn2lq3ult5t7l5,2024-07-26T19:39:42.164519
|
| 5 |
-
kfpo6khkcuirmkshjufdob6k1dn9a2oo,2025-07-26T20:45:07.000759
|
| 6 |
-
TEST_TOKEN,2025-07-26T20:45:07.000759
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
utils.py
CHANGED
|
@@ -15,10 +15,62 @@ import random
|
|
| 15 |
import string
|
| 16 |
import os
|
| 17 |
from datetime import datetime, timedelta
|
| 18 |
-
import streamlit as st
|
| 19 |
|
| 20 |
TOKEN_FILE = "tokens.txt"
|
| 21 |
EXPIRED_FILE = "tokens_expired.txt"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
def generate_random_unique_tokens(num_tokens=10, token_file=TOKEN_FILE):
|
| 24 |
'''Generates a list of random unique tokens and saves them to a file.'''
|
|
@@ -43,18 +95,25 @@ def generate_random_unique_tokens(num_tokens=10, token_file=TOKEN_FILE):
|
|
| 43 |
|
| 44 |
def confirm_api_token(token, token_file=TOKEN_FILE, expired_file=EXPIRED_FILE):
|
| 45 |
'''Checks if the given token is valid and not expired.'''
|
|
|
|
|
|
|
| 46 |
with open(token_file, 'r') as f:
|
| 47 |
-
tokens = set(f.read().splitlines())
|
| 48 |
-
if token in tokens:
|
| 49 |
now = datetime.now()
|
| 50 |
-
if token in load_expired_tokens(expired_file):
|
| 51 |
-
if now < load_token_expiration(token, expired_file):
|
| 52 |
-
return True
|
|
|
|
|
|
|
|
|
|
| 53 |
else:
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
|
|
|
|
|
|
| 58 |
|
| 59 |
def load_expired_tokens(expired_file=EXPIRED_FILE):
|
| 60 |
'''Loads expired tokens from the file.'''
|
|
@@ -63,8 +122,8 @@ def load_expired_tokens(expired_file=EXPIRED_FILE):
|
|
| 63 |
with open(expired_file, 'r') as f:
|
| 64 |
for line in f:
|
| 65 |
print(line)
|
| 66 |
-
|
| 67 |
-
|
| 68 |
token, expiry_date = line.strip().split(',')
|
| 69 |
expired_tokens[token] = datetime.fromisoformat(expiry_date)
|
| 70 |
return expired_tokens
|
|
|
|
| 15 |
import string
|
| 16 |
import os
|
| 17 |
from datetime import datetime, timedelta
|
|
|
|
| 18 |
|
| 19 |
TOKEN_FILE = "tokens.txt"
|
| 20 |
EXPIRED_FILE = "tokens_expired.txt"
|
| 21 |
+
NEW_TOKEN_INSTRUCTIONS="""<div style="background-color: #e6f2ff; padding: 20px; border-radius: 5px;">
|
| 22 |
+
<h3 style="color: #4CAF50;">Get Your SNET API Token</h3>
|
| 23 |
+
|
| 24 |
+
<p style="color: #666; font-size: 16px;">
|
| 25 |
+
To get an API token for the SNET platform:
|
| 26 |
+
<ol>
|
| 27 |
+
<li>Purchase tokens on the SNET platform using AGIX</li>
|
| 28 |
+
<li> <del> Input the email address you used to sign up for the dashboard </del>. Any text will work for testing purposes</li>
|
| 29 |
+
<li>An API token will be generated for you</li>
|
| 30 |
+
</ol>
|
| 31 |
+
|
| 32 |
+
The generated token will be valid for unlimited calls to the forecasting API for 15 minutes from your first call, for any of your fields.
|
| 33 |
+
</p>
|
| 34 |
+
|
| 35 |
+
<p style="color: #666; font-size: 16px;">
|
| 36 |
+
You can find us on the SNET platform at:
|
| 37 |
+
<a href="https://beta.singularitynet.io/servicedetails/org/EnigmaAi/service/farmingID" style="color: #007bff; text-decoration: none;">SNET Platform</a>
|
| 38 |
+
</p>
|
| 39 |
+
</div>
|
| 40 |
+
"""
|
| 41 |
+
|
| 42 |
+
import pandas as pd
|
| 43 |
+
import os
|
| 44 |
+
|
| 45 |
+
def manage_user_tokens(current_user, api_token, valid_until):
|
| 46 |
+
"""
|
| 47 |
+
Manages the storage and retrieval of user API tokens.
|
| 48 |
+
|
| 49 |
+
Args:
|
| 50 |
+
current_user (str): The username of the currently logged-in user.
|
| 51 |
+
api_token (str): The API token to be stored.
|
| 52 |
+
valid_until (str): The expiration date of the API token (in 'YYYY-MM-DD HH:MM:SS' format).
|
| 53 |
+
|
| 54 |
+
Returns:
|
| 55 |
+
None
|
| 56 |
+
"""
|
| 57 |
+
filename = f'{current_user}_tokens.csv'
|
| 58 |
+
# Check if the file exists
|
| 59 |
+
if not os.path.exists(filename):
|
| 60 |
+
# Create a new DataFrame and save it to the file
|
| 61 |
+
df = pd.DataFrame({'token': [api_token], 'valid_until': [valid_until]})
|
| 62 |
+
df.to_csv(filename, index=False)
|
| 63 |
+
else:
|
| 64 |
+
# Load the existing DataFrame
|
| 65 |
+
df = pd.read_csv(filename)
|
| 66 |
+
# Check if the token already exists in the DataFrame
|
| 67 |
+
if api_token not in df['token'].values:
|
| 68 |
+
# Append the new token and valid_until to the DataFrame
|
| 69 |
+
new_row = {'token': api_token, 'valid_until': valid_until}
|
| 70 |
+
new_row_df = pd.DataFrame(new_row, index=[0])
|
| 71 |
+
df = pd.concat([df, new_row_df], ignore_index=True)
|
| 72 |
+
df.to_csv(filename, index=False)
|
| 73 |
+
return df
|
| 74 |
|
| 75 |
def generate_random_unique_tokens(num_tokens=10, token_file=TOKEN_FILE):
|
| 76 |
'''Generates a list of random unique tokens and saves them to a file.'''
|
|
|
|
| 95 |
|
| 96 |
def confirm_api_token(token, token_file=TOKEN_FILE, expired_file=EXPIRED_FILE):
|
| 97 |
'''Checks if the given token is valid and not expired.'''
|
| 98 |
+
print(f'Checking token: {token} >>>>>>>>>>>>>>>>>>>')
|
| 99 |
+
msg = 'Token is valid'
|
| 100 |
with open(token_file, 'r') as f:
|
| 101 |
+
tokens = set(f.read().splitlines()) # Load All possible tokens
|
| 102 |
+
if token in tokens: # Check if the token is one of the possible tokens
|
| 103 |
now = datetime.now()
|
| 104 |
+
if token in load_expired_tokens(expired_file): # Check if the token have been used before
|
| 105 |
+
if now < load_token_expiration(token, expired_file): # Check if the token has been expired
|
| 106 |
+
return {'valid': True, 'message': msg}
|
| 107 |
+
else: # If the token has been expired, return invalid
|
| 108 |
+
msg = 'Token has expired'
|
| 109 |
+
return {'valid': False, 'message': msg}
|
| 110 |
else:
|
| 111 |
+
msg = 'Token is valid'
|
| 112 |
+
expiry_date = now + timedelta(minutes=15)
|
| 113 |
+
save_expired_token(token, expiry_date, expired_file) # If the token is valid and have not been used before, set the expiration date to 15 minutes
|
| 114 |
+
return {'valid': True, 'message': msg}
|
| 115 |
+
msg = 'Token is invalid'
|
| 116 |
+
return {'valid': False, 'message': msg}
|
| 117 |
|
| 118 |
def load_expired_tokens(expired_file=EXPIRED_FILE):
|
| 119 |
'''Loads expired tokens from the file.'''
|
|
|
|
| 122 |
with open(expired_file, 'r') as f:
|
| 123 |
for line in f:
|
| 124 |
print(line)
|
| 125 |
+
print(line.strip().split(','))
|
| 126 |
+
print('------------')
|
| 127 |
token, expiry_date = line.strip().split(',')
|
| 128 |
expired_tokens[token] = datetime.fromisoformat(expiry_date)
|
| 129 |
return expired_tokens
|