Spaces:
Running
Running
""" | |
Service for storing and retrieving profile data using SQLite | |
""" | |
import sqlite3 | |
from models import Profile, Skill, Project, Education, SocialMedia | |
from config import get_settings | |
import json | |
import logging | |
from typing import Dict, Any, Optional, List | |
import requests | |
settings = get_settings() | |
logger = logging.getLogger(__name__) | |
class StorageService: | |
"""Service for storing and retrieving profile data using SQLite""" | |
def __init__(self): | |
self.db_path = settings.SQLITE_DB_PATH | |
self.external_api_url = settings.EXTERNAL_API_URL | |
self._create_table() | |
def _create_table(self): | |
"""Create the profiles table if it doesn't exist""" | |
try: | |
conn = sqlite3.connect(self.db_path) | |
cursor = conn.cursor() | |
cursor.execute(""" | |
CREATE TABLE IF NOT EXISTS profiles ( | |
id INTEGER PRIMARY KEY AUTOINCREMENT, | |
name TEXT NOT NULL, | |
title TEXT NOT NULL, | |
email TEXT NOT NULL, | |
bio TEXT NOT NULL, | |
tagline TEXT, | |
social TEXT, | |
profileImg TEXT, | |
projects TEXT, | |
skills TEXT, | |
educations TEXT, | |
experiences TEXT | |
) | |
""") | |
conn.commit() | |
conn.close() | |
logger.info("Profiles table created or already exists") | |
except Exception as e: | |
logger.error(f"Error creating table: {e}") | |
raise | |
def profile_to_dict(self, profile: Profile) -> Dict[str, Any]: | |
"""Convert Profile object to dictionary for SQLite storage""" | |
return { | |
"name": profile.name, | |
"title": profile.title, | |
"email": profile.email, | |
"bio": profile.bio, | |
"tagline": profile.tagline if profile.tagline else None, | |
"social": json.dumps({ | |
"linkedin": profile.social.linkedin if profile.social else None, | |
"github": profile.social.github if profile.social else None, | |
"instagram": profile.social.instagram if profile.social else None | |
}), | |
"profileImg": profile.profileImg, | |
"projects": json.dumps([ | |
{ | |
"title": project.title, | |
"description": project.description, | |
"techStack": project.techStack, | |
"githubUrl": project.githubUrl, | |
"demoUrl": project.demoUrl | |
} for project in profile.projects | |
]), | |
"skills": json.dumps([ | |
{ | |
"name": skill.name, | |
"category": skill.category.value if skill.category else None, | |
"img": skill.img | |
} for skill in profile.skills | |
]), | |
"experiences": json.dumps([ | |
{ | |
"company": exp.company, | |
"position": exp.position, | |
"startDate": exp.startDate, | |
"endDate": exp.endDate, | |
"description": exp.description | |
} for exp in profile.experiences | |
]), | |
"educations": json.dumps([ | |
{ | |
"school": edu.school, | |
"degree": edu.degree, | |
"fieldOfStudy": edu.fieldOfStudy, | |
"startDate": edu.startDate, | |
"endDate": edu.endDate | |
} for edu in profile.educations | |
]) | |
} | |
def send_to_external_api(self, profile_data: Dict[str, Any], profile_id: str) -> Dict[str, Any]: | |
""" | |
Send profile data to the external API | |
Args: | |
profile_data: Dictionary containing profile data | |
profile_id: ID of the stored profile | |
Returns: | |
Response from the external API or error details | |
""" | |
try: | |
if not self.external_api_url: | |
logger.warning("EXTERNAL_API_URL is not configured, skipping external API sync") | |
return {"success": False, "reason": "External API URL not configured"} | |
# Add the ID to the profile data | |
profile_data["id"] = profile_id | |
# Send the data to the external API | |
response = requests.post( | |
f"{self.external_api_url}/profiles", | |
json=profile_data, | |
headers={"Content-Type": "application/json"} | |
) | |
# Check if the request was successful | |
if response.status_code in (200, 201): | |
logger.info(f"Profile successfully sent to external API") | |
return { | |
"success": True, | |
"external_id": response.json().get("id", None), | |
"external_url": f"{self.external_api_url}/profiles/{profile_id}" | |
} | |
else: | |
logger.error(f"Failed to send profile to external API: {response.status_code} - {response.text}") | |
return { | |
"success": False, | |
"status_code": response.status_code, | |
"message": response.text | |
} | |
except Exception as e: | |
logger.error(f"Error sending profile to external API: {e}") | |
return { | |
"success": False, | |
"exception": str(e) | |
} | |
def store_profile(self, profile: Profile, error_handler=None) -> str: | |
""" | |
Store profile data in SQLite | |
Args: | |
profile: The Profile object to store | |
error_handler: Optional function to handle errors (useful for framework-specific error handling) | |
Returns: | |
String ID of the stored profile | |
""" | |
profile_dict = self.profile_to_dict(profile) | |
try: | |
conn = sqlite3.connect(self.db_path) | |
cursor = conn.cursor() | |
cursor.execute(""" | |
INSERT INTO profiles (name, title, email, bio, tagline, social, profileImg, projects, skills, educations, experiences) | |
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) | |
""", ( | |
profile_dict["name"], | |
profile_dict["title"], | |
profile_dict["email"], | |
profile_dict["bio"], | |
profile_dict["tagline"], | |
profile_dict["social"], | |
profile_dict["profileImg"], | |
profile_dict["projects"], | |
profile_dict["skills"], | |
profile_dict["educations"], | |
profile_dict["experiences"] | |
)) | |
conn.commit() | |
profile_id = str(cursor.lastrowid) | |
conn.close() | |
logger.info(f"Profile saved successfully with ID: {profile_id}") | |
# Send to external API | |
external_api_result = self.send_to_external_api(profile_dict, profile_id) | |
# Store the external API result in the session state for later use | |
import streamlit as st | |
if "st" in globals() and hasattr(st, "session_state"): | |
st.session_state.external_api_result = external_api_result | |
return profile_id | |
except Exception as e: | |
logger.error(f"SQLite error: {e}") | |
if error_handler: | |
error_handler(f"Error connecting to SQLite: {str(e)}") | |
return None | |
def get_profile(self, profile_id: int) -> Optional[Dict[str, Any]]: | |
""" | |
Retrieve a profile from SQLite by its ID | |
Args: | |
profile_id: The ID of the profile to retrieve | |
Returns: | |
A dictionary representing the profile, or None if not found | |
""" | |
try: | |
conn = sqlite3.connect(self.db_path) | |
cursor = conn.cursor() | |
cursor.execute("SELECT * FROM profiles WHERE id = ?", (profile_id,)) | |
row = cursor.fetchone() | |
conn.close() | |
if row: | |
profile = { | |
"id": row[0], | |
"name": row[1], | |
"title": row[2], | |
"email": row[3], | |
"bio": row[4], | |
"tagline": row[5], | |
"social": json.loads(row[6]) if row[6] else None, | |
"profileImg": row[7], | |
"projects": json.loads(row[8]) if row[8] else [], | |
"skills": json.loads(row[9]) if row[9] else [], | |
"educations": json.loads(row[10]) if row[10] else [], | |
"experiences": json.loads(row[11]) if row[11] else [] | |
} | |
logger.debug(f"Retrieved profile: {profile_id}") | |
return profile | |
else: | |
logger.warning(f"Profile not found: {profile_id}") | |
return None | |
except Exception as e: | |
logger.error(f"Error retrieving profile {profile_id}: {e}") | |
return None | |
# Create a global instance | |
storage_service = StorageService() | |