cryogenic22 commited on
Commit
7ac74fa
·
verified ·
1 Parent(s): 9f87ccc

Update auth/auth_manager.py

Browse files
Files changed (1) hide show
  1. auth/auth_manager.py +189 -281
auth/auth_manager.py CHANGED
@@ -1,296 +1,204 @@
1
- def show_chart_analysis_tab(claude_service, analysis_service):
2
- """Display chart analysis functionality"""
3
- # Get user expertise level
4
- expertise_level = create_expertise_selector()
5
-
6
- # Create sidebar and get inputs
7
- upload_option, uploaded_files, patterns, indicators, comparison_type = create_sidebar()
8
-
9
- # Main content area
10
- col1, col2 = st.columns([2, 1])
11
-
12
- with col1:
13
- st.title("📈 Stock Chart Analysis Assistant")
 
 
14
 
15
- if upload_option == "Ask Question":
16
- question = st.text_input(
17
- "What would you like to know?",
18
- key="main_question_input"
19
- )
20
 
21
- # Main analysis section
22
- if uploaded_files:
23
- # Store all uploaded images
24
- st.session_state.current_images = [file.getvalue() for file in uploaded_files]
 
 
 
 
 
 
 
 
 
25
 
26
- analyze_clicked = show_analysis_section(uploaded_files)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
- # Store analysis results in session state
29
- if 'analysis_results' not in st.session_state:
30
- st.session_state.analysis_results = []
 
 
 
31
 
32
- if analyze_clicked:
33
- if not uploaded_files:
34
- st.warning("Please upload at least one chart.")
35
- else:
36
- with st.spinner("Analyzing charts..."):
37
- results = analysis_service.analyze_multiple_charts(
38
- st.session_state.current_images,
39
- patterns,
40
- indicators,
41
- comparison_type,
42
- expertise_level
43
- )
44
-
45
- if results:
46
- st.session_state.current_analysis = results[-1]['analysis']
47
- st.session_state.chat_history.extend(results)
48
- st.session_state.analysis_results = results
49
 
50
- # Display analysis results from session state
51
- if st.session_state.analysis_results:
52
- results = st.session_state.analysis_results
53
-
54
- # First show comparative analysis if it exists
55
- for result in results:
56
- if result.get('analysis_type') != 'Individual':
57
- with st.container():
58
- st.subheader(f"{result['analysis_type']} Results")
59
- st.markdown(result['analysis'])
60
-
61
- # Add follow-up section immediately after analysis
62
- follow_up = show_follow_up_section(f"comparative_followup")
63
- if follow_up:
64
- with st.spinner("Processing follow-up..."):
65
- response = analysis_service.handle_follow_up_question(
66
- follow_up,
67
- result['analysis'],
68
- st.session_state.current_images
69
- )
70
- if response:
71
- st.session_state.chat_history.append(response)
72
- st.markdown(response['analysis'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
- # Then show individual analyses
75
- individual_analyses = [r for r in results if r.get('analysis_type') == 'Individual']
76
- for idx, result in enumerate(individual_analyses):
77
- with st.container():
78
- st.subheader(f"Analysis Results - Chart {idx + 1}")
79
- st.markdown(result['analysis'])
80
-
81
- # Add follow-up section for each analysis
82
- container_key = f"individual_followup_{idx}"
83
- follow_up = show_follow_up_section(container_key)
84
- if follow_up:
85
- with st.spinner("Processing follow-up..."):
86
- response = analysis_service.handle_follow_up_question(
87
- follow_up,
88
- result['analysis'],
89
- st.session_state.current_images[idx] if idx < len(st.session_state.current_images) else None
90
- )
91
- if response:
92
- st.session_state.chat_history.append(response)
93
- st.markdown(response['analysis'])
94
 
95
- # Risk warning at the bottom
96
- st.warning(
97
- "⚠️ This analysis is AI-generated and for informational purposes only. "
98
- "Do not make trading decisions solely based on this information."
99
- )
100
-
101
- with col2:
102
- # Chat history
103
- show_chat_history(st.session_state.chat_history)
104
 
105
- # Save options
106
- save_name = show_save_options()
107
- if save_name and st.session_state.chat_history:
108
- filename = save_chat_history(
109
- st.session_state.chat_history,
110
- st.session_state.current_images[0] if st.session_state.current_images else None,
111
- f"{save_name}.json" if save_name else None
112
- )
113
- if filename:
114
- st.success(f"Chat saved as {filename}")
115
- else:
116
- st.info("Chat saved to session state")# app.py
117
-
118
- import streamlit as st
119
- from services.claude_service import ClaudeService
120
- from services.chart_analysis import ChartAnalysisService
121
- from ui.components import (
122
- create_sidebar,
123
- show_analysis_section,
124
- show_chat_history,
125
- show_follow_up_section,
126
- show_save_options,
127
- create_expertise_selector
128
- )
129
- from utils.file_handlers import save_chat_history
130
- from utils.learning_module import LearningModule
131
 
132
- def init_session_state():
133
- """Initialize session state variables"""
134
- if 'chat_history' not in st.session_state:
135
- st.session_state.chat_history = []
136
- if 'current_image' not in st.session_state:
137
- st.session_state.current_image = None
138
- if 'current_analysis' not in st.session_state:
139
- st.session_state.current_analysis = None
140
- if 'current_images' not in st.session_state:
141
- st.session_state.current_images = []
142
- if 'conversation_context' not in st.session_state:
143
- st.session_state.conversation_context = []
144
- if 'current_conversation_id' not in st.session_state:
145
- st.session_state.current_conversation_id = None
146
 
147
- def show_chart_analysis_tab(claude_service, analysis_service):
148
- """Display chart analysis functionality"""
149
- # Get user expertise level
150
- expertise_level = create_expertise_selector()
151
-
152
- # Create sidebar and get inputs
153
- upload_option, uploaded_files, patterns, indicators, comparison_type = create_sidebar()
154
-
155
- # Main content area
156
- col1, col2 = st.columns([2, 1])
157
-
158
- with col1:
159
- st.title("📈 Stock Chart Analysis Assistant")
160
-
161
- if upload_option == "Ask Question":
162
- question = st.text_input(
163
- "What would you like to know?",
164
- key="main_question_input"
165
- )
166
-
167
- # Main analysis section
168
- if uploaded_files:
169
- # Store all uploaded images
170
- st.session_state.current_images = [file.getvalue() for file in uploaded_files]
171
 
172
- analyze_clicked = show_analysis_section(uploaded_files)
173
-
174
- if analyze_clicked:
175
- if not uploaded_files:
176
- st.warning("Please upload at least one chart.")
177
- else:
178
- with st.spinner("Analyzing charts..."):
179
- results = analysis_service.analyze_multiple_charts(
180
- st.session_state.current_images,
181
- patterns,
182
- indicators,
183
- comparison_type,
184
- expertise_level
185
- )
186
-
187
- if results:
188
- # Store current analysis
189
- st.session_state.current_analysis = results[-1]['analysis'] # Latest analysis
190
- st.session_state.chat_history.extend(results)
191
-
192
- # Display analyses
193
- # First show comparative analysis if it exists
194
- for result in results:
195
- if result.get('analysis_type') != 'Individual':
196
- st.subheader(f"{result['analysis_type']} Results")
197
- st.write(result['analysis'])
198
- # Add follow-up section immediately
199
- follow_up = show_follow_up_section(f"comparative_followup")
200
- if follow_up:
201
- with st.spinner("Processing follow-up..."):
202
- response = analysis_service.handle_follow_up_question(
203
- follow_up,
204
- result['analysis'],
205
- st.session_state.current_images
206
- )
207
- if response:
208
- st.session_state.chat_history.append(response)
209
- st.write(response['analysis'])
210
-
211
- # Then show individual analyses
212
- individual_analyses = [r for r in results if r.get('analysis_type') == 'Individual']
213
- for idx, result in enumerate(individual_analyses):
214
- st.subheader(f"Analysis Results - Chart {idx + 1}")
215
- st.write(result['analysis'])
216
- # Add follow-up section for each individual analysis
217
- follow_up = show_follow_up_section(f"individual_followup_{idx}")
218
- if follow_up:
219
- with st.spinner("Processing follow-up..."):
220
- response = analysis_service.handle_follow_up_question(
221
- follow_up,
222
- result['analysis'],
223
- st.session_state.current_images[idx] if idx < len(st.session_state.current_images) else None
224
- )
225
- if response:
226
- st.session_state.chat_history.append(response)
227
- st.write(response['analysis'])
228
-
229
- # Risk warning
230
- st.warning(
231
- "⚠️ This analysis is AI-generated and for informational purposes only. "
232
- "Do not make trading decisions solely based on this information."
233
- )
234
-
235
- with col2:
236
- # Chat history
237
- show_chat_history(st.session_state.chat_history)
238
-
239
- # Save options
240
- save_name = show_save_options()
241
- if save_name and st.session_state.chat_history:
242
- filename = save_chat_history(
243
- st.session_state.chat_history,
244
- st.session_state.current_images[0] if st.session_state.current_images else None,
245
- f"{save_name}.json" if save_name else None
246
- )
247
- if filename:
248
- st.success(f"Chat saved as {filename}")
249
- else:
250
- st.info("Chat saved to session state")
251
 
252
- def show_learning_tab(learning_module):
253
- """Display learning center functionality"""
254
- st.title("📚 Trading Learning Center")
255
-
256
- # Create tabs for different learning options
257
- learn_tab1, learn_tab2 = st.tabs(["Structured Courses", "Custom Learning"])
258
-
259
- with learn_tab1:
260
- st.header("Learn Trading Step by Step")
261
- learning_module.display_course_selection()
262
-
263
- with learn_tab2:
264
- st.header("Ask Any Trading Question")
265
- learning_module.display_custom_learning()
 
 
 
 
 
 
 
266
 
267
- def main():
268
- st.set_page_config(
269
- page_title="Stock Chart Assistant",
270
- layout="wide",
271
- initial_sidebar_state="expanded"
272
- )
273
-
274
- # Initialize services
275
- try:
276
- claude_service = ClaudeService()
277
- analysis_service = ChartAnalysisService(claude_service)
278
- learning_module = LearningModule(claude_service)
279
- except ValueError as e:
280
- st.error(str(e))
281
- return
282
-
283
- # Initialize session state
284
- init_session_state()
285
-
286
- # Main application tabs
287
- tab1, tab2 = st.tabs(["Chart Analysis", "Learning Center"])
288
-
289
- with tab1:
290
- show_chart_analysis_tab(claude_service, analysis_service)
291
-
292
- with tab2:
293
- show_learning_tab(learning_module)
294
 
295
- if __name__ == "__main__":
296
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # auth/auth_manager.py
2
+
3
+ import streamlit as st
4
+ import json
5
+ import os
6
+ from pathlib import Path
7
+ import hashlib
8
+ from datetime import datetime, timedelta
9
+
10
+ class AuthManager:
11
+ def __init__(self):
12
+ """Initialize AuthManager with storage in HuggingFace's /data directory"""
13
+ # Use HuggingFace's /data directory for persistent storage
14
+ self.storage_path = Path("/data/users")
15
+ self.ensure_storage()
16
 
17
+ # Initialize demo user if not exists
18
+ self._init_demo_user()
 
 
 
19
 
20
+ # Initialize session state for auth
21
+ if 'auth' not in st.session_state:
22
+ st.session_state.auth = {
23
+ 'authenticated': False,
24
+ 'user': None,
25
+ 'login_time': None
26
+ }
27
+
28
+ def ensure_storage(self):
29
+ """Ensure storage directories exist and are writable"""
30
+ try:
31
+ # Create main storage directory
32
+ self.storage_path.mkdir(parents=True, exist_ok=True)
33
 
34
+ # Test write permissions
35
+ test_file = self.storage_path / ".write_test"
36
+ test_file.touch()
37
+ test_file.unlink()
38
+ except Exception as e:
39
+ st.error(f"Failed to access storage: {str(e)}")
40
+ raise RuntimeError("Storage is not accessible")
41
+
42
+ def _init_demo_user(self):
43
+ """Initialize demo Synaptyx user"""
44
+ demo_user = {
45
+ "username": "synaptyx",
46
+ "password_hash": self._hash_password("demo"),
47
+ "display_name": "Synaptyx Demo",
48
+ "storage_path": "/data/users/synaptyx",
49
+ "created_at": datetime.now().isoformat(),
50
+ "last_login": None,
51
+ "settings": {
52
+ "expertise_level": "Intermediate",
53
+ "theme": "default",
54
+ "notifications_enabled": True
55
+ }
56
+ }
57
 
58
+ user_file = self.storage_path / "synaptyx.json"
59
+ if not user_file.exists():
60
+ # Create user storage directories
61
+ user_storage = Path(demo_user["storage_path"])
62
+ for dir_name in ["chats", "images", "context", "exports"]:
63
+ (user_storage / dir_name).mkdir(parents=True, exist_ok=True)
64
 
65
+ # Save user data
66
+ with open(user_file, "w") as f:
67
+ json.dump(demo_user, f, indent=4)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
 
69
+ def _hash_password(self, password):
70
+ """Hash password using SHA-256 with salt"""
71
+ salt = "synaptyx_salt" # In production, use a proper salt management system
72
+ salted = password + salt
73
+ return hashlib.sha256(salted.encode()).hexdigest()
74
+
75
+ def login(self, username, password):
76
+ """Authenticate user and set up session"""
77
+ try:
78
+ user_file = self.storage_path / f"{username}.json"
79
+ if not user_file.exists():
80
+ return False
81
+
82
+ with open(user_file, "r") as f:
83
+ user_data = json.load(f)
84
+
85
+ if user_data["password_hash"] == self._hash_password(password):
86
+ # Update last login
87
+ user_data["last_login"] = datetime.now().isoformat()
88
+ with open(user_file, "w") as f:
89
+ json.dump(user_data, f, indent=4)
90
+
91
+ # Update session state
92
+ st.session_state.auth = {
93
+ 'authenticated': True,
94
+ 'user': user_data,
95
+ 'login_time': datetime.now().isoformat()
96
+ }
97
+ return True
98
+
99
+ return False
100
+ except Exception as e:
101
+ st.error(f"Login error: {str(e)}")
102
+ return False
103
+
104
+ def is_authenticated(self):
105
+ """Check if user is authenticated and session is valid"""
106
+ if not st.session_state.auth.get('authenticated'):
107
+ return False
108
 
109
+ # Check session age (optional)
110
+ if st.session_state.auth.get('login_time'):
111
+ login_time = datetime.fromisoformat(st.session_state.auth['login_time'])
112
+ session_age = datetime.now() - login_time
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
 
114
+ # Session timeout after 12 hours
115
+ if session_age > timedelta(hours=12):
116
+ self.logout()
117
+ return False
 
 
 
 
 
118
 
119
+ return True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
 
121
+ def get_user_storage_paths(self):
122
+ """Get user's storage paths"""
123
+ if not self.is_authenticated():
124
+ return None
125
+
126
+ base_path = Path(st.session_state.auth['user']["storage_path"])
127
+ return {
128
+ "chats": base_path / "chats",
129
+ "images": base_path / "images",
130
+ "context": base_path / "context",
131
+ "exports": base_path / "exports"
132
+ }
 
 
133
 
134
+ def get_user_settings(self):
135
+ """Get user's settings"""
136
+ if not self.is_authenticated():
137
+ return None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
 
139
+ return st.session_state.auth['user'].get('settings', {})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
 
141
+ def update_user_settings(self, settings):
142
+ """Update user's settings"""
143
+ if not self.is_authenticated():
144
+ return False
145
+
146
+ try:
147
+ user_file = self.storage_path / f"{st.session_state.auth['user']['username']}.json"
148
+ with open(user_file, "r") as f:
149
+ user_data = json.load(f)
150
+
151
+ user_data['settings'].update(settings)
152
+
153
+ with open(user_file, "w") as f:
154
+ json.dump(user_data, f, indent=4)
155
+
156
+ # Update session state
157
+ st.session_state.auth['user'] = user_data
158
+ return True
159
+ except Exception as e:
160
+ st.error(f"Failed to update settings: {str(e)}")
161
+ return False
162
 
163
+ def logout(self):
164
+ """Log out user and clear session"""
165
+ if 'auth' in st.session_state:
166
+ st.session_state.auth = {
167
+ 'authenticated': False,
168
+ 'user': None,
169
+ 'login_time': None
170
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
171
 
172
+ def get_user_stats(self):
173
+ """Get user's usage statistics"""
174
+ if not self.is_authenticated():
175
+ return None
176
+
177
+ try:
178
+ stats = {
179
+ 'total_analyses': 0,
180
+ 'total_chats': 0,
181
+ 'storage_used': 0
182
+ }
183
+
184
+ paths = self.get_user_storage_paths()
185
+ if not paths:
186
+ return stats
187
+
188
+ # Count analyses and chats
189
+ stats['total_chats'] = len(list(paths['chats'].glob('*.json')))
190
+
191
+ # Calculate storage used
192
+ for path in paths.values():
193
+ if path.exists():
194
+ stats['storage_used'] += sum(f.stat().st_size
195
+ for f in path.rglob('*')
196
+ if f.is_file())
197
+
198
+ # Convert to MB
199
+ stats['storage_used'] = round(stats['storage_used'] / (1024 * 1024), 2)
200
+
201
+ return stats
202
+ except Exception as e:
203
+ st.error(f"Failed to get user stats: {str(e)}")
204
+ return None