deep-research-ai / src /modules /output_generation.py
debashis2007's picture
Upload folder using huggingface_hub
1eae9f8 verified
Raw
History Blame Contribute Delete
13.2 kB
"""
Output generation module for the Deep Research AI system.
This module handles the final synthesis and formatting of research results
into user-friendly, well-structured outputs in various formats.
"""
from enum import Enum
from typing import Any
from ..config import Config
from ..llm_client import LLMClient
from ..models import Source, ResearchResult, OutputFormat
from ..prompts.output_prompts import (
REPORT_GENERATION_PROMPT,
SUMMARY_GENERATION_PROMPT,
ANSWER_FORMATTING_PROMPT,
VISUALIZATION_SUGGESTION_PROMPT,
MULTI_FORMAT_OUTPUT_PROMPT,
RESPONSE_QUALITY_PROMPT,
FOLLOWUP_QUESTIONS_PROMPT,
EXPORT_FORMAT_PROMPT,
)
class SummaryLength(Enum):
"""Summary length options."""
BRIEF = "brief"
STANDARD = "standard"
DETAILED = "detailed"
class AudienceType(Enum):
"""Target audience types."""
GENERAL = "general"
PROFESSIONAL = "professional"
ACADEMIC = "academic"
TECHNICAL = "technical"
class ExportFormat(Enum):
"""Export format options."""
PDF = "pdf"
DOCX = "docx"
SLIDES = "slides"
EMAIL = "email"
SOCIAL = "social"
class OutputGenerator:
"""
Generates formatted output from research results.
Provides comprehensive output generation including:
- Full research reports
- Summaries at various lengths
- Multi-format output generation
- Quality assessment
- Follow-up question generation
"""
def __init__(self, config: Config | None = None) -> None:
"""
Initialize the OutputGenerator.
Args:
config: Configuration object. Uses default if not provided.
"""
self.config = config or Config()
self.llm_client = LLMClient(self.config.llm_config)
async def generate_report(
self,
query: str,
findings: dict[str, Any],
sources: list[Source],
confidence: float
) -> dict[str, Any]:
"""
Generate a comprehensive research report.
Args:
query: Original research query
findings: Synthesized research findings
sources: Sources used in research
confidence: Overall confidence score
Returns:
Dictionary containing the full research report
"""
sources_text = self._format_sources(sources)
prompt = REPORT_GENERATION_PROMPT.format(
query=query,
findings=str(findings),
sources=sources_text,
confidence=f"{confidence:.2%}"
)
result = await self.llm_client.call_json(prompt)
return {
"report": result.get("report", {}),
"metadata": result.get("metadata", {}),
"format": OutputFormat.MARKDOWN
}
async def generate_summary(
self,
findings: dict[str, Any],
length: SummaryLength = SummaryLength.STANDARD
) -> dict[str, Any]:
"""
Generate a summary of research findings.
Args:
findings: Research findings to summarize
length: Desired summary length
Returns:
Dictionary containing the summary
"""
prompt = SUMMARY_GENERATION_PROMPT.format(
findings=str(findings),
length=length.value
)
result = await self.llm_client.call_json(prompt)
return {
"summary": result.get("summary", {}),
"metadata": result.get("metadata", {})
}
async def format_answer(
self,
answer: str,
audience: AudienceType = AudienceType.GENERAL,
output_format: OutputFormat = OutputFormat.MARKDOWN
) -> dict[str, Any]:
"""
Format an answer for a specific audience and format.
Args:
answer: The answer to format
audience: Target audience
output_format: Desired output format
Returns:
Dictionary containing the formatted answer
"""
prompt = ANSWER_FORMATTING_PROMPT.format(
answer=answer,
audience=audience.value,
format=output_format.value
)
result = await self.llm_client.call_json(prompt)
return {
"formatted_answer": result.get("formatted_answer", {}),
"readability_metrics": result.get("readability_metrics", {})
}
async def suggest_visualizations(
self,
data: dict[str, Any],
findings: dict[str, Any]
) -> dict[str, Any]:
"""
Suggest visualizations for research data.
Args:
data: Numerical or structured data
findings: Research findings
Returns:
Dictionary with visualization suggestions
"""
prompt = VISUALIZATION_SUGGESTION_PROMPT.format(
data=str(data),
findings=str(findings)
)
result = await self.llm_client.call_json(prompt)
return {
"visualizations": result.get("visualizations", []),
"recommended_count": result.get("recommended_count", 0),
"data_visualization_potential": result.get("data_visualization_potential", "low")
}
async def generate_multi_format(
self,
content: str,
citations: str
) -> dict[str, Any]:
"""
Generate output in multiple formats simultaneously.
Args:
content: Research content
citations: Citation information
Returns:
Dictionary with content in multiple formats
"""
prompt = MULTI_FORMAT_OUTPUT_PROMPT.format(
content=content,
citations=citations
)
result = await self.llm_client.call_json(prompt)
return {
"outputs": result.get("outputs", {}),
"recommended_format": result.get("recommended_format", "markdown"),
"format_notes": result.get("format_notes", {})
}
async def assess_quality(
self,
query: str,
response: str,
sources: list[Source]
) -> dict[str, Any]:
"""
Assess the quality of a generated response.
Args:
query: Original query
response: Generated response
sources: Sources used
Returns:
Dictionary with quality assessment
"""
sources_text = self._format_sources(sources)
prompt = RESPONSE_QUALITY_PROMPT.format(
query=query,
response=response,
sources=sources_text
)
result = await self.llm_client.call_json(prompt)
return {
"quality_assessment": result.get("quality_assessment", {}),
"confidence_level": result.get("confidence_level", "medium"),
"ready_for_delivery": result.get("ready_for_delivery", False),
"revision_needed": result.get("revision_needed", True)
}
async def generate_followup_questions(
self,
query: str,
findings: dict[str, Any],
gaps: list[str]
) -> dict[str, Any]:
"""
Generate relevant follow-up questions.
Args:
query: Original query
findings: Research findings
gaps: Identified information gaps
Returns:
Dictionary with follow-up questions
"""
prompt = FOLLOWUP_QUESTIONS_PROMPT.format(
query=query,
findings=str(findings),
gaps=str(gaps)
)
result = await self.llm_client.call_json(prompt)
return {
"follow_up_questions": result.get("follow_up_questions", []),
"recommended_next_question": result.get("recommended_next_question", ""),
"research_continuation_score": result.get("research_continuation_score", 0.0)
}
async def prepare_for_export(
self,
report: dict[str, Any],
export_format: ExportFormat
) -> dict[str, Any]:
"""
Prepare research output for export.
Args:
report: Research report
export_format: Target export format
Returns:
Dictionary with export-ready content
"""
prompt = EXPORT_FORMAT_PROMPT.format(
report=str(report),
export_format=export_format.value
)
result = await self.llm_client.call_json(prompt)
return {
"export_ready": result.get("export_ready", {}),
"export_metadata": result.get("export_metadata", {})
}
async def create_research_result(
self,
query: str,
findings: dict[str, Any],
sources: list[Source],
confidence: float,
audience: AudienceType = AudienceType.GENERAL
) -> ResearchResult:
"""
Create a complete ResearchResult object.
This method combines all output generation capabilities into
a single comprehensive research result.
Args:
query: Original query
findings: Research findings
sources: Sources used
confidence: Confidence score
audience: Target audience
Returns:
Complete ResearchResult object
"""
# Generate the main report
report_result = await self.generate_report(
query, findings, sources, confidence
)
# Generate summary
summary_result = await self.generate_summary(
findings, SummaryLength.STANDARD
)
# Assess quality
report_text = self._report_to_text(report_result["report"])
quality_result = await self.assess_quality(query, report_text, sources)
# Generate follow-up questions
gaps = findings.get("information_gaps", [])
followup_result = await self.generate_followup_questions(
query, findings, gaps
)
# Build the research result
return ResearchResult(
query=query,
answer=summary_result["summary"].get("text", ""),
confidence=confidence,
sources=sources,
reasoning_steps=findings.get("reasoning_steps", []),
verification_status=findings.get("verification_status", "unverified"),
metadata={
"full_report": report_result["report"],
"quality_assessment": quality_result["quality_assessment"],
"follow_up_questions": followup_result["follow_up_questions"],
"audience": audience.value
}
)
def _format_sources(self, sources: list[Source]) -> str:
"""Format sources for prompts."""
formatted = []
for i, source in enumerate(sources, 1):
formatted.append(f"""
Source {i}:
- Title: {source.title}
- URL: {source.url}
- Credibility: {source.credibility_score}
""")
return "\n".join(formatted)
def _report_to_text(self, report: dict) -> str:
"""Convert report dict to plain text."""
parts = []
if "title" in report:
parts.append(f"# {report['title']}\n")
if "executive_summary" in report:
parts.append(f"## Executive Summary\n{report['executive_summary']}\n")
if "main_findings" in report:
parts.append("## Main Findings\n")
for finding in report["main_findings"]:
parts.append(f"### {finding.get('theme', 'Finding')}\n")
parts.append(f"{finding.get('content', '')}\n")
if "conclusion" in report:
conclusion = report["conclusion"]
parts.append("## Conclusion\n")
parts.append(f"{conclusion.get('answer', '')}\n")
return "\n".join(parts)
def render_markdown(self, report: dict) -> str:
"""
Render a report as markdown.
Args:
report: Report dictionary
Returns:
Markdown formatted string
"""
return self._report_to_text(report)
def render_html(self, report: dict) -> str:
"""
Render a report as HTML.
Args:
report: Report dictionary
Returns:
HTML formatted string
"""
md = self._report_to_text(report)
# Basic markdown to HTML conversion
html = md.replace("# ", "<h1>").replace("\n## ", "</h1>\n<h2>")
html = html.replace("\n### ", "</h2>\n<h3>").replace("\n\n", "</p>\n<p>")
return f"<html><body>{html}</body></html>"
# Module singleton instance
output_generator = OutputGenerator()