|
|
|
|
|
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() |
|
|
|
|
|
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: |
|
|
|
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 = 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.") |
|
|