Spaces:
Running
Running
capradeepgujaran
commited on
Commit
•
5e2e371
1
Parent(s):
5be175f
Update app.py
Browse files
app.py
CHANGED
@@ -45,7 +45,7 @@ class QuizGenerator:
|
|
45 |
}
|
46 |
],
|
47 |
model="gemma2-9b-it",
|
48 |
-
temperature=0
|
49 |
max_tokens=6000
|
50 |
)
|
51 |
|
@@ -70,39 +70,29 @@ class QuizGenerator:
|
|
70 |
raise QuizGenerationError(f"Failed to generate questions: {str(e)}")
|
71 |
|
72 |
def _create_prompt(self, text: str, num_questions: int) -> str:
|
73 |
-
"""Create a simple, clear prompt optimized for
|
74 |
-
return f"""Create
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
1. The JSON must start with [ and end with ]
|
97 |
-
2. Each question object must be wrapped in {{ }}
|
98 |
-
3. Questions must be separated by commas
|
99 |
-
4. No trailing commas after the last question
|
100 |
-
5. Each question must have exactly 4 options
|
101 |
-
6. correct_answer must be a number (0, 1, 2, or 3)
|
102 |
-
7. Return only the JSON with no other text
|
103 |
-
|
104 |
-
Text to use:
|
105 |
-
{text.strip()}"""
|
106 |
|
107 |
def _parse_response(self, response_text: str) -> List[Dict]:
|
108 |
"""Parse response with improved error handling"""
|
@@ -110,7 +100,7 @@ class QuizGenerator:
|
|
110 |
# Clean up the response text
|
111 |
cleaned = response_text.strip()
|
112 |
|
113 |
-
# Remove markdown formatting
|
114 |
cleaned = cleaned.replace('```json', '').replace('```', '').strip()
|
115 |
|
116 |
# Find the JSON array
|
@@ -122,40 +112,35 @@ class QuizGenerator:
|
|
122 |
|
123 |
json_str = cleaned[start:end]
|
124 |
|
125 |
-
#
|
126 |
-
json_str = re.sub(r',(\s*})', r'\1', json_str)
|
127 |
-
json_str = re.sub(r',(\s*])', r'\1', json_str)
|
128 |
-
json_str = re.sub(r'}\s*{', '},{', json_str) # Fix spacing between objects
|
129 |
-
json_str = re.sub(r'\n\s*\n', '\n', json_str) # Remove extra newlines
|
130 |
-
|
131 |
-
# Fix missing commas between objects
|
132 |
-
json_str = re.sub(r'}\s*{', '},{', json_str)
|
133 |
-
|
134 |
-
# Ensure array brackets
|
135 |
-
if not json_str.startswith('['):
|
136 |
-
json_str = '[' + json_str
|
137 |
-
if not json_str.endswith(']'):
|
138 |
-
json_str = json_str + ']'
|
139 |
|
|
|
140 |
try:
|
141 |
return json.loads(json_str)
|
142 |
except json.JSONDecodeError:
|
143 |
-
#
|
144 |
-
|
145 |
-
|
146 |
-
fixed_str = re.sub(r'}\s*]', '}]', fixed_str) # Fix spacing before closing bracket
|
147 |
|
148 |
-
try:
|
149 |
-
return json.loads(fixed_str)
|
150 |
-
except:
|
151 |
-
# Last resort: Try using ast.literal_eval
|
152 |
-
import ast
|
153 |
-
return ast.literal_eval(fixed_str)
|
154 |
-
|
155 |
except Exception as e:
|
156 |
print(f"Parse error details: {str(e)}")
|
157 |
print(f"Attempted to parse: {response_text}")
|
158 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
159 |
|
160 |
def _validate_questions(self, questions: List[Dict], num_questions: int) -> List[Question]:
|
161 |
"""Validate questions with strict checking"""
|
@@ -540,6 +525,88 @@ class QuizApp:
|
|
540 |
self.quiz_generator = QuizGenerator(api_key)
|
541 |
self.certificate_generator = CertificateGenerator()
|
542 |
self.current_questions: List[Question] = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
543 |
|
544 |
def generate_questions(self, text: str, num_questions: int) -> Tuple[bool, List[Question]]:
|
545 |
"""
|
@@ -720,7 +787,7 @@ def create_quiz_interface():
|
|
720 |
# Header
|
721 |
gr.Markdown("""
|
722 |
<div style="text-align: center;">
|
723 |
-
<h1>🎓
|
724 |
<h3>Transform Your Knowledge into Recognized Achievements</h3></p>
|
725 |
</div>
|
726 |
|
@@ -728,14 +795,15 @@ def create_quiz_interface():
|
|
728 |
<h4>Assessment Overview:</h4>
|
729 |
<ul style="list-style-type: none; padding-left: 0;">
|
730 |
<li>📌 <strong>Basic Level:</strong> 5 questions - Perfect for beginners</li>
|
731 |
-
<li>📚 <strong>Intermediate Level:</strong> 10 questions - For
|
732 |
<li>🎯 <strong>Advanced Level:</strong> 20 questions - Comprehensive assessment</li>
|
733 |
<li>⏱️ <strong>Passing Score:</strong> 80% or higher</li>
|
734 |
<li>🏆 <strong>Certificate:</strong> Awarded upon successful completion</li>
|
735 |
</ul>
|
736 |
-
<p style="margin-top: 15px;"><i>This assessment evaluates your understanding of
|
737 |
</div>
|
738 |
-
""", show_label=False)
|
|
|
739 |
with gr.Tabs() as tabs:
|
740 |
# Profile Setup Tab
|
741 |
with gr.Tab(id=1, label="📋 Step 1: Profile Setup"):
|
@@ -745,20 +813,19 @@ def create_quiz_interface():
|
|
745 |
|
746 |
text_input = gr.Textbox(
|
747 |
label="Learning Content",
|
748 |
-
|
|
|
749 |
lines=10
|
750 |
)
|
751 |
|
752 |
-
|
753 |
-
|
754 |
-
|
755 |
-
|
756 |
-
|
757 |
-
|
758 |
-
)
|
759 |
|
760 |
with gr.Row():
|
761 |
-
company_logo = gr.Image(label="Company Logo (Optional)", type="filepath")
|
762 |
participant_photo = gr.Image(label="Your Photo (Optional)", type="filepath")
|
763 |
|
764 |
generate_btn = gr.Button("Generate Assessment", variant="primary", size="lg")
|
@@ -814,40 +881,33 @@ def create_quiz_interface():
|
|
814 |
)
|
815 |
|
816 |
# Certification Tab (Hidden by default)
|
|
|
817 |
with gr.Tab(id=3, label="🎓 Step 3: Get Certified", visible=False) as cert_tab:
|
818 |
score_display = gr.Number(label="Your Score", visible=False)
|
819 |
course_name = gr.Textbox(
|
820 |
label="Certification Title",
|
821 |
-
value="
|
822 |
-
interactive=False
|
823 |
)
|
824 |
-
certificate_display = gr.Image(label="Your Certificate")
|
|
|
825 |
|
826 |
-
# Update view_cert_btn click handler to show certification tab
|
827 |
def show_certificate_tab():
|
828 |
return [
|
829 |
gr.update(visible=True), # Make cert_tab visible
|
|
|
|
|
|
|
830 |
gr.update(selected=3) # Switch to cert_tab
|
831 |
]
|
832 |
|
833 |
|
834 |
# Helper Functions
|
835 |
-
def on_generate_questions(text,
|
836 |
-
|
837 |
-
|
838 |
-
"",
|
839 |
-
gr.update(visible=False),
|
840 |
-
gr.update(choices=[], visible=False),
|
841 |
-
"",
|
842 |
-
[],
|
843 |
-
0,
|
844 |
-
[None] * 5,
|
845 |
-
gr.update(selected=1),
|
846 |
-
gr.update(visible=False),
|
847 |
-
gr.update(visible=False)
|
848 |
-
]
|
849 |
|
850 |
-
success, questions = quiz_app.generate_questions(
|
851 |
if not success or not questions:
|
852 |
return [
|
853 |
"",
|
@@ -856,15 +916,14 @@ def create_quiz_interface():
|
|
856 |
"",
|
857 |
[],
|
858 |
0,
|
859 |
-
[None] *
|
860 |
gr.update(selected=1),
|
861 |
gr.update(visible=False),
|
862 |
gr.update(visible=False)
|
863 |
]
|
864 |
|
865 |
question = questions[0]
|
866 |
-
question_md = f"""### Question 1
|
867 |
-
{question.question}"""
|
868 |
|
869 |
return [
|
870 |
question_md,
|
@@ -938,48 +997,62 @@ def create_quiz_interface():
|
|
938 |
if 0 <= current_idx < len(final_answers):
|
939 |
final_answers[current_idx] = current_answer
|
940 |
|
941 |
-
# Check for unanswered questions
|
942 |
if not all(a is not None for a in final_answers[:len(questions)]):
|
943 |
-
#
|
944 |
unanswered = [i+1 for i, a in enumerate(final_answers[:len(questions)]) if a is None]
|
945 |
warning_content = f"""
|
946 |
-
<div style="background-color: #fff3cd; padding: 20px; border-radius:
|
947 |
-
<
|
948 |
-
|
949 |
-
<h3 style="color: #856404; margin: 0;">Please Complete All Questions</h3>
|
950 |
-
</div>
|
951 |
-
<p style="color: #856404; margin: 10px 0;">The following questions are unanswered:</p>
|
952 |
-
<p style="color: #856404; font-weight: bold; margin: 5px 0;">Question(s) {', '.join(map(str, unanswered))}</p>
|
953 |
-
<p style="color: #856404; margin: 10px 0;">Please answer all questions before submitting.</p>
|
954 |
</div>
|
955 |
"""
|
956 |
return [
|
957 |
-
warning_content,
|
958 |
-
gr.update(visible=True),
|
959 |
-
0,
|
960 |
-
"
|
961 |
-
gr.update(visible=True),
|
962 |
-
gr.update(visible=True),
|
963 |
-
gr.update(visible=False),
|
964 |
-
gr.update(selected=2)
|
965 |
]
|
966 |
-
|
967 |
-
# Rest of the original function remains the same...
|
968 |
score, passed, feedback = quiz_app.calculate_score(final_answers[:len(questions)])
|
969 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
970 |
|
971 |
for i, (q, f) in enumerate(zip(questions, feedback)):
|
972 |
icon = "✅" if f.is_correct else "❌"
|
973 |
color = "green" if f.is_correct else "red"
|
|
|
|
|
974 |
feedback_content += f"""### Question {i+1}
|
975 |
-
|
976 |
-
|
977 |
-
|
|
|
|
|
|
|
978 |
|
|
|
979 |
if passed:
|
980 |
-
feedback_content += f"""
|
|
|
|
|
|
|
|
|
981 |
else:
|
982 |
-
feedback_content += f"""
|
|
|
|
|
|
|
|
|
|
|
983 |
|
984 |
return [
|
985 |
feedback_content, # feedback_box
|
@@ -991,11 +1064,10 @@ def create_quiz_interface():
|
|
991 |
gr.update(visible=passed), # view_cert_btn
|
992 |
gr.update(selected=2) # tabs
|
993 |
]
|
994 |
-
|
995 |
# Event Handlers
|
996 |
generate_btn.click(
|
997 |
fn=on_generate_questions,
|
998 |
-
inputs=[text_input,
|
999 |
outputs=[
|
1000 |
question_display,
|
1001 |
question_box,
|
@@ -1039,7 +1111,7 @@ def create_quiz_interface():
|
|
1039 |
|
1040 |
reset_btn.click(
|
1041 |
fn=on_generate_questions,
|
1042 |
-
inputs=[text_input,
|
1043 |
outputs=[
|
1044 |
question_display,
|
1045 |
question_box,
|
@@ -1053,10 +1125,10 @@ def create_quiz_interface():
|
|
1053 |
view_cert_btn
|
1054 |
]
|
1055 |
)
|
1056 |
-
|
1057 |
view_cert_btn.click(
|
1058 |
fn=show_certificate_tab,
|
1059 |
-
outputs=[cert_tab, tabs]
|
1060 |
)
|
1061 |
|
1062 |
current_options.change(
|
@@ -1066,11 +1138,15 @@ def create_quiz_interface():
|
|
1066 |
)
|
1067 |
|
1068 |
score_display.change(
|
1069 |
-
fn=lambda s, n, c,
|
1070 |
-
|
|
|
|
|
|
|
|
|
1071 |
outputs=certificate_display
|
1072 |
)
|
1073 |
-
|
1074 |
return demo
|
1075 |
|
1076 |
if __name__ == "__main__":
|
|
|
45 |
}
|
46 |
],
|
47 |
model="gemma2-9b-it",
|
48 |
+
temperature=0,
|
49 |
max_tokens=6000
|
50 |
)
|
51 |
|
|
|
70 |
raise QuizGenerationError(f"Failed to generate questions: {str(e)}")
|
71 |
|
72 |
def _create_prompt(self, text: str, num_questions: int) -> str:
|
73 |
+
"""Create a simple, clear prompt optimized for llama-3.2-3b-preview"""
|
74 |
+
return f"""Create {num_questions} multiple choice questions about this text. Return only the JSON array in this exact format:
|
75 |
+
[
|
76 |
+
{{
|
77 |
+
"question": "Write the question here?",
|
78 |
+
"options": [
|
79 |
+
"First option",
|
80 |
+
"Second option",
|
81 |
+
"Third option",
|
82 |
+
"Fourth option"
|
83 |
+
],
|
84 |
+
"correct_answer": 0
|
85 |
+
}}
|
86 |
+
]
|
87 |
+
|
88 |
+
Rules:
|
89 |
+
1. Return only the JSON array
|
90 |
+
2. Each question must have exactly 4 options
|
91 |
+
3. correct_answer must be 0, 1, 2, or 3
|
92 |
+
4. No explanations or additional text
|
93 |
+
|
94 |
+
Text to use:
|
95 |
+
{text.strip()}"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
|
97 |
def _parse_response(self, response_text: str) -> List[Dict]:
|
98 |
"""Parse response with improved error handling"""
|
|
|
100 |
# Clean up the response text
|
101 |
cleaned = response_text.strip()
|
102 |
|
103 |
+
# Remove any markdown formatting
|
104 |
cleaned = cleaned.replace('```json', '').replace('```', '').strip()
|
105 |
|
106 |
# Find the JSON array
|
|
|
112 |
|
113 |
json_str = cleaned[start:end]
|
114 |
|
115 |
+
# Remove any trailing commas before closing brackets
|
116 |
+
json_str = re.sub(r',(\s*})', r'\1', json_str)
|
117 |
+
json_str = re.sub(r',(\s*])', r'\1', json_str)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
118 |
|
119 |
+
# Try to parse the cleaned JSON
|
120 |
try:
|
121 |
return json.loads(json_str)
|
122 |
except json.JSONDecodeError:
|
123 |
+
# If that fails, try using ast.literal_eval as a fallback
|
124 |
+
import ast
|
125 |
+
return ast.literal_eval(json_str)
|
|
|
126 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
127 |
except Exception as e:
|
128 |
print(f"Parse error details: {str(e)}")
|
129 |
print(f"Attempted to parse: {response_text}")
|
130 |
+
|
131 |
+
# Last resort: try to fix the JSON manually
|
132 |
+
try:
|
133 |
+
# Remove any trailing commas and fix newlines
|
134 |
+
fixed = re.sub(r',(\s*[}\]])', r'\1', response_text)
|
135 |
+
fixed = fixed.replace('}\n{', '},{')
|
136 |
+
fixed = fixed.strip()
|
137 |
+
if not fixed.startswith('['):
|
138 |
+
fixed = '[' + fixed
|
139 |
+
if not fixed.endswith(']'):
|
140 |
+
fixed = fixed + ']'
|
141 |
+
return json.loads(fixed)
|
142 |
+
except:
|
143 |
+
raise ValueError(f"Failed to parse response: {str(e)}")
|
144 |
|
145 |
def _validate_questions(self, questions: List[Dict], num_questions: int) -> List[Question]:
|
146 |
"""Validate questions with strict checking"""
|
|
|
525 |
self.quiz_generator = QuizGenerator(api_key)
|
526 |
self.certificate_generator = CertificateGenerator()
|
527 |
self.current_questions: List[Question] = []
|
528 |
+
self.logo_path = "atgc_logo.png"
|
529 |
+
self.selected_level = "Basic" # Default level
|
530 |
+
|
531 |
+
# Map difficulty levels to number of questions
|
532 |
+
self.difficulty_levels = {
|
533 |
+
"Basic": 5,
|
534 |
+
"Intermediate": 10,
|
535 |
+
"Advanced": 20
|
536 |
+
}
|
537 |
+
|
538 |
+
# Add fixed content here
|
539 |
+
self.fixed_content = """# Power BI: A Comprehensive Learning Guide
|
540 |
+
|
541 |
+
## Introduction to Power BI
|
542 |
+
|
543 |
+
Power BI represents Microsoft's flagship business intelligence platform, offering a comprehensive suite of tools for data analysis and visualization. This guide will walk you through the essential concepts, from basic data connectivity to advanced implementations, helping you master this powerful platform.
|
544 |
+
|
545 |
+
## Understanding Data Connectivity and Management
|
546 |
+
|
547 |
+
The foundation of any Power BI solution begins with data connectivity. Power BI offers two primary methods for connecting to data sources: Import mode and DirectQuery mode. Import mode loads data directly into Power BI's memory, providing faster performance and offline access capabilities. In contrast, DirectQuery maintains a live connection to your data source, ensuring real-time data access albeit with potentially slower performance due to query execution time.
|
548 |
+
|
549 |
+
When working with data sources, Power BI supports a vast array of connections including SQL Server databases, Excel spreadsheets, CSV files, web services, and SharePoint lists. Understanding how to effectively use these connections is crucial for building robust solutions. For instance, when working with Excel data, you can import not only basic tables but also Power Pivot Data Models and Power View Reports, providing flexibility in how you structure your data imports.
|
550 |
+
|
551 |
+
## Mastering Data Modeling
|
552 |
+
|
553 |
+
Data modeling in Power BI follows best practices from dimensional modeling, with the star schema being a fundamental concept. In a star schema, you organize your data around a central fact table connected to multiple dimension tables. This structure optimizes query performance and creates clear, intuitive relationships between your data elements.
|
554 |
+
|
555 |
+
A critical distinction in Power BI modeling is understanding the difference between calculated columns and measures. Calculated columns compute values for each row and store them in memory, making them ideal for values that need to be filtered or grouped. Measures, on the other hand, calculate results at query time based on user interactions, making them perfect for aggregations and complex calculations that need to respond to different filter contexts.
|
556 |
+
|
557 |
+
## DAX: The Language of Data Analysis
|
558 |
+
|
559 |
+
Data Analysis Expressions (DAX) serves as the formula language in Power BI, enabling you to create sophisticated calculations and data analyses. Beginning with basic functions, you'll learn to create fundamental calculations like total sales or year-to-date values. For example, a simple year-to-date sales calculation might look like:
|
560 |
+
|
561 |
+
```
|
562 |
+
YTD Sales = TOTALYTD(SUM(Sales[Amount]), 'Date'[Date])
|
563 |
+
```
|
564 |
+
|
565 |
+
As you advance, you'll encounter more complex scenarios requiring advanced DAX concepts. Time intelligence functions allow you to create period-over-period comparisons, while context transition helps you navigate between row and filter contexts effectively. Understanding these concepts becomes crucial when building sophisticated financial or sales analysis solutions.
|
566 |
+
|
567 |
+
## Advanced Analysis and Visualization
|
568 |
+
|
569 |
+
Power BI's visualization capabilities extend far beyond basic charts and graphs. The platform offers a rich set of visualization tools, from standard bar and line charts to sophisticated custom visuals available through the marketplace. Learning to choose the right visualization for your data story becomes crucial for effective communication.
|
570 |
+
|
571 |
+
Consider a sales analysis scenario: you might combine a line chart showing trends over time with a map visualization displaying regional performance, while using drill-through capabilities to provide detailed product-level analysis. These interactive features allow users to explore data naturally, moving from high-level overviews to detailed insights seamlessly.
|
572 |
+
|
573 |
+
## Security and Administration
|
574 |
+
|
575 |
+
Security in Power BI operates at multiple levels. Row-level security (RLS) allows you to control data access at a granular level, ensuring users see only the data they're authorized to view. For example, regional managers might only see sales data for their specific territories, while executive leadership sees all regions.
|
576 |
+
|
577 |
+
Administration extends beyond security to include workspace management, sharing permissions, and gateway configuration. The Enterprise Gateway facilitates secure data refresh from on-premises sources, while Personal Gateway serves individual users' needs. Understanding these components helps you build a secure and efficient BI environment.
|
578 |
+
|
579 |
+
## Performance Optimization and Best Practices
|
580 |
+
|
581 |
+
Optimizing Power BI solutions requires attention to several key areas. Data model optimization involves choosing the right storage mode, implementing appropriate relationships, and creating efficient measures. Query performance can be enhanced through proper use of variables in DAX, implementing query folding in Power Query, and utilizing aggregations for large datasets.
|
582 |
+
|
583 |
+
For large-scale implementations, consider incremental refresh strategies to manage data loading efficiently. This might involve setting up refresh windows to load only the most recent data while maintaining historical information in a static form.
|
584 |
+
|
585 |
+
## Real-World Implementation Scenarios
|
586 |
+
|
587 |
+
Practical application of Power BI often involves complex scenarios combining multiple concepts. Consider a financial reporting solution that requires:
|
588 |
+
- Integration with multiple data sources
|
589 |
+
- Implementation of security roles
|
590 |
+
- Automated refresh schedules
|
591 |
+
- Excel integration for detailed analysis
|
592 |
+
|
593 |
+
Or a sales performance dashboard featuring:
|
594 |
+
- Real-time data tracking
|
595 |
+
- Predictive analytics integration
|
596 |
+
- Mobile optimization
|
597 |
+
- Automated alerting systems
|
598 |
+
|
599 |
+
These scenarios require combining technical knowledge with business understanding to create effective solutions.
|
600 |
+
|
601 |
+
## Conclusion
|
602 |
+
|
603 |
+
Mastering Power BI requires understanding not just individual components but how they work together to create effective business intelligence solutions. From basic data connectivity through advanced DAX calculations to security implementation, each element plays a crucial role in building robust, scalable BI systems. Regular practice with real-world scenarios helps reinforce these concepts and builds the experience needed to handle complex business requirements effectively.
|
604 |
+
|
605 |
+
Continue your learning journey by experimenting with different features, challenging yourself with complex scenarios, and staying updated with the platform's evolving capabilities. Remember that effective BI solutions balance technical capability with business needs, creating insights that drive meaningful business decisions."""
|
606 |
+
|
607 |
+
def get_certificate_title(self, base_title: str) -> str:
|
608 |
+
"""Get certificate title with difficulty level"""
|
609 |
+
return f"{base_title} - {self.selected_level} Level"
|
610 |
|
611 |
def generate_questions(self, text: str, num_questions: int) -> Tuple[bool, List[Question]]:
|
612 |
"""
|
|
|
787 |
# Header
|
788 |
gr.Markdown("""
|
789 |
<div style="text-align: center;">
|
790 |
+
<h1>🎓 Power BI Assessment Certification </h1>
|
791 |
<h3>Transform Your Knowledge into Recognized Achievements</h3></p>
|
792 |
</div>
|
793 |
|
|
|
795 |
<h4>Assessment Overview:</h4>
|
796 |
<ul style="list-style-type: none; padding-left: 0;">
|
797 |
<li>📌 <strong>Basic Level:</strong> 5 questions - Perfect for beginners</li>
|
798 |
+
<li>📚 <strong>Intermediate Level:</strong> 10 questions - For those with HR experience</li>
|
799 |
<li>🎯 <strong>Advanced Level:</strong> 20 questions - Comprehensive assessment</li>
|
800 |
<li>⏱️ <strong>Passing Score:</strong> 80% or higher</li>
|
801 |
<li>🏆 <strong>Certificate:</strong> Awarded upon successful completion</li>
|
802 |
</ul>
|
803 |
+
<p style="margin-top: 15px;"><i>This assessment evaluates your understanding of Power BI.</i></p>
|
804 |
</div>
|
805 |
+
""", show_label=False)
|
806 |
+
|
807 |
with gr.Tabs() as tabs:
|
808 |
# Profile Setup Tab
|
809 |
with gr.Tab(id=1, label="📋 Step 1: Profile Setup"):
|
|
|
813 |
|
814 |
text_input = gr.Textbox(
|
815 |
label="Learning Content",
|
816 |
+
value=quiz_app.fixed_content, # Set the fixed content
|
817 |
+
interactive=False, # Make it non-editable
|
818 |
lines=10
|
819 |
)
|
820 |
|
821 |
+
difficulty_level = gr.Radio(
|
822 |
+
choices=["Basic", "Intermediate", "Advanced"],
|
823 |
+
value="Basic",
|
824 |
+
label="Select Difficulty Level",
|
825 |
+
info="Basic: 5 questions | Intermediate: 10 questions | Advanced: 20 questions")
|
826 |
+
|
|
|
827 |
|
828 |
with gr.Row():
|
|
|
829 |
participant_photo = gr.Image(label="Your Photo (Optional)", type="filepath")
|
830 |
|
831 |
generate_btn = gr.Button("Generate Assessment", variant="primary", size="lg")
|
|
|
881 |
)
|
882 |
|
883 |
# Certification Tab (Hidden by default)
|
884 |
+
|
885 |
with gr.Tab(id=3, label="🎓 Step 3: Get Certified", visible=False) as cert_tab:
|
886 |
score_display = gr.Number(label="Your Score", visible=False)
|
887 |
course_name = gr.Textbox(
|
888 |
label="Certification Title",
|
889 |
+
value=lambda: f"Power BI Assessment Certification", # Dynamic title with level
|
890 |
+
interactive=False
|
891 |
)
|
892 |
+
certificate_display = gr.Image(label="Your Certificate")
|
893 |
+
|
894 |
|
|
|
895 |
def show_certificate_tab():
|
896 |
return [
|
897 |
gr.update(visible=True), # Make cert_tab visible
|
898 |
+
gr.update(
|
899 |
+
value=f"Power BI Assessment Certification" # Update title with level
|
900 |
+
),
|
901 |
gr.update(selected=3) # Switch to cert_tab
|
902 |
]
|
903 |
|
904 |
|
905 |
# Helper Functions
|
906 |
+
def on_generate_questions(text, level):
|
907 |
+
quiz_app.selected_level = level # Store selected level
|
908 |
+
num_questions = quiz_app.difficulty_levels[level] # Get number of questions for level
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
909 |
|
910 |
+
success, questions = quiz_app.generate_questions(quiz_app.fixed_content, num_questions)
|
911 |
if not success or not questions:
|
912 |
return [
|
913 |
"",
|
|
|
916 |
"",
|
917 |
[],
|
918 |
0,
|
919 |
+
[None] * num_questions, # Updated to use dynamic size
|
920 |
gr.update(selected=1),
|
921 |
gr.update(visible=False),
|
922 |
gr.update(visible=False)
|
923 |
]
|
924 |
|
925 |
question = questions[0]
|
926 |
+
question_md = f"""### Question 1\n{question.question}"""
|
|
|
927 |
|
928 |
return [
|
929 |
question_md,
|
|
|
997 |
if 0 <= current_idx < len(final_answers):
|
998 |
final_answers[current_idx] = current_answer
|
999 |
|
|
|
1000 |
if not all(a is not None for a in final_answers[:len(questions)]):
|
1001 |
+
# Create list of unanswered question numbers
|
1002 |
unanswered = [i+1 for i, a in enumerate(final_answers[:len(questions)]) if a is None]
|
1003 |
warning_content = f"""
|
1004 |
+
<div style="background-color: #fff3cd; padding: 20px; border-radius: 10px; border-left: 5px solid #ffa000;">
|
1005 |
+
<h3 style="color: #ff6b6b; margin: 0;">⚠️ Please Complete All Questions</h3>
|
1006 |
+
<p style="margin: 10px 0;">Unanswered Questions: {', '.join(map(str, unanswered))}</p>
|
|
|
|
|
|
|
|
|
|
|
1007 |
</div>
|
1008 |
"""
|
1009 |
return [
|
1010 |
+
warning_content, # feedback_box
|
1011 |
+
gr.update(visible=True), # results_group
|
1012 |
+
0, # score
|
1013 |
+
"", # result_message
|
1014 |
+
gr.update(visible=True), # question_box
|
1015 |
+
gr.update(visible=True), # reset_btn
|
1016 |
+
gr.update(visible=False), # view_cert_btn
|
1017 |
+
gr.update(selected=2) # tabs
|
1018 |
]
|
1019 |
+
|
|
|
1020 |
score, passed, feedback = quiz_app.calculate_score(final_answers[:len(questions)])
|
1021 |
+
|
1022 |
+
# Create feedback content using proper Markdown with emojis
|
1023 |
+
feedback_content = f"""# Assessment Results
|
1024 |
+
|
1025 |
+
**Score: {score:.1f}%**
|
1026 |
+
|
1027 |
+
"""
|
1028 |
|
1029 |
for i, (q, f) in enumerate(zip(questions, feedback)):
|
1030 |
icon = "✅" if f.is_correct else "❌"
|
1031 |
color = "green" if f.is_correct else "red"
|
1032 |
+
|
1033 |
+
# Using markdown syntax with color formatting
|
1034 |
feedback_content += f"""### Question {i+1}
|
1035 |
+
{q.question}
|
1036 |
+
|
1037 |
+
{icon} **Your answer:** {f.selected or 'No answer'}
|
1038 |
+
{'' if f.is_correct else f'**Correct answer:** {f.correct_answer}'}
|
1039 |
+
|
1040 |
+
"""
|
1041 |
|
1042 |
+
# Add summary box
|
1043 |
if passed:
|
1044 |
+
feedback_content += f"""
|
1045 |
+
---
|
1046 |
+
## 🎉 Congratulations!
|
1047 |
+
You passed with a score of {score:.1f}%!
|
1048 |
+
"""
|
1049 |
else:
|
1050 |
+
feedback_content += f"""
|
1051 |
+
---
|
1052 |
+
## Need Improvement
|
1053 |
+
You scored {score:.1f}%. You need 80% or higher to pass.
|
1054 |
+
Please try again.
|
1055 |
+
"""
|
1056 |
|
1057 |
return [
|
1058 |
feedback_content, # feedback_box
|
|
|
1064 |
gr.update(visible=passed), # view_cert_btn
|
1065 |
gr.update(selected=2) # tabs
|
1066 |
]
|
|
|
1067 |
# Event Handlers
|
1068 |
generate_btn.click(
|
1069 |
fn=on_generate_questions,
|
1070 |
+
inputs=[text_input, difficulty_level], # Replace num_questions with difficulty_level
|
1071 |
outputs=[
|
1072 |
question_display,
|
1073 |
question_box,
|
|
|
1111 |
|
1112 |
reset_btn.click(
|
1113 |
fn=on_generate_questions,
|
1114 |
+
inputs=[text_input, difficulty_level], # Replace num_questions with difficulty_level
|
1115 |
outputs=[
|
1116 |
question_display,
|
1117 |
question_box,
|
|
|
1125 |
view_cert_btn
|
1126 |
]
|
1127 |
)
|
1128 |
+
|
1129 |
view_cert_btn.click(
|
1130 |
fn=show_certificate_tab,
|
1131 |
+
outputs=[cert_tab, course_name, tabs] # Add course_name to outputs
|
1132 |
)
|
1133 |
|
1134 |
current_options.change(
|
|
|
1138 |
)
|
1139 |
|
1140 |
score_display.change(
|
1141 |
+
fn=lambda s, n, c, p: quiz_app.certificate_generator.generate(
|
1142 |
+
s, n,
|
1143 |
+
quiz_app.get_certificate_title(c), # Add difficulty level to title
|
1144 |
+
quiz_app.logo_path, p
|
1145 |
+
) or gr.update(value=None),
|
1146 |
+
inputs=[score_display, name, course_name, participant_photo],
|
1147 |
outputs=certificate_display
|
1148 |
)
|
1149 |
+
|
1150 |
return demo
|
1151 |
|
1152 |
if __name__ == "__main__":
|