1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
7pub enum ConceptType {
8 Entity,
10 Concept,
12 Process,
14 Property,
16 Relationship,
18 Other,
20}
21
22impl Default for ConceptType {
23 fn default() -> Self {
24 Self::Concept
25 }
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct Concept {
31 pub label: String,
33 pub concept_type: ConceptType,
35 pub confidence: f32,
37 pub description: Option<String>,
39 pub related: Vec<String>,
41}
42
43impl Concept {
44 pub fn new(label: impl Into<String>) -> Self {
46 Self {
47 label: label.into(),
48 concept_type: ConceptType::default(),
49 confidence: 1.0,
50 description: None,
51 related: Vec::new(),
52 }
53 }
54
55 pub fn with_type(mut self, concept_type: ConceptType) -> Self {
57 self.concept_type = concept_type;
58 self
59 }
60
61 pub fn with_confidence(mut self, confidence: f32) -> Self {
63 self.confidence = confidence.clamp(0.0, 1.0);
64 self
65 }
66
67 pub fn with_description(mut self, description: impl Into<String>) -> Self {
69 self.description = Some(description.into());
70 self
71 }
72
73 pub fn with_related(mut self, related: Vec<String>) -> Self {
75 self.related = related;
76 self
77 }
78}
79
80#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
82pub enum RelationType {
83 IsA,
85 PartOf,
87 Causes,
89 Enables,
91 Requires,
93 RelatedTo,
95 Produces,
97 Regulates,
99 InteractsWith,
101 LocatedIn,
103 Custom(String),
105}
106
107impl Default for RelationType {
108 fn default() -> Self {
109 Self::RelatedTo
110 }
111}
112
113#[derive(Debug, Clone, Serialize, Deserialize)]
115pub struct Relationship {
116 pub source: String,
118 pub target: String,
120 pub relation_type: RelationType,
122 pub label: String,
124 pub confidence: f32,
126 pub bidirectional: bool,
128}
129
130impl Relationship {
131 pub fn new(source: impl Into<String>, target: impl Into<String>, label: impl Into<String>) -> Self {
133 Self {
134 source: source.into(),
135 target: target.into(),
136 relation_type: RelationType::default(),
137 label: label.into(),
138 confidence: 1.0,
139 bidirectional: false,
140 }
141 }
142
143 pub fn with_type(mut self, relation_type: RelationType) -> Self {
145 self.relation_type = relation_type;
146 self
147 }
148
149 pub fn with_confidence(mut self, confidence: f32) -> Self {
151 self.confidence = confidence.clamp(0.0, 1.0);
152 self
153 }
154
155 pub fn bidirectional(mut self) -> Self {
157 self.bidirectional = true;
158 self
159 }
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize)]
164pub struct ExtractionResponse {
165 pub concepts: Vec<Concept>,
167 pub relationships: Vec<Relationship>,
169 pub raw_response: Option<String>,
171 pub tokens_used: Option<u32>,
173}
174
175impl ExtractionResponse {
176 pub fn empty() -> Self {
178 Self {
179 concepts: Vec::new(),
180 relationships: Vec::new(),
181 raw_response: None,
182 tokens_used: None,
183 }
184 }
185
186 pub fn from_concepts(concepts: Vec<Concept>) -> Self {
188 Self {
189 concepts,
190 relationships: Vec::new(),
191 raw_response: None,
192 tokens_used: None,
193 }
194 }
195}
196
197#[cfg(test)]
198mod tests {
199 use super::*;
200
201 #[test]
202 fn test_concept_builder() {
203 let concept = Concept::new("mitochondria")
204 .with_type(ConceptType::Concept)
205 .with_confidence(0.95)
206 .with_description("Powerhouse of the cell")
207 .with_related(vec!["ATP".into(), "cell".into()]);
208
209 assert_eq!(concept.label, "mitochondria");
210 assert_eq!(concept.concept_type, ConceptType::Concept);
211 assert!((concept.confidence - 0.95).abs() < 0.001);
212 assert_eq!(concept.description, Some("Powerhouse of the cell".into()));
213 assert_eq!(concept.related.len(), 2);
214 }
215
216 #[test]
217 fn test_relationship_builder() {
218 let rel = Relationship::new("mitochondria", "ATP", "produces")
219 .with_type(RelationType::Produces)
220 .with_confidence(0.9);
221
222 assert_eq!(rel.source, "mitochondria");
223 assert_eq!(rel.target, "ATP");
224 assert_eq!(rel.relation_type, RelationType::Produces);
225 }
226}