Spaces:
Runtime error
Runtime error
import json | |
import os | |
import time | |
from typing import Dict | |
from swarms.utils.loguru_logger import initialize_logger | |
from swarms.telemetry.capture_sys_data import ( | |
capture_system_data, | |
log_agent_data, | |
) | |
logger = initialize_logger(log_folder="onboarding_process") | |
class OnboardingProcess: | |
""" | |
This class handles the onboarding process for users. It collects user data including their | |
full name, first name, email, Swarms API key, and system data, then autosaves it in both a | |
main JSON file and a cache file for reliability. It supports loading previously saved or cached data. | |
""" | |
def __init__( | |
self, | |
auto_save_path: str = "user_data.json", | |
cache_save_path: str = "user_data_cache.json", | |
) -> None: | |
""" | |
Initializes the OnboardingProcess with an autosave file path and a cache path. | |
Args: | |
auto_save_path (str): The path where user data is automatically saved. | |
cache_save_path (str): The path where user data is cached for reliability. | |
""" | |
self.user_data: Dict[str, str] = {} | |
self.system_data: Dict[str, str] = capture_system_data() | |
self.auto_save_path = auto_save_path | |
self.cache_save_path = cache_save_path | |
self.load_existing_data() | |
def load_existing_data(self) -> None: | |
""" | |
Loads existing user data from the auto-save file or cache if available. | |
""" | |
if os.path.exists(self.auto_save_path): | |
try: | |
with open(self.auto_save_path, "r") as f: | |
self.user_data = json.load(f) | |
logger.info( | |
"Existing user data loaded from {}", | |
self.auto_save_path, | |
) | |
return | |
except json.JSONDecodeError as e: | |
logger.error( | |
"Failed to load user data from main file: {}", e | |
) | |
# Fallback to cache if main file fails | |
if os.path.exists(self.cache_save_path): | |
try: | |
with open(self.cache_save_path, "r") as f: | |
self.user_data = json.load(f) | |
logger.info( | |
"User data loaded from cache: {}", | |
self.cache_save_path, | |
) | |
except json.JSONDecodeError as e: | |
logger.error( | |
"Failed to load user data from cache: {}", e | |
) | |
def save_data(self, retry_attempts: int = 3) -> None: | |
""" | |
Saves the current user data to both the auto-save file and the cache file. If the main | |
save fails, the cache is updated instead. Implements retry logic with exponential backoff | |
in case both save attempts fail. | |
Args: | |
retry_attempts (int): The number of retries if saving fails. | |
""" | |
attempt = 0 | |
backoff_time = 1 # Starting backoff time (in seconds) | |
while attempt < retry_attempts: | |
try: | |
combined_data = {**self.user_data, **self.system_data} | |
log_agent_data(combined_data) | |
return # Exit the function if saving was successful | |
except Exception as e: | |
logger.error( | |
"Error saving user data (Attempt {}): {}", | |
attempt + 1, | |
e, | |
) | |
# Retry after a short delay (exponential backoff) | |
time.sleep(backoff_time) | |
attempt += 1 | |
backoff_time *= ( | |
2 # Double the backoff time for each retry | |
) | |
logger.error( | |
"Failed to save user data after {} attempts.", | |
retry_attempts, | |
) | |
def ask_input(self, prompt: str, key: str) -> None: | |
""" | |
Asks the user for input, validates it, and saves it in the user_data dictionary. | |
Autosaves and caches after each valid input. | |
Args: | |
prompt (str): The prompt message to display to the user. | |
key (str): The key under which the input will be saved in user_data. | |
Raises: | |
ValueError: If the input is empty or only contains whitespace. | |
""" | |
try: | |
response = input(prompt) | |
if response.strip().lower() == "quit": | |
logger.info( | |
"User chose to quit the onboarding process." | |
) | |
exit(0) | |
if not response.strip(): | |
raise ValueError( | |
f"{key.capitalize()} cannot be empty." | |
) | |
self.user_data[key] = response.strip() | |
self.save_data() | |
return response | |
except ValueError as e: | |
logger.warning(e) | |
self.ask_input(prompt, key) | |
except KeyboardInterrupt: | |
logger.warning( | |
"Onboarding process interrupted by the user." | |
) | |
exit(1) | |
def collect_user_info(self) -> None: | |
""" | |
Initiates the onboarding process by collecting the user's full name, first name, email, | |
Swarms API key, and system data. Additionally, it reminds the user to set their WORKSPACE_DIR environment variable. | |
""" | |
logger.info("Initiating swarms cloud onboarding process...") | |
self.ask_input( | |
"Enter your first name (or type 'quit' to exit): ", | |
"first_name", | |
) | |
self.ask_input( | |
"Enter your Last Name (or type 'quit' to exit): ", | |
"last_name", | |
) | |
self.ask_input( | |
"Enter your email (or type 'quit' to exit): ", "email" | |
) | |
workspace = self.ask_input( | |
"Enter your WORKSPACE_DIR: This is where logs, errors, and agent configurations will be stored (or type 'quit' to exit). Remember to set this as an environment variable: https://docs.swarms.world/en/latest/swarms/install/quickstart/ || ", | |
"workspace_dir", | |
) | |
os.environ["WORKSPACE_DIR"] = workspace | |
logger.info( | |
"Important: Please ensure you have set your WORKSPACE_DIR environment variable as per the instructions provided." | |
) | |
logger.info( | |
"Additionally, remember to add your API keys for your respective models in your .env file." | |
) | |
logger.success("Onboarding process completed successfully!") | |
def run(self) -> None: | |
""" | |
Main method to run the onboarding process. It handles unexpected errors and ensures | |
proper finalization. | |
""" | |
try: | |
self.collect_user_info() | |
except Exception as e: | |
logger.error("An unexpected error occurred: {}", e) | |
finally: | |
logger.info("Finalizing the onboarding process.") | |
# if __name__ == "__main__": | |
# onboarding = OnboardingProcess() | |
# onboarding.run() | |