""" JSON renderer for report generation. """ from .base_renderer import BaseRenderer from typing import Dict, Any, Tuple, List import json class JsonRenderer(BaseRenderer): """Renders content to JSON format with format-specific extraction.""" @classmethod def get_supported_formats(cls) -> List[str]: """Return supported JSON formats.""" return ['json'] @classmethod def get_format_aliases(cls) -> List[str]: """Return format aliases.""" return ['data'] @classmethod def get_priority(cls) -> int: """Return priority for JSON renderer.""" return 80 def getExtractionPrompt(self, user_prompt: str, title: str) -> str: """Return only JSON-specific guidelines; global prompt is built centrally.""" return ( "JSON FORMAT GUIDELINES:\n" "- Output ONLY a single valid JSON object (no fences, no pre/post text).\n" "- Choose a structure that best fits the user's intent; include a top-level title and data.\n" "- Prefer arrays/objects that map cleanly to the extracted facts.\n" "- Include minimal metadata only if useful (e.g., generatedAt, sources).\n" "OUTPUT: Return ONLY valid, parseable JSON." ) async def render(self, extracted_content: str, title: str) -> Tuple[str, str]: """Render extracted content to JSON format.""" try: # The extracted content should already be JSON from the AI # Just validate and format it json_content = self._clean_json_content(extracted_content, title) return json_content, "application/json" except Exception as e: self.logger.error(f"Error rendering JSON: {str(e)}") # Return minimal JSON fallback fallback_data = { "title": title, "sections": [{"type": "text", "content": f"Error rendering report: {str(e)}"}], "metadata": {"error": str(e)} } return json.dumps(fallback_data, indent=2), "application/json" def _clean_json_content(self, content: str, title: str) -> str: """Clean and validate JSON content from AI.""" content = content.strip() # Remove markdown code blocks if present if content.startswith("```") and content.endswith("```"): lines = content.split('\n') if len(lines) > 2: content = '\n'.join(lines[1:-1]).strip() # Validate JSON try: parsed = json.loads(content) # Re-format with proper indentation return json.dumps(parsed, indent=2, ensure_ascii=False) except json.JSONDecodeError: # If not valid JSON, return as-is return content