File size: 3,688 Bytes
65dfa4b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
da17d99
65dfa4b
 
 
da17d99
65dfa4b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
854be79
 
65dfa4b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
854be79
65dfa4b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
854be79
 
 
 
 
 
 
65dfa4b
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
"""Pydantic models for API request/response schemas."""

from pydantic import BaseModel, Field


# ── Request models ───────────────────────────────────────────────────


class SearchRequest(BaseModel):
    """RAG search query."""

    query: str = Field(..., min_length=1, max_length=2000)
    top_k: int = Field(default=5, ge=1, le=50)
    year_min: int | None = Field(default=None, ge=1900, le=2100)
    year_max: int | None = Field(default=None, ge=1900, le=2100)
    venue: str | None = None


class PaperBrowseRequest(BaseModel):
    """Filters for browsing papers."""

    venue: str | None = None
    volume: str | None = None
    year: int | None = Field(default=None, ge=1900, le=2100)
    method: str | None = None
    dataset: str | None = None
    author: str | None = None
    limit: int = Field(default=20, ge=1, le=100)
    offset: int = Field(default=0, ge=0)


class TrendRequest(BaseModel):
    """Request for tracking a specific entity trend over time."""

    name: str = Field(..., min_length=1, max_length=500)


# ── Response models ──────────────────────────────────────────────────


class SourcePaper(BaseModel):
    """A paper cited as a source in a RAG response."""

    paper_id: str
    title: str
    year: int
    venue: str | None
    chunk_type: str
    authors: list[str] = Field(default_factory=list)
    used_in_answer: bool = False


class SearchResponse(BaseModel):
    """RAG search result."""

    answer: str
    sources: list[SourcePaper]
    model: str
    usage: dict = Field(default_factory=dict)


class PaperDetail(BaseModel):
    """Full paper with authors and enrichment data."""

    id: str
    title: str
    abstract: str | None
    year: int | None
    venue: str | None
    url: str | None
    authors: list[str] = Field(default_factory=list)
    methods: list[dict] = Field(default_factory=list)
    datasets: list[dict] = Field(default_factory=list)


class PaperSummary(BaseModel):
    """Paper listing with basic metadata."""

    id: str
    title: str
    abstract: str | None
    year: int | None
    venue: str | None
    url: str | None
    authors: list[str] = Field(default_factory=list)


class PaperListResponse(BaseModel):
    """Paginated paper listing."""

    papers: list[PaperSummary]
    count: int
    limit: int
    offset: int


class TrendPoint(BaseModel):
    """A single year's data point in a trend."""

    year: int
    paper_count: int


class TrendResponse(BaseModel):
    """Trend data for an entity over time."""

    name: str
    trend: list[TrendPoint]


class RankedEntity(BaseModel):
    """An entity (method/dataset/task/topic) with count and rank."""

    name: str
    year: int
    count: int
    rank: int


class CooccurrenceRow(BaseModel):
    """A co-occurrence pair with frequency."""

    entity_a: str
    entity_b: str
    co_count: int


class EnrichmentStatsResponse(BaseModel):
    """Database enrichment statistics."""

    total_papers: int
    total_methods: int
    total_datasets: int
    total_tasks: int
    total_topics: int
    papers_with_methods: int


class GrowthPoint(BaseModel):
    """Year-over-year growth data."""

    year: int
    paper_count: int
    prev_count: int | None
    growth_pct: float | None


class EntityListItem(BaseModel):
    """A unique entity name with its paper count."""

    name: str
    count: int


class HealthResponse(BaseModel):
    """System health status."""

    status: str
    paper_count: int
    chunk_count: int