Coverage for src / local_deep_research / database / models / reports.py: 96%
53 statements
« prev ^ index » next coverage.py v7.12.0, created at 2026-01-11 00:51 +0000
« prev ^ index » next coverage.py v7.12.0, created at 2026-01-11 00:51 +0000
1"""
2Report generation and storage models.
3"""
5from sqlalchemy import (
6 JSON,
7 Boolean,
8 Column,
9 Float,
10 ForeignKey,
11 Integer,
12 String,
13 Text,
14)
15from sqlalchemy.orm import relationship
16from sqlalchemy_utc import UtcDateTime, utcnow
18from .base import Base
21class Report(Base):
22 """
23 Generated research reports.
24 Can be in various formats and languages.
25 """
27 __tablename__ = "reports"
29 id = Column(Integer, primary_key=True)
30 research_task_id = Column(
31 Integer, ForeignKey("research_tasks.id", ondelete="CASCADE")
32 )
34 # Report metadata
35 title = Column(String(500))
36 subtitle = Column(String(500))
37 abstract = Column(Text) # Summary/abstract
38 content = Column(Text) # Full report content (usually markdown)
40 # Format and presentation
41 format = Column(String(50), default="markdown") # markdown, html, pdf, docx
42 template = Column(String(100)) # Template used for generation
43 style = Column(String(100)) # Style/theme applied
44 language = Column(String(10), default="en")
46 # Statistics
47 word_count = Column(Integer)
48 section_count = Column(Integer)
49 reference_count = Column(Integer)
50 image_count = Column(Integer)
52 # Generation metadata
53 generation_params = Column(JSON) # Parameters used for generation
54 generation_model = Column(String(100)) # AI model used
55 generation_time_seconds = Column(Float)
57 # Versioning
58 version = Column(Integer, default=1)
59 is_draft = Column(Boolean, default=False)
61 # Timestamps
62 created_at = Column(UtcDateTime, default=utcnow())
63 updated_at = Column(UtcDateTime, default=utcnow(), onupdate=utcnow())
64 published_at = Column(UtcDateTime)
66 # Relationships
67 research_task = relationship("ResearchTask", back_populates="reports")
68 sections = relationship(
69 "ReportSection",
70 back_populates="report",
71 cascade="all, delete-orphan",
72 order_by="ReportSection.section_order",
73 )
75 def __repr__(self):
76 return f"<Report(title='{self.title}', format='{self.format}', draft={self.is_draft})>"
79class ReportSection(Base):
80 """
81 Individual sections within a report.
82 Allows for structured document generation.
83 """
85 __tablename__ = "report_sections"
87 id = Column(Integer, primary_key=True)
88 report_id = Column(Integer, ForeignKey("reports.id", ondelete="CASCADE"))
90 # Section metadata
91 title = Column(String(500))
92 subtitle = Column(String(500))
93 content = Column(Text)
95 # Structure
96 section_order = Column(Integer, nullable=False) # Order within report
97 section_type = Column(
98 String(50)
99 ) # introduction, methodology, findings, conclusion, references, appendix
100 section_level = Column(Integer, default=1) # 1=H1, 2=H2, etc.
101 parent_section_id = Column(
102 Integer, ForeignKey("report_sections.id")
103 ) # For nested sections
105 # References and citations
106 references = Column(JSON) # List of SearchResult IDs used
107 citations = Column(JSON) # Formatted citations
109 # Generation metadata
110 auto_generated = Column(Boolean, default=True)
111 edited = Column(Boolean, default=False)
113 # Timestamps
114 created_at = Column(UtcDateTime, default=utcnow())
115 updated_at = Column(UtcDateTime, default=utcnow(), onupdate=utcnow())
117 # Relationships
118 report = relationship("Report", back_populates="sections")
119 subsections = relationship(
120 "ReportSection", backref="parent_section", remote_side=[id]
121 )
123 def __repr__(self):
124 return f"<ReportSection(title='{self.title}', order={self.section_order}, type='{self.section_type}')>"