Skip to main content

semantic_scholar/models/
paper.rs

1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4/// A paper in the Semantic Scholar corpus.
5#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6#[serde(rename_all = "camelCase")]
7pub struct Paper {
8    #[serde(default)]
9    pub paper_id: String,
10    #[serde(default)]
11    pub corpus_id: Option<u64>,
12    #[serde(default)]
13    pub external_ids: Option<ExternalIds>,
14    #[serde(default)]
15    pub url: Option<String>,
16    #[serde(default)]
17    pub title: Option<String>,
18    #[serde(default, rename = "abstract")]
19    pub abstract_text: Option<String>,
20    #[serde(default)]
21    pub venue: Option<String>,
22    #[serde(default)]
23    pub publication_venue: Option<PublicationVenue>,
24    #[serde(default)]
25    pub year: Option<u32>,
26    #[serde(default)]
27    pub reference_count: Option<u32>,
28    #[serde(default)]
29    pub citation_count: Option<u32>,
30    #[serde(default)]
31    pub influential_citation_count: Option<u32>,
32    #[serde(default)]
33    pub is_open_access: Option<bool>,
34    #[serde(default)]
35    pub open_access_pdf: Option<OpenAccessPdf>,
36    #[serde(default)]
37    pub fields_of_study: Option<Vec<String>>,
38    #[serde(default)]
39    pub s2_fields_of_study: Option<Vec<S2FieldOfStudy>>,
40    #[serde(default)]
41    pub publication_types: Option<Vec<String>>,
42    #[serde(default)]
43    pub publication_date: Option<String>,
44    #[serde(default)]
45    pub journal: Option<Journal>,
46    #[serde(default)]
47    pub citation_styles: Option<CitationStyles>,
48    #[serde(default)]
49    pub authors: Option<Vec<AuthorRef>>,
50    #[serde(default)]
51    pub citations: Option<Vec<Citation>>,
52    #[serde(default)]
53    pub references: Option<Vec<Reference>>,
54    #[serde(default)]
55    pub tldr: Option<Tldr>,
56}
57
58impl fmt::Display for Paper {
59    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60        let title = self.title.as_deref().unwrap_or("(untitled)");
61        write!(f, "{title}")?;
62        if let Some(year) = self.year {
63            write!(f, " ({year})")?;
64        }
65        if let Some(authors) = &self.authors {
66            let names: Vec<&str> = authors
67                .iter()
68                .filter_map(|a| a.name.as_deref())
69                .take(3)
70                .collect();
71            if !names.is_empty() {
72                write!(f, " — {}", names.join(", "))?;
73                if authors.len() > 3 {
74                    write!(f, " et al.")?;
75                }
76            }
77        }
78        Ok(())
79    }
80}
81
82/// External identifiers for a paper (DOI, ArXiv, etc.).
83#[derive(Debug, Clone, Default, Serialize, Deserialize)]
84pub struct ExternalIds {
85    #[serde(default, rename = "DOI")]
86    pub doi: Option<String>,
87    #[serde(default, rename = "ArXiv")]
88    pub arxiv: Option<String>,
89    #[serde(default, rename = "MAG")]
90    pub mag: Option<String>,
91    #[serde(default, rename = "ACL")]
92    pub acl: Option<String>,
93    #[serde(default, rename = "PubMed")]
94    pub pubmed: Option<String>,
95    #[serde(default, rename = "PubMedCentral")]
96    pub pubmed_central: Option<String>,
97    #[serde(default, rename = "DBLP")]
98    pub dblp: Option<String>,
99    #[serde(default, rename = "CorpusId")]
100    pub corpus_id: Option<u64>,
101}
102
103#[derive(Debug, Clone, Default, Serialize, Deserialize)]
104pub struct PublicationVenue {
105    #[serde(default)]
106    pub id: Option<String>,
107    #[serde(default)]
108    pub name: Option<String>,
109    #[serde(default, rename = "type")]
110    pub venue_type: Option<String>,
111    #[serde(default)]
112    pub alternate_names: Option<Vec<String>>,
113    #[serde(default)]
114    pub url: Option<String>,
115}
116
117#[derive(Debug, Clone, Default, Serialize, Deserialize)]
118pub struct OpenAccessPdf {
119    #[serde(default)]
120    pub url: Option<String>,
121    #[serde(default)]
122    pub status: Option<String>,
123}
124
125#[derive(Debug, Clone, Default, Serialize, Deserialize)]
126pub struct S2FieldOfStudy {
127    #[serde(default)]
128    pub category: Option<String>,
129    #[serde(default)]
130    pub source: Option<String>,
131}
132
133#[derive(Debug, Clone, Default, Serialize, Deserialize)]
134pub struct Journal {
135    #[serde(default)]
136    pub name: Option<String>,
137    #[serde(default)]
138    pub pages: Option<String>,
139    #[serde(default)]
140    pub volume: Option<String>,
141}
142
143#[derive(Debug, Clone, Default, Serialize, Deserialize)]
144pub struct CitationStyles {
145    #[serde(default)]
146    pub bibtex: Option<String>,
147}
148
149/// Minimal author reference embedded in paper responses.
150#[derive(Debug, Clone, Default, Serialize, Deserialize)]
151#[serde(rename_all = "camelCase")]
152pub struct AuthorRef {
153    #[serde(default)]
154    pub author_id: Option<String>,
155    #[serde(default)]
156    pub name: Option<String>,
157}
158
159/// A citing paper with citation context.
160#[derive(Debug, Clone, Default, Serialize, Deserialize)]
161#[serde(rename_all = "camelCase")]
162pub struct Citation {
163    #[serde(default)]
164    pub citing_paper: Option<Paper>,
165    #[serde(default)]
166    pub contexts: Option<Vec<String>>,
167    #[serde(default)]
168    pub intents: Option<Vec<String>>,
169    #[serde(default)]
170    pub is_influential: Option<bool>,
171}
172
173/// A referenced paper with citation context.
174#[derive(Debug, Clone, Default, Serialize, Deserialize)]
175#[serde(rename_all = "camelCase")]
176pub struct Reference {
177    #[serde(default)]
178    pub cited_paper: Option<Paper>,
179    #[serde(default)]
180    pub contexts: Option<Vec<String>>,
181    #[serde(default)]
182    pub intents: Option<Vec<String>>,
183    #[serde(default)]
184    pub is_influential: Option<bool>,
185}
186
187/// TL;DR auto-generated summary.
188#[derive(Debug, Clone, Default, Serialize, Deserialize)]
189pub struct Tldr {
190    #[serde(default)]
191    pub model: Option<String>,
192    #[serde(default)]
193    pub text: Option<String>,
194}
195
196// ---------------------------------------------------------------------------
197// Response types
198// ---------------------------------------------------------------------------
199
200/// Response from `GET /paper/search`.
201#[derive(Debug, Clone, Serialize, Deserialize)]
202pub struct PaperSearchResponse {
203    #[serde(default)]
204    pub total: u64,
205    #[serde(default)]
206    pub offset: Option<u32>,
207    #[serde(default)]
208    pub next: Option<u32>,
209    #[serde(default)]
210    pub data: Vec<Paper>,
211}
212
213/// Response from `GET /paper/{id}/citations`.
214#[derive(Debug, Clone, Serialize, Deserialize)]
215pub struct CitationResponse {
216    #[serde(default)]
217    pub offset: Option<u32>,
218    #[serde(default)]
219    pub next: Option<u32>,
220    #[serde(default)]
221    pub data: Vec<Citation>,
222}
223
224/// Response from `GET /paper/{id}/references`.
225#[derive(Debug, Clone, Serialize, Deserialize)]
226pub struct ReferenceResponse {
227    #[serde(default)]
228    pub offset: Option<u32>,
229    #[serde(default)]
230    pub next: Option<u32>,
231    #[serde(default)]
232    pub data: Vec<Reference>,
233}
234
235/// Response from `GET /recommendations/v1/papers/forpaper/{id}`.
236#[derive(Debug, Clone, Serialize, Deserialize)]
237#[serde(rename_all = "camelCase")]
238pub struct RecommendationResponse {
239    #[serde(default)]
240    pub recommended_papers: Vec<Paper>,
241}