Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -908,107 +908,26 @@ def display_evaluation(evaluation: Dict[str, Any]):
|
|
| 908 |
tabs = st.tabs(["Communication", "Teaching", "Recommendations", "Transcript"])
|
| 909 |
|
| 910 |
with tabs[0]:
|
| 911 |
-
|
| 912 |
-
|
| 913 |
-
|
| 914 |
-
|
| 915 |
-
|
| 916 |
-
|
| 917 |
-
|
| 918 |
-
|
| 919 |
-
|
| 920 |
-
|
| 921 |
-
|
| 922 |
-
with col2:
|
| 923 |
-
st.metric("Words per Minute",
|
| 924 |
-
f"{evaluation['communication']['speed']['wpm']:.1f}")
|
| 925 |
-
st.caption("Acceptable Range: 130-150 WPM")
|
| 926 |
-
progress_bar.progress(0.4)
|
| 927 |
-
|
| 928 |
-
# Fluency metrics
|
| 929 |
-
st.subheader("Fluency")
|
| 930 |
-
col1, col2, col3 = st.columns(3)
|
| 931 |
-
with col1:
|
| 932 |
-
st.metric("Score", "Pass" if evaluation["communication"]["fluency"]["score"] == 1
|
| 933 |
-
else "Need Improvement")
|
| 934 |
-
with col2:
|
| 935 |
-
st.metric("Fillers/Min",
|
| 936 |
-
f"{evaluation['communication']['fluency']['fillersPerMin']:.1f}")
|
| 937 |
-
with col3:
|
| 938 |
-
st.metric("Errors/Min",
|
| 939 |
-
f"{evaluation['communication']['fluency']['errorsPerMin']:.1f}")
|
| 940 |
-
progress_bar.progress(0.6)
|
| 941 |
-
|
| 942 |
-
# Flow metrics
|
| 943 |
-
st.subheader("Flow")
|
| 944 |
-
col1, col2 = st.columns(2)
|
| 945 |
-
with col1:
|
| 946 |
-
st.metric("Score", "Pass" if evaluation["communication"]["flow"]["score"] == 1
|
| 947 |
-
else "Need Improvement")
|
| 948 |
-
with col2:
|
| 949 |
-
st.metric("Pauses/Min",
|
| 950 |
-
f"{evaluation['communication']['flow']['pausesPerMin']:.1f}")
|
| 951 |
-
st.caption("Acceptable Range: 8-12 pauses/min")
|
| 952 |
-
|
| 953 |
-
# Intonation metrics
|
| 954 |
-
st.subheader("Intonation")
|
| 955 |
-
|
| 956 |
-
# Frequency/Pitch section
|
| 957 |
-
st.write("**Frequency/Pitch Metrics:**")
|
| 958 |
-
col1, col2, col3 = st.columns(3)
|
| 959 |
-
with col1:
|
| 960 |
-
st.metric("Base Frequency",
|
| 961 |
-
f"{evaluation['communication']['intonation']['pitch']:.1f} Hz")
|
| 962 |
-
with col2:
|
| 963 |
-
st.metric("Pitch Score",
|
| 964 |
-
"Pass" if evaluation["communication"]["intonation"]["pitchScore"] == 1
|
| 965 |
-
else "Need Improvement")
|
| 966 |
-
with col3:
|
| 967 |
-
st.metric("Pitch Variation (σ)",
|
| 968 |
-
f"{evaluation['communication']['intonation']['pitchVariation']:.1f} Hz")
|
| 969 |
-
st.caption("Acceptable Pitch Variation Range: 80-90 Hz")
|
| 970 |
-
|
| 971 |
-
# Patterns section
|
| 972 |
-
st.write("**Pattern Analysis:**")
|
| 973 |
-
col1, col2, col3, col4 = st.columns(4)
|
| 974 |
-
with col1:
|
| 975 |
-
st.metric("Pattern Score",
|
| 976 |
-
"Pass" if evaluation["communication"]["intonation"]["patternScore"] == 1
|
| 977 |
-
else "Need Improvement")
|
| 978 |
-
with col2:
|
| 979 |
-
st.metric("Rising Patterns",
|
| 980 |
-
evaluation["communication"]["intonation"]["risingPatterns"])
|
| 981 |
-
with col3:
|
| 982 |
-
st.metric("Falling Patterns",
|
| 983 |
-
evaluation["communication"]["intonation"]["fallingPatterns"])
|
| 984 |
-
with col4:
|
| 985 |
-
st.metric("Variations/Min",
|
| 986 |
-
f"{evaluation['communication']['intonation']['variationsPerMin']:.1f}")
|
| 987 |
-
st.caption("Acceptable Variations per Minute: >=8")
|
| 988 |
-
progress_bar.progress(0.8)
|
| 989 |
-
|
| 990 |
-
# Energy metrics
|
| 991 |
-
st.subheader("Energy")
|
| 992 |
-
col1, col2, col3 = st.columns(3)
|
| 993 |
-
with col1:
|
| 994 |
-
st.metric("Score",
|
| 995 |
-
"Pass" if evaluation["communication"]["energy"]["score"] == 1
|
| 996 |
-
else "Need Improvement")
|
| 997 |
-
with col2:
|
| 998 |
-
st.metric("Mean Amplitude",
|
| 999 |
-
f"{evaluation['communication']['energy']['meanAmplitude']:.1f}")
|
| 1000 |
-
with col3:
|
| 1001 |
-
st.metric("Amplitude Deviation (σ/μ)",
|
| 1002 |
-
f"{evaluation['communication']['energy']['amplitudeDeviation']:.2f}")
|
| 1003 |
-
|
| 1004 |
-
st.caption("""
|
| 1005 |
-
Acceptable Ranges:
|
| 1006 |
-
- Mean Amplitude: 20 - 40 (normalized RMS value)
|
| 1007 |
-
- Amplitude Deviation (σ/μ): >0.2
|
| 1008 |
-
""")
|
| 1009 |
|
| 1010 |
-
|
| 1011 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1012 |
|
| 1013 |
with tabs[1]:
|
| 1014 |
st.header("Teaching Analysis")
|
|
@@ -1128,122 +1047,53 @@ def display_evaluation(evaluation: Dict[str, Any]):
|
|
| 1128 |
# Geography Fit with improved formatting
|
| 1129 |
st.subheader("🌍 Geography Fit")
|
| 1130 |
geography_fit = recommendations.get("geographyFit", "Not specified")
|
| 1131 |
-
st.
|
| 1132 |
|
| 1133 |
# Improvements Needed with better formatting
|
| 1134 |
st.subheader("💡 Suggested Improvements")
|
| 1135 |
improvements = recommendations.get("improvements", [])
|
| 1136 |
if isinstance(improvements, list):
|
| 1137 |
for i, improvement in enumerate(improvements, 1):
|
| 1138 |
-
if isinstance(improvement,
|
| 1139 |
-
|
| 1140 |
-
|
| 1141 |
-
|
| 1142 |
-
|
| 1143 |
-
|
| 1144 |
-
|
| 1145 |
-
|
| 1146 |
-
|
| 1147 |
-
|
| 1148 |
-
|
| 1149 |
-
elif "interaction" in improvement.lower() or "audience" in improvement.lower():
|
| 1150 |
-
aspect = "Engagement"
|
| 1151 |
-
elif "citation" in improvement.lower() or "accuracy" in improvement.lower():
|
| 1152 |
-
aspect = "Content Quality"
|
| 1153 |
-
elif "connection" in improvement.lower() or "narrative" in improvement.lower():
|
| 1154 |
-
aspect = "Structure and Flow"
|
| 1155 |
-
else:
|
| 1156 |
-
aspect = "General Improvement"
|
| 1157 |
|
| 1158 |
st.markdown(f"""
|
| 1159 |
-
|
| 1160 |
-
|
| 1161 |
-
|
|
|
|
|
|
|
| 1162 |
|
| 1163 |
-
# Rigor Assessment with enhanced
|
| 1164 |
st.subheader("📊 Rigor Assessment")
|
| 1165 |
rigor = recommendations.get("rigor", {})
|
| 1166 |
|
| 1167 |
-
# Handle different rigor data structures
|
| 1168 |
if isinstance(rigor, dict):
|
| 1169 |
for category, assessment in rigor.items():
|
| 1170 |
-
|
| 1171 |
-
|
| 1172 |
-
|
| 1173 |
-
|
| 1174 |
-
|
| 1175 |
-
|
| 1176 |
-
|
| 1177 |
-
|
| 1178 |
-
|
| 1179 |
-
|
| 1180 |
-
|
| 1181 |
-
|
| 1182 |
-
|
| 1183 |
-
|
| 1184 |
-
|
| 1185 |
-
# If rigor is a string, display it directly
|
| 1186 |
-
st.write(rigor)
|
| 1187 |
-
else:
|
| 1188 |
-
st.write("No rigor assessment available")
|
| 1189 |
-
|
| 1190 |
-
# Add visual separator before metrics
|
| 1191 |
-
st.markdown("---")
|
| 1192 |
-
|
| 1193 |
-
# Summary metrics with error handling
|
| 1194 |
-
st.subheader("📈 Overall Scores")
|
| 1195 |
-
col1, col2, col3 = st.columns(3)
|
| 1196 |
-
|
| 1197 |
-
with col1:
|
| 1198 |
-
# Calculate teaching score correctly from the teaching data
|
| 1199 |
-
teaching_data = evaluation.get("teaching", {})
|
| 1200 |
-
concept_assessment = teaching_data.get("Concept Assessment", {})
|
| 1201 |
-
code_assessment = teaching_data.get("Code Assessment", {})
|
| 1202 |
-
|
| 1203 |
-
# Calculate concept scores
|
| 1204 |
-
concept_scores = [
|
| 1205 |
-
category.get("Score", 0)
|
| 1206 |
-
for category in concept_assessment.values()
|
| 1207 |
-
]
|
| 1208 |
-
|
| 1209 |
-
# Calculate code scores
|
| 1210 |
-
code_scores = [
|
| 1211 |
-
category.get("Score", 0)
|
| 1212 |
-
for category in code_assessment.values()
|
| 1213 |
-
]
|
| 1214 |
-
|
| 1215 |
-
# Calculate overall teaching score
|
| 1216 |
-
all_teaching_scores = concept_scores + code_scores
|
| 1217 |
-
teaching_score = (sum(all_teaching_scores) / len(all_teaching_scores) * 100) if all_teaching_scores else 0
|
| 1218 |
-
st.metric("Teaching Score", f"{teaching_score:.1f}%")
|
| 1219 |
-
|
| 1220 |
-
with col2:
|
| 1221 |
-
# Calculate communication score
|
| 1222 |
-
communication = evaluation.get("communication", {})
|
| 1223 |
-
comm_categories = ["speed", "fluency", "flow", "intonation", "energy"]
|
| 1224 |
-
comm_scores = [
|
| 1225 |
-
communication.get(cat, {}).get("score", 0)
|
| 1226 |
-
for cat in comm_categories
|
| 1227 |
-
]
|
| 1228 |
-
comm_score = (sum(comm_scores) / len(comm_scores) * 100) if comm_scores else 0
|
| 1229 |
-
st.metric("Communication Score", f"{comm_score:.1f}%")
|
| 1230 |
-
|
| 1231 |
-
with col3:
|
| 1232 |
-
# Calculate overall score (average of teaching and communication)
|
| 1233 |
-
overall_score = (teaching_score + comm_score) / 2
|
| 1234 |
-
st.metric("Overall Score", f"{overall_score:.1f}%")
|
| 1235 |
-
|
| 1236 |
-
# Additional metrics row
|
| 1237 |
-
col1, col2 = st.columns(2)
|
| 1238 |
-
with col1:
|
| 1239 |
-
# Count total improvement points
|
| 1240 |
-
improvement_count = len(improvements) if isinstance(improvements, list) else 1
|
| 1241 |
-
st.metric("Improvement Points", improvement_count)
|
| 1242 |
-
|
| 1243 |
-
with col2:
|
| 1244 |
-
# Display words per minute if available
|
| 1245 |
-
wpm = communication.get("speed", {}).get("wpm", 0)
|
| 1246 |
-
st.metric("Speaking Speed", f"{wpm:.1f} WPM")
|
| 1247 |
|
| 1248 |
# Transcript tab with error handling
|
| 1249 |
with tabs[3]:
|
|
@@ -1255,6 +1105,54 @@ def display_evaluation(evaluation: Dict[str, Any]):
|
|
| 1255 |
st.error(f"Error displaying results: {str(e)}")
|
| 1256 |
st.error("Please check the evaluation data structure and try again.")
|
| 1257 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1258 |
def check_dependencies() -> List[str]:
|
| 1259 |
"""Check if required dependencies are installed"""
|
| 1260 |
missing = []
|
|
@@ -1266,6 +1164,115 @@ def check_dependencies() -> List[str]:
|
|
| 1266 |
|
| 1267 |
def main():
|
| 1268 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1269 |
st.set_page_config(page_title="🎓 Mentor Demo Review System", layout="wide")
|
| 1270 |
|
| 1271 |
st.title("🎓 Mentor Demo Review System")
|
|
@@ -1332,6 +1339,13 @@ def main():
|
|
| 1332 |
)
|
| 1333 |
|
| 1334 |
if uploaded_file:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1335 |
# Create temp directory for processing
|
| 1336 |
temp_dir = tempfile.mkdtemp()
|
| 1337 |
video_path = os.path.join(temp_dir, uploaded_file.name)
|
|
|
|
| 908 |
tabs = st.tabs(["Communication", "Teaching", "Recommendations", "Transcript"])
|
| 909 |
|
| 910 |
with tabs[0]:
|
| 911 |
+
st.markdown("""
|
| 912 |
+
<div class="category-header slide-in">
|
| 913 |
+
<h2>Communication Metrics</h2>
|
| 914 |
+
</div>
|
| 915 |
+
""", unsafe_allow_html=True)
|
| 916 |
+
|
| 917 |
+
# Update metrics to use the new card style
|
| 918 |
+
metrics = evaluation.get("communication", {})
|
| 919 |
+
for category, data in metrics.items():
|
| 920 |
+
score = data.get("score", 0)
|
| 921 |
+
score_class = "score-pass" if score == 1 else "score-fail"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 922 |
|
| 923 |
+
st.markdown(f"""
|
| 924 |
+
<div class="metric-card fade-in">
|
| 925 |
+
<h3>{category.title()}</h3>
|
| 926 |
+
<span class="score-badge {score_class}">
|
| 927 |
+
{"Pass" if score == 1 else "Needs Improvement"}
|
| 928 |
+
</span>
|
| 929 |
+
</div>
|
| 930 |
+
""", unsafe_allow_html=True)
|
| 931 |
|
| 932 |
with tabs[1]:
|
| 933 |
st.header("Teaching Analysis")
|
|
|
|
| 1047 |
# Geography Fit with improved formatting
|
| 1048 |
st.subheader("🌍 Geography Fit")
|
| 1049 |
geography_fit = recommendations.get("geographyFit", "Not specified")
|
| 1050 |
+
st.info(geography_fit)
|
| 1051 |
|
| 1052 |
# Improvements Needed with better formatting
|
| 1053 |
st.subheader("💡 Suggested Improvements")
|
| 1054 |
improvements = recommendations.get("improvements", [])
|
| 1055 |
if isinstance(improvements, list):
|
| 1056 |
for i, improvement in enumerate(improvements, 1):
|
| 1057 |
+
if isinstance(improvement, str):
|
| 1058 |
+
# Create categories based on content keywords
|
| 1059 |
+
category = "General"
|
| 1060 |
+
if any(keyword in improvement.lower() for keyword in ["voice", "volume", "pitch", "pace"]):
|
| 1061 |
+
category = "Voice and Delivery"
|
| 1062 |
+
elif any(keyword in improvement.lower() for keyword in ["explain", "concept", "understanding"]):
|
| 1063 |
+
category = "Teaching Approach"
|
| 1064 |
+
elif any(keyword in improvement.lower() for keyword in ["engage", "interact", "question"]):
|
| 1065 |
+
category = "Engagement"
|
| 1066 |
+
elif any(keyword in improvement.lower() for keyword in ["code", "technical", "implementation"]):
|
| 1067 |
+
category = "Technical Content"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1068 |
|
| 1069 |
st.markdown(f"""
|
| 1070 |
+
<div class="recommendation-card">
|
| 1071 |
+
<h4>{i}. {category}</h4>
|
| 1072 |
+
<p>{improvement}</p>
|
| 1073 |
+
</div>
|
| 1074 |
+
""", unsafe_allow_html=True)
|
| 1075 |
|
| 1076 |
+
# Rigor Assessment with enhanced formatting
|
| 1077 |
st.subheader("📊 Rigor Assessment")
|
| 1078 |
rigor = recommendations.get("rigor", {})
|
| 1079 |
|
|
|
|
| 1080 |
if isinstance(rigor, dict):
|
| 1081 |
for category, assessment in rigor.items():
|
| 1082 |
+
# Format category name
|
| 1083 |
+
category_display = " ".join(word.capitalize() for word in category.replace("assessment", "").split())
|
| 1084 |
+
|
| 1085 |
+
# Get score and format assessment data
|
| 1086 |
+
score = "Pass" if isinstance(assessment, dict) and assessment.get('score') == 1 else "Needs Improvement"
|
| 1087 |
+
score_color = "green" if score == "Pass" else "orange"
|
| 1088 |
+
|
| 1089 |
+
# Display assessment in a card format
|
| 1090 |
+
st.markdown(f"""
|
| 1091 |
+
<div class="rigor-card">
|
| 1092 |
+
<h4>{category_display}</h4>
|
| 1093 |
+
<p class="score-badge {score_color.lower()}-score">{score}</p>
|
| 1094 |
+
<p>{assessment.get('justification', '') if isinstance(assessment, dict) else assessment}</p>
|
| 1095 |
+
</div>
|
| 1096 |
+
""", unsafe_allow_html=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1097 |
|
| 1098 |
# Transcript tab with error handling
|
| 1099 |
with tabs[3]:
|
|
|
|
| 1105 |
st.error(f"Error displaying results: {str(e)}")
|
| 1106 |
st.error("Please check the evaluation data structure and try again.")
|
| 1107 |
|
| 1108 |
+
# Add these styles to the existing CSS in the main function
|
| 1109 |
+
st.markdown("""
|
| 1110 |
+
<style>
|
| 1111 |
+
/* ... existing styles ... */
|
| 1112 |
+
|
| 1113 |
+
.recommendation-card {
|
| 1114 |
+
background-color: #f8f9fa;
|
| 1115 |
+
border-left: 4px solid #1f77b4;
|
| 1116 |
+
padding: 15px;
|
| 1117 |
+
margin: 10px 0;
|
| 1118 |
+
border-radius: 4px;
|
| 1119 |
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
| 1120 |
+
}
|
| 1121 |
+
|
| 1122 |
+
.recommendation-card h4 {
|
| 1123 |
+
color: #1f77b4;
|
| 1124 |
+
margin: 0 0 10px 0;
|
| 1125 |
+
}
|
| 1126 |
+
|
| 1127 |
+
.rigor-card {
|
| 1128 |
+
background-color: #ffffff;
|
| 1129 |
+
border: 1px solid #e0e0e0;
|
| 1130 |
+
padding: 20px;
|
| 1131 |
+
margin: 10px 0;
|
| 1132 |
+
border-radius: 8px;
|
| 1133 |
+
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
| 1134 |
+
}
|
| 1135 |
+
|
| 1136 |
+
.score-badge {
|
| 1137 |
+
display: inline-block;
|
| 1138 |
+
padding: 4px 12px;
|
| 1139 |
+
border-radius: 15px;
|
| 1140 |
+
font-weight: bold;
|
| 1141 |
+
margin: 10px 0;
|
| 1142 |
+
}
|
| 1143 |
+
|
| 1144 |
+
.green-score {
|
| 1145 |
+
background-color: #28a745;
|
| 1146 |
+
color: white;
|
| 1147 |
+
}
|
| 1148 |
+
|
| 1149 |
+
.orange-score {
|
| 1150 |
+
background-color: #fd7e14;
|
| 1151 |
+
color: white;
|
| 1152 |
+
}
|
| 1153 |
+
</style>
|
| 1154 |
+
""", unsafe_allow_html=True)
|
| 1155 |
+
|
| 1156 |
def check_dependencies() -> List[str]:
|
| 1157 |
"""Check if required dependencies are installed"""
|
| 1158 |
missing = []
|
|
|
|
| 1164 |
|
| 1165 |
def main():
|
| 1166 |
try:
|
| 1167 |
+
# Add custom CSS for animations and styling
|
| 1168 |
+
st.markdown("""
|
| 1169 |
+
<style>
|
| 1170 |
+
@keyframes fadeIn {
|
| 1171 |
+
from { opacity: 0; }
|
| 1172 |
+
to { opacity: 1; }
|
| 1173 |
+
}
|
| 1174 |
+
|
| 1175 |
+
@keyframes slideIn {
|
| 1176 |
+
from { transform: translateX(-100%); }
|
| 1177 |
+
to { transform: translateX(0); }
|
| 1178 |
+
}
|
| 1179 |
+
|
| 1180 |
+
@keyframes pulse {
|
| 1181 |
+
0% { transform: scale(1); }
|
| 1182 |
+
50% { transform: scale(1.05); }
|
| 1183 |
+
100% { transform: scale(1); }
|
| 1184 |
+
}
|
| 1185 |
+
|
| 1186 |
+
.fade-in {
|
| 1187 |
+
animation: fadeIn 1s ease-in;
|
| 1188 |
+
}
|
| 1189 |
+
|
| 1190 |
+
.slide-in {
|
| 1191 |
+
animation: slideIn 0.5s ease-out;
|
| 1192 |
+
}
|
| 1193 |
+
|
| 1194 |
+
.pulse {
|
| 1195 |
+
animation: pulse 2s infinite;
|
| 1196 |
+
}
|
| 1197 |
+
|
| 1198 |
+
.metric-card {
|
| 1199 |
+
background-color: #f0f2f6;
|
| 1200 |
+
border-radius: 10px;
|
| 1201 |
+
padding: 20px;
|
| 1202 |
+
margin: 10px 0;
|
| 1203 |
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
| 1204 |
+
transition: transform 0.3s ease;
|
| 1205 |
+
}
|
| 1206 |
+
|
| 1207 |
+
.metric-card:hover {
|
| 1208 |
+
transform: translateY(-5px);
|
| 1209 |
+
}
|
| 1210 |
+
|
| 1211 |
+
.stButton>button {
|
| 1212 |
+
transition: all 0.3s ease;
|
| 1213 |
+
}
|
| 1214 |
+
|
| 1215 |
+
.stButton>button:hover {
|
| 1216 |
+
transform: scale(1.05);
|
| 1217 |
+
}
|
| 1218 |
+
|
| 1219 |
+
.category-header {
|
| 1220 |
+
background: linear-gradient(90deg, #1f77b4, #2c3e50);
|
| 1221 |
+
color: white;
|
| 1222 |
+
padding: 10px;
|
| 1223 |
+
border-radius: 5px;
|
| 1224 |
+
margin: 10px 0;
|
| 1225 |
+
}
|
| 1226 |
+
|
| 1227 |
+
.score-badge {
|
| 1228 |
+
padding: 5px 10px;
|
| 1229 |
+
border-radius: 15px;
|
| 1230 |
+
font-weight: bold;
|
| 1231 |
+
}
|
| 1232 |
+
|
| 1233 |
+
.score-pass {
|
| 1234 |
+
background-color: #28a745;
|
| 1235 |
+
color: white;
|
| 1236 |
+
}
|
| 1237 |
+
|
| 1238 |
+
.score-fail {
|
| 1239 |
+
background-color: #dc3545;
|
| 1240 |
+
color: white;
|
| 1241 |
+
}
|
| 1242 |
+
</style>
|
| 1243 |
+
""", unsafe_allow_html=True)
|
| 1244 |
+
|
| 1245 |
+
# Animated title
|
| 1246 |
+
st.markdown("""
|
| 1247 |
+
<div class="fade-in">
|
| 1248 |
+
<h1 style='text-align: center; color: #1f77b4;'>
|
| 1249 |
+
🎓 Mentor Demo Review System
|
| 1250 |
+
</h1>
|
| 1251 |
+
</div>
|
| 1252 |
+
""", unsafe_allow_html=True)
|
| 1253 |
+
|
| 1254 |
+
# Animated sidebar
|
| 1255 |
+
with st.sidebar:
|
| 1256 |
+
st.markdown("""
|
| 1257 |
+
<div class="slide-in">
|
| 1258 |
+
<h2>Instructions</h2>
|
| 1259 |
+
</div>
|
| 1260 |
+
""", unsafe_allow_html=True)
|
| 1261 |
+
|
| 1262 |
+
st.markdown("""
|
| 1263 |
+
<div class="fade-in">
|
| 1264 |
+
<ol>
|
| 1265 |
+
<li>Upload your teaching video</li>
|
| 1266 |
+
<li>Wait for the analysis</li>
|
| 1267 |
+
<li>Review the detailed feedback</li>
|
| 1268 |
+
<li>Download the report</li>
|
| 1269 |
+
</ol>
|
| 1270 |
+
|
| 1271 |
+
<p><strong>Supported formats:</strong> MP4, AVI, MOV<br>
|
| 1272 |
+
<strong>Maximum file size:</strong> 500mb</p>
|
| 1273 |
+
</div>
|
| 1274 |
+
""", unsafe_allow_html=True)
|
| 1275 |
+
|
| 1276 |
st.set_page_config(page_title="🎓 Mentor Demo Review System", layout="wide")
|
| 1277 |
|
| 1278 |
st.title("🎓 Mentor Demo Review System")
|
|
|
|
| 1339 |
)
|
| 1340 |
|
| 1341 |
if uploaded_file:
|
| 1342 |
+
# Add a pulsing animation while processing
|
| 1343 |
+
st.markdown("""
|
| 1344 |
+
<div class="pulse" style="text-align: center;">
|
| 1345 |
+
<h3>Processing your video...</h3>
|
| 1346 |
+
</div>
|
| 1347 |
+
""", unsafe_allow_html=True)
|
| 1348 |
+
|
| 1349 |
# Create temp directory for processing
|
| 1350 |
temp_dir = tempfile.mkdtemp()
|
| 1351 |
video_path = os.path.join(temp_dir, uploaded_file.name)
|