Spaces:
Sleeping
Sleeping
| from langchain_core.prompts import PromptTemplate | |
| from app.core.llm import llm | |
| from app.prompts.course_prompt import COURSE_TEMPLATE | |
| from app.prompts.quiz_prompt import QUIZ_TEMPLATE | |
| from app.prompts.complete_course_prompt import COMPLETE_COURSE_TEMPLATE | |
| import json | |
| import re | |
| def generate_course_and_quiz(params): | |
| """Legacy function - generates course and quiz separately""" | |
| course_prompt = PromptTemplate.from_template(COURSE_TEMPLATE) | |
| course = llm.invoke( | |
| course_prompt.format(**params) | |
| ).content | |
| quiz_prompt = PromptTemplate.from_template(QUIZ_TEMPLATE) | |
| quiz_raw = llm.invoke( | |
| quiz_prompt.format(course=course) | |
| ).content | |
| # Extract JSON from response | |
| json_match = re.search(r'\[.*\]', quiz_raw, re.DOTALL) | |
| if json_match: | |
| quiz_json = json_match.group(0) | |
| quiz = json.loads(quiz_json) | |
| else: | |
| # Fallback quiz if JSON parsing fails | |
| quiz = [ | |
| { | |
| "question": "What is the main topic of this course?", | |
| "options": ["Option A", "Option B", "Option C", "Option D"], | |
| "answer": 0 | |
| } | |
| ] | |
| return course, quiz | |
| def generate_complete_learning_package(params): | |
| """ | |
| Generate course, quiz, and video-ready scenes in a single LLM inference. | |
| Returns: | |
| dict: { | |
| "course": str, | |
| "quiz": list, | |
| "video_scenes": list | |
| } | |
| """ | |
| complete_prompt = PromptTemplate.from_template(COMPLETE_COURSE_TEMPLATE) | |
| response = llm.invoke( | |
| complete_prompt.format(**params) | |
| ).content | |
| # Extract JSON from response | |
| json_match = re.search(r'\{.*\}', response, re.DOTALL) | |
| if json_match: | |
| try: | |
| complete_data = json.loads(json_match.group(0)) | |
| # Validate structure | |
| required_keys = ["course", "quiz", "video_scenes"] | |
| if all(key in complete_data for key in required_keys): | |
| return complete_data | |
| else: | |
| raise ValueError("Missing required keys in LLM response") | |
| except json.JSONDecodeError as e: | |
| print(f"JSON parsing error: {e}") | |
| return _fallback_generation(params) | |
| else: | |
| print("No JSON found in LLM response") | |
| return _fallback_generation(params) | |
| def _fallback_generation(params): | |
| """Fallback to separate generation if unified approach fails""" | |
| print("Falling back to separate generation...") | |
| course, quiz = generate_course_and_quiz(params) | |
| # Basic scene parsing from course | |
| scenes = [] | |
| sections = re.split(r'\n\d+\.\s*|\n\n', course) | |
| sections = [s.strip() for s in sections if s.strip()] | |
| for i, section in enumerate(sections[:8]): | |
| sentences = section.split('.') | |
| title = sentences[0].strip() if sentences else section[:50] | |
| content = section.strip() | |
| duration = max(5, min(15, len(content.split()) * 0.5)) | |
| scenes.append({ | |
| "title": title, | |
| "content": content, | |
| "duration": int(duration), | |
| "visual_prompt": f"{params.get('style', 'cartoon')}, {title}, educational content" | |
| }) | |
| return { | |
| "course": course, | |
| "quiz": quiz, | |
| "video_scenes": scenes | |
| } | |