Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -429,6 +429,8 @@ def extract_and_fix_json(text, subject="General"):
|
|
| 429 |
dict: Parsed JSON or generic plan
|
| 430 |
"""
|
| 431 |
if not text or not isinstance(text, str):
|
|
|
|
|
|
|
| 432 |
return None
|
| 433 |
|
| 434 |
# Store raw response for debug
|
|
@@ -443,31 +445,50 @@ def extract_and_fix_json(text, subject="General"):
|
|
| 443 |
text = re.sub(r'```javascript\s*', '', text, flags=re.IGNORECASE)
|
| 444 |
text = re.sub(r'```python\s*', '', text, flags=re.IGNORECASE)
|
| 445 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 446 |
# Find JSON boundaries
|
| 447 |
start_idx = text.find('{')
|
| 448 |
end_idx = text.rfind('}')
|
| 449 |
|
| 450 |
if start_idx == -1 or end_idx == -1 or end_idx <= start_idx:
|
|
|
|
|
|
|
| 451 |
return None
|
| 452 |
|
| 453 |
json_str = text[start_idx:end_idx+1]
|
| 454 |
|
| 455 |
-
#
|
| 456 |
if st.session_state.show_debug:
|
| 457 |
with st.expander("π JSON String Being Parsed", expanded=False):
|
| 458 |
-
st.code(json_str[:
|
| 459 |
|
| 460 |
try:
|
| 461 |
# First try: Direct parse
|
| 462 |
-
|
|
|
|
|
|
|
|
|
|
| 463 |
except json.JSONDecodeError as e:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 464 |
# Second try: Apply fixes
|
| 465 |
json_str = fix_json_string(json_str)
|
| 466 |
try:
|
| 467 |
-
|
| 468 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 469 |
# Third try: Create generic plan
|
| 470 |
-
return
|
| 471 |
|
| 472 |
def fix_json_string(json_str):
|
| 473 |
"""
|
|
@@ -643,7 +664,10 @@ def generate_study_plan(api_key, **kwargs):
|
|
| 643 |
"""
|
| 644 |
Generate study plan using Gemini
|
| 645 |
"""
|
| 646 |
-
|
|
|
|
|
|
|
|
|
|
| 647 |
|
| 648 |
# Extract parameters
|
| 649 |
subject = kwargs.get('subject', 'General Learning')
|
|
@@ -690,11 +714,23 @@ Return valid JSON with this exact structure:
|
|
| 690 |
"success_metrics": ["Metric 1", "Metric 2"]
|
| 691 |
}}
|
| 692 |
|
| 693 |
-
IMPORTANT:
|
| 694 |
-
|
|
|
|
|
|
|
|
|
|
| 695 |
|
| 696 |
try:
|
|
|
|
|
|
|
| 697 |
model = genai.GenerativeModel('gemini-2.5-flash')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 698 |
response = model.generate_content(
|
| 699 |
prompt,
|
| 700 |
generation_config=genai.GenerationConfig(
|
|
@@ -702,15 +738,34 @@ Include ALL {weeks} weeks in the weekly_schedule array."""
|
|
| 702 |
temperature=0.7
|
| 703 |
)
|
| 704 |
)
|
|
|
|
| 705 |
raw_text = response.text
|
| 706 |
st.session_state.raw_response = raw_text
|
| 707 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 708 |
plan = extract_and_fix_json(raw_text, subject)
|
| 709 |
|
| 710 |
if plan:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 711 |
# Post-process the plan
|
| 712 |
plan['generated_at'] = datetime.now().isoformat()
|
| 713 |
plan['total_days'] = days_available
|
|
|
|
| 714 |
|
| 715 |
# Initialize week tracking
|
| 716 |
for week in plan.get('weekly_schedule', []):
|
|
@@ -728,9 +783,16 @@ Include ALL {weeks} weeks in the weekly_schedule array."""
|
|
| 728 |
|
| 729 |
return plan
|
| 730 |
else:
|
|
|
|
|
|
|
|
|
|
| 731 |
return create_generic_plan(subject, days_available)
|
| 732 |
|
| 733 |
except Exception as e:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 734 |
return create_generic_plan(subject, days_available)
|
| 735 |
|
| 736 |
def generate_weekly_test(api_key, week_number, weekly_tasks, subject):
|
|
@@ -1124,16 +1186,46 @@ tab1, tab2, tab3, tab4, tab5, tab6 = st.tabs([
|
|
| 1124 |
"π€ Export"
|
| 1125 |
])
|
| 1126 |
|
|
|
|
| 1127 |
# ============================================
|
| 1128 |
-
# TAB 1: DEFINE GOAL
|
| 1129 |
# ============================================
|
| 1130 |
|
| 1131 |
with tab1:
|
| 1132 |
st.markdown('<h2 class="sub-header">Define Your Learning Goal</h2>', unsafe_allow_html=True)
|
| 1133 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1134 |
# Option 1: Upload Existing Plan
|
| 1135 |
st.info("π€ **Option 1: Upload Existing Plan**")
|
| 1136 |
-
uploaded_file = st.file_uploader("Upload saved study plan (JSON)", type=['json'])
|
| 1137 |
|
| 1138 |
if uploaded_file is not None and not st.session_state.plan_loaded:
|
| 1139 |
try:
|
|
@@ -1142,8 +1234,8 @@ with tab1:
|
|
| 1142 |
st.session_state.subject = plan['subject']
|
| 1143 |
st.session_state.plan_loaded = True
|
| 1144 |
st.success(f"β
Plan loaded: {plan['subject']}")
|
| 1145 |
-
except:
|
| 1146 |
-
st.error("β Invalid plan file")
|
| 1147 |
|
| 1148 |
st.markdown("---")
|
| 1149 |
|
|
@@ -1156,7 +1248,8 @@ with tab1:
|
|
| 1156 |
subject = st.text_input(
|
| 1157 |
"What do you want to learn?",
|
| 1158 |
placeholder="e.g., Data Science, Python, Web Development...",
|
| 1159 |
-
help="Enter the subject or topic"
|
|
|
|
| 1160 |
)
|
| 1161 |
|
| 1162 |
col1a, col2a = st.columns(2)
|
|
@@ -1165,7 +1258,8 @@ with tab1:
|
|
| 1165 |
"Hours per day:",
|
| 1166 |
min_value=1,
|
| 1167 |
max_value=8,
|
| 1168 |
-
value=2
|
|
|
|
| 1169 |
)
|
| 1170 |
|
| 1171 |
with col2a:
|
|
@@ -1173,30 +1267,35 @@ with tab1:
|
|
| 1173 |
"Days available:",
|
| 1174 |
min_value=7,
|
| 1175 |
max_value=365,
|
| 1176 |
-
value=60
|
|
|
|
| 1177 |
)
|
| 1178 |
|
| 1179 |
study_days = st.multiselect(
|
| 1180 |
"Study days:",
|
| 1181 |
["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
|
| 1182 |
-
default=["Mon", "Tue", "Wed", "Thu", "Fri"]
|
|
|
|
| 1183 |
)
|
| 1184 |
|
| 1185 |
with col2:
|
| 1186 |
current_level = st.selectbox(
|
| 1187 |
"Your level:",
|
| 1188 |
["Beginner", "Intermediate", "Advanced"],
|
| 1189 |
-
index=0
|
|
|
|
| 1190 |
)
|
| 1191 |
|
|
|
|
|
|
|
| 1192 |
# Generate Plan Button
|
| 1193 |
-
if st.button("π Generate AI Study Plan", type="primary", use_container_width=True):
|
| 1194 |
if not st.session_state.api_key:
|
| 1195 |
-
st.error("β οΈ API Key Required")
|
| 1196 |
elif not subject:
|
| 1197 |
-
st.error("β οΈ Please enter a subject")
|
| 1198 |
elif not study_days:
|
| 1199 |
-
st.error("β οΈ Please select study
|
| 1200 |
else:
|
| 1201 |
with st.spinner("π€ AI is creating your personalized study plan..."):
|
| 1202 |
try:
|
|
@@ -1216,34 +1315,67 @@ with tab1:
|
|
| 1216 |
'study_days': study_days
|
| 1217 |
}
|
| 1218 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1219 |
# Generate plan
|
| 1220 |
plan = generate_study_plan(st.session_state.api_key, **plan_data)
|
| 1221 |
|
| 1222 |
if plan:
|
| 1223 |
st.session_state.study_plan = plan
|
| 1224 |
st.session_state.subject = subject
|
|
|
|
|
|
|
|
|
|
| 1225 |
st.session_state.plan_loaded = True
|
| 1226 |
|
| 1227 |
-
# Show debug info
|
| 1228 |
-
if st.session_state.show_debug:
|
| 1229 |
-
with st.expander("π Raw AI Response", expanded=True):
|
| 1230 |
-
st.text_area("Full Response", st.session_state.raw_response, height=300)
|
| 1231 |
-
|
| 1232 |
st.success("β
Study plan generated successfully!")
|
| 1233 |
st.balloons()
|
| 1234 |
|
| 1235 |
# Show plan summary
|
| 1236 |
st.info(f"π
**Schedule:** {len(study_days)} days/week ({', '.join(study_days)}) Γ {hours_per_day} hours/day")
|
| 1237 |
-
st.info(f"π **Duration:** {plan.get('total_weeks', 0)} weeks")
|
| 1238 |
|
| 1239 |
# Show learning quality
|
| 1240 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1241 |
|
| 1242 |
else:
|
| 1243 |
-
st.error("β Failed to generate plan")
|
| 1244 |
|
| 1245 |
except Exception as e:
|
| 1246 |
st.error(f"β Error: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1247 |
|
| 1248 |
# ============================================
|
| 1249 |
# TAB 2: STUDY PLAN
|
|
|
|
| 429 |
dict: Parsed JSON or generic plan
|
| 430 |
"""
|
| 431 |
if not text or not isinstance(text, str):
|
| 432 |
+
if st.session_state.show_debug:
|
| 433 |
+
st.warning("β οΈ No text to parse in extract_and_fix_json")
|
| 434 |
return None
|
| 435 |
|
| 436 |
# Store raw response for debug
|
|
|
|
| 445 |
text = re.sub(r'```javascript\s*', '', text, flags=re.IGNORECASE)
|
| 446 |
text = re.sub(r'```python\s*', '', text, flags=re.IGNORECASE)
|
| 447 |
|
| 448 |
+
# Show cleaned text in debug
|
| 449 |
+
if st.session_state.show_debug:
|
| 450 |
+
with st.expander("π§Ή Cleaned Text (first 500 chars)", expanded=False):
|
| 451 |
+
st.code(text[:500] + "..." if len(text) > 500 else text)
|
| 452 |
+
|
| 453 |
# Find JSON boundaries
|
| 454 |
start_idx = text.find('{')
|
| 455 |
end_idx = text.rfind('}')
|
| 456 |
|
| 457 |
if start_idx == -1 or end_idx == -1 or end_idx <= start_idx:
|
| 458 |
+
if st.session_state.show_debug:
|
| 459 |
+
st.error(f"β No JSON found. Start: {start_idx}, End: {end_idx}")
|
| 460 |
return None
|
| 461 |
|
| 462 |
json_str = text[start_idx:end_idx+1]
|
| 463 |
|
| 464 |
+
# Show JSON string in debug
|
| 465 |
if st.session_state.show_debug:
|
| 466 |
with st.expander("π JSON String Being Parsed", expanded=False):
|
| 467 |
+
st.code(json_str[:1000] + "..." if len(json_str) > 1000 else json_str)
|
| 468 |
|
| 469 |
try:
|
| 470 |
# First try: Direct parse
|
| 471 |
+
parsed_json = json.loads(json_str)
|
| 472 |
+
if st.session_state.show_debug:
|
| 473 |
+
st.success("β
JSON parsed successfully on first try")
|
| 474 |
+
return parsed_json
|
| 475 |
except json.JSONDecodeError as e:
|
| 476 |
+
if st.session_state.show_debug:
|
| 477 |
+
st.warning(f"β οΈ First parse failed: {str(e)}")
|
| 478 |
+
st.info("Trying to fix JSON...")
|
| 479 |
+
|
| 480 |
# Second try: Apply fixes
|
| 481 |
json_str = fix_json_string(json_str)
|
| 482 |
try:
|
| 483 |
+
parsed_json = json.loads(json_str)
|
| 484 |
+
if st.session_state.show_debug:
|
| 485 |
+
st.success("β
JSON parsed successfully after fixes")
|
| 486 |
+
return parsed_json
|
| 487 |
+
except json.JSONDecodeError as e2:
|
| 488 |
+
if st.session_state.show_debug:
|
| 489 |
+
st.error(f"β Second parse failed: {str(e2)}")
|
| 490 |
# Third try: Create generic plan
|
| 491 |
+
return None
|
| 492 |
|
| 493 |
def fix_json_string(json_str):
|
| 494 |
"""
|
|
|
|
| 664 |
"""
|
| 665 |
Generate study plan using Gemini
|
| 666 |
"""
|
| 667 |
+
if not api_key:
|
| 668 |
+
st.error("β No API key provided")
|
| 669 |
+
return create_generic_plan(kwargs.get('subject', 'General'),
|
| 670 |
+
kwargs.get('days_available', 60))
|
| 671 |
|
| 672 |
# Extract parameters
|
| 673 |
subject = kwargs.get('subject', 'General Learning')
|
|
|
|
| 714 |
"success_metrics": ["Metric 1", "Metric 2"]
|
| 715 |
}}
|
| 716 |
|
| 717 |
+
IMPORTANT:
|
| 718 |
+
1. Make sure topics_allocation values are NUMBERS (not strings like "10 hours")
|
| 719 |
+
2. Include ALL {weeks} weeks in the weekly_schedule array
|
| 720 |
+
3. Return ONLY JSON, no additional text
|
| 721 |
+
4. Make tasks specific and actionable for {subject}"""
|
| 722 |
|
| 723 |
try:
|
| 724 |
+
# Configure API
|
| 725 |
+
genai.configure(api_key=api_key)
|
| 726 |
model = genai.GenerativeModel('gemini-2.5-flash')
|
| 727 |
+
|
| 728 |
+
# Show prompt in debug mode
|
| 729 |
+
if st.session_state.show_debug:
|
| 730 |
+
with st.expander("π Prompt Sent to AI", expanded=False):
|
| 731 |
+
st.code(prompt[:1000] + "..." if len(prompt) > 1000 else prompt)
|
| 732 |
+
|
| 733 |
+
# Generate response
|
| 734 |
response = model.generate_content(
|
| 735 |
prompt,
|
| 736 |
generation_config=genai.GenerationConfig(
|
|
|
|
| 738 |
temperature=0.7
|
| 739 |
)
|
| 740 |
)
|
| 741 |
+
|
| 742 |
raw_text = response.text
|
| 743 |
st.session_state.raw_response = raw_text
|
| 744 |
|
| 745 |
+
# Show raw response in debug mode
|
| 746 |
+
if st.session_state.show_debug:
|
| 747 |
+
with st.expander("π Raw AI Response", expanded=False):
|
| 748 |
+
st.text_area("AI Response", raw_text, height=200, key="ai_response_raw")
|
| 749 |
+
|
| 750 |
+
# Extract JSON
|
| 751 |
plan = extract_and_fix_json(raw_text, subject)
|
| 752 |
|
| 753 |
if plan:
|
| 754 |
+
# Show success in debug mode
|
| 755 |
+
if st.session_state.show_debug:
|
| 756 |
+
st.success("β
JSON successfully extracted")
|
| 757 |
+
with st.expander("π Extracted Plan Preview", expanded=False):
|
| 758 |
+
st.json({
|
| 759 |
+
"subject": plan.get('subject'),
|
| 760 |
+
"total_weeks": plan.get('total_weeks'),
|
| 761 |
+
"weekly_schedule_length": len(plan.get('weekly_schedule', [])),
|
| 762 |
+
"first_week_focus": plan.get('weekly_schedule', [{}])[0].get('focus', 'N/A') if plan.get('weekly_schedule') else 'N/A'
|
| 763 |
+
})
|
| 764 |
+
|
| 765 |
# Post-process the plan
|
| 766 |
plan['generated_at'] = datetime.now().isoformat()
|
| 767 |
plan['total_days'] = days_available
|
| 768 |
+
plan['user_level'] = current_level
|
| 769 |
|
| 770 |
# Initialize week tracking
|
| 771 |
for week in plan.get('weekly_schedule', []):
|
|
|
|
| 783 |
|
| 784 |
return plan
|
| 785 |
else:
|
| 786 |
+
st.warning("β οΈ Could not extract valid JSON from AI response")
|
| 787 |
+
if st.session_state.show_debug:
|
| 788 |
+
st.info("Falling back to generic plan")
|
| 789 |
return create_generic_plan(subject, days_available)
|
| 790 |
|
| 791 |
except Exception as e:
|
| 792 |
+
st.error(f"β AI Generation Error: {str(e)}")
|
| 793 |
+
if st.session_state.show_debug:
|
| 794 |
+
with st.expander("π Error Details", expanded=False):
|
| 795 |
+
st.exception(e)
|
| 796 |
return create_generic_plan(subject, days_available)
|
| 797 |
|
| 798 |
def generate_weekly_test(api_key, week_number, weekly_tasks, subject):
|
|
|
|
| 1186 |
"π€ Export"
|
| 1187 |
])
|
| 1188 |
|
| 1189 |
+
|
| 1190 |
# ============================================
|
| 1191 |
+
# TAB 1: DEFINE GOAL
|
| 1192 |
# ============================================
|
| 1193 |
|
| 1194 |
with tab1:
|
| 1195 |
st.markdown('<h2 class="sub-header">Define Your Learning Goal</h2>', unsafe_allow_html=True)
|
| 1196 |
|
| 1197 |
+
# Debug Mode Toggle
|
| 1198 |
+
col_debug1, col_debug2 = st.columns([1, 3])
|
| 1199 |
+
with col_debug1:
|
| 1200 |
+
st.session_state.show_debug = st.checkbox("π Debug Mode", value=False)
|
| 1201 |
+
|
| 1202 |
+
# API Status
|
| 1203 |
+
with col_debug2:
|
| 1204 |
+
if not st.session_state.api_key:
|
| 1205 |
+
st.error("β οΈ **API Key Missing:** Set GEMINI_API_KEY in Hugging Face Secrets")
|
| 1206 |
+
else:
|
| 1207 |
+
st.success("β
**API Key Loaded**")
|
| 1208 |
+
|
| 1209 |
+
# Test API Button
|
| 1210 |
+
if st.session_state.api_key and st.session_state.show_debug:
|
| 1211 |
+
if st.button("Test API Connection", type="secondary", key="test_api"):
|
| 1212 |
+
try:
|
| 1213 |
+
genai.configure(api_key=st.session_state.api_key)
|
| 1214 |
+
model = genai.GenerativeModel('gemini-2.5-flash')
|
| 1215 |
+
test_response = model.generate_content("Say 'API is working'",
|
| 1216 |
+
generation_config=genai.GenerationConfig(max_output_tokens=10))
|
| 1217 |
+
if test_response.text:
|
| 1218 |
+
st.success(f"β
**API Connected:** {test_response.text}")
|
| 1219 |
+
else:
|
| 1220 |
+
st.error("β No response from API")
|
| 1221 |
+
except Exception as e:
|
| 1222 |
+
st.error(f"β **API Error:** {str(e)}")
|
| 1223 |
+
|
| 1224 |
+
st.markdown("---")
|
| 1225 |
+
|
| 1226 |
# Option 1: Upload Existing Plan
|
| 1227 |
st.info("π€ **Option 1: Upload Existing Plan**")
|
| 1228 |
+
uploaded_file = st.file_uploader("Upload saved study plan (JSON)", type=['json'], key="upload_plan")
|
| 1229 |
|
| 1230 |
if uploaded_file is not None and not st.session_state.plan_loaded:
|
| 1231 |
try:
|
|
|
|
| 1234 |
st.session_state.subject = plan['subject']
|
| 1235 |
st.session_state.plan_loaded = True
|
| 1236 |
st.success(f"β
Plan loaded: {plan['subject']}")
|
| 1237 |
+
except Exception as e:
|
| 1238 |
+
st.error(f"β Invalid plan file: {str(e)}")
|
| 1239 |
|
| 1240 |
st.markdown("---")
|
| 1241 |
|
|
|
|
| 1248 |
subject = st.text_input(
|
| 1249 |
"What do you want to learn?",
|
| 1250 |
placeholder="e.g., Data Science, Python, Web Development...",
|
| 1251 |
+
help="Enter the subject or topic",
|
| 1252 |
+
key="subject_input"
|
| 1253 |
)
|
| 1254 |
|
| 1255 |
col1a, col2a = st.columns(2)
|
|
|
|
| 1258 |
"Hours per day:",
|
| 1259 |
min_value=1,
|
| 1260 |
max_value=8,
|
| 1261 |
+
value=2,
|
| 1262 |
+
key="hours_slider"
|
| 1263 |
)
|
| 1264 |
|
| 1265 |
with col2a:
|
|
|
|
| 1267 |
"Days available:",
|
| 1268 |
min_value=7,
|
| 1269 |
max_value=365,
|
| 1270 |
+
value=60,
|
| 1271 |
+
key="days_slider"
|
| 1272 |
)
|
| 1273 |
|
| 1274 |
study_days = st.multiselect(
|
| 1275 |
"Study days:",
|
| 1276 |
["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
|
| 1277 |
+
default=["Mon", "Tue", "Wed", "Thu", "Fri"],
|
| 1278 |
+
key="study_days_select"
|
| 1279 |
)
|
| 1280 |
|
| 1281 |
with col2:
|
| 1282 |
current_level = st.selectbox(
|
| 1283 |
"Your level:",
|
| 1284 |
["Beginner", "Intermediate", "Advanced"],
|
| 1285 |
+
index=0,
|
| 1286 |
+
key="level_select"
|
| 1287 |
)
|
| 1288 |
|
| 1289 |
+
st.markdown("---")
|
| 1290 |
+
|
| 1291 |
# Generate Plan Button
|
| 1292 |
+
if st.button("π Generate AI Study Plan", type="primary", use_container_width=True, key="generate_plan_btn"):
|
| 1293 |
if not st.session_state.api_key:
|
| 1294 |
+
st.error("β οΈ **API Key Required:** Please set GEMINI_API_KEY in Hugging Face Secrets.")
|
| 1295 |
elif not subject:
|
| 1296 |
+
st.error("β οΈ Please enter a subject/topic")
|
| 1297 |
elif not study_days:
|
| 1298 |
+
st.error("β οΈ Please select at least one study day")
|
| 1299 |
else:
|
| 1300 |
with st.spinner("π€ AI is creating your personalized study plan..."):
|
| 1301 |
try:
|
|
|
|
| 1315 |
'study_days': study_days
|
| 1316 |
}
|
| 1317 |
|
| 1318 |
+
# Show plan data in debug mode
|
| 1319 |
+
if st.session_state.show_debug:
|
| 1320 |
+
with st.expander("π Plan Data Sent to AI", expanded=True):
|
| 1321 |
+
st.json(plan_data)
|
| 1322 |
+
|
| 1323 |
# Generate plan
|
| 1324 |
plan = generate_study_plan(st.session_state.api_key, **plan_data)
|
| 1325 |
|
| 1326 |
if plan:
|
| 1327 |
st.session_state.study_plan = plan
|
| 1328 |
st.session_state.subject = subject
|
| 1329 |
+
st.session_state.current_week = 1
|
| 1330 |
+
st.session_state.weekly_streak = 0
|
| 1331 |
+
st.session_state.longest_weekly_streak = 0
|
| 1332 |
st.session_state.plan_loaded = True
|
| 1333 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1334 |
st.success("β
Study plan generated successfully!")
|
| 1335 |
st.balloons()
|
| 1336 |
|
| 1337 |
# Show plan summary
|
| 1338 |
st.info(f"π
**Schedule:** {len(study_days)} days/week ({', '.join(study_days)}) Γ {hours_per_day} hours/day")
|
| 1339 |
+
st.info(f"π **Duration:** {plan.get('total_weeks', 0)} weeks ({days_available} days)")
|
| 1340 |
|
| 1341 |
# Show learning quality
|
| 1342 |
+
if learning_quality['is_optimal']:
|
| 1343 |
+
st.success(f"π― **Learning Quality:** {learning_quality['quality_score']:.0f}/100 (Excellent)")
|
| 1344 |
+
else:
|
| 1345 |
+
st.warning(f"π **Learning Quality:** {learning_quality['quality_score']:.0f}/100 (Needs improvement)")
|
| 1346 |
+
|
| 1347 |
+
st.caption(f"Coverage: {learning_quality['coverage_percentage']:.0f}% | Total hours: {learning_quality['total_hours']}h")
|
| 1348 |
|
| 1349 |
else:
|
| 1350 |
+
st.error("β Failed to generate plan. Check debug mode for details.")
|
| 1351 |
|
| 1352 |
except Exception as e:
|
| 1353 |
st.error(f"β Error: {str(e)}")
|
| 1354 |
+
if st.session_state.show_debug:
|
| 1355 |
+
with st.expander("π Error Details", expanded=True):
|
| 1356 |
+
st.exception(e)
|
| 1357 |
+
|
| 1358 |
+
# Debug Info Section
|
| 1359 |
+
if st.session_state.show_debug and st.session_state.raw_response:
|
| 1360 |
+
st.markdown("---")
|
| 1361 |
+
st.subheader("π Debug Information")
|
| 1362 |
+
|
| 1363 |
+
col_debug_a, col_debug_b = st.columns(2)
|
| 1364 |
+
|
| 1365 |
+
with col_debug_a:
|
| 1366 |
+
st.metric("Raw Response Length", f"{len(st.session_state.raw_response)} chars")
|
| 1367 |
+
|
| 1368 |
+
with col_debug_b:
|
| 1369 |
+
if st.session_state.study_plan:
|
| 1370 |
+
plan_type = "AI Generated" if st.session_state.study_plan.get('generated_at') else "Generic"
|
| 1371 |
+
st.metric("Plan Type", plan_type)
|
| 1372 |
+
|
| 1373 |
+
with st.expander("π Raw AI Response", expanded=False):
|
| 1374 |
+
st.text_area("Full Response", st.session_state.raw_response, height=300, key="raw_response_display")
|
| 1375 |
+
|
| 1376 |
+
if st.session_state.study_plan:
|
| 1377 |
+
with st.expander("π Parsed Plan Structure", expanded=False):
|
| 1378 |
+
st.json(st.session_state.study_plan)
|
| 1379 |
|
| 1380 |
# ============================================
|
| 1381 |
# TAB 2: STUDY PLAN
|