| | |
| |
|
| | import pandas as pd |
| | import gradio as gr |
| | from openai import OpenAIError |
| |
|
| | |
| | from ankigen_core.utils import get_logger, ResponseCache |
| | from ankigen_core.llm_interface import OpenAIClientManager, structured_output_completion |
| |
|
| | |
| | |
| |
|
| | logger = get_logger() |
| |
|
| |
|
| | async def analyze_learning_path( |
| | client_manager: OpenAIClientManager, |
| | cache: ResponseCache, |
| | |
| | api_key: str, |
| | description: str, |
| | model: str, |
| | ): |
| | """Analyze a job description or learning goal to create a structured learning path.""" |
| | logger.info( |
| | f"Starting learning path analysis for description (length: {len(description)}) using model {model}" |
| | ) |
| |
|
| | |
| | if not api_key: |
| | logger.warning("No API key provided for learning path analysis") |
| | raise gr.Error("OpenAI API key is required") |
| |
|
| | try: |
| | |
| | await client_manager.initialize_client(api_key) |
| | openai_client = client_manager.get_client() |
| | except (ValueError, RuntimeError, OpenAIError, Exception) as e: |
| | logger.error(f"Client initialization failed in learning path analysis: {e}") |
| | raise gr.Error(f"OpenAI Client Error: {e}") |
| |
|
| | |
| | system_prompt = """You are an expert curriculum designer and educational consultant. |
| | Your task is to analyze learning goals and create structured, achievable learning paths. |
| | Break down complex topics into manageable subjects, identify prerequisites, |
| | and suggest practical projects that reinforce learning. |
| | Focus on creating a logical progression that builds upon previous knowledge. |
| | Ensure the output strictly follows the requested JSON format. |
| | """ |
| |
|
| | path_prompt = f""" |
| | Analyze this description and create a structured learning path. |
| | Return your analysis as a JSON object with the following structure: |
| | {{ |
| | "subjects": [ |
| | {{ |
| | "Subject": "name of the subject", |
| | "Prerequisites": "required prior knowledge (list or text)", |
| | "Time Estimate": "estimated time to learn (e.g., '2 weeks', '10 hours')" |
| | }} |
| | // ... more subjects |
| | ], |
| | "learning_order": "recommended sequence of study (text description)", |
| | "projects": "suggested practical projects (list or text description)" |
| | }} |
| | |
| | Description to analyze: |
| | --- START DESCRIPTION --- |
| | {description} |
| | --- END DESCRIPTION --- |
| | """ |
| |
|
| | |
| | try: |
| | logger.debug("Calling LLM for learning path analysis...") |
| | response = await structured_output_completion( |
| | openai_client=openai_client, |
| | model=model, |
| | response_format={"type": "json_object"}, |
| | system_prompt=system_prompt, |
| | user_prompt=path_prompt, |
| | cache=cache, |
| | ) |
| |
|
| | |
| | if ( |
| | not response |
| | or not isinstance(response, dict) |
| | or "subjects" not in response |
| | or "learning_order" not in response |
| | or "projects" not in response |
| | or not isinstance(response["subjects"], list) |
| | ): |
| | logger.error( |
| | f"Invalid or incomplete response format received from API for learning path. Response: {str(response)[:500]}" |
| | ) |
| | raise gr.Error( |
| | "Failed to analyze learning path due to invalid API response format. Please try again." |
| | ) |
| |
|
| | |
| | validated_subjects = [] |
| | for subj in response["subjects"]: |
| | if ( |
| | isinstance(subj, dict) |
| | and "Subject" in subj |
| | and "Prerequisites" in subj |
| | and "Time Estimate" in subj |
| | ): |
| | validated_subjects.append(subj) |
| | else: |
| | logger.warning( |
| | f"Skipping invalid subject entry in learning path response: {subj}" |
| | ) |
| |
|
| | if not validated_subjects: |
| | logger.error( |
| | "No valid subjects found in the API response for learning path." |
| | ) |
| | raise gr.Error("API returned no valid subjects for the learning path.") |
| |
|
| | subjects_df = pd.DataFrame(validated_subjects) |
| | |
| | for col in ["Subject", "Prerequisites", "Time Estimate"]: |
| | if col not in subjects_df.columns: |
| | subjects_df[col] = "" |
| | logger.warning(f"Added missing column '{col}' to subjects DataFrame.") |
| |
|
| | |
| | learning_order_text = ( |
| | f"### Recommended Learning Order\n{response['learning_order']}" |
| | ) |
| | projects_text = f"### Suggested Projects\n{response['projects']}" |
| |
|
| | logger.info("Successfully analyzed learning path.") |
| | return subjects_df, learning_order_text, projects_text |
| |
|
| | except (ValueError, OpenAIError, RuntimeError, gr.Error) as e: |
| | |
| | logger.error(f"Error during learning path analysis: {str(e)}", exc_info=True) |
| | |
| | if isinstance(e, gr.Error): |
| | raise e |
| | else: |
| | raise gr.Error(f"Failed to analyze learning path: {str(e)}") |
| | except Exception as e: |
| | logger.error( |
| | f"Unexpected error during learning path analysis: {str(e)}", exc_info=True |
| | ) |
| | raise gr.Error("An unexpected error occurred during learning path analysis.") |
| |
|