""" Nomination Assistant for Award Identification AI-assisted preparation of award nominations and grant applications. FEATURES (Planned): ------------------ 1. DOCUMENT GENERATION: - Executive summaries - Project descriptions - Budget justifications - Team CVs and bios 2. TEMPLATE MATCHING: - Match to funder templates - Format compliance checking - Character/word limit validation 3. QUALITY ASSURANCE: - CriticAgent validation - Reviewer simulation - Gap identification 4. COLLABORATION: - Multi-author editing - Comment and review workflows - Version control HUMAN-IN-THE-LOOP: ----------------- Document preparation requires extensive human input: - Initial content drafting - Review and revision cycles - Final approval before submission This assistant accelerates the process but doesn't replace human expertise in grant writing. Author: SPARKNET Team Project: VISTA/Horizon EU Status: Placeholder - In Development """ from typing import Optional, Dict, Any, List from dataclasses import dataclass, field from datetime import datetime from enum import Enum from loguru import logger class DocumentTemplate(str, Enum): """Standard document templates.""" HORIZON_PROPOSAL = "horizon_proposal" ERC_APPLICATION = "erc_application" NATIONAL_GRANT = "national_grant" AWARD_NOMINATION = "award_nomination" LETTER_OF_INTENT = "letter_of_intent" BUDGET_TEMPLATE = "budget_template" CV_EUROPASS = "cv_europass" CUSTOM = "custom" class ReviewStatus(str, Enum): """Document review status.""" DRAFT = "draft" INTERNAL_REVIEW = "internal_review" REVISION_NEEDED = "revision_needed" APPROVED = "approved" SUBMITTED = "submitted" @dataclass class DocumentSection: """ Section of a nomination document. Represents a structured section with content and metadata. """ section_id: str title: str content: str word_limit: Optional[int] = None current_words: int = 0 status: str = "draft" ai_generated: bool = False human_reviewed: bool = False reviewer_comments: List[str] = field(default_factory=list) suggestions: List[str] = field(default_factory=list) @dataclass class DocumentReview: """ Review of a nomination document. Contains feedback from AI and human reviewers. """ review_id: str document_id: str reviewer_type: str # "ai", "human", "external" reviewer_name: Optional[str] = None overall_score: Optional[float] = None section_scores: Dict[str, float] = field(default_factory=dict) strengths: List[str] = field(default_factory=list) weaknesses: List[str] = field(default_factory=list) suggestions: List[str] = field(default_factory=list) decision: str = "pending" # approve, revise, reject created_at: datetime = field(default_factory=datetime.now) class NominationAssistant: """ AI assistant for preparing nominations and applications. This component: - Generates document sections - Checks format compliance - Simulates reviewer feedback - Manages revision workflows INTEGRATION WITH CRITICAGENT: ----------------------------- Uses CriticAgent for: - Document quality validation - Format compliance checking - Reviewer perspective simulation - Gap and weakness identification CONFIDENCE SCORING: ------------------ All AI-generated content includes: - Confidence score (0.0-1.0) - Source references where applicable - Suggestions for improvement - Flag for human review Generated content with low confidence scores is automatically flagged for human review. """ def __init__( self, llm_client: Optional[Any] = None, critic_agent: Optional[Any] = None, template_library: Optional[Dict[str, Any]] = None, ): """ Initialize Nomination Assistant. Args: llm_client: LangChain LLM client for content generation critic_agent: CriticAgent for validation template_library: Library of document templates """ self.llm_client = llm_client self.critic_agent = critic_agent self.template_library = template_library or {} self.name = "NominationAssistant" # Threshold for requiring human review self.confidence_threshold = 0.7 logger.info(f"Initialized {self.name} (placeholder)") async def generate_section( self, document_id: str, section_type: str, context: Dict[str, Any], word_limit: Optional[int] = None, ) -> DocumentSection: """ Generate a document section using AI. Args: document_id: Parent document ID section_type: Type of section to generate context: Context information for generation word_limit: Optional word limit Returns: Generated section with confidence score TODO: Implement actual LLM generation """ logger.info(f"Generating {section_type} section for document: {document_id}") # Placeholder response return DocumentSection( section_id=f"sec_{datetime.now().strftime('%Y%m%d_%H%M%S')}", title=section_type.replace("_", " ").title(), content="[AI-generated content placeholder]", word_limit=word_limit, current_words=0, status="draft", ai_generated=True, human_reviewed=False, suggestions=["Complete implementation with actual LLM generation"], ) async def check_format_compliance( self, document_id: str, template: DocumentTemplate, ) -> Dict[str, Any]: """ Check document compliance with template requirements. Args: document_id: Document to check template: Template to check against Returns: Compliance report with issues TODO: Implement actual compliance checking """ logger.info(f"Checking format compliance for document: {document_id}") # Placeholder response return { "document_id": document_id, "template": template.value, "compliant": False, "issues": [ { "type": "placeholder", "message": "Compliance checking not yet implemented", "severity": "info", } ], "word_counts": {}, "missing_sections": [], } async def simulate_review( self, document_id: str, reviewer_perspective: str = "general", ) -> DocumentReview: """ Simulate reviewer feedback using AI. Generates feedback from the perspective of a grant reviewer to identify potential weaknesses. Args: document_id: Document to review reviewer_perspective: Type of reviewer to simulate Returns: Simulated review with scores and feedback TODO: Implement actual review simulation """ logger.info(f"Simulating {reviewer_perspective} review for document: {document_id}") # Placeholder response return DocumentReview( review_id=f"rev_{datetime.now().strftime('%Y%m%d_%H%M%S')}", document_id=document_id, reviewer_type="ai", reviewer_name=f"AI ({reviewer_perspective})", overall_score=0.0, strengths=["Review simulation not yet implemented"], weaknesses=["Cannot assess without implementation"], suggestions=["Complete the AI review simulation feature"], decision="pending", ) async def suggest_improvements( self, section: DocumentSection, ) -> List[str]: """ Suggest improvements for a document section. Uses CriticAgent to analyze section and generate actionable improvement suggestions. Args: section: Section to analyze Returns: List of improvement suggestions TODO: Implement CriticAgent integration """ logger.info(f"Generating improvement suggestions for section: {section.section_id}") # Placeholder response return [ "Improvement suggestions not yet implemented", "Will integrate with CriticAgent for validation", ] async def validate_with_critic( self, document_id: str, ) -> Dict[str, Any]: """ Validate document using CriticAgent. Performs comprehensive validation including: - Content quality assessment - Format compliance - Logical consistency - Citation verification Args: document_id: Document to validate Returns: Validation result with scores and issues TODO: Implement CriticAgent integration """ logger.info(f"Validating document with CriticAgent: {document_id}") # Placeholder response return { "document_id": document_id, "valid": False, "overall_score": 0.0, "dimension_scores": { "completeness": 0.0, "clarity": 0.0, "accuracy": 0.0, "compliance": 0.0, }, "issues": ["CriticAgent validation not yet implemented"], "suggestions": ["Complete CriticAgent integration"], "human_review_required": True, "confidence": 0.0, } def requires_human_review( self, confidence_score: float, section_type: str, ) -> bool: """ Determine if content requires human review. Human review is required when: - Confidence is below threshold - Section is critical (executive summary, budget) - Content makes claims about capabilities Args: confidence_score: AI confidence score section_type: Type of section Returns: True if human review required """ # Low confidence always requires review if confidence_score < self.confidence_threshold: return True # Critical sections always require review critical_sections = [ "executive_summary", "budget", "team_qualifications", "methodology", ] if section_type.lower() in critical_sections: return True return False