Spaces:
Paused
Paused
| """ | |
| Material Upload UI Integration - Functions for Gradio interface | |
| Handles material upload, analysis, and content generation | |
| """ | |
| from typing import List, Tuple, Optional, Dict, Any | |
| import json | |
| import logging | |
| logger = logging.getLogger(__name__) | |
| def analyze_uploaded_materials(files: List[Any]) -> Tuple[str, str, str, str, str, str, str, str]: | |
| """ | |
| Analyze uploaded lecture materials. | |
| Args: | |
| files: List of uploaded file objects from Gradio | |
| Returns: | |
| Tuple of (concepts, objectives, definitions, structure, themes, difficulty, summary, focus_areas) | |
| """ | |
| if not files: | |
| return ("No files uploaded", "", "", "", "", "", "", "") | |
| try: | |
| from src.ai_engine import MaterialAnalyzer, MaterialProcessor, FileManager | |
| # Initialize | |
| processor = MaterialProcessor() | |
| file_manager = FileManager() | |
| all_analyses = [] | |
| error_messages = [] | |
| # Process each file | |
| for file_obj in files: | |
| try: | |
| # Upload to manager | |
| success, result = file_manager.upload_file(str(file_obj.name) if hasattr(file_obj, 'name') else file_obj) | |
| if success: | |
| file_id = result | |
| # Get file path | |
| file_path = file_manager.get_file_path(file_id) | |
| if file_path: | |
| # Process and analyze | |
| analysis, content = processor.process_material(file_path) | |
| all_analyses.append(analysis) | |
| # Mark for cleanup (delete in 30 seconds) | |
| file_manager.mark_processed(file_id, delete_after=30) | |
| else: | |
| error_messages.append(f"Error uploading: {result}") | |
| except Exception as e: | |
| error_messages.append(f"Error processing file: {str(e)[:100]}") | |
| logger.error(f"Material processing error: {str(e)}") | |
| continue | |
| if not all_analyses: | |
| return ( | |
| "β " + " | ".join(error_messages), | |
| "", | |
| "", | |
| "", | |
| "", | |
| "", | |
| "", | |
| "" | |
| ) | |
| # If multiple materials, combine analysis (use first one for simplicity, or combine) | |
| combined = all_analyses[0] | |
| if len(all_analyses) > 1: | |
| combined = combine_multiple_analyses(all_analyses) | |
| # Format outputs for display | |
| concepts_str = format_concepts(combined.get("key_concepts", [])) | |
| objectives_str = format_objectives(combined.get("learning_objectives", [])) | |
| definitions_str = format_definitions(combined.get("key_definitions", [])) | |
| structure_str = format_structure(combined.get("structure", {})) | |
| themes_str = format_themes(combined.get("main_themes", [])) | |
| difficulty_str = combined.get("difficulty_level", "Unknown") | |
| summary_str = combined.get("summary", "No summary available") | |
| focus_str = format_focus_areas(combined.get("focus_areas", [])) | |
| return ( | |
| concepts_str, | |
| objectives_str, | |
| definitions_str, | |
| structure_str, | |
| themes_str, | |
| difficulty_str, | |
| summary_str, | |
| focus_str | |
| ) | |
| except Exception as e: | |
| logger.error(f"Material analysis error: {str(e)}") | |
| return ( | |
| f"β Analysis error: {str(e)[:200]}", | |
| "", | |
| "", | |
| "", | |
| "", | |
| "", | |
| "", | |
| "" | |
| ) | |
| def generate_from_material_analysis( | |
| concepts: str, | |
| objectives: str, | |
| definitions: str, | |
| document_type: str, | |
| output_formats: List[str], | |
| content_generator | |
| ) -> str: | |
| """ | |
| Generate documents based on material analysis. | |
| Args: | |
| concepts: Extracted concepts | |
| objectives: Learning objectives | |
| definitions: Key definitions | |
| document_type: Type of document to generate | |
| output_formats: List of output formats | |
| content_generator: ContentGenerator instance | |
| Returns: | |
| Status message | |
| """ | |
| try: | |
| from utils import FileHandler | |
| # Parse extracted information | |
| status_messages = [] | |
| # Build prompt from analysis | |
| prompt = build_prompt_from_analysis( | |
| concepts, objectives, definitions, document_type | |
| ) | |
| # Generate content using content_generator | |
| generated_content = content_generator.generate_section( | |
| title=f"{document_type} - Study Material", | |
| context=concepts + "\n" + objectives, | |
| topic=document_type, | |
| word_count=1000, | |
| style="academic" | |
| ) | |
| status_messages.append(f"β Generated content ({len(generated_content)} chars)") | |
| # Could generate multiple formats here if needed | |
| if "pdf" in output_formats or "docx" in output_formats: | |
| status_messages.append("β Ready for export to PDF/Word") | |
| return "\n".join(status_messages) | |
| except Exception as e: | |
| logger.error(f"Document generation error: {str(e)}") | |
| return f"β Generation error: {str(e)[:200]}" | |
| def format_concepts(concepts: List[Dict[str, Any]]) -> str: | |
| """Format concepts for display.""" | |
| if not concepts: | |
| return "No concepts extracted" | |
| lines = ["**Key Concepts Extracted:**\n"] | |
| for i, concept in enumerate(concepts[:15], 1): | |
| importance = concept.get("importance", 0) | |
| concept_name = concept.get("concept", "Unknown") | |
| bar = "β" * (importance // 10) + "β" * (10 - importance // 10) | |
| lines.append(f"{i}. **{concept_name}** [{bar}] {importance}%") | |
| return "\n".join(lines) | |
| def format_objectives(objectives: List[str]) -> str: | |
| """Format learning objectives for display.""" | |
| if not objectives: | |
| return "No learning objectives found" | |
| lines = ["**Learning Objectives:**\n"] | |
| for i, obj in enumerate(objectives, 1): | |
| lines.append(f"{i}. {obj}") | |
| return "\n".join(lines) | |
| def format_definitions(definitions: List[Dict[str, str]]) -> str: | |
| """Format definitions for display.""" | |
| if not definitions: | |
| return "No definitions extracted" | |
| lines = ["**Key Definitions:**\n"] | |
| for i, d in enumerate(definitions[:10], 1): | |
| term = d.get("term", "Unknown") | |
| definition = d.get("definition", "")[:150] + ("..." if len(d.get("definition", "")) > 150 else "") | |
| lines.append(f"**{i}. {term}:** {definition}") | |
| return "\n".join(lines) | |
| def format_structure(structure: Dict[str, Any]) -> str: | |
| """Format document structure for display.""" | |
| if not structure: | |
| return "No structure information" | |
| lines = [ | |
| f"**Document Structure Analysis:**", | |
| f"- Total Lines: {structure.get('total_lines', 0)}", | |
| f"- Paragraphs: {structure.get('total_paragraphs', 0)}", | |
| f"- Sections: {structure.get('estimated_sections', 0)}", | |
| f"- Avg Paragraph Length: {structure.get('average_paragraph_length', 0)} chars", | |
| f"- Has Lists: {'Yes' if structure.get('has_lists') else 'No'}", | |
| f"- Has Numbering: {'Yes' if structure.get('has_numbering') else 'No'}", | |
| ] | |
| return "\n".join(lines) | |
| def format_themes(themes: List[Dict[str, Any]]) -> str: | |
| """Format main themes for display.""" | |
| if not themes: | |
| return "No themes identified" | |
| lines = ["**Main Themes:**\n"] | |
| for i, theme in enumerate(themes[:10], 1): | |
| theme_name = theme.get("theme", "Unknown") | |
| importance = theme.get("importance", 0) | |
| mentions = theme.get("mentions", 0) | |
| lines.append(f"{i}. **{theme_name}** - Mentions: {mentions}, Importance: {importance}%") | |
| return "\n".join(lines) | |
| def format_focus_areas(focus_areas: List[str]) -> str: | |
| """Format focus areas for display.""" | |
| if not focus_areas: | |
| return "No focus areas identified" | |
| lines = ["**Suggested Focus Areas:**\n"] | |
| for i, area in enumerate(focus_areas[:5], 1): | |
| lines.append(f"{i}. {area}") | |
| return "\n".join(lines) | |
| def build_prompt_from_analysis( | |
| concepts: str, | |
| objectives: str, | |
| definitions: str, | |
| document_type: str | |
| ) -> str: | |
| """Build a generation prompt from extracted material analysis.""" | |
| prompt = f""" | |
| Based on the following extracted material analysis, generate a {document_type}: | |
| Key Concepts: | |
| {concepts} | |
| Learning Objectives: | |
| {objectives} | |
| Key Definitions: | |
| {definitions} | |
| Task: Create a comprehensive {document_type} that covers all the above material, | |
| organized by learning objectives, with clear explanations of each concept and definition. | |
| Ensure the output is: | |
| - Well-structured and easy to understand | |
| - Academic in tone | |
| - Comprehensive but concise | |
| - Includes all key concepts and definitions | |
| """ | |
| return prompt | |
| def combine_multiple_analyses(analyses: List[Dict[str, Any]]) -> Dict[str, Any]: | |
| """ | |
| Combine multiple material analyses into one comprehensive analysis. | |
| Args: | |
| analyses: List of individual material analyses | |
| Returns: | |
| Combined analysis | |
| """ | |
| if not analyses: | |
| return {} | |
| if len(analyses) == 1: | |
| return analyses[0] | |
| # Combine concepts (remove duplicates, keep highest importance) | |
| all_concepts = {} | |
| for analysis in analyses: | |
| for concept in analysis.get("key_concepts", []): | |
| concept_name = concept.get("concept", "Unknown").lower() | |
| if concept_name not in all_concepts: | |
| all_concepts[concept_name] = concept | |
| else: | |
| # Keep the one with higher importance | |
| if concept.get("importance", 0) > all_concepts[concept_name].get("importance", 0): | |
| all_concepts[concept_name] = concept | |
| # Combine objectives | |
| all_objectives = [] | |
| seen_objectives = set() | |
| for analysis in analyses: | |
| for obj in analysis.get("learning_objectives", []): | |
| if obj not in seen_objectives: | |
| all_objectives.append(obj) | |
| seen_objectives.add(obj) | |
| # Combine definitions | |
| all_definitions = [] | |
| seen_terms = set() | |
| for analysis in analyses: | |
| for definition in analysis.get("key_definitions", []): | |
| term = definition.get("term", "").lower() | |
| if term not in seen_terms: | |
| all_definitions.append(definition) | |
| seen_terms.add(term) | |
| # Use first analysis as base, then override with combined data | |
| combined = analyses[0].copy() | |
| combined["key_concepts"] = list(all_concepts.values())[:20] | |
| combined["learning_objectives"] = all_objectives | |
| combined["key_definitions"] = all_definitions | |
| combined["material_count"] = len(analyses) | |
| return combined | |
| def get_material_upload_instructions() -> str: | |
| """Get instructions for material upload tab.""" | |
| return """ | |
| ### π Upload & Analyze Lecture Materials | |
| This tool allows you to upload your lecture materials (PDFs, Word documents, PowerPoint slides, etc.) | |
| and automatically extract: | |
| - **Key Concepts** - Important topics and terms with importance scores | |
| - **Learning Objectives** - What you're expected to learn | |
| - **Key Definitions** - Important terms and their definitions | |
| - **Document Structure** - How the material is organized | |
| - **Main Themes** - Primary topics and their relationships | |
| - **Difficulty Level** - Whether this is beginner, intermediate, or advanced material | |
| - **Focus Areas** - Where you should concentrate your study efforts | |
| #### Supported File Formats: | |
| - π PDF files (.pdf) | |
| - π PowerPoint presentations (.pptx, .ppt) | |
| - π Word documents (.docx, .doc) | |
| - π Text files (.txt) | |
| - ποΈ Markdown files (.md) | |
| #### How to Use: | |
| 1. Click "Upload Lecture Materials" and select one or more files | |
| 2. Click "Analyze Materials" to extract insights | |
| 3. Review the analysis results | |
| 4. Use "Generate Documents Based on Analysis" to create study materials | |
| 5. Files are automatically deleted after processing (privacy protected) | |
| #### Privacy Note: | |
| - Files are processed temporarily and automatically deleted | |
| - No data is stored permanently | |
| - Analysis happens locally without external storage | |
| """ | |