Spaces:
Sleeping
Sleeping
shikharyashmaurya
commited on
Commit
•
d173cda
1
Parent(s):
fb83ace
Upload user-authenticated-revision-app5.py
Browse files
user-authenticated-revision-app5.py
ADDED
@@ -0,0 +1,259 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
import networkx as nx
|
3 |
+
import matplotlib.pyplot as plt
|
4 |
+
import textwrap
|
5 |
+
from io import BytesIO
|
6 |
+
import uuid
|
7 |
+
|
8 |
+
class RevisionApp:
|
9 |
+
def __init__(self):
|
10 |
+
self.initialize_session_state()
|
11 |
+
self.handle_user_selection()
|
12 |
+
self.create_ui()
|
13 |
+
|
14 |
+
def initialize_session_state(self):
|
15 |
+
if 'users' not in st.session_state:
|
16 |
+
st.session_state.users = {}
|
17 |
+
if 'current_user' not in st.session_state:
|
18 |
+
st.session_state.current_user = None
|
19 |
+
if 'user_sessions' not in st.session_state:
|
20 |
+
st.session_state.user_sessions = {}
|
21 |
+
|
22 |
+
def handle_user_selection(self):
|
23 |
+
st.sidebar.title("User Selection")
|
24 |
+
user_name = st.sidebar.text_input("Enter your name:")
|
25 |
+
if st.sidebar.button("Set User"):
|
26 |
+
if user_name:
|
27 |
+
# Check if the username is already in use in this session
|
28 |
+
if user_name in st.session_state.user_sessions:
|
29 |
+
st.sidebar.error(f"The name '{user_name}' is already in use. Please choose a different name.")
|
30 |
+
else:
|
31 |
+
# Generate a unique session ID for this user
|
32 |
+
session_id = str(uuid.uuid4())
|
33 |
+
st.session_state.current_user = f"{user_name}_{session_id}"
|
34 |
+
st.session_state.user_sessions[user_name] = session_id
|
35 |
+
if st.session_state.current_user not in st.session_state.users:
|
36 |
+
st.session_state.users[st.session_state.current_user] = {}
|
37 |
+
st.success(f"User set to: {user_name}")
|
38 |
+
st.experimental_rerun()
|
39 |
+
|
40 |
+
def create_ui(self):
|
41 |
+
if st.session_state.current_user:
|
42 |
+
display_name = st.session_state.current_user.split('_')[0] # Extract the user's name without the session ID
|
43 |
+
st.title(f"Concept Revision App - Welcome, {display_name}!")
|
44 |
+
|
45 |
+
# Navigation
|
46 |
+
page = st.sidebar.selectbox("Choose a page", ["Tree View", "Mind Map", "Search"])
|
47 |
+
|
48 |
+
if page == "Tree View":
|
49 |
+
self.show_tree_view()
|
50 |
+
elif page == "Mind Map":
|
51 |
+
self.show_mind_map()
|
52 |
+
elif page == "Search":
|
53 |
+
self.show_search()
|
54 |
+
else:
|
55 |
+
st.title("Concept Revision App")
|
56 |
+
st.write("Please enter your name in the sidebar to begin.")
|
57 |
+
|
58 |
+
# The rest of the methods (show_tree_view, show_concept_details, show_mind_map, show_search, search_data, custom_tree_layout)
|
59 |
+
# remain the same as in the previous version, just ensure you're using st.session_state.current_user
|
60 |
+
# to access the correct user data in st.session_state.users
|
61 |
+
|
62 |
+
# Example of how to modify a method to use the new user identifier:
|
63 |
+
def show_tree_view(self):
|
64 |
+
st.header("Tree View")
|
65 |
+
|
66 |
+
# Input for new concept
|
67 |
+
new_key = st.text_input("Enter a new concept:")
|
68 |
+
if st.button("Add Concept"):
|
69 |
+
if new_key and new_key not in st.session_state.users[st.session_state.current_user]:
|
70 |
+
st.session_state.users[st.session_state.current_user][new_key] = {'next': [], 'text': []}
|
71 |
+
st.success(f"Added new concept: {new_key}")
|
72 |
+
st.experimental_rerun()
|
73 |
+
|
74 |
+
# Display concepts
|
75 |
+
user_data = st.session_state.users[st.session_state.current_user]
|
76 |
+
selected_concept = st.selectbox("Select a concept to view details:",
|
77 |
+
options=[""] + list(user_data.keys()))
|
78 |
+
|
79 |
+
if selected_concept:
|
80 |
+
self.show_concept_details(selected_concept)
|
81 |
+
|
82 |
+
# ... (other methods remain the same, just ensure you're using st.session_state.current_user consistently)
|
83 |
+
# def show_tree_view(self):
|
84 |
+
# st.header("Tree View")
|
85 |
+
|
86 |
+
# # Input for new concept
|
87 |
+
# new_key = st.text_input("Enter a new concept:")
|
88 |
+
# if st.button("Add Concept"):
|
89 |
+
# if new_key and new_key not in st.session_state.users[st.session_state.current_user]:
|
90 |
+
# st.session_state.users[st.session_state.current_user][new_key] = {'next': [], 'text': []}
|
91 |
+
# st.success(f"Added new concept: {new_key}")
|
92 |
+
# st.experimental_rerun()
|
93 |
+
|
94 |
+
# # Display concepts
|
95 |
+
# user_data = st.session_state.users[st.session_state.current_user]
|
96 |
+
# selected_concept = st.selectbox("Select a concept to view details:",
|
97 |
+
# options=[""] + list(user_data.keys()))
|
98 |
+
|
99 |
+
# if selected_concept:
|
100 |
+
# self.show_concept_details(selected_concept)
|
101 |
+
|
102 |
+
def show_concept_details(self, key):
|
103 |
+
user_data = st.session_state.users[st.session_state.current_user]
|
104 |
+
st.subheader(f"Concept: {key}")
|
105 |
+
|
106 |
+
# Display related concepts
|
107 |
+
st.write("Related Concepts:")
|
108 |
+
for next_item in user_data[key]['next']:
|
109 |
+
if st.button(f"Go to {next_item}", key=f"goto_{next_item}"):
|
110 |
+
self.show_concept_details(next_item)
|
111 |
+
return
|
112 |
+
|
113 |
+
# Add related concept
|
114 |
+
new_related = st.text_input(f"Add related concept to {key}:", key=f"related_{key}")
|
115 |
+
if st.button(f"Add related to {key}", key=f"add_related_{key}"):
|
116 |
+
if new_related and new_related not in user_data[key]['next']:
|
117 |
+
if new_related not in user_data:
|
118 |
+
user_data[new_related] = {'next': [], 'text': []}
|
119 |
+
user_data[key]['next'].append(new_related)
|
120 |
+
st.success(f"Added {new_related} as related to {key}")
|
121 |
+
st.experimental_rerun()
|
122 |
+
|
123 |
+
# Display information
|
124 |
+
st.write("Information:")
|
125 |
+
for i, text_item in enumerate(user_data[key]['text']):
|
126 |
+
st.text_area(f"Info {i+1}", value=text_item, key=f"info_{key}_{i}", height=100, disabled=True)
|
127 |
+
|
128 |
+
# Add information
|
129 |
+
new_info = st.text_area(f"Add information to {key}:", key=f"new_info_{key}")
|
130 |
+
if st.button(f"Add info to {key}", key=f"add_info_{key}"):
|
131 |
+
if new_info:
|
132 |
+
user_data[key]['text'].append(new_info)
|
133 |
+
st.success(f"Added new information to {key}")
|
134 |
+
st.experimental_rerun()
|
135 |
+
|
136 |
+
def show_mind_map(self):
|
137 |
+
st.header("Mind Map")
|
138 |
+
|
139 |
+
user_data = st.session_state.users[st.session_state.current_user]
|
140 |
+
G = nx.Graph()
|
141 |
+
for key, value in user_data.items():
|
142 |
+
G.add_node(key)
|
143 |
+
for next_item in value['next']:
|
144 |
+
if next_item in user_data:
|
145 |
+
G.add_edge(key, next_item)
|
146 |
+
|
147 |
+
pos = self.custom_tree_layout(G)
|
148 |
+
|
149 |
+
plt.figure(figsize=(12, 8))
|
150 |
+
nx.draw(G, pos, with_labels=False, node_color='lightblue', node_size=3000, alpha=0.8)
|
151 |
+
|
152 |
+
for node, (x, y) in pos.items():
|
153 |
+
lines = textwrap.wrap(node, width=10)
|
154 |
+
plt.annotate('\n'.join(lines), (x, y), horizontalalignment='center', verticalalignment='center')
|
155 |
+
|
156 |
+
plt.axis('off')
|
157 |
+
|
158 |
+
buf = BytesIO()
|
159 |
+
plt.savefig(buf, format="png")
|
160 |
+
buf.seek(0)
|
161 |
+
|
162 |
+
st.image(buf, caption='Mind Map', use_column_width=True)
|
163 |
+
|
164 |
+
def show_search(self):
|
165 |
+
st.header("Search")
|
166 |
+
|
167 |
+
query = st.text_input("Enter search term:")
|
168 |
+
if st.button("Search"):
|
169 |
+
results = self.search_data(query)
|
170 |
+
if results:
|
171 |
+
for key in results:
|
172 |
+
with st.expander(f"Concept: {key}"):
|
173 |
+
st.write("Related Concepts:")
|
174 |
+
for related in st.session_state.users[st.session_state.current_user][key]['next']:
|
175 |
+
st.write(f"- {related}")
|
176 |
+
st.write("Information:")
|
177 |
+
for info in st.session_state.users[st.session_state.current_user][key]['text']:
|
178 |
+
st.write(f"- {info}")
|
179 |
+
else:
|
180 |
+
st.write("No results found.")
|
181 |
+
|
182 |
+
def search_data(self, query):
|
183 |
+
query = query.lower()
|
184 |
+
user_data = st.session_state.users[st.session_state.current_user]
|
185 |
+
results = set()
|
186 |
+
for key, value in user_data.items():
|
187 |
+
if query in key.lower():
|
188 |
+
results.add(key)
|
189 |
+
for next_item in value['next']:
|
190 |
+
if query in next_item.lower():
|
191 |
+
results.add(key)
|
192 |
+
for text_item in value['text']:
|
193 |
+
if query in text_item.lower():
|
194 |
+
results.add(key)
|
195 |
+
return list(results)
|
196 |
+
|
197 |
+
def custom_tree_layout(self, G):
|
198 |
+
if not G.nodes():
|
199 |
+
return {}
|
200 |
+
|
201 |
+
def bfs_tree(root):
|
202 |
+
tree = nx.bfs_tree(G, root)
|
203 |
+
return tree
|
204 |
+
|
205 |
+
def assign_positions(tree, root):
|
206 |
+
pos = {}
|
207 |
+
level_width = {}
|
208 |
+
max_depth = 0
|
209 |
+
|
210 |
+
def dfs(node, depth, order):
|
211 |
+
nonlocal max_depth
|
212 |
+
max_depth = max(max_depth, depth)
|
213 |
+
if depth not in level_width:
|
214 |
+
level_width[depth] = 0
|
215 |
+
level_width[depth] += 1
|
216 |
+
children = list(tree.successors(node))
|
217 |
+
if not children:
|
218 |
+
pos[node] = (order, -depth)
|
219 |
+
return order + 1
|
220 |
+
|
221 |
+
start = order
|
222 |
+
for child in children:
|
223 |
+
order = dfs(child, depth + 1, order)
|
224 |
+
pos[node] = (start + (order - start - 1) / 2, -depth)
|
225 |
+
return order
|
226 |
+
|
227 |
+
dfs(root, 0, 0)
|
228 |
+
|
229 |
+
# Normalize positions
|
230 |
+
max_width = max(level_width.values()) if level_width else 1
|
231 |
+
for node in pos:
|
232 |
+
x, y = pos[node]
|
233 |
+
pos[node] = (x / max_width, y / max_depth if max_depth != 0 else 0)
|
234 |
+
|
235 |
+
return pos
|
236 |
+
|
237 |
+
# Handle disconnected components
|
238 |
+
components = list(nx.connected_components(G))
|
239 |
+
if not components:
|
240 |
+
return {}
|
241 |
+
|
242 |
+
pos = {}
|
243 |
+
y_offset = 0
|
244 |
+
for component in components:
|
245 |
+
subgraph = G.subgraph(component)
|
246 |
+
root = max(subgraph.nodes(), key=lambda n: subgraph.degree(n))
|
247 |
+
tree = bfs_tree(root)
|
248 |
+
component_pos = assign_positions(tree, root)
|
249 |
+
|
250 |
+
# Adjust y-positions for each component
|
251 |
+
for node, (x, y) in component_pos.items():
|
252 |
+
pos[node] = (x, y + y_offset)
|
253 |
+
|
254 |
+
y_offset -= 1.5 # Increase vertical separation between components
|
255 |
+
|
256 |
+
return pos
|
257 |
+
|
258 |
+
if __name__ == "__main__":
|
259 |
+
app = RevisionApp()
|