# app.py import streamlit as st from services.claude_service import ClaudeService from services.chart_analysis import ChartAnalysisService from ui.components import ( create_sidebar, show_analysis_section, show_chat_history, show_follow_up_section, show_save_options, create_expertise_selector ) from utils.file_handlers import save_chat_history from utils.learning_module import LearningModule from auth.auth_manager import AuthManager from storage.storage_manager import UserStorageManager from pages.login import show_login_page, show_logout_button from pages.previous_chats import show_previous_chats_tab def init_session_state(): if 'chat_history' not in st.session_state: st.session_state.chat_history = [] if 'current_image' not in st.session_state: st.session_state.current_image = None if 'current_analysis' not in st.session_state: st.session_state.current_analysis = None if 'current_images' not in st.session_state: st.session_state.current_images = [] if 'analysis_results' not in st.session_state: st.session_state.analysis_results = [] if 'followups' not in st.session_state: st.session_state.followups = [] if 'conversation_context' not in st.session_state: st.session_state.conversation_context = [] def reset_session_state(): """Reset session state for a new chat""" st.session_state.chat_history = [] st.session_state.current_image = None st.session_state.current_analysis = None st.session_state.current_images = [] st.session_state.analysis_results = [] st.session_state.conversation_context = [] def show_chart_analysis_tab(claude_service, analysis_service, storage_manager): """Display chart analysis functionality""" # Get user expertise level expertise_level = create_expertise_selector() # Create sidebar and get inputs result = create_sidebar() # Check if we need to start a new chat if result[0] == "new_chat": # Save current chat if there's content if st.session_state.chat_history: storage_manager.save_chat( st.session_state.chat_history, st.session_state.current_images, st.session_state.get('last_saved_chat'), claude_service ) st.success("Previous chat saved! Starting new chat...") # Reset session state reset_session_state() st.rerun() # Unpack the sidebar results upload_option, uploaded_files, patterns, indicators, comparison_type = result # Main content area col1, col2 = st.columns([2, 1]) with col1: st.title("📈 Stock Chart Analysis Assistant") if upload_option == "Ask Question": question = st.text_input( "What would you like to know?", key="main_question_input" ) # Main analysis section if uploaded_files: # Store all uploaded images st.session_state.current_images = [file.getvalue() for file in uploaded_files] analyze_clicked = show_analysis_section(uploaded_files) if analyze_clicked: if not uploaded_files: st.warning("Please upload at least one chart.") else: with st.spinner("Analyzing charts..."): results = analysis_service.analyze_multiple_charts( st.session_state.current_images, patterns, indicators, comparison_type, expertise_level ) if results: st.session_state.current_analysis = results[-1]['analysis'] st.session_state.chat_history.extend(results) st.session_state.analysis_results = results # Display analysis results from session state if st.session_state.analysis_results: results = st.session_state.analysis_results # First show comparative analysis if it exists for idx, result in enumerate(results): if result.get('analysis_type') != 'Individual': with st.container(): st.subheader(f"{result['analysis_type']} Results") st.markdown(result['analysis']) # Add enhanced follow-up section with context follow_up = show_follow_up_section( key_suffix=f"comparative_{idx}", previous_response=result['analysis'] ) if follow_up: with st.spinner("Processing follow-up..."): response = analysis_service.handle_follow_up_question( follow_up, result['analysis'], st.session_state.current_images ) if response: st.session_state.chat_history.append(response) # Show response in the chat interface st.markdown(response['analysis']) # Save to storage with smart naming storage_manager.save_chat( st.session_state.chat_history, st.session_state.current_images, None, claude_service ) # Then show individual analyses individual_analyses = [r for r in results if r.get('analysis_type') == 'Individual'] for idx, result in enumerate(individual_analyses): with st.container(): st.subheader(f"Analysis Results - Chart {idx + 1}") st.markdown(result['analysis']) # Add enhanced follow-up section for each analysis follow_up = show_follow_up_section( key_suffix=f"individual_{idx}", previous_response=result['analysis'] ) if follow_up: with st.spinner("Processing follow-up..."): response = analysis_service.handle_follow_up_question( follow_up, result['analysis'], st.session_state.current_images[idx] if idx < len(st.session_state.current_images) else None ) if response: st.session_state.chat_history.append(response) # Show response in the chat interface st.markdown(response['analysis']) # Save to storage with smart naming storage_manager.save_chat( st.session_state.chat_history, st.session_state.current_images, None, claude_service ) # Risk warning at the bottom st.warning( "⚠️ This analysis is AI-generated and for informational purposes only. " "Do not make trading decisions solely based on this information." ) with col2: # Add a collapsible history section with st.expander("💬 View Chat History", expanded=False): if st.session_state.chat_history: # Show only last 3 interactions by default show_full = st.checkbox("Show full history", value=False) if show_full: history_to_show = st.session_state.chat_history else: history_to_show = st.session_state.chat_history[-3:] if len(st.session_state.chat_history) > 3: st.info(f"Showing last 3 of {len(st.session_state.chat_history)} interactions") # Display the selected history show_chat_history(history_to_show) else: st.info("No chat history yet") # Add save options in a separate expander with st.expander("💾 Save Analysis", expanded=False): save_name = show_save_options() if save_name and st.session_state.chat_history: filename = storage_manager.save_chat( st.session_state.chat_history, st.session_state.current_images[0] if st.session_state.current_images else None, f"{save_name}.json" if save_name else None, claude_service ) if filename: st.success(f"Chat saved as {filename}") else: st.info("Chat saved to session state") def show_learning_tab(learning_module): """Display learning center functionality""" st.title("📚 Trading Learning Center") # Create tabs for different learning options learn_tab1, learn_tab2 = st.tabs(["Structured Courses", "Custom Learning"]) with learn_tab1: st.header("Learn Trading Step by Step") learning_module.display_course_selection() with learn_tab2: st.header("Ask Any Trading Question") learning_module.display_custom_learning() def main(): st.set_page_config( page_title="Stock Chart Assistant", layout="wide", initial_sidebar_state="expanded" ) try: # Initialize authentication auth_manager = AuthManager() # Show login page if not authenticated if not auth_manager.is_authenticated(): show_login_page(auth_manager) return # Get user's storage paths and initialize storage storage_paths = auth_manager.get_user_storage_paths() storage_manager = UserStorageManager(storage_paths) # Initialize services claude_service = ClaudeService() analysis_service = ChartAnalysisService(claude_service) learning_module = LearningModule(claude_service) # Initialize session state init_session_state() # Show logout button in sidebar show_logout_button(auth_manager) # Load previous context if available if 'chat_history' not in st.session_state: context = storage_manager.get_context() if context: st.session_state.chat_history = context.get('chat_history', []) st.session_state.current_analysis = context.get('current_analysis') # Main application tabs tab1, tab2, tab3 = st.tabs(["Chart Analysis", "Learning Center", "Previous Chats"]) with tab1: show_chart_analysis_tab(claude_service, analysis_service, storage_manager) with tab2: show_learning_tab(learning_module) with tab3: show_previous_chats_tab(storage_manager) # Save context before closing storage_manager.save_context({ 'chat_history': st.session_state.chat_history, 'current_analysis': st.session_state.current_analysis }) except Exception as e: st.error(f"An error occurred: {str(e)}") st.warning("Please try refreshing the page. If the error persists, contact support.") if __name__ == "__main__": main()