Skip to main content

graphrag_core/config/
json_parser.rs

1//! Hand-rolled JSON loader/writer for `Config`.
2//!
3//! Extracted from `config/mod.rs` (Phase 4 file split). Provides
4//! `Config::from_file` (read) and `Config::to_file` (write) via the lightweight
5//! `json` crate. Distinct from `config::json5_loader` (serde-based typed JSON5)
6//! and `config::loader` (multi-format dispatcher).
7
8#![allow(clippy::needless_borrow, clippy::manual_clamp)]
9
10use super::*;
11use crate::Result;
12use std::fs;
13
14impl Config {
15    /// Load configuration from a JSON file
16    pub fn from_file(path: &str) -> Result<Self> {
17        let content = fs::read_to_string(path)?;
18        let parsed = json::parse(&content)?;
19
20        let config = Config {
21            output_dir: parsed["output_dir"]
22                .as_str()
23                .unwrap_or("./output")
24                .to_string(),
25            suppress_progress_bars: parsed["suppress_progress_bars"].as_bool().unwrap_or(false),
26            chunk_size: parsed["chunk_size"]
27                .as_usize()
28                .unwrap_or(default_chunk_size()),
29            chunk_overlap: parsed["chunk_overlap"]
30                .as_usize()
31                .unwrap_or(default_chunk_overlap()),
32            max_entities_per_chunk: parsed["max_entities_per_chunk"].as_usize(),
33            top_k_results: parsed["top_k_results"].as_usize(),
34            similarity_threshold: parsed["similarity_threshold"].as_f32(),
35            approach: parsed["approach"]
36                .as_str()
37                .unwrap_or(&default_approach())
38                .to_string(),
39            embeddings: EmbeddingConfig {
40                dimension: parsed["embeddings"]["dimension"]
41                    .as_usize()
42                    .unwrap_or(default_embedding_dim()),
43                backend: parsed["embeddings"]["backend"]
44                    .as_str()
45                    .unwrap_or(&default_embedding_backend())
46                    .to_string(),
47                model: parsed["embeddings"]["model"]
48                    .as_str()
49                    .map(|s| s.to_string()),
50                fallback_to_hash: parsed["embeddings"]["fallback_to_hash"]
51                    .as_bool()
52                    .unwrap_or(true),
53                api_endpoint: parsed["embeddings"]["api_endpoint"]
54                    .as_str()
55                    .map(|s| s.to_string()),
56                api_key: parsed["embeddings"]["api_key"]
57                    .as_str()
58                    .map(|s| s.to_string()),
59                cache_dir: parsed["embeddings"]["cache_dir"]
60                    .as_str()
61                    .map(|s| s.to_string()),
62                batch_size: parsed["embeddings"]["batch_size"]
63                    .as_usize()
64                    .unwrap_or(default_batch_size()),
65            },
66            graph: GraphConfig {
67                max_connections: parsed["graph"]["max_connections"]
68                    .as_usize()
69                    .unwrap_or(default_max_connections()),
70                similarity_threshold: parsed["graph"]["similarity_threshold"]
71                    .as_f32()
72                    .unwrap_or(default_similarity_threshold()),
73                extract_relationships: parsed["graph"]["extract_relationships"]
74                    .as_bool()
75                    .unwrap_or(default_true()),
76                relationship_confidence_threshold: parsed["graph"]
77                    ["relationship_confidence_threshold"]
78                    .as_f32()
79                    .unwrap_or(default_relationship_confidence()),
80                traversal: TraversalConfigParams {
81                    max_depth: parsed["graph"]["traversal"]["max_depth"]
82                        .as_usize()
83                        .unwrap_or(default_max_traversal_depth()),
84                    max_paths: parsed["graph"]["traversal"]["max_paths"]
85                        .as_usize()
86                        .unwrap_or(default_max_paths()),
87                    use_edge_weights: parsed["graph"]["traversal"]["use_edge_weights"]
88                        .as_bool()
89                        .unwrap_or(default_true()),
90                    min_relationship_strength: parsed["graph"]["traversal"]
91                        ["min_relationship_strength"]
92                        .as_f32()
93                        .unwrap_or(default_min_relationship_strength()),
94                },
95            },
96            text: TextConfig {
97                chunk_size: parsed["text"]["chunk_size"]
98                    .as_usize()
99                    .unwrap_or(default_chunk_size()),
100                chunk_overlap: parsed["text"]["chunk_overlap"]
101                    .as_usize()
102                    .unwrap_or(default_chunk_overlap()),
103                languages: if parsed["text"]["languages"].is_array() {
104                    parsed["text"]["languages"]
105                        .members()
106                        .map(|v| v.as_str().unwrap_or("en").to_string())
107                        .collect()
108                } else {
109                    default_languages()
110                },
111            },
112            entities: EntityConfig {
113                min_confidence: parsed["entities"]["min_confidence"]
114                    .as_f32()
115                    .unwrap_or(default_min_confidence()),
116                entity_types: if parsed["entities"]["entity_types"].is_array() {
117                    parsed["entities"]["entity_types"]
118                        .members()
119                        .map(|v| v.as_str().unwrap_or("PERSON").to_string())
120                        .collect()
121                } else {
122                    default_entity_types()
123                },
124                use_gleaning: parsed["entities"]["use_gleaning"]
125                    .as_bool()
126                    .unwrap_or(false),
127                max_gleaning_rounds: parsed["entities"]["max_gleaning_rounds"]
128                    .as_usize()
129                    .unwrap_or(default_max_gleaning_rounds()),
130                enable_triple_reflection: parsed["entities"]["enable_triple_reflection"]
131                    .as_bool()
132                    .unwrap_or(false),
133                validation_min_confidence: parsed["entities"]["validation_min_confidence"]
134                    .as_f32()
135                    .unwrap_or(default_validation_confidence()),
136                use_atomic_facts: parsed["entities"]["use_atomic_facts"]
137                    .as_bool()
138                    .unwrap_or(false),
139                max_fact_tokens: parsed["entities"]["max_fact_tokens"]
140                    .as_usize()
141                    .unwrap_or(default_max_fact_tokens()),
142            },
143            retrieval: RetrievalConfig {
144                top_k: parsed["retrieval"]["top_k"]
145                    .as_usize()
146                    .unwrap_or(default_top_k()),
147                search_algorithm: parsed["retrieval"]["search_algorithm"]
148                    .as_str()
149                    .unwrap_or(&default_search_algorithm())
150                    .to_string(),
151            },
152            parallel: ParallelConfig {
153                num_threads: parsed["parallel"]["num_threads"]
154                    .as_usize()
155                    .unwrap_or(default_num_threads()),
156                enabled: parsed["parallel"]["enabled"].as_bool().unwrap_or(true),
157                min_batch_size: parsed["parallel"]["min_batch_size"]
158                    .as_usize()
159                    .unwrap_or(default_min_batch_size()),
160                chunk_batch_size: parsed["parallel"]["chunk_batch_size"]
161                    .as_usize()
162                    .unwrap_or(default_chunk_batch_size()),
163                parallel_embeddings: parsed["parallel"]["parallel_embeddings"]
164                    .as_bool()
165                    .unwrap_or(true),
166                parallel_graph_ops: parsed["parallel"]["parallel_graph_ops"]
167                    .as_bool()
168                    .unwrap_or(true),
169                parallel_vector_ops: parsed["parallel"]["parallel_vector_ops"]
170                    .as_bool()
171                    .unwrap_or(true),
172            },
173            ollama: crate::ollama::OllamaConfig {
174                enabled: parsed["ollama"]["enabled"].as_bool().unwrap_or(false),
175                host: parsed["ollama"]["host"]
176                    .as_str()
177                    .unwrap_or("http://localhost")
178                    .to_string(),
179                port: parsed["ollama"]["port"].as_u16().unwrap_or(11434),
180                embedding_model: parsed["ollama"]["embedding_model"]
181                    .as_str()
182                    .unwrap_or("nomic-embed-text")
183                    .to_string(),
184                chat_model: parsed["ollama"]["chat_model"]
185                    .as_str()
186                    .unwrap_or("llama3.2:3b")
187                    .to_string(),
188                timeout_seconds: parsed["ollama"]["timeout_seconds"].as_u64().unwrap_or(30),
189                max_retries: parsed["ollama"]["max_retries"].as_u32().unwrap_or(3),
190                fallback_to_hash: parsed["ollama"]["fallback_to_hash"]
191                    .as_bool()
192                    .unwrap_or(true),
193                max_tokens: parsed["ollama"]["max_tokens"].as_u32(),
194                temperature: parsed["ollama"]["temperature"].as_f32(),
195                enable_caching: parsed["ollama"]["enable_caching"].as_bool().unwrap_or(true),
196                keep_alive: parsed["ollama"]["keep_alive"]
197                    .as_str()
198                    .map(|s| s.to_string()),
199                num_ctx: parsed["ollama"]["num_ctx"].as_u32(),
200            },
201            gliner: GlinerConfig {
202                enabled: parsed["gliner"]["enabled"].as_bool().unwrap_or(false),
203                model_path: parsed["gliner"]["model_path"]
204                    .as_str()
205                    .unwrap_or("")
206                    .to_string(),
207                tokenizer_path: parsed["gliner"]["tokenizer_path"]
208                    .as_str()
209                    .unwrap_or("")
210                    .to_string(),
211                mode: parsed["gliner"]["mode"]
212                    .as_str()
213                    .unwrap_or("span")
214                    .to_string(),
215                entity_labels: if parsed["gliner"]["entity_labels"].is_array() {
216                    parsed["gliner"]["entity_labels"]
217                        .members()
218                        .filter_map(|v| v.as_str().map(|s| s.to_string()))
219                        .collect()
220                } else {
221                    vec!["person".into(), "organization".into(), "location".into()]
222                },
223                relation_labels: if parsed["gliner"]["relation_labels"].is_array() {
224                    parsed["gliner"]["relation_labels"]
225                        .members()
226                        .filter_map(|v| v.as_str().map(|s| s.to_string()))
227                        .collect()
228                } else {
229                    vec!["related to".into(), "part of".into()]
230                },
231                entity_threshold: parsed["gliner"]["entity_threshold"].as_f32().unwrap_or(0.4),
232                relation_threshold: parsed["gliner"]["relation_threshold"]
233                    .as_f32()
234                    .unwrap_or(0.5),
235                use_gpu: parsed["gliner"]["use_gpu"].as_bool().unwrap_or(false),
236                max_concurrent_chunks: parsed["gliner"]["max_concurrent_chunks"].as_usize(),
237            },
238            enhancements: enhancements::EnhancementsConfig {
239                enabled: parsed["enhancements"]["enabled"].as_bool().unwrap_or(true),
240                query_analysis: enhancements::QueryAnalysisConfig {
241                    enabled: parsed["enhancements"]["query_analysis"]["enabled"]
242                        .as_bool()
243                        .unwrap_or(true),
244                    min_confidence: parsed["enhancements"]["query_analysis"]["min_confidence"]
245                        .as_f32()
246                        .unwrap_or(0.6),
247                    enable_strategy_suggestion: parsed["enhancements"]["query_analysis"]
248                        ["enable_strategy_suggestion"]
249                        .as_bool()
250                        .unwrap_or(true),
251                    enable_keyword_analysis: parsed["enhancements"]["query_analysis"]
252                        ["enable_keyword_analysis"]
253                        .as_bool()
254                        .unwrap_or(true),
255                    enable_complexity_scoring: parsed["enhancements"]["query_analysis"]
256                        ["enable_complexity_scoring"]
257                        .as_bool()
258                        .unwrap_or(true),
259                },
260                adaptive_retrieval: enhancements::AdaptiveRetrievalConfig {
261                    enabled: parsed["enhancements"]["adaptive_retrieval"]["enabled"]
262                        .as_bool()
263                        .unwrap_or(true),
264                    use_query_analysis: parsed["enhancements"]["adaptive_retrieval"]
265                        ["use_query_analysis"]
266                        .as_bool()
267                        .unwrap_or(true),
268                    enable_cross_strategy_fusion: parsed["enhancements"]["adaptive_retrieval"]
269                        ["enable_cross_strategy_fusion"]
270                        .as_bool()
271                        .unwrap_or(true),
272                    diversity_threshold: parsed["enhancements"]["adaptive_retrieval"]
273                        ["diversity_threshold"]
274                        .as_f32()
275                        .unwrap_or(0.8),
276                    enable_diversity_selection: parsed["enhancements"]["adaptive_retrieval"]
277                        ["enable_diversity_selection"]
278                        .as_bool()
279                        .unwrap_or(true),
280                    enable_confidence_weighting: parsed["enhancements"]["adaptive_retrieval"]
281                        ["enable_confidence_weighting"]
282                        .as_bool()
283                        .unwrap_or(true),
284                },
285                performance_benchmarking: enhancements::BenchmarkingConfig {
286                    enabled: parsed["enhancements"]["performance_benchmarking"]["enabled"]
287                        .as_bool()
288                        .unwrap_or(false),
289                    auto_recommendations: parsed["enhancements"]["performance_benchmarking"]
290                        ["auto_recommendations"]
291                        .as_bool()
292                        .unwrap_or(true),
293                    comprehensive_testing: parsed["enhancements"]["performance_benchmarking"]
294                        ["comprehensive_testing"]
295                        .as_bool()
296                        .unwrap_or(false),
297                    iterations: parsed["enhancements"]["performance_benchmarking"]["iterations"]
298                        .as_usize()
299                        .unwrap_or(3),
300                    include_parallel: parsed["enhancements"]["performance_benchmarking"]
301                        ["include_parallel"]
302                        .as_bool()
303                        .unwrap_or(true),
304                    enable_memory_profiling: parsed["enhancements"]["performance_benchmarking"]
305                        ["enable_memory_profiling"]
306                        .as_bool()
307                        .unwrap_or(false),
308                },
309                enhanced_function_registry: enhancements::FunctionRegistryConfig {
310                    enabled: parsed["enhancements"]["enhanced_function_registry"]["enabled"]
311                        .as_bool()
312                        .unwrap_or(true),
313                    categorization: parsed["enhancements"]["enhanced_function_registry"]
314                        ["categorization"]
315                        .as_bool()
316                        .unwrap_or(true),
317                    usage_statistics: parsed["enhancements"]["enhanced_function_registry"]
318                        ["usage_statistics"]
319                        .as_bool()
320                        .unwrap_or(true),
321                    dynamic_registration: parsed["enhancements"]["enhanced_function_registry"]
322                        ["dynamic_registration"]
323                        .as_bool()
324                        .unwrap_or(true),
325                    performance_monitoring: parsed["enhancements"]["enhanced_function_registry"]
326                        ["performance_monitoring"]
327                        .as_bool()
328                        .unwrap_or(false),
329                    recommendation_system: parsed["enhancements"]["enhanced_function_registry"]
330                        ["recommendation_system"]
331                        .as_bool()
332                        .unwrap_or(true),
333                },
334                #[cfg(feature = "lightrag")]
335                lightrag: enhancements::LightRAGConfig {
336                    enabled: parsed["enhancements"]["lightrag"]["enabled"]
337                        .as_bool()
338                        .unwrap_or(true),
339                    max_keywords: parsed["enhancements"]["lightrag"]["max_keywords"]
340                        .as_usize()
341                        .unwrap_or(20),
342                    high_level_weight: parsed["enhancements"]["lightrag"]["high_level_weight"]
343                        .as_f32()
344                        .unwrap_or(0.6),
345                    low_level_weight: parsed["enhancements"]["lightrag"]["low_level_weight"]
346                        .as_f32()
347                        .unwrap_or(0.4),
348                    merge_strategy: parsed["enhancements"]["lightrag"]["merge_strategy"]
349                        .as_str()
350                        .unwrap_or("weighted")
351                        .to_string(),
352                    language: parsed["enhancements"]["lightrag"]["language"]
353                        .as_str()
354                        .unwrap_or("English")
355                        .to_string(),
356                    enable_cache: parsed["enhancements"]["lightrag"]["enable_cache"]
357                        .as_bool()
358                        .unwrap_or(true),
359                },
360                #[cfg(feature = "leiden")]
361                leiden: enhancements::LeidenCommunitiesConfig {
362                    enabled: parsed["enhancements"]["leiden"]["enabled"]
363                        .as_bool()
364                        .unwrap_or(true),
365                    max_cluster_size: parsed["enhancements"]["leiden"]["max_cluster_size"]
366                        .as_usize()
367                        .unwrap_or(10),
368                    use_lcc: parsed["enhancements"]["leiden"]["use_lcc"]
369                        .as_bool()
370                        .unwrap_or(true),
371                    seed: parsed["enhancements"]["leiden"]["seed"].as_u64(),
372                    resolution: parsed["enhancements"]["leiden"]["resolution"]
373                        .as_f32()
374                        .unwrap_or(1.0),
375                    max_levels: parsed["enhancements"]["leiden"]["max_levels"]
376                        .as_usize()
377                        .unwrap_or(5),
378                    min_improvement: parsed["enhancements"]["leiden"]["min_improvement"]
379                        .as_f32()
380                        .unwrap_or(0.001),
381                    enable_hierarchical: parsed["enhancements"]["leiden"]["enable_hierarchical"]
382                        .as_bool()
383                        .unwrap_or(true),
384                    generate_summaries: parsed["enhancements"]["leiden"]["generate_summaries"]
385                        .as_bool()
386                        .unwrap_or(true),
387                    max_summary_length: parsed["enhancements"]["leiden"]["max_summary_length"]
388                        .as_usize()
389                        .unwrap_or(5),
390                    use_extractive_summary: parsed["enhancements"]["leiden"]
391                        ["use_extractive_summary"]
392                        .as_bool()
393                        .unwrap_or(true),
394                    adaptive_routing: enhancements::AdaptiveRoutingConfig {
395                        enabled: parsed["enhancements"]["leiden"]["adaptive_routing"]["enabled"]
396                            .as_bool()
397                            .unwrap_or(true),
398                        default_level: parsed["enhancements"]["leiden"]["adaptive_routing"]
399                            ["default_level"]
400                            .as_usize()
401                            .unwrap_or(1),
402                        keyword_weight: parsed["enhancements"]["leiden"]["adaptive_routing"]
403                            ["keyword_weight"]
404                            .as_f32()
405                            .unwrap_or(0.5),
406                        length_weight: parsed["enhancements"]["leiden"]["adaptive_routing"]
407                            ["length_weight"]
408                            .as_f32()
409                            .unwrap_or(0.3),
410                        entity_weight: parsed["enhancements"]["leiden"]["adaptive_routing"]
411                            ["entity_weight"]
412                            .as_f32()
413                            .unwrap_or(0.2),
414                    },
415                },
416                #[cfg(feature = "cross-encoder")]
417                cross_encoder: enhancements::CrossEncoderConfig {
418                    enabled: parsed["enhancements"]["cross_encoder"]["enabled"]
419                        .as_bool()
420                        .unwrap_or(true),
421                    model_name: parsed["enhancements"]["cross_encoder"]["model_name"]
422                        .as_str()
423                        .unwrap_or("cross-encoder/ms-marco-MiniLM-L-6-v2")
424                        .to_string(),
425                    max_length: parsed["enhancements"]["cross_encoder"]["max_length"]
426                        .as_usize()
427                        .unwrap_or(512),
428                    batch_size: parsed["enhancements"]["cross_encoder"]["batch_size"]
429                        .as_usize()
430                        .unwrap_or(32),
431                    top_k: parsed["enhancements"]["cross_encoder"]["top_k"]
432                        .as_usize()
433                        .unwrap_or(10),
434                    min_confidence: parsed["enhancements"]["cross_encoder"]["min_confidence"]
435                        .as_f32()
436                        .unwrap_or(0.0),
437                    normalize_scores: parsed["enhancements"]["cross_encoder"]["normalize_scores"]
438                        .as_bool()
439                        .unwrap_or(true),
440                },
441                #[cfg(feature = "lazygraphrag")]
442                concept_selection: enhancements::ConceptSelectionConfig {
443                    enabled: parsed["enhancements"]["concept_selection"]["enabled"]
444                        .as_bool()
445                        .unwrap_or(true),
446                    top_k: parsed["enhancements"]["concept_selection"]["top_k"]
447                        .as_usize()
448                        .unwrap_or(20),
449                    min_score: parsed["enhancements"]["concept_selection"]["min_score"]
450                        .as_f32()
451                        .unwrap_or(0.1),
452                    degree_weight: parsed["enhancements"]["concept_selection"]["degree_weight"]
453                        .as_f32()
454                        .unwrap_or(0.4),
455                    pagerank_weight: parsed["enhancements"]["concept_selection"]["pagerank_weight"]
456                        .as_f32()
457                        .unwrap_or(0.4),
458                    idf_weight: parsed["enhancements"]["concept_selection"]["idf_weight"]
459                        .as_f32()
460                        .unwrap_or(0.2),
461                    use_semantic_matching: parsed["enhancements"]["concept_selection"]
462                        ["use_semantic_matching"]
463                        .as_bool()
464                        .unwrap_or(true),
465                    max_query_concepts: parsed["enhancements"]["concept_selection"]
466                        ["max_query_concepts"]
467                        .as_usize()
468                        .unwrap_or(10),
469                },
470            },
471            auto_save: AutoSaveConfig {
472                enabled: parsed["auto_save"]["enabled"].as_bool().unwrap_or(false),
473                base_dir: parsed["auto_save"]["base_dir"]
474                    .as_str()
475                    .map(|s| s.to_string()),
476                interval_seconds: parsed["auto_save"]["interval_seconds"]
477                    .as_u64()
478                    .unwrap_or(default_auto_save_interval()),
479                workspace_name: parsed["auto_save"]["workspace_name"]
480                    .as_str()
481                    .map(|s| s.to_string()),
482                max_versions: parsed["auto_save"]["max_versions"]
483                    .as_usize()
484                    .unwrap_or(default_max_versions()),
485            },
486            summarization: if parsed["summarization"].is_object() {
487                crate::summarization::HierarchicalConfig {
488                    merge_size: parsed["summarization"]["merge_size"]
489                        .as_usize()
490                        .unwrap_or(3),
491                    max_summary_length: parsed["summarization"]["max_summary_length"]
492                        .as_usize()
493                        .unwrap_or(250),
494                    min_node_size: parsed["summarization"]["min_node_size"]
495                        .as_usize()
496                        .unwrap_or(50),
497                    overlap_sentences: parsed["summarization"]["overlap_sentences"]
498                        .as_usize()
499                        .unwrap_or(2),
500                    llm_config: if parsed["summarization"]["llm_config"].is_object() {
501                        crate::summarization::LLMConfig {
502                            enabled: parsed["summarization"]["llm_config"]["enabled"]
503                                .as_bool()
504                                .unwrap_or(false),
505                            model_name: parsed["summarization"]["llm_config"]["model_name"]
506                                .as_str()
507                                .unwrap_or("llama3.1:8b")
508                                .to_string(),
509                            temperature: parsed["summarization"]["llm_config"]["temperature"]
510                                .as_f32()
511                                .unwrap_or(0.3),
512                            max_tokens: parsed["summarization"]["llm_config"]["max_tokens"]
513                                .as_usize()
514                                .unwrap_or(180),
515                            strategy: match parsed["summarization"]["llm_config"]["strategy"]
516                                .as_str()
517                                .unwrap_or("progressive")
518                            {
519                                "uniform" => crate::summarization::LLMStrategy::Uniform,
520                                "adaptive" => crate::summarization::LLMStrategy::Adaptive,
521                                "progressive" => crate::summarization::LLMStrategy::Progressive,
522                                _ => crate::summarization::LLMStrategy::Progressive,
523                            },
524                            level_configs: std::collections::HashMap::new(), // Would need more complex parsing
525                        }
526                    } else {
527                        crate::summarization::LLMConfig::default()
528                    },
529                }
530            } else {
531                crate::summarization::HierarchicalConfig::default()
532            },
533            zero_cost_approach: if parsed["zero_cost_approach"].is_object() {
534                ZeroCostApproachConfig {
535                    approach: parsed["zero_cost_approach"]["approach"]
536                        .as_str()
537                        .unwrap_or("pure_algorithmic")
538                        .to_string(),
539                    lazy_graphrag: if parsed["zero_cost_approach"]["lazy_graphrag"].is_object() {
540                        LazyGraphRAGConfig {
541                            enabled: parsed["zero_cost_approach"]["lazy_graphrag"]["enabled"]
542                                .as_bool()
543                                .unwrap_or(false),
544                            concept_extraction: ConceptExtractionConfig::default(),
545                            co_occurrence: CoOccurrenceConfig::default(),
546                            indexing: LazyIndexingConfig::default(),
547                            query_expansion: LazyQueryExpansionConfig::default(),
548                            relevance_scoring: LazyRelevanceScoringConfig::default(),
549                        }
550                    } else {
551                        LazyGraphRAGConfig::default()
552                    },
553                    e2_graphrag: E2GraphRAGConfig::default(),
554                    pure_algorithmic: PureAlgorithmicConfig::default(),
555                    hybrid_strategy: HybridStrategyConfig::default(),
556                }
557            } else {
558                ZeroCostApproachConfig::default()
559            },
560            advanced_features: AdvancedFeaturesConfig::default(),
561        };
562
563        Ok(config)
564    }
565
566    /// Save configuration to a JSON file
567    pub fn to_file(&self, path: &str) -> Result<()> {
568        let mut config_json = json::JsonValue::new_object();
569
570        // Embeddings
571        let mut embeddings = json::JsonValue::new_object();
572        embeddings["dimension"] = json::JsonValue::from(self.embeddings.dimension);
573        if let Some(endpoint) = &self.embeddings.api_endpoint {
574            embeddings["api_endpoint"] = json::JsonValue::from(endpoint.as_str());
575        }
576        if let Some(key) = &self.embeddings.api_key {
577            embeddings["api_key"] = json::JsonValue::from(key.as_str());
578        }
579        config_json["embeddings"] = embeddings;
580
581        // Graph
582        let mut graph = json::JsonValue::new_object();
583        graph["max_connections"] = json::JsonValue::from(self.graph.max_connections);
584        graph["similarity_threshold"] = json::JsonValue::from(self.graph.similarity_threshold);
585        graph["extract_relationships"] = json::JsonValue::from(self.graph.extract_relationships);
586        graph["relationship_confidence_threshold"] =
587            json::JsonValue::from(self.graph.relationship_confidence_threshold);
588
589        let mut traversal = json::JsonValue::new_object();
590        traversal["max_depth"] = json::JsonValue::from(self.graph.traversal.max_depth);
591        traversal["max_paths"] = json::JsonValue::from(self.graph.traversal.max_paths);
592        traversal["use_edge_weights"] =
593            json::JsonValue::from(self.graph.traversal.use_edge_weights);
594        traversal["min_relationship_strength"] =
595            json::JsonValue::from(self.graph.traversal.min_relationship_strength);
596        graph["traversal"] = traversal;
597
598        config_json["graph"] = graph;
599
600        // Text
601        let mut text = json::JsonValue::new_object();
602        text["chunk_size"] = json::JsonValue::from(self.text.chunk_size);
603        text["chunk_overlap"] = json::JsonValue::from(self.text.chunk_overlap);
604        let languages_array: Vec<json::JsonValue> = self
605            .text
606            .languages
607            .iter()
608            .map(|s| json::JsonValue::from(s.as_str()))
609            .collect();
610        text["languages"] = json::JsonValue::from(languages_array);
611        config_json["text"] = text;
612
613        // Entities
614        let mut entities = json::JsonValue::new_object();
615        entities["min_confidence"] = json::JsonValue::from(self.entities.min_confidence);
616        let entity_types_array: Vec<json::JsonValue> = self
617            .entities
618            .entity_types
619            .iter()
620            .map(|s| json::JsonValue::from(s.as_str()))
621            .collect();
622        entities["entity_types"] = json::JsonValue::from(entity_types_array);
623        entities["use_gleaning"] = json::JsonValue::from(self.entities.use_gleaning);
624        entities["max_gleaning_rounds"] = json::JsonValue::from(self.entities.max_gleaning_rounds);
625        config_json["entities"] = entities;
626
627        // Retrieval
628        let mut retrieval = json::JsonValue::new_object();
629        retrieval["top_k"] = json::JsonValue::from(self.retrieval.top_k);
630        retrieval["search_algorithm"] =
631            json::JsonValue::from(self.retrieval.search_algorithm.as_str());
632        config_json["retrieval"] = retrieval;
633
634        // Parallel
635        let mut parallel = json::JsonValue::new_object();
636        parallel["num_threads"] = json::JsonValue::from(self.parallel.num_threads);
637        parallel["enabled"] = json::JsonValue::from(self.parallel.enabled);
638        parallel["min_batch_size"] = json::JsonValue::from(self.parallel.min_batch_size);
639        parallel["chunk_batch_size"] = json::JsonValue::from(self.parallel.chunk_batch_size);
640        parallel["parallel_embeddings"] = json::JsonValue::from(self.parallel.parallel_embeddings);
641        parallel["parallel_graph_ops"] = json::JsonValue::from(self.parallel.parallel_graph_ops);
642        parallel["parallel_vector_ops"] = json::JsonValue::from(self.parallel.parallel_vector_ops);
643        config_json["parallel"] = parallel;
644
645        // Enhancements
646        let mut enhancements = json::JsonValue::new_object();
647        enhancements["enabled"] = json::JsonValue::from(self.enhancements.enabled);
648
649        let mut query_analysis = json::JsonValue::new_object();
650        query_analysis["enabled"] = json::JsonValue::from(self.enhancements.query_analysis.enabled);
651        query_analysis["min_confidence"] =
652            json::JsonValue::from(self.enhancements.query_analysis.min_confidence);
653        query_analysis["enable_strategy_suggestion"] =
654            json::JsonValue::from(self.enhancements.query_analysis.enable_strategy_suggestion);
655        query_analysis["enable_keyword_analysis"] =
656            json::JsonValue::from(self.enhancements.query_analysis.enable_keyword_analysis);
657        query_analysis["enable_complexity_scoring"] =
658            json::JsonValue::from(self.enhancements.query_analysis.enable_complexity_scoring);
659        enhancements["query_analysis"] = query_analysis;
660
661        let mut adaptive_retrieval = json::JsonValue::new_object();
662        adaptive_retrieval["enabled"] =
663            json::JsonValue::from(self.enhancements.adaptive_retrieval.enabled);
664        adaptive_retrieval["use_query_analysis"] =
665            json::JsonValue::from(self.enhancements.adaptive_retrieval.use_query_analysis);
666        adaptive_retrieval["enable_cross_strategy_fusion"] = json::JsonValue::from(
667            self.enhancements
668                .adaptive_retrieval
669                .enable_cross_strategy_fusion,
670        );
671        adaptive_retrieval["diversity_threshold"] =
672            json::JsonValue::from(self.enhancements.adaptive_retrieval.diversity_threshold);
673        adaptive_retrieval["enable_diversity_selection"] = json::JsonValue::from(
674            self.enhancements
675                .adaptive_retrieval
676                .enable_diversity_selection,
677        );
678        adaptive_retrieval["enable_confidence_weighting"] = json::JsonValue::from(
679            self.enhancements
680                .adaptive_retrieval
681                .enable_confidence_weighting,
682        );
683        enhancements["adaptive_retrieval"] = adaptive_retrieval;
684
685        let mut performance_benchmarking = json::JsonValue::new_object();
686        performance_benchmarking["enabled"] =
687            json::JsonValue::from(self.enhancements.performance_benchmarking.enabled);
688        performance_benchmarking["auto_recommendations"] = json::JsonValue::from(
689            self.enhancements
690                .performance_benchmarking
691                .auto_recommendations,
692        );
693        performance_benchmarking["comprehensive_testing"] = json::JsonValue::from(
694            self.enhancements
695                .performance_benchmarking
696                .comprehensive_testing,
697        );
698        performance_benchmarking["iterations"] =
699            json::JsonValue::from(self.enhancements.performance_benchmarking.iterations);
700        performance_benchmarking["include_parallel"] =
701            json::JsonValue::from(self.enhancements.performance_benchmarking.include_parallel);
702        performance_benchmarking["enable_memory_profiling"] = json::JsonValue::from(
703            self.enhancements
704                .performance_benchmarking
705                .enable_memory_profiling,
706        );
707        enhancements["performance_benchmarking"] = performance_benchmarking;
708
709        let mut enhanced_function_registry = json::JsonValue::new_object();
710        enhanced_function_registry["enabled"] =
711            json::JsonValue::from(self.enhancements.enhanced_function_registry.enabled);
712        enhanced_function_registry["categorization"] =
713            json::JsonValue::from(self.enhancements.enhanced_function_registry.categorization);
714        enhanced_function_registry["usage_statistics"] = json::JsonValue::from(
715            self.enhancements
716                .enhanced_function_registry
717                .usage_statistics,
718        );
719        enhanced_function_registry["dynamic_registration"] = json::JsonValue::from(
720            self.enhancements
721                .enhanced_function_registry
722                .dynamic_registration,
723        );
724        enhanced_function_registry["performance_monitoring"] = json::JsonValue::from(
725            self.enhancements
726                .enhanced_function_registry
727                .performance_monitoring,
728        );
729        enhanced_function_registry["recommendation_system"] = json::JsonValue::from(
730            self.enhancements
731                .enhanced_function_registry
732                .recommendation_system,
733        );
734        enhancements["enhanced_function_registry"] = enhanced_function_registry;
735
736        config_json["enhancements"] = enhancements;
737
738        // Summarization
739        let mut summarization = json::JsonValue::new_object();
740        summarization["merge_size"] = json::JsonValue::from(self.summarization.merge_size);
741        summarization["max_summary_length"] =
742            json::JsonValue::from(self.summarization.max_summary_length);
743        summarization["min_node_size"] = json::JsonValue::from(self.summarization.min_node_size);
744        summarization["overlap_sentences"] =
745            json::JsonValue::from(self.summarization.overlap_sentences);
746
747        let mut llm_config = json::JsonValue::new_object();
748        llm_config["enabled"] = json::JsonValue::from(self.summarization.llm_config.enabled);
749        llm_config["model_name"] =
750            json::JsonValue::from(self.summarization.llm_config.model_name.as_str());
751        llm_config["temperature"] =
752            json::JsonValue::from(self.summarization.llm_config.temperature);
753        llm_config["max_tokens"] = json::JsonValue::from(self.summarization.llm_config.max_tokens);
754        let strategy_str = match self.summarization.llm_config.strategy {
755            crate::summarization::LLMStrategy::Uniform => "uniform",
756            crate::summarization::LLMStrategy::Adaptive => "adaptive",
757            crate::summarization::LLMStrategy::Progressive => "progressive",
758        };
759        llm_config["strategy"] = json::JsonValue::from(strategy_str);
760
761        summarization["llm_config"] = llm_config;
762        config_json["summarization"] = summarization;
763
764        let content = json::stringify_pretty(config_json, 2);
765        fs::write(path, content)?;
766        Ok(())
767    }
768}