1use crate::cli::VectorCommands;
4use crate::data::vector_db::VectorDatabase;
5use anyhow::Result;
6use colored::*;
7
8pub async fn handle(command: VectorCommands) -> Result<()> {
10 match command {
11 VectorCommands::List => {
12 let databases = VectorDatabase::list_databases()?;
13
14 if databases.is_empty() {
15 println!("No vector databases found.");
16 println!(
17 "Create one by running: {}",
18 "lc embed -d <name> -m <model> \"your text\"".dimmed()
19 );
20 } else {
21 println!("\n{} Vector databases:", "đ".bold().blue());
22
23 for db_name in databases {
24 match VectorDatabase::new(&db_name) {
25 Ok(db) => {
26 let count = db.count().unwrap_or(0);
27 let model_info = db.get_model_info().unwrap_or(None);
28
29 print!(" {} {} ({} vectors)", "âĸ".blue(), db_name.bold(), count);
30
31 if let Some((model, provider)) = model_info {
32 print!(" - {}:{}", provider.dimmed(), model.dimmed());
33 }
34
35 println!();
36 }
37 Err(_) => {
38 println!(" {} {} (error reading)", "âĸ".red(), db_name.bold());
39 }
40 }
41 }
42 }
43 }
44 VectorCommands::Create { name } => {
45 let databases = VectorDatabase::list_databases()?;
47 if databases.contains(&name) {
48 anyhow::bail!("Vector database '{}' already exists", name);
49 }
50
51 let _ = VectorDatabase::new(&name)?;
53 println!(
54 "{} Vector database '{}' created successfully",
55 "â".green(),
56 name
57 );
58 println!(
59 "Use {} to add embeddings",
60 format!("lc embed -d {} <text>", name).dimmed()
61 );
62 }
63 VectorCommands::Delete { name, yes } => {
64 let databases = VectorDatabase::list_databases()?;
66 if !databases.contains(&name) {
67 anyhow::bail!("Vector database '{}' not found", name);
68 }
69
70 if !yes {
72 println!(
73 "{} Are you sure you want to delete database '{}'? This cannot be undone.",
74 "â ī¸".yellow(),
75 name.bold()
76 );
77 print!("Type 'yes' to confirm: ");
78 use std::io::{self, Write};
79 io::stdout().flush()?;
80
81 let mut input = String::new();
82 io::stdin().read_line(&mut input)?;
83
84 if input.trim().to_lowercase() != "yes" {
85 println!("Deletion cancelled.");
86 return Ok(());
87 }
88 }
89
90 VectorDatabase::delete_database(&name)?;
91 println!(
92 "{} Vector database '{}' deleted successfully",
93 "â".green(),
94 name
95 );
96 }
97 VectorCommands::Info { name } => {
98 let databases = VectorDatabase::list_databases()?;
100 if !databases.contains(&name) {
101 anyhow::bail!("Vector database '{}' not found", name);
102 }
103
104 let db = VectorDatabase::new(&name)?;
105 let count = db.count()?;
106 let model_info = db.get_model_info()?;
107
108 println!("\n{} Database: {}", "âšī¸".bold().blue(), name.bold());
109 println!(" Vector count: {}", count);
110
111 if let Some((model, provider)) = model_info {
112 println!(" Model: {}", model);
113 println!(" Provider: {}", provider);
114 } else {
115 println!(" Model: {}", "Not set".dimmed());
116 println!(" Provider: {}", "Not set".dimmed());
117 }
118
119 if count > 0 {
121 println!("\n{} Recent entries:", "đ".bold().blue());
122 let vectors = db.get_all_vectors()?;
123 for (i, entry) in vectors.iter().take(10).enumerate() {
124 let preview = if entry.text.len() > 80 {
125 format!("{}...", &entry.text[..80])
126 } else {
127 entry.text.clone()
128 };
129
130 let source_info = if let Some(ref file_path) = entry.file_path {
131 if let (Some(chunk_idx), Some(total_chunks)) =
132 (entry.chunk_index, entry.total_chunks)
133 {
134 format!(" [{}:{}/{}]", file_path, chunk_idx + 1, total_chunks)
135 } else {
136 format!(" [{}]", file_path)
137 }
138 } else {
139 String::new()
140 };
141
142 println!(
143 " {}. {}{} ({})",
144 i + 1,
145 preview,
146 source_info.dimmed(),
147 entry
148 .created_at
149 .format("%Y-%m-%d %H:%M")
150 .to_string()
151 .dimmed()
152 );
153 }
154
155 if vectors.len() > 10 {
156 println!(" ... and {} more", vectors.len() - 10);
157 }
158 }
159 }
160 VectorCommands::Stats { name } => {
161 let databases = VectorDatabase::list_databases()?;
162 if !databases.contains(&name) {
163 anyhow::bail!("Vector database '{}' not found", name);
164 }
165
166 let db = VectorDatabase::new(&name)?;
167 let count = db.count()?;
168 let model_info = db.get_model_info()?;
169
170 println!("\n{} Vector database: {}", "đ".bold().blue(), name.bold());
171 println!("Vectors: {}", count);
172
173 if let Some((model, provider)) = model_info {
174 println!("Model: {}:{}", provider, model);
175
176 if count > 0 {
178 let vectors = db.get_all_vectors()?;
179 if let Some(first) = vectors.first() {
180 println!("Dimensions: {}", first.vector.len());
181 }
182 }
183 } else {
184 println!("Model: {}", "Not set".dimmed());
185 }
186
187 let embeddings_dir = VectorDatabase::embeddings_dir()?;
189 let db_path = embeddings_dir.join(format!("{}.db", name));
190 if let Ok(metadata) = std::fs::metadata(&db_path) {
191 let size_mb = metadata.len() as f64 / (1024.0 * 1024.0);
192 println!("Size: {:.2} MB", size_mb);
193 }
194
195 if count > 0 {
196 println!("\n{} Recent entries:", "đ".bold().blue());
197 let vectors = db.get_all_vectors()?;
198 for (i, entry) in vectors.iter().take(5).enumerate() {
199 let preview = if entry.text.len() > 60 {
200 format!("{}...", &entry.text[..60])
201 } else {
202 entry.text.clone()
203 };
204
205 let source_info = if let Some(ref file_path) = entry.file_path {
206 if let (Some(chunk_idx), Some(total_chunks)) =
207 (entry.chunk_index, entry.total_chunks)
208 {
209 format!(" [{}:{}/{}]", file_path, chunk_idx + 1, total_chunks)
210 } else {
211 format!(" [{}]", file_path)
212 }
213 } else {
214 String::new()
215 };
216
217 println!(
218 " {}. {}{} ({})",
219 i + 1,
220 preview,
221 source_info.dimmed(),
222 entry
223 .created_at
224 .format("%Y-%m-%d %H:%M")
225 .to_string()
226 .dimmed()
227 );
228 }
229
230 if vectors.len() > 5 {
231 println!(" ... and {} more", vectors.len() - 5);
232 }
233 }
234 }
235 VectorCommands::Clear { name, yes } => {
236 let databases = VectorDatabase::list_databases()?;
238 if !databases.contains(&name) {
239 anyhow::bail!("Vector database '{}' not found", name);
240 }
241
242 let db = VectorDatabase::new(&name)?;
243 let count = db.count()?;
244
245 if count == 0 {
246 println!("Vector database '{}' is already empty.", name);
247 return Ok(());
248 }
249
250 if !yes {
252 println!(
253 "{} Are you sure you want to clear {} vectors from database '{}'? This cannot be undone.",
254 "â ī¸".yellow(),
255 count,
256 name.bold()
257 );
258 print!("Type 'yes' to confirm: ");
259 use std::io::{self, Write};
260 io::stdout().flush()?;
261
262 let mut input = String::new();
263 io::stdin().read_line(&mut input)?;
264
265 if input.trim().to_lowercase() != "yes" {
266 println!("Clear operation cancelled.");
267 return Ok(());
268 }
269 }
270
271 VectorDatabase::delete_database(&name)?;
273 let _ = VectorDatabase::new(&name)?;
274
275 println!(
276 "{} Vector database '{}' cleared successfully ({} vectors removed)",
277 "â".green(),
278 name,
279 count
280 );
281 }
282 }
283
284 Ok(())
285}