Stock_Agent_optimized / storage /storage_manager.py
cryogenic22's picture
Update storage/storage_manager.py
2d534a3 verified
# storage/storage_manager.py
import json
from pathlib import Path
from datetime import datetime
import shutil
import streamlit as st
class UserStorageManager:
def __init__(self, storage_paths):
self.paths = storage_paths
self.ensure_directories()
def ensure_directories(self):
"""Ensure all required directories exist"""
try:
for path in self.paths.values():
path.mkdir(parents=True, exist_ok=True)
except Exception as e:
st.error(f"Error creating directories: {str(e)}")
def save_chat(self, chat_data, images=None, filename=None, claude_service=None):
"""Save chat with associated images and smart naming"""
try:
timestamp = datetime.now().isoformat()
formatted_timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
# Generate smart name if available, with fallback handling
chat_title = None
try:
if claude_service and isinstance(chat_data, list):
from utils.smart_naming import generate_chat_name
chat_title = generate_chat_name(chat_data, claude_service)
except Exception as e:
st.warning(f"Could not generate smart name: {str(e)}. Using default naming.")
chat_id = filename or f"chat_{formatted_timestamp}"
if filename:
chat_id = filename.replace('.json', '')
# Save chat data
chat_file = self.paths["chats"] / f"{chat_id}.json"
# Add metadata
chat_metadata = {
'id': chat_id,
'timestamp': timestamp,
'formatted_timestamp': formatted_timestamp,
'title': chat_title or f"Trading Analysis {formatted_timestamp}",
'data': chat_data
}
# Save chat metadata
with open(chat_file, "w") as f:
json.dump(chat_metadata, f, indent=4)
# Save associated images
if images:
image_dir = self.paths["images"] / chat_id
image_dir.mkdir(exist_ok=True)
if isinstance(images, list):
for idx, img_data in enumerate(images):
img_file = image_dir / f"image_{idx}.png"
with open(img_file, "wb") as f:
f.write(img_data)
else:
img_file = image_dir / "image_0.png"
with open(img_file, "wb") as f:
f.write(images)
# Update chat metadata with image references
chat_metadata['image_paths'] = [str(p) for p in image_dir.glob("*.png")]
with open(chat_file, "w") as f:
json.dump(chat_metadata, f, indent=4)
return chat_id
except Exception as e:
st.error(f"Error saving chat: {str(e)}")
return None
def get_all_chats(self):
"""Get all user's chats with metadata"""
try:
chats = []
# Sort chat files by modification time for most recent first
chat_files = sorted(
self.paths["chats"].glob("*.json"),
key=lambda x: x.stat().st_mtime,
reverse=True
)
for chat_file in chat_files:
try:
with open(chat_file, "r") as f:
chat_data = json.load(f)
# Load associated images if they exist
chat_id = chat_data.get('id', chat_file.stem)
image_dir = self.paths["images"] / chat_id
if image_dir.exists():
images = []
for img_file in sorted(image_dir.glob("*.png")):
with open(img_file, "rb") as f:
images.append(f.read())
chat_data['images'] = images
chats.append(chat_data)
except Exception as e:
st.warning(f"Error loading chat {chat_file.name}: {str(e)}")
continue
return chats
except Exception as e:
st.error(f"Error loading chats: {str(e)}")
return []
def get_chat(self, chat_id):
"""Get specific chat with images"""
try:
chat_file = self.paths["chats"] / f"{chat_id}.json"
if not chat_file.exists():
return None
with open(chat_file, "r") as f:
chat_data = json.load(f)
# Load associated images
image_dir = self.paths["images"] / chat_id
if image_dir.exists():
images = []
for img_file in sorted(image_dir.glob("*.png")):
with open(img_file, "rb") as f:
images.append(f.read())
chat_data['images'] = images
return chat_data
except Exception as e:
st.error(f"Error loading chat: {str(e)}")
return None
def save_context(self, context_data):
"""Save conversation context"""
try:
context_file = self.paths["context"] / "context.json"
with open(context_file, "w") as f:
json.dump(context_data, f, indent=4)
except Exception as e:
st.error(f"Error saving context: {str(e)}")
def get_context(self):
"""Get saved conversation context"""
try:
context_file = self.paths["context"] / "context.json"
if context_file.exists():
with open(context_file, "r") as f:
return json.load(f)
return None
except Exception as e:
st.error(f"Error loading context: {str(e)}")
return None
def clear_context(self):
"""Clear conversation context"""
try:
context_file = self.paths["context"] / "context.json"
if context_file.exists():
context_file.unlink()
except Exception as e:
st.error(f"Error clearing context: {str(e)}")
def delete_chat(self, chat_id):
"""Delete a chat and its associated images"""
try:
# Delete chat file
chat_file = self.paths["chats"] / f"{chat_id}.json"
if chat_file.exists():
chat_file.unlink()
# Delete associated images
image_dir = self.paths["images"] / chat_id
if image_dir.exists():
shutil.rmtree(image_dir)
return True
except Exception as e:
st.error(f"Error deleting chat: {str(e)}")
return False
def get_storage_stats(self):
"""Get storage usage statistics"""
try:
stats = {
'total_chats': 0,
'total_images': 0,
'storage_used': 0 # in bytes
}
# Count chats
stats['total_chats'] = len(list(self.paths["chats"].glob("*.json")))
# Count images
for image_dir in self.paths["images"].glob("*"):
if image_dir.is_dir():
stats['total_images'] += len(list(image_dir.glob("*.png")))
# Calculate storage used
for path_type, path in self.paths.items():
if path.exists():
for file_path in path.rglob("*"):
if file_path.is_file():
stats['storage_used'] += file_path.stat().st_size
return stats
except Exception as e:
st.error(f"Error getting storage stats: {str(e)}")
return None