decompressed-cli 0.1.0__tar.gz → 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/PKG-INFO +1 -1
- {decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/pyproject.toml +1 -1
- decompressed_cli-0.1.1/src/decompressed_cli/commands/imports_cmd.py +220 -0
- {decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/src/decompressed_cli/main.py +2 -1
- {decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/src/decompressed_cli.egg-info/PKG-INFO +1 -1
- {decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/src/decompressed_cli.egg-info/SOURCES.txt +1 -0
- {decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/README.md +0 -0
- {decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/setup.cfg +0 -0
- {decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/src/decompressed_cli/__init__.py +0 -0
- {decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/src/decompressed_cli/commands/__init__.py +0 -0
- {decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/src/decompressed_cli/commands/config_cmd.py +0 -0
- {decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/src/decompressed_cli/commands/data_cmd.py +0 -0
- {decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/src/decompressed_cli/commands/datasets_cmd.py +0 -0
- {decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/src/decompressed_cli/commands/versions_cmd.py +0 -0
- {decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/src/decompressed_cli/config.py +0 -0
- {decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/src/decompressed_cli.egg-info/dependency_links.txt +0 -0
- {decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/src/decompressed_cli.egg-info/entry_points.txt +0 -0
- {decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/src/decompressed_cli.egg-info/requires.txt +0 -0
- {decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/src/decompressed_cli.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"""Import commands for pulling vectors from external databases."""
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
import typer
|
|
5
|
+
from rich.console import Console
|
|
6
|
+
from rich.table import Table
|
|
7
|
+
from rich.panel import Panel
|
|
8
|
+
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn
|
|
9
|
+
|
|
10
|
+
from ..config import get_client
|
|
11
|
+
|
|
12
|
+
app = typer.Typer(no_args_is_help=True)
|
|
13
|
+
console = Console()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@app.command("pull")
|
|
17
|
+
def pull(
|
|
18
|
+
connector: str = typer.Argument(..., help="Connector name or ID to import from"),
|
|
19
|
+
dataset_name: str = typer.Argument(..., help="Name for the new dataset"),
|
|
20
|
+
project: str = typer.Option(None, "--project", "-p", help="Project name or ID"),
|
|
21
|
+
no_metadata: bool = typer.Option(False, "--no-metadata", help="Skip importing metadata"),
|
|
22
|
+
batch_size: int = typer.Option(100, "--batch-size", "-b", help="Vectors per batch"),
|
|
23
|
+
no_wait: bool = typer.Option(False, "--no-wait", help="Don't wait for completion"),
|
|
24
|
+
):
|
|
25
|
+
"""
|
|
26
|
+
Pull vectors from an external database into a new dataset.
|
|
27
|
+
|
|
28
|
+
Example:
|
|
29
|
+
dcp imports pull pinecone-prod my-backup
|
|
30
|
+
dcp imports pull qdrant-index imported-vectors --project ml-team
|
|
31
|
+
"""
|
|
32
|
+
try:
|
|
33
|
+
client = get_client()
|
|
34
|
+
|
|
35
|
+
console.print(f"[cyan]Connecting to connector:[/cyan] {connector}")
|
|
36
|
+
|
|
37
|
+
# Initialize import
|
|
38
|
+
session = client.imports.init(
|
|
39
|
+
connector_id=connector,
|
|
40
|
+
dataset_name=dataset_name,
|
|
41
|
+
project=project,
|
|
42
|
+
include_metadata=not no_metadata,
|
|
43
|
+
batch_size=batch_size,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
console.print(Panel(
|
|
47
|
+
f"[green]✓[/green] Connected to [cyan]{session.connector_type}[/cyan]\n"
|
|
48
|
+
f"[dim]Estimated vectors:[/dim] {session.estimated_vectors:,}\n"
|
|
49
|
+
f"[dim]Dimension:[/dim] {session.dimension}\n"
|
|
50
|
+
f"[dim]Dataset ID:[/dim] {session.dataset_id}",
|
|
51
|
+
title="Import Initialized",
|
|
52
|
+
border_style="green"
|
|
53
|
+
))
|
|
54
|
+
|
|
55
|
+
# Start the import
|
|
56
|
+
result = client.imports.start(session.import_session_id)
|
|
57
|
+
console.print(f"[cyan]Import job started:[/cyan] {result.job_id[:8]}...")
|
|
58
|
+
|
|
59
|
+
if no_wait:
|
|
60
|
+
console.print(f"\n[yellow]Import running in background.[/yellow]")
|
|
61
|
+
console.print(f"Check status: [cyan]dcp imports status {session.import_session_id}[/cyan]")
|
|
62
|
+
return
|
|
63
|
+
|
|
64
|
+
# Wait with progress
|
|
65
|
+
with Progress(
|
|
66
|
+
SpinnerColumn(),
|
|
67
|
+
TextColumn("[progress.description]{task.description}"),
|
|
68
|
+
BarColumn(),
|
|
69
|
+
TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
|
|
70
|
+
console=console,
|
|
71
|
+
) as progress:
|
|
72
|
+
task = progress.add_task("Importing vectors...", total=100)
|
|
73
|
+
|
|
74
|
+
while True:
|
|
75
|
+
job = client.imports.status(session.import_session_id)
|
|
76
|
+
|
|
77
|
+
if job.progress:
|
|
78
|
+
progress.update(task, completed=job.progress)
|
|
79
|
+
|
|
80
|
+
if job.status == "completed":
|
|
81
|
+
progress.update(task, completed=100)
|
|
82
|
+
break
|
|
83
|
+
elif job.status == "failed":
|
|
84
|
+
console.print(f"\n[red]✗ Import failed:[/red] {job.error_message}")
|
|
85
|
+
raise typer.Exit(1)
|
|
86
|
+
|
|
87
|
+
time.sleep(2)
|
|
88
|
+
|
|
89
|
+
console.print(Panel(
|
|
90
|
+
f"[green]✓[/green] Import complete!\n"
|
|
91
|
+
f"[dim]Dataset:[/dim] {dataset_name}\n"
|
|
92
|
+
f"[dim]Dataset ID:[/dim] {session.dataset_id}",
|
|
93
|
+
title="Success",
|
|
94
|
+
border_style="green"
|
|
95
|
+
))
|
|
96
|
+
|
|
97
|
+
except ValueError as e:
|
|
98
|
+
console.print(f"[red]Error:[/red] {e}")
|
|
99
|
+
raise typer.Exit(1)
|
|
100
|
+
except Exception as e:
|
|
101
|
+
console.print(f"[red]Error:[/red] {e}")
|
|
102
|
+
raise typer.Exit(1)
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
@app.command("append")
|
|
106
|
+
def append(
|
|
107
|
+
connector: str = typer.Argument(..., help="Connector name or ID to import from"),
|
|
108
|
+
dataset: str = typer.Argument(..., help="Existing dataset name or ID to append to"),
|
|
109
|
+
no_metadata: bool = typer.Option(False, "--no-metadata", help="Skip importing metadata"),
|
|
110
|
+
batch_size: int = typer.Option(100, "--batch-size", "-b", help="Vectors per batch"),
|
|
111
|
+
no_wait: bool = typer.Option(False, "--no-wait", help="Don't wait for completion"),
|
|
112
|
+
):
|
|
113
|
+
"""
|
|
114
|
+
Append vectors from an external database to an existing dataset.
|
|
115
|
+
|
|
116
|
+
Example:
|
|
117
|
+
dcp imports append pinecone-prod my-dataset
|
|
118
|
+
"""
|
|
119
|
+
try:
|
|
120
|
+
client = get_client()
|
|
121
|
+
|
|
122
|
+
# Resolve dataset ID
|
|
123
|
+
ds = client.datasets.get(dataset)
|
|
124
|
+
|
|
125
|
+
console.print(f"[cyan]Connecting to connector:[/cyan] {connector}")
|
|
126
|
+
console.print(f"[cyan]Appending to dataset:[/cyan] {ds.name} (v{ds.current_version})")
|
|
127
|
+
|
|
128
|
+
# Initialize append import
|
|
129
|
+
session = client.imports.init_append(
|
|
130
|
+
connector_id=connector,
|
|
131
|
+
dataset_id=ds.id,
|
|
132
|
+
include_metadata=not no_metadata,
|
|
133
|
+
batch_size=batch_size,
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
console.print(Panel(
|
|
137
|
+
f"[green]✓[/green] Connected to [cyan]{session.connector_type}[/cyan]\n"
|
|
138
|
+
f"[dim]Estimated vectors:[/dim] {session.estimated_vectors:,}\n"
|
|
139
|
+
f"[dim]Dimension:[/dim] {session.dimension}",
|
|
140
|
+
title="Append Import Initialized",
|
|
141
|
+
border_style="green"
|
|
142
|
+
))
|
|
143
|
+
|
|
144
|
+
# Start the import
|
|
145
|
+
result = client.imports.start(session.import_session_id)
|
|
146
|
+
console.print(f"[cyan]Import job started:[/cyan] {result.job_id[:8]}...")
|
|
147
|
+
|
|
148
|
+
if no_wait:
|
|
149
|
+
console.print(f"\n[yellow]Import running in background.[/yellow]")
|
|
150
|
+
console.print(f"Check status: [cyan]dcp imports status {session.import_session_id}[/cyan]")
|
|
151
|
+
return
|
|
152
|
+
|
|
153
|
+
# Wait with progress
|
|
154
|
+
with Progress(
|
|
155
|
+
SpinnerColumn(),
|
|
156
|
+
TextColumn("[progress.description]{task.description}"),
|
|
157
|
+
BarColumn(),
|
|
158
|
+
TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
|
|
159
|
+
console=console,
|
|
160
|
+
) as progress:
|
|
161
|
+
task = progress.add_task("Importing vectors...", total=100)
|
|
162
|
+
|
|
163
|
+
while True:
|
|
164
|
+
job = client.imports.status(session.import_session_id)
|
|
165
|
+
|
|
166
|
+
if job.progress:
|
|
167
|
+
progress.update(task, completed=job.progress)
|
|
168
|
+
|
|
169
|
+
if job.status == "completed":
|
|
170
|
+
progress.update(task, completed=100)
|
|
171
|
+
break
|
|
172
|
+
elif job.status == "failed":
|
|
173
|
+
console.print(f"\n[red]✗ Import failed:[/red] {job.error_message}")
|
|
174
|
+
raise typer.Exit(1)
|
|
175
|
+
|
|
176
|
+
time.sleep(2)
|
|
177
|
+
|
|
178
|
+
console.print(f"[green]✓[/green] Appended vectors to [cyan]{ds.name}[/cyan]")
|
|
179
|
+
|
|
180
|
+
except ValueError as e:
|
|
181
|
+
console.print(f"[red]Error:[/red] {e}")
|
|
182
|
+
raise typer.Exit(1)
|
|
183
|
+
except Exception as e:
|
|
184
|
+
console.print(f"[red]Error:[/red] {e}")
|
|
185
|
+
raise typer.Exit(1)
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
@app.command("status")
|
|
189
|
+
def status(
|
|
190
|
+
session_id: str = typer.Argument(..., help="Import session ID"),
|
|
191
|
+
):
|
|
192
|
+
"""Check status of an import job."""
|
|
193
|
+
try:
|
|
194
|
+
client = get_client()
|
|
195
|
+
job = client.imports.status(session_id)
|
|
196
|
+
|
|
197
|
+
status_color = {
|
|
198
|
+
"initialized": "yellow",
|
|
199
|
+
"in_progress": "cyan",
|
|
200
|
+
"completed": "green",
|
|
201
|
+
"failed": "red",
|
|
202
|
+
}.get(job.status, "white")
|
|
203
|
+
|
|
204
|
+
panel_content = f"""[cyan]Session ID:[/cyan] {job.import_session_id}
|
|
205
|
+
[cyan]Dataset ID:[/cyan] {job.dataset_id or 'N/A'}
|
|
206
|
+
[cyan]Status:[/cyan] [{status_color}]{job.status}[/{status_color}]
|
|
207
|
+
[cyan]Progress:[/cyan] {job.progress or 0}%
|
|
208
|
+
[cyan]Job ID:[/cyan] {job.job_id or 'N/A'}"""
|
|
209
|
+
|
|
210
|
+
if job.error_message:
|
|
211
|
+
panel_content += f"\n[red]Error:[/red] {job.error_message}"
|
|
212
|
+
|
|
213
|
+
console.print(Panel(panel_content, title="Import Status", border_style=status_color))
|
|
214
|
+
|
|
215
|
+
except ValueError as e:
|
|
216
|
+
console.print(f"[red]Error:[/red] {e}")
|
|
217
|
+
raise typer.Exit(1)
|
|
218
|
+
except Exception as e:
|
|
219
|
+
console.print(f"[red]Error:[/red] {e}")
|
|
220
|
+
raise typer.Exit(1)
|
|
@@ -4,7 +4,7 @@ import typer
|
|
|
4
4
|
from rich.console import Console
|
|
5
5
|
|
|
6
6
|
from . import __version__
|
|
7
|
-
from .commands import config_cmd, datasets_cmd, versions_cmd, data_cmd
|
|
7
|
+
from .commands import config_cmd, datasets_cmd, versions_cmd, data_cmd, imports_cmd
|
|
8
8
|
|
|
9
9
|
app = typer.Typer(
|
|
10
10
|
name="dcp",
|
|
@@ -17,6 +17,7 @@ console = Console()
|
|
|
17
17
|
app.add_typer(config_cmd.app, name="config", help="Manage CLI configuration")
|
|
18
18
|
app.add_typer(datasets_cmd.app, name="datasets", help="Manage datasets")
|
|
19
19
|
app.add_typer(data_cmd.app, name="data", help="Pull/push data (alias)")
|
|
20
|
+
app.add_typer(imports_cmd.app, name="imports", help="Import vectors from external databases")
|
|
20
21
|
|
|
21
22
|
# Register top-level versioning commands
|
|
22
23
|
app.command("log")(versions_cmd.log)
|
|
@@ -13,4 +13,5 @@ src/decompressed_cli/commands/__init__.py
|
|
|
13
13
|
src/decompressed_cli/commands/config_cmd.py
|
|
14
14
|
src/decompressed_cli/commands/data_cmd.py
|
|
15
15
|
src/decompressed_cli/commands/datasets_cmd.py
|
|
16
|
+
src/decompressed_cli/commands/imports_cmd.py
|
|
16
17
|
src/decompressed_cli/commands/versions_cmd.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/src/decompressed_cli/commands/config_cmd.py
RENAMED
|
File without changes
|
|
File without changes
|
{decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/src/decompressed_cli/commands/datasets_cmd.py
RENAMED
|
File without changes
|
{decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/src/decompressed_cli/commands/versions_cmd.py
RENAMED
|
File without changes
|
|
File without changes
|
{decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/src/decompressed_cli.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/src/decompressed_cli.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/src/decompressed_cli.egg-info/requires.txt
RENAMED
|
File without changes
|
{decompressed_cli-0.1.0 → decompressed_cli-0.1.1}/src/decompressed_cli.egg-info/top_level.txt
RENAMED
|
File without changes
|