sailadachetansurya commited on
Commit
13c04c0
Β·
1 Parent(s): 1618ac3

temp storage fix for memories

Browse files
Dockerfile CHANGED
@@ -12,6 +12,8 @@ RUN apt-get update && apt-get install -y \
12
  # Update pip first
13
  RUN pip install --upgrade pip
14
 
 
 
15
  COPY requirements.txt ./
16
  COPY src/ ./src/
17
 
 
12
  # Update pip first
13
  RUN pip install --upgrade pip
14
 
15
+ RUN apt-get update && apt-get install -y libgl1 && apt-get clean
16
+
17
  COPY requirements.txt ./
18
  COPY src/ ./src/
19
 
src/pages/4_πŸ“_Memory_Wall.py CHANGED
@@ -1,7 +1,9 @@
 
1
  import streamlit as st
2
  import json
3
  import os
4
  from datetime import datetime
 
5
  from PIL import Image
6
 
7
  # --- Load Custom CSS ---
@@ -17,27 +19,85 @@ else:
17
  st.error(f"CSS file not found at: {css_file_path}")
18
 
19
 
20
- # Constants
21
- MEMORY_FILE = "memories.json"
22
- IMAGE_DIR = "memory_images"
23
-
24
- # Ensure image folder exists
25
- if not os.path.exists(IMAGE_DIR):
26
- os.makedirs(IMAGE_DIR)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
  # Load existing memories from JSON
29
  def load_memories():
30
- if os.path.exists(MEMORY_FILE):
31
- with open(MEMORY_FILE, "r", encoding="utf-8") as f:
32
- return json.load(f)
33
- return []
 
 
 
 
 
 
 
34
 
35
  # Save memory to JSON
36
  def save_memory(memory):
37
- memories = load_memories()
38
- memories.append(memory)
39
- with open(MEMORY_FILE, "w", encoding="utf-8") as f:
40
- json.dump(memories, f, indent=2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
  # πŸ”  Page UI
43
  st.markdown('<h1 class="animated">πŸ“ Memory Wall</h1>', unsafe_allow_html=True)
 
1
+ import shutil
2
  import streamlit as st
3
  import json
4
  import os
5
  from datetime import datetime
6
+ from pathlib import Path
7
  from PIL import Image
8
 
9
  # --- Load Custom CSS ---
 
19
  st.error(f"CSS file not found at: {css_file_path}")
20
 
21
 
22
+ # Constants - Using Path objects for better path handling
23
+ PERSISTENT_DIR = Path("/data") # Persistent storage in Hugging Face
24
+ MEMORY_FILE = PERSISTENT_DIR / "memories.json" # Will persist between sessions
25
+ IMAGE_DIR = PERSISTENT_DIR / "memory_images" # Will persist between sessions
26
+
27
+ # Temporary directory for files that can be erased
28
+ TEMP_DIR = Path("/tmp") / "transient_files"
29
+ TEMP_DIR.mkdir(exist_ok=True, parents=True)
30
+
31
+ # Initialize storage
32
+ def init_storage():
33
+ """Create required directories with proper permissions"""
34
+ try:
35
+ IMAGE_DIR.mkdir(exist_ok=True, parents=True)
36
+ # Set permissions (rw for owner, r for others)
37
+ os.chmod(IMAGE_DIR, 0o755)
38
+ if not MEMORY_FILE.exists():
39
+ MEMORY_FILE.touch()
40
+ os.chmod(MEMORY_FILE, 0o644)
41
+ except Exception as e:
42
+ st.error(f"Storage initialization failed: {e}")
43
+ raise
44
+
45
+ # Initialize storage when module loads
46
+ init_storage()
47
 
48
  # Load existing memories from JSON
49
  def load_memories():
50
+ try:
51
+ if MEMORY_FILE.stat().st_size > 0: # Check if file has content
52
+ with open(MEMORY_FILE, "r", encoding="utf-8") as f:
53
+ return json.load(f)
54
+ return []
55
+ except json.JSONDecodeError:
56
+ st.warning("Memories file corrupted, starting fresh")
57
+ return []
58
+ except Exception as e:
59
+ st.error(f"Error loading memories: {e}")
60
+ return []
61
 
62
  # Save memory to JSON
63
  def save_memory(memory):
64
+ try:
65
+ memories = load_memories()
66
+ memories.append(memory)
67
+ with open(MEMORY_FILE, "w", encoding="utf-8") as f:
68
+ json.dump(memories, f, indent=2, ensure_ascii=False)
69
+ os.chmod(MEMORY_FILE, 0o644) # Maintain permissions
70
+ return True
71
+ except Exception as e:
72
+ st.error(f"Error saving memory: {e}")
73
+ return False
74
+
75
+ # For temporary files (like uploads/previews)
76
+ def save_temp_file(file_data, filename):
77
+ """Save temporary file that can be erased"""
78
+ temp_path = TEMP_DIR / filename
79
+ try:
80
+ with open(temp_path, "wb") as f:
81
+ if hasattr(file_data, "read"):
82
+ f.write(file_data.read())
83
+ else:
84
+ f.write(file_data)
85
+ return temp_path
86
+ except Exception as e:
87
+ st.error(f"Error saving temporary file: {e}")
88
+ return None
89
+
90
+ # Cleanup temporary files (call this periodically)
91
+ def cleanup_temp_files():
92
+ """Remove all temporary files"""
93
+ for item in TEMP_DIR.glob("*"):
94
+ try:
95
+ if item.is_file():
96
+ item.unlink()
97
+ else:
98
+ shutil.rmtree(item)
99
+ except Exception as e:
100
+ st.warning(f"Couldn't delete {item}: {e}")
101
 
102
  # πŸ”  Page UI
103
  st.markdown('<h1 class="animated">πŸ“ Memory Wall</h1>', unsafe_allow_html=True)
src/pages/7_πŸ“–_Story_Time.py CHANGED
@@ -1,14 +1,11 @@
1
  import streamlit as st
2
  import os
3
  import json
4
- from streamlit_echarts import st_echarts
5
 
6
  # Load your external CSS file
7
- # Get the directory where this script is located
8
  script_dir = os.path.dirname(os.path.abspath(__file__))
9
  css_file_path = os.path.join(script_dir, "style.css")
10
 
11
- # Check if file exists before trying to open it
12
  if os.path.exists(css_file_path):
13
  with open(css_file_path) as f:
14
  st.markdown(f"<style>{f.read()}</style>", unsafe_allow_html=True)
@@ -35,27 +32,13 @@ def load_markdown(file_path):
35
  return f.read()
36
 
37
  def donut_progress(percent):
38
- option = {
39
- "series": [
40
- {
41
- "type": "pie",
42
- "radius": ["70%", "90%"],
43
- "avoidLabelOverlap": False,
44
- "label": {"show": False},
45
- "labelLine": {"show": False},
46
- "data": [
47
- {"value": percent, "name": "Completed", "itemStyle": {"color": "#00aaff"}},
48
- {"value": 100 - percent, "name": "Remaining", "itemStyle": {"color": "#eee"}},
49
- ],
50
- }
51
- ]
52
- }
53
- st_echarts(option, height=100) # smaller height here
54
-
55
 
56
  st.title("πŸ“š Interactive Story Hub")
57
 
58
- # Initialize session state for story and unlocked parts
59
  if "active_story" not in st.session_state:
60
  st.session_state.active_story = None
61
 
@@ -79,11 +62,10 @@ if st.session_state.active_story:
79
  parts = meta["parts"]
80
  passwords = meta["passwords"]
81
 
82
- # Initialize unlocked state if needed
83
  if story_id not in st.session_state.unlocked_parts:
84
  st.session_state.unlocked_parts[story_id] = [0]
85
 
86
- # Show progress donut
87
  total_parts = len(parts)
88
  unlocked_count = len(st.session_state.unlocked_parts[story_id])
89
  progress_pct = unlocked_count / total_parts * 100
@@ -108,18 +90,17 @@ if st.session_state.active_story:
108
  st.rerun()
109
  else:
110
  st.error("❌ Incorrect password.")
111
- break # Show only one unlock form at a time
112
 
113
  st.markdown("---")
114
  if st.button("πŸ”™ Back to story list"):
115
  st.session_state.active_story = None
116
  st.rerun()
117
 
118
- # ========== VIEW: STORY SELECTION (Fancy Cards) ==========
119
  else:
120
- st.markdown("<style>.stButton>button{width:100%;}</style>", unsafe_allow_html=True) # make buttons full width inside cards
121
 
122
- # Layout cards in 2 columns (adjust as you want)
123
  cols = st.columns(2)
124
  for idx, folder in enumerate(story_folders):
125
  meta_path = os.path.join(stories_dir, folder, "metadata.json")
@@ -130,9 +111,7 @@ else:
130
  continue
131
 
132
  col = cols[idx % 2]
133
-
134
  with col:
135
- # Create card container div with your CSS class "story-card"
136
  card_html = f"""
137
  <div class="story-card">
138
  <div class="story-card-title">{meta.get("title", folder)}</div>
@@ -141,7 +120,6 @@ else:
141
  """
142
  st.markdown(card_html, unsafe_allow_html=True)
143
 
144
- # Button below card
145
  if st.button("Read", key=folder):
146
  st.session_state.active_story = folder
147
- st.rerun()
 
1
  import streamlit as st
2
  import os
3
  import json
 
4
 
5
  # Load your external CSS file
 
6
  script_dir = os.path.dirname(os.path.abspath(__file__))
7
  css_file_path = os.path.join(script_dir, "style.css")
8
 
 
9
  if os.path.exists(css_file_path):
10
  with open(css_file_path) as f:
11
  st.markdown(f"<style>{f.read()}</style>", unsafe_allow_html=True)
 
32
  return f.read()
33
 
34
  def donut_progress(percent):
35
+ # New progress bar implementation
36
+ st.progress(int(percent), text=f"Completed: {percent:.0f}%")
37
+ st.caption(f"Unlocked {int(percent)}% of the story")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
 
39
  st.title("πŸ“š Interactive Story Hub")
40
 
41
+ # Initialize session state
42
  if "active_story" not in st.session_state:
43
  st.session_state.active_story = None
44
 
 
62
  parts = meta["parts"]
63
  passwords = meta["passwords"]
64
 
 
65
  if story_id not in st.session_state.unlocked_parts:
66
  st.session_state.unlocked_parts[story_id] = [0]
67
 
68
+ # Show progress (now using native progress bar)
69
  total_parts = len(parts)
70
  unlocked_count = len(st.session_state.unlocked_parts[story_id])
71
  progress_pct = unlocked_count / total_parts * 100
 
90
  st.rerun()
91
  else:
92
  st.error("❌ Incorrect password.")
93
+ break
94
 
95
  st.markdown("---")
96
  if st.button("πŸ”™ Back to story list"):
97
  st.session_state.active_story = None
98
  st.rerun()
99
 
100
+ # ========== VIEW: STORY SELECTION ==========
101
  else:
102
+ st.markdown("<style>.stButton>button{width:100%;}</style>", unsafe_allow_html=True)
103
 
 
104
  cols = st.columns(2)
105
  for idx, folder in enumerate(story_folders):
106
  meta_path = os.path.join(stories_dir, folder, "metadata.json")
 
111
  continue
112
 
113
  col = cols[idx % 2]
 
114
  with col:
 
115
  card_html = f"""
116
  <div class="story-card">
117
  <div class="story-card-title">{meta.get("title", folder)}</div>
 
120
  """
121
  st.markdown(card_html, unsafe_allow_html=True)
122
 
 
123
  if st.button("Read", key=folder):
124
  st.session_state.active_story = folder
125
+ st.rerun()
src/pages/style.css ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ body {
2
+ background-color: #FFF1E6;
3
+ }
4
+
5
+ h1, h2, h3 {
6
+ color: #FF6F61;
7
+ }
8
+
9
+ .stButton > button {
10
+ background-color: #CBAACB;
11
+ color: white;
12
+ }
13
+
14
+ .sidebar .sidebar-content {
15
+ background-color: #FFF1E6;
16
+ }
17
+
18
+ .css-1d391kg {
19
+ background-color: #FF6F61;
20
+ color: white;
21
+ }
22
+
23
+ .animated {
24
+ animation: pulse 2s infinite;
25
+ color: #ff69b4;
26
+ }
27
+ @keyframes pulse {
28
+ 0% { transform: scale(1); }
29
+ 50% { transform: scale(1.1); }
30
+ 100% { transform: scale(1); }
31
+ }
32
+
33
+ .fade-in {
34
+ animation: fadeIn 2s ease-in forwards;
35
+ opacity: 0;
36
+ }
37
+
38
+ @keyframes fadeIn {
39
+ to {
40
+ opacity: 1;
41
+ }
42
+ }
43
+
44
+ .bounce {
45
+ animation: bounce 1s infinite;
46
+ }
47
+
48
+ @keyframes bounce {
49
+ 0%, 100% { transform: translateY(0); }
50
+ 50% { transform: translateY(-10px); }
51
+ }
52
+
53
+ .swing {
54
+ animation: swing 1s ease-in-out infinite;
55
+ transform-origin: top center;
56
+ }
57
+
58
+ @keyframes swing {
59
+ 0% { transform: rotate(0deg); }
60
+ 50% { transform: rotate(10deg); }
61
+ 100% { transform: rotate(0deg); }
62
+ }
63
+
64
+ .rotate {
65
+ animation: spin 3s linear infinite;
66
+ }
67
+
68
+ @keyframes spin {
69
+ 100% { transform: rotate(360deg); }
70
+ }
71
+
72
+ .glow {
73
+ color: #ff69b4;
74
+ text-shadow: 0 0 5px #ff69b4, 0 0 10px #ff69b4, 0 0 20px #ff69b4;
75
+ animation: glow-pulse 2s infinite alternate;
76
+ }
77
+
78
+ @keyframes glow-pulse {
79
+ from { text-shadow: 0 0 5px #ff69b4; }
80
+ to { text-shadow: 0 0 20px #ff69b4; }
81
+ }
82
+
83
+ :root {
84
+ --coral-pink: #f88379ff; /* your coral pink */
85
+ }
86
+
87
+ /* Card container */
88
+ .story-card {
89
+ background-color: #F4C2C2;
90
+ border: 3px solid var(--coral-pink);
91
+ border-radius: 16px;
92
+ padding: 20px;
93
+ margin-bottom: 20px;
94
+ box-shadow: 0 4px 8px rgba(248, 131, 121, 0.3);
95
+ transition: transform 0.3s ease, box-shadow 0.3s ease;
96
+ cursor: pointer;
97
+ }
98
+
99
+ .story-card:hover {
100
+ transform: scale(1.05);
101
+ box-shadow: 0 8px 16px rgba(224, 127, 189, 0.6);
102
+ border-color: #f3a2bd; /* stronger coral */
103
+ }
104
+
105
+ /* Card title with glow */
106
+ .story-card-title {
107
+ font-size: 1.5rem;
108
+ color: #4f6d7aff;
109
+ font-weight: 700;
110
+ margin-bottom: 8px;
111
+ text-align: center;
112
+ animation: glow-pulse 2s infinite alternate;
113
+ }
114
+
115
+ /* Card description */
116
+ .story-card-desc {
117
+ color: #555;
118
+ font-size: 1rem;
119
+ margin-bottom: 12px;
120
+ text-align: center;
121
+ }
122
+
123
+ /* Read button inside card */
124
+ .story-card-button button {
125
+ width: 100%;
126
+ background-color: var(--coral-pink);
127
+ border: none;
128
+ border-radius: 12px;
129
+ padding: 10px;
130
+ color: FFF0F5;
131
+ font-weight: 600;
132
+ font-size: 1rem;
133
+ transition: background-color 0.3s ease;
134
+ cursor: pointer;
135
+ }
136
+
137
+ .story-card-button button:hover {
138
+ background-color: #E0B0FF;
139
+ }
140
+
141
+
142
+
143
+ /* --coral-pink: #f88379ff;
144
+ --lemon-chiffon: #fdf5bfff;
145
+ --tiffany-blue: #92d1c3ff;
146
+ --cambridge-blue: #8bb8a8ff;
147
+ --paynes-gray: #4f6d7aff; */