vectorgov-cli 0.1.0__py3-none-any.whl
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.
- vectorgov/cli/__init__.py +12 -0
- vectorgov/cli/commands/__init__.py +7 -0
- vectorgov/cli/commands/ask.py +158 -0
- vectorgov/cli/commands/auth.py +106 -0
- vectorgov/cli/commands/config.py +114 -0
- vectorgov/cli/commands/docs.py +113 -0
- vectorgov/cli/commands/feedback.py +59 -0
- vectorgov/cli/commands/search.py +97 -0
- vectorgov/cli/main.py +53 -0
- vectorgov/cli/utils/__init__.py +8 -0
- vectorgov/cli/utils/config.py +110 -0
- vectorgov/cli/utils/output.py +103 -0
- vectorgov_cli-0.1.0.dist-info/METADATA +273 -0
- vectorgov_cli-0.1.0.dist-info/RECORD +16 -0
- vectorgov_cli-0.1.0.dist-info/WHEEL +4 -0
- vectorgov_cli-0.1.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Comando de perguntas do CLI VectorGov.
|
|
3
|
+
|
|
4
|
+
Este comando busca contexto relevante e prepara para uso com LLMs.
|
|
5
|
+
O usuário deve usar seu próprio LLM (OpenAI, Anthropic, Google, etc).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
from typing import Optional
|
|
10
|
+
|
|
11
|
+
import typer
|
|
12
|
+
from rich.console import Console
|
|
13
|
+
from rich.markdown import Markdown
|
|
14
|
+
from rich.panel import Panel
|
|
15
|
+
from rich.syntax import Syntax
|
|
16
|
+
|
|
17
|
+
from ..utils.config import ConfigManager
|
|
18
|
+
from ..utils.output import OutputFormat
|
|
19
|
+
|
|
20
|
+
app = typer.Typer()
|
|
21
|
+
console = Console()
|
|
22
|
+
config_manager = ConfigManager()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@app.callback(invoke_without_command=True)
|
|
26
|
+
def ask(
|
|
27
|
+
query: str = typer.Argument(..., help="Pergunta em linguagem natural"),
|
|
28
|
+
top_k: int = typer.Option(5, "--top-k", "-k", help="Número de chunks para contexto"),
|
|
29
|
+
mode: str = typer.Option(
|
|
30
|
+
"balanced",
|
|
31
|
+
"--mode", "-m",
|
|
32
|
+
help="Modo de busca: fast, balanced, precise"
|
|
33
|
+
),
|
|
34
|
+
output: OutputFormat = typer.Option(
|
|
35
|
+
OutputFormat.text,
|
|
36
|
+
"--output", "-o",
|
|
37
|
+
help="Formato de saída: text, json, messages"
|
|
38
|
+
),
|
|
39
|
+
raw: bool = typer.Option(False, "--raw", help="Saída sem formatação (JSON bruto)"),
|
|
40
|
+
show_code: bool = typer.Option(False, "--code", help="Mostrar código de exemplo para LLM"),
|
|
41
|
+
):
|
|
42
|
+
"""
|
|
43
|
+
Busca contexto relevante para responder uma pergunta.
|
|
44
|
+
|
|
45
|
+
O VectorGov retorna os chunks mais relevantes da legislação.
|
|
46
|
+
Use os métodos to_messages() ou to_context() para integrar com seu LLM.
|
|
47
|
+
|
|
48
|
+
Exemplos:
|
|
49
|
+
vectorgov ask "O que é ETP?"
|
|
50
|
+
vectorgov ask "Quando o ETP pode ser dispensado?" --mode precise
|
|
51
|
+
vectorgov ask "critérios de julgamento" --output messages
|
|
52
|
+
vectorgov ask "O que é ETP?" --code # Mostra código de exemplo
|
|
53
|
+
"""
|
|
54
|
+
# Obtém API key
|
|
55
|
+
api_key = config_manager.get("api_key")
|
|
56
|
+
if not api_key:
|
|
57
|
+
console.print("[red]Erro:[/red] API key não configurada.")
|
|
58
|
+
console.print(" Use 'vectorgov auth login' para configurar.")
|
|
59
|
+
raise typer.Exit(1)
|
|
60
|
+
|
|
61
|
+
# Valida parâmetros
|
|
62
|
+
if top_k < 1 or top_k > 20:
|
|
63
|
+
console.print("[red]Erro:[/red] top_k deve estar entre 1 e 20.")
|
|
64
|
+
raise typer.Exit(1)
|
|
65
|
+
|
|
66
|
+
if mode not in ["fast", "balanced", "precise"]:
|
|
67
|
+
console.print("[red]Erro:[/red] mode deve ser: fast, balanced ou precise.")
|
|
68
|
+
raise typer.Exit(1)
|
|
69
|
+
|
|
70
|
+
# Executa busca
|
|
71
|
+
try:
|
|
72
|
+
from vectorgov import VectorGov
|
|
73
|
+
|
|
74
|
+
if not raw:
|
|
75
|
+
console.print(f"Buscando contexto para: [cyan]{query}[/cyan]", style="dim")
|
|
76
|
+
|
|
77
|
+
vg = VectorGov(api_key=api_key)
|
|
78
|
+
results = vg.search(query, top_k=top_k, mode=mode)
|
|
79
|
+
|
|
80
|
+
# Formata saída
|
|
81
|
+
if raw:
|
|
82
|
+
# JSON bruto para pipes
|
|
83
|
+
messages = results.to_messages(query)
|
|
84
|
+
data = {
|
|
85
|
+
"query": query,
|
|
86
|
+
"total": results.total,
|
|
87
|
+
"cached": results.cached,
|
|
88
|
+
"latency_ms": results.latency_ms,
|
|
89
|
+
"query_id": results.query_id,
|
|
90
|
+
"messages": messages,
|
|
91
|
+
"context": results.to_context(),
|
|
92
|
+
}
|
|
93
|
+
print(json.dumps(data, ensure_ascii=False, indent=2))
|
|
94
|
+
|
|
95
|
+
elif output == OutputFormat.json or str(output) == "messages":
|
|
96
|
+
# Formato messages para usar com LLMs
|
|
97
|
+
messages = results.to_messages(query)
|
|
98
|
+
data = {
|
|
99
|
+
"messages": messages,
|
|
100
|
+
"metadata": {
|
|
101
|
+
"query": query,
|
|
102
|
+
"total": results.total,
|
|
103
|
+
"query_id": results.query_id,
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
console.print_json(json.dumps(data, ensure_ascii=False))
|
|
107
|
+
|
|
108
|
+
else: # text
|
|
109
|
+
# Mostra contexto formatado
|
|
110
|
+
console.print()
|
|
111
|
+
|
|
112
|
+
# Info da busca
|
|
113
|
+
cache_str = "[green]✓ Cache[/green]" if results.cached else "[dim]Sem cache[/dim]"
|
|
114
|
+
console.print(f"Encontrados: [cyan]{results.total}[/cyan] chunks | "
|
|
115
|
+
f"Latência: [cyan]{results.latency_ms}ms[/cyan] | {cache_str}")
|
|
116
|
+
console.print()
|
|
117
|
+
|
|
118
|
+
# Mostra cada hit
|
|
119
|
+
for i, hit in enumerate(results.hits, 1):
|
|
120
|
+
title = f"[bold]#{i}[/bold] Art. {hit.article_number} ({hit.document_id})"
|
|
121
|
+
console.print(Panel(
|
|
122
|
+
hit.text[:500] + ("..." if len(hit.text) > 500 else ""),
|
|
123
|
+
title=title,
|
|
124
|
+
border_style="blue"
|
|
125
|
+
))
|
|
126
|
+
console.print()
|
|
127
|
+
|
|
128
|
+
# Query ID para feedback
|
|
129
|
+
console.print(f"[dim]Query ID: {results.query_id}[/dim]")
|
|
130
|
+
console.print("[dim]Use 'vectorgov feedback <query_id> --like' para avaliar[/dim]")
|
|
131
|
+
|
|
132
|
+
# Mostra código de exemplo se solicitado
|
|
133
|
+
if show_code:
|
|
134
|
+
console.print()
|
|
135
|
+
console.print("[bold yellow]Código de exemplo para usar com LLM:[/bold yellow]")
|
|
136
|
+
code = f'''from vectorgov import VectorGov
|
|
137
|
+
from openai import OpenAI # ou anthropic, google-generativeai, etc.
|
|
138
|
+
|
|
139
|
+
vg = VectorGov(api_key="vg_xxx")
|
|
140
|
+
openai = OpenAI()
|
|
141
|
+
|
|
142
|
+
results = vg.search("{query}", top_k={top_k})
|
|
143
|
+
|
|
144
|
+
# Usar com OpenAI
|
|
145
|
+
response = openai.chat.completions.create(
|
|
146
|
+
model="gpt-4o",
|
|
147
|
+
messages=results.to_messages("{query}")
|
|
148
|
+
)
|
|
149
|
+
print(response.choices[0].message.content)
|
|
150
|
+
|
|
151
|
+
# Ou usar contexto diretamente
|
|
152
|
+
context = results.to_context()
|
|
153
|
+
'''
|
|
154
|
+
console.print(Syntax(code, "python", theme="monokai"))
|
|
155
|
+
|
|
156
|
+
except Exception as e:
|
|
157
|
+
console.print(f"[red]Erro:[/red] {e}")
|
|
158
|
+
raise typer.Exit(1)
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Comandos de autenticação do CLI VectorGov.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from rich.console import Console
|
|
7
|
+
from rich.prompt import Prompt
|
|
8
|
+
|
|
9
|
+
from ..utils.config import ConfigManager
|
|
10
|
+
|
|
11
|
+
app = typer.Typer(no_args_is_help=True)
|
|
12
|
+
console = Console()
|
|
13
|
+
config_manager = ConfigManager()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@app.command()
|
|
17
|
+
def login(
|
|
18
|
+
api_key: str = typer.Option(
|
|
19
|
+
None,
|
|
20
|
+
"--api-key", "-k",
|
|
21
|
+
help="API key do VectorGov. Se não fornecida, será solicitada interativamente."
|
|
22
|
+
),
|
|
23
|
+
):
|
|
24
|
+
"""
|
|
25
|
+
Configura a API key para autenticação.
|
|
26
|
+
|
|
27
|
+
Exemplo:
|
|
28
|
+
vectorgov auth login
|
|
29
|
+
vectorgov auth login --api-key vg_sua_chave
|
|
30
|
+
"""
|
|
31
|
+
if not api_key:
|
|
32
|
+
api_key = Prompt.ask("Digite sua API key", password=True)
|
|
33
|
+
|
|
34
|
+
if not api_key.startswith("vg_"):
|
|
35
|
+
console.print("[red]Erro:[/red] API key deve começar com 'vg_'")
|
|
36
|
+
raise typer.Exit(1)
|
|
37
|
+
|
|
38
|
+
# Testa a API key
|
|
39
|
+
console.print("Validando API key...", style="dim")
|
|
40
|
+
try:
|
|
41
|
+
from vectorgov import VectorGov
|
|
42
|
+
vg = VectorGov(api_key=api_key)
|
|
43
|
+
# Faz uma busca simples para validar
|
|
44
|
+
vg.search("teste", top_k=1)
|
|
45
|
+
console.print("[green]✓[/green] API key válida!")
|
|
46
|
+
except Exception as e:
|
|
47
|
+
console.print(f"[red]✗[/red] Erro ao validar API key: {e}")
|
|
48
|
+
raise typer.Exit(1)
|
|
49
|
+
|
|
50
|
+
# Salva a configuração
|
|
51
|
+
config_manager.set("api_key", api_key)
|
|
52
|
+
console.print("[green]✓[/green] Configuração salva com sucesso!")
|
|
53
|
+
console.print(f" Arquivo: {config_manager.config_file}")
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@app.command()
|
|
57
|
+
def logout():
|
|
58
|
+
"""
|
|
59
|
+
Remove a API key salva.
|
|
60
|
+
|
|
61
|
+
Exemplo:
|
|
62
|
+
vectorgov auth logout
|
|
63
|
+
"""
|
|
64
|
+
if config_manager.get("api_key"):
|
|
65
|
+
config_manager.delete("api_key")
|
|
66
|
+
console.print("[green]✓[/green] API key removida com sucesso!")
|
|
67
|
+
else:
|
|
68
|
+
console.print("[yellow]![/yellow] Nenhuma API key configurada.")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@app.command()
|
|
72
|
+
def status():
|
|
73
|
+
"""
|
|
74
|
+
Mostra o status da autenticação atual.
|
|
75
|
+
|
|
76
|
+
Exemplo:
|
|
77
|
+
vectorgov auth status
|
|
78
|
+
"""
|
|
79
|
+
api_key = config_manager.get("api_key")
|
|
80
|
+
|
|
81
|
+
if not api_key:
|
|
82
|
+
console.print("[yellow]![/yellow] Nenhuma API key configurada.")
|
|
83
|
+
console.print(" Use 'vectorgov auth login' para configurar.")
|
|
84
|
+
return
|
|
85
|
+
|
|
86
|
+
# Mascara a API key
|
|
87
|
+
masked = api_key[:8] + "..." + api_key[-4:]
|
|
88
|
+
console.print(f"[green]✓[/green] API key configurada: {masked}")
|
|
89
|
+
|
|
90
|
+
# Testa a conexão
|
|
91
|
+
console.print("Testando conexão...", style="dim")
|
|
92
|
+
try:
|
|
93
|
+
from vectorgov import VectorGov
|
|
94
|
+
vg = VectorGov(api_key=api_key)
|
|
95
|
+
vg.search("teste", top_k=1)
|
|
96
|
+
console.print("[green]✓[/green] Conexão OK!")
|
|
97
|
+
except Exception as e:
|
|
98
|
+
console.print(f"[red]✗[/red] Erro na conexão: {e}")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@app.command()
|
|
102
|
+
def whoami():
|
|
103
|
+
"""
|
|
104
|
+
Alias para 'status'. Mostra informações da conta atual.
|
|
105
|
+
"""
|
|
106
|
+
status()
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Comando de configuração do CLI VectorGov.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from rich.console import Console
|
|
7
|
+
from rich.table import Table
|
|
8
|
+
|
|
9
|
+
from ..utils.config import ConfigManager
|
|
10
|
+
|
|
11
|
+
app = typer.Typer(no_args_is_help=True)
|
|
12
|
+
console = Console()
|
|
13
|
+
config_manager = ConfigManager()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@app.command("set")
|
|
17
|
+
def config_set(
|
|
18
|
+
key: str = typer.Argument(..., help="Nome da configuração"),
|
|
19
|
+
value: str = typer.Argument(..., help="Valor da configuração"),
|
|
20
|
+
):
|
|
21
|
+
"""
|
|
22
|
+
Define uma configuração.
|
|
23
|
+
|
|
24
|
+
Exemplos:
|
|
25
|
+
vectorgov config set api_key vg_sua_chave
|
|
26
|
+
vectorgov config set default_mode precise
|
|
27
|
+
"""
|
|
28
|
+
# Valida chaves conhecidas
|
|
29
|
+
valid_keys = ["api_key", "default_mode", "default_top_k", "output_format"]
|
|
30
|
+
|
|
31
|
+
if key not in valid_keys:
|
|
32
|
+
console.print(f"[yellow]Aviso:[/yellow] '{key}' não é uma chave conhecida.")
|
|
33
|
+
console.print(f"Chaves válidas: {', '.join(valid_keys)}")
|
|
34
|
+
|
|
35
|
+
config_manager.set(key, value)
|
|
36
|
+
console.print(f"[green]✓[/green] Configuração '{key}' salva!")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@app.command("get")
|
|
40
|
+
def config_get(
|
|
41
|
+
key: str = typer.Argument(..., help="Nome da configuração"),
|
|
42
|
+
):
|
|
43
|
+
"""
|
|
44
|
+
Obtém uma configuração.
|
|
45
|
+
|
|
46
|
+
Exemplos:
|
|
47
|
+
vectorgov config get api_key
|
|
48
|
+
vectorgov config get default_mode
|
|
49
|
+
"""
|
|
50
|
+
value = config_manager.get(key)
|
|
51
|
+
|
|
52
|
+
if value is None:
|
|
53
|
+
console.print(f"[yellow]![/yellow] Configuração '{key}' não definida.")
|
|
54
|
+
else:
|
|
55
|
+
# Mascara API key
|
|
56
|
+
if key == "api_key" and value:
|
|
57
|
+
value = value[:8] + "..." + value[-4:]
|
|
58
|
+
console.print(f"{key}: {value}")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@app.command("list")
|
|
62
|
+
def config_list():
|
|
63
|
+
"""
|
|
64
|
+
Lista todas as configurações.
|
|
65
|
+
|
|
66
|
+
Exemplo:
|
|
67
|
+
vectorgov config list
|
|
68
|
+
"""
|
|
69
|
+
configs = config_manager.list_all()
|
|
70
|
+
|
|
71
|
+
if not configs:
|
|
72
|
+
console.print("[yellow]![/yellow] Nenhuma configuração definida.")
|
|
73
|
+
return
|
|
74
|
+
|
|
75
|
+
table = Table(title="Configurações")
|
|
76
|
+
table.add_column("Chave", style="cyan")
|
|
77
|
+
table.add_column("Valor")
|
|
78
|
+
|
|
79
|
+
for key, value in configs.items():
|
|
80
|
+
# Mascara API key
|
|
81
|
+
if key == "api_key" and value:
|
|
82
|
+
value = value[:8] + "..." + value[-4:]
|
|
83
|
+
table.add_row(key, str(value))
|
|
84
|
+
|
|
85
|
+
console.print(table)
|
|
86
|
+
console.print(f"\nArquivo: {config_manager.config_file}")
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@app.command("delete")
|
|
90
|
+
def config_delete(
|
|
91
|
+
key: str = typer.Argument(..., help="Nome da configuração"),
|
|
92
|
+
):
|
|
93
|
+
"""
|
|
94
|
+
Remove uma configuração.
|
|
95
|
+
|
|
96
|
+
Exemplo:
|
|
97
|
+
vectorgov config delete default_mode
|
|
98
|
+
"""
|
|
99
|
+
if config_manager.get(key):
|
|
100
|
+
config_manager.delete(key)
|
|
101
|
+
console.print(f"[green]✓[/green] Configuração '{key}' removida!")
|
|
102
|
+
else:
|
|
103
|
+
console.print(f"[yellow]![/yellow] Configuração '{key}' não existe.")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@app.command("path")
|
|
107
|
+
def config_path():
|
|
108
|
+
"""
|
|
109
|
+
Mostra o caminho do arquivo de configuração.
|
|
110
|
+
|
|
111
|
+
Exemplo:
|
|
112
|
+
vectorgov config path
|
|
113
|
+
"""
|
|
114
|
+
console.print(f"Arquivo de configuração: {config_manager.config_file}")
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Comando de documentos do CLI VectorGov.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import typer
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
from rich.table import Table
|
|
9
|
+
|
|
10
|
+
from ..utils.config import ConfigManager
|
|
11
|
+
|
|
12
|
+
app = typer.Typer(no_args_is_help=True)
|
|
13
|
+
console = Console()
|
|
14
|
+
config_manager = ConfigManager()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@app.command("list")
|
|
18
|
+
def list_docs(
|
|
19
|
+
output: str = typer.Option("table", "--output", "-o", help="Formato: table, json"),
|
|
20
|
+
):
|
|
21
|
+
"""
|
|
22
|
+
Lista documentos disponíveis na base.
|
|
23
|
+
|
|
24
|
+
Exemplos:
|
|
25
|
+
vectorgov docs list
|
|
26
|
+
vectorgov docs list --output json
|
|
27
|
+
"""
|
|
28
|
+
# Obtém API key
|
|
29
|
+
api_key = config_manager.get("api_key")
|
|
30
|
+
if not api_key:
|
|
31
|
+
console.print("[red]Erro:[/red] API key não configurada.")
|
|
32
|
+
console.print(" Use 'vectorgov auth login' para configurar.")
|
|
33
|
+
raise typer.Exit(1)
|
|
34
|
+
|
|
35
|
+
try:
|
|
36
|
+
from vectorgov import VectorGov
|
|
37
|
+
|
|
38
|
+
vg = VectorGov(api_key=api_key)
|
|
39
|
+
docs = vg.list_documents()
|
|
40
|
+
|
|
41
|
+
if output == "json":
|
|
42
|
+
data = [
|
|
43
|
+
{
|
|
44
|
+
"id": d.id,
|
|
45
|
+
"title": d.title,
|
|
46
|
+
"type": d.type,
|
|
47
|
+
"year": d.year,
|
|
48
|
+
"chunks": d.chunks_count,
|
|
49
|
+
}
|
|
50
|
+
for d in docs
|
|
51
|
+
]
|
|
52
|
+
console.print_json(json.dumps(data, ensure_ascii=False))
|
|
53
|
+
else:
|
|
54
|
+
table = Table(title="Documentos Disponíveis")
|
|
55
|
+
table.add_column("ID", style="cyan")
|
|
56
|
+
table.add_column("Título")
|
|
57
|
+
table.add_column("Tipo", style="green")
|
|
58
|
+
table.add_column("Ano", justify="right")
|
|
59
|
+
table.add_column("Chunks", justify="right")
|
|
60
|
+
|
|
61
|
+
for d in docs:
|
|
62
|
+
table.add_row(
|
|
63
|
+
d.id,
|
|
64
|
+
d.title[:50] + "..." if len(d.title) > 50 else d.title,
|
|
65
|
+
d.type,
|
|
66
|
+
str(d.year),
|
|
67
|
+
str(d.chunks_count),
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
console.print(table)
|
|
71
|
+
console.print(f"\nTotal: {len(docs)} documentos")
|
|
72
|
+
|
|
73
|
+
except Exception as e:
|
|
74
|
+
console.print(f"[red]Erro:[/red] {e}")
|
|
75
|
+
raise typer.Exit(1)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@app.command("info")
|
|
79
|
+
def doc_info(
|
|
80
|
+
document_id: str = typer.Argument(..., help="ID do documento"),
|
|
81
|
+
):
|
|
82
|
+
"""
|
|
83
|
+
Mostra informações detalhadas de um documento.
|
|
84
|
+
|
|
85
|
+
Exemplos:
|
|
86
|
+
vectorgov docs info LEI-14133-2021
|
|
87
|
+
vectorgov docs info IN-58-2022
|
|
88
|
+
"""
|
|
89
|
+
# Obtém API key
|
|
90
|
+
api_key = config_manager.get("api_key")
|
|
91
|
+
if not api_key:
|
|
92
|
+
console.print("[red]Erro:[/red] API key não configurada.")
|
|
93
|
+
console.print(" Use 'vectorgov auth login' para configurar.")
|
|
94
|
+
raise typer.Exit(1)
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
from vectorgov import VectorGov
|
|
98
|
+
|
|
99
|
+
vg = VectorGov(api_key=api_key)
|
|
100
|
+
doc = vg.get_document(document_id)
|
|
101
|
+
|
|
102
|
+
console.print(f"\n[bold]{doc.title}[/bold]")
|
|
103
|
+
console.print(f"ID: [cyan]{doc.id}[/cyan]")
|
|
104
|
+
console.print(f"Tipo: [green]{doc.type}[/green]")
|
|
105
|
+
console.print(f"Ano: {doc.year}")
|
|
106
|
+
console.print(f"Chunks: {doc.chunks_count}")
|
|
107
|
+
|
|
108
|
+
if hasattr(doc, 'description') and doc.description:
|
|
109
|
+
console.print(f"\nDescrição: {doc.description}")
|
|
110
|
+
|
|
111
|
+
except Exception as e:
|
|
112
|
+
console.print(f"[red]Erro:[/red] {e}")
|
|
113
|
+
raise typer.Exit(1)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Comando de feedback do CLI VectorGov.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from rich.console import Console
|
|
7
|
+
|
|
8
|
+
from ..utils.config import ConfigManager
|
|
9
|
+
|
|
10
|
+
app = typer.Typer()
|
|
11
|
+
console = Console()
|
|
12
|
+
config_manager = ConfigManager()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@app.callback(invoke_without_command=True)
|
|
16
|
+
def feedback(
|
|
17
|
+
query_id: str = typer.Argument(..., help="ID da query (obtido após search ou ask)"),
|
|
18
|
+
like: bool = typer.Option(None, "--like", "-l", help="Marcar como positivo"),
|
|
19
|
+
dislike: bool = typer.Option(None, "--dislike", "-d", help="Marcar como negativo"),
|
|
20
|
+
):
|
|
21
|
+
"""
|
|
22
|
+
Envia feedback sobre uma resposta (like/dislike).
|
|
23
|
+
|
|
24
|
+
Exemplos:
|
|
25
|
+
vectorgov feedback abc123 --like
|
|
26
|
+
vectorgov feedback abc123 --dislike
|
|
27
|
+
"""
|
|
28
|
+
# Valida opções
|
|
29
|
+
if like is None and dislike is None:
|
|
30
|
+
console.print("[red]Erro:[/red] Especifique --like ou --dislike")
|
|
31
|
+
raise typer.Exit(1)
|
|
32
|
+
|
|
33
|
+
if like and dislike:
|
|
34
|
+
console.print("[red]Erro:[/red] Use apenas --like OU --dislike, não ambos")
|
|
35
|
+
raise typer.Exit(1)
|
|
36
|
+
|
|
37
|
+
is_like = like if like is not None else not dislike
|
|
38
|
+
|
|
39
|
+
# Obtém API key
|
|
40
|
+
api_key = config_manager.get("api_key")
|
|
41
|
+
if not api_key:
|
|
42
|
+
console.print("[red]Erro:[/red] API key não configurada.")
|
|
43
|
+
console.print(" Use 'vectorgov auth login' para configurar.")
|
|
44
|
+
raise typer.Exit(1)
|
|
45
|
+
|
|
46
|
+
# Envia feedback
|
|
47
|
+
try:
|
|
48
|
+
from vectorgov import VectorGov
|
|
49
|
+
|
|
50
|
+
vg = VectorGov(api_key=api_key)
|
|
51
|
+
vg.feedback(query_id, like=is_like)
|
|
52
|
+
|
|
53
|
+
emoji = "👍" if is_like else "👎"
|
|
54
|
+
status = "positivo" if is_like else "negativo"
|
|
55
|
+
console.print(f"[green]✓[/green] Feedback {emoji} {status} enviado com sucesso!")
|
|
56
|
+
|
|
57
|
+
except Exception as e:
|
|
58
|
+
console.print(f"[red]Erro:[/red] {e}")
|
|
59
|
+
raise typer.Exit(1)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Comando de busca do CLI VectorGov.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from typing import Optional
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
from rich.console import Console
|
|
10
|
+
from rich.table import Table
|
|
11
|
+
from rich.panel import Panel
|
|
12
|
+
|
|
13
|
+
from ..utils.config import ConfigManager
|
|
14
|
+
from ..utils.output import OutputFormat, format_search_results
|
|
15
|
+
|
|
16
|
+
app = typer.Typer()
|
|
17
|
+
console = Console()
|
|
18
|
+
config_manager = ConfigManager()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@app.callback(invoke_without_command=True)
|
|
22
|
+
def search(
|
|
23
|
+
query: str = typer.Argument(..., help="Pergunta ou termo de busca"),
|
|
24
|
+
top_k: int = typer.Option(5, "--top-k", "-k", help="Número de resultados (1-20)"),
|
|
25
|
+
mode: str = typer.Option(
|
|
26
|
+
"balanced",
|
|
27
|
+
"--mode", "-m",
|
|
28
|
+
help="Modo de busca: fast, balanced, precise"
|
|
29
|
+
),
|
|
30
|
+
use_cache: bool = typer.Option(False, "--cache", help="Usar cache semântico"),
|
|
31
|
+
output: OutputFormat = typer.Option(
|
|
32
|
+
OutputFormat.table,
|
|
33
|
+
"--output", "-o",
|
|
34
|
+
help="Formato de saída: table, json, text"
|
|
35
|
+
),
|
|
36
|
+
raw: bool = typer.Option(False, "--raw", help="Saída sem formatação (JSON bruto)"),
|
|
37
|
+
):
|
|
38
|
+
"""
|
|
39
|
+
Busca documentos na base de legislação.
|
|
40
|
+
|
|
41
|
+
Exemplos:
|
|
42
|
+
vectorgov search "O que é ETP?"
|
|
43
|
+
vectorgov search "pesquisa de preços" --top-k 10
|
|
44
|
+
vectorgov search "licitação" --mode precise --output json
|
|
45
|
+
"""
|
|
46
|
+
# Obtém API key
|
|
47
|
+
api_key = config_manager.get("api_key")
|
|
48
|
+
if not api_key:
|
|
49
|
+
console.print("[red]Erro:[/red] API key não configurada.")
|
|
50
|
+
console.print(" Use 'vectorgov auth login' para configurar.")
|
|
51
|
+
raise typer.Exit(1)
|
|
52
|
+
|
|
53
|
+
# Valida parâmetros
|
|
54
|
+
if top_k < 1 or top_k > 20:
|
|
55
|
+
console.print("[red]Erro:[/red] top_k deve estar entre 1 e 20.")
|
|
56
|
+
raise typer.Exit(1)
|
|
57
|
+
|
|
58
|
+
if mode not in ["fast", "balanced", "precise"]:
|
|
59
|
+
console.print("[red]Erro:[/red] mode deve ser: fast, balanced ou precise.")
|
|
60
|
+
raise typer.Exit(1)
|
|
61
|
+
|
|
62
|
+
# Executa busca
|
|
63
|
+
try:
|
|
64
|
+
from vectorgov import VectorGov
|
|
65
|
+
|
|
66
|
+
if not raw:
|
|
67
|
+
console.print(f"Buscando: [cyan]{query}[/cyan]", style="dim")
|
|
68
|
+
|
|
69
|
+
vg = VectorGov(api_key=api_key)
|
|
70
|
+
results = vg.search(query, top_k=top_k, mode=mode, use_cache=use_cache)
|
|
71
|
+
|
|
72
|
+
# Formata saída
|
|
73
|
+
if raw:
|
|
74
|
+
# JSON bruto para pipes
|
|
75
|
+
data = {
|
|
76
|
+
"query": query,
|
|
77
|
+
"total": results.total,
|
|
78
|
+
"cached": results.cached,
|
|
79
|
+
"latency_ms": results.latency_ms,
|
|
80
|
+
"query_id": results.query_id,
|
|
81
|
+
"hits": [
|
|
82
|
+
{
|
|
83
|
+
"text": h.text,
|
|
84
|
+
"article_number": h.article_number,
|
|
85
|
+
"document_id": h.document_id,
|
|
86
|
+
"score": h.score,
|
|
87
|
+
}
|
|
88
|
+
for h in results.hits
|
|
89
|
+
]
|
|
90
|
+
}
|
|
91
|
+
print(json.dumps(data, ensure_ascii=False, indent=2))
|
|
92
|
+
else:
|
|
93
|
+
format_search_results(console, results, output, query)
|
|
94
|
+
|
|
95
|
+
except Exception as e:
|
|
96
|
+
console.print(f"[red]Erro:[/red] {e}")
|
|
97
|
+
raise typer.Exit(1)
|
vectorgov/cli/main.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Ponto de entrada principal do CLI VectorGov.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
from rich.console import Console
|
|
7
|
+
|
|
8
|
+
from .commands import auth, search, ask, feedback, docs, config
|
|
9
|
+
|
|
10
|
+
# Console para output formatado
|
|
11
|
+
console = Console()
|
|
12
|
+
|
|
13
|
+
# App principal
|
|
14
|
+
app = typer.Typer(
|
|
15
|
+
name="vectorgov",
|
|
16
|
+
help="CLI para a API VectorGov - Busca semântica em legislação brasileira",
|
|
17
|
+
add_completion=True,
|
|
18
|
+
no_args_is_help=True,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
# Registra subcomandos
|
|
22
|
+
app.add_typer(auth.app, name="auth", help="Autenticação e gerenciamento de credenciais")
|
|
23
|
+
app.add_typer(search.app, name="search", help="Buscar documentos na base de legislação")
|
|
24
|
+
app.add_typer(ask.app, name="ask", help="Fazer perguntas com resposta de IA")
|
|
25
|
+
app.add_typer(feedback.app, name="feedback", help="Enviar feedback sobre respostas")
|
|
26
|
+
app.add_typer(docs.app, name="docs", help="Listar e consultar documentos disponíveis")
|
|
27
|
+
app.add_typer(config.app, name="config", help="Gerenciar configurações")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@app.command()
|
|
31
|
+
def version():
|
|
32
|
+
"""Mostra a versão do CLI."""
|
|
33
|
+
from vectorgov import __version__
|
|
34
|
+
console.print(f"vectorgov-cli versão {__version__}")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@app.callback()
|
|
38
|
+
def callback():
|
|
39
|
+
"""
|
|
40
|
+
VectorGov CLI - Busca semântica em legislação brasileira.
|
|
41
|
+
|
|
42
|
+
Use 'vectorgov COMANDO --help' para mais informações sobre cada comando.
|
|
43
|
+
"""
|
|
44
|
+
pass
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def main():
|
|
48
|
+
"""Função principal executada pelo entry point."""
|
|
49
|
+
app()
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
if __name__ == "__main__":
|
|
53
|
+
main()
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Gerenciador de configuração do CLI VectorGov.
|
|
3
|
+
|
|
4
|
+
Armazena configurações em ~/.vectorgov/config.yaml
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Any, Dict, Optional
|
|
10
|
+
|
|
11
|
+
import yaml
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ConfigManager:
|
|
15
|
+
"""Gerencia configurações do CLI em arquivo YAML."""
|
|
16
|
+
|
|
17
|
+
def __init__(self):
|
|
18
|
+
"""Inicializa o gerenciador de configuração."""
|
|
19
|
+
self.config_dir = Path.home() / ".vectorgov"
|
|
20
|
+
self.config_file = self.config_dir / "config.yaml"
|
|
21
|
+
self._config: Optional[Dict[str, Any]] = None
|
|
22
|
+
|
|
23
|
+
def _ensure_dir(self):
|
|
24
|
+
"""Garante que o diretório de configuração existe."""
|
|
25
|
+
self.config_dir.mkdir(parents=True, exist_ok=True)
|
|
26
|
+
|
|
27
|
+
def _load(self) -> Dict[str, Any]:
|
|
28
|
+
"""Carrega configuração do arquivo."""
|
|
29
|
+
if self._config is not None:
|
|
30
|
+
return self._config
|
|
31
|
+
|
|
32
|
+
if self.config_file.exists():
|
|
33
|
+
with open(self.config_file, "r", encoding="utf-8") as f:
|
|
34
|
+
self._config = yaml.safe_load(f) or {}
|
|
35
|
+
else:
|
|
36
|
+
self._config = {}
|
|
37
|
+
|
|
38
|
+
return self._config
|
|
39
|
+
|
|
40
|
+
def _save(self):
|
|
41
|
+
"""Salva configuração no arquivo."""
|
|
42
|
+
self._ensure_dir()
|
|
43
|
+
with open(self.config_file, "w", encoding="utf-8") as f:
|
|
44
|
+
yaml.dump(self._config, f, default_flow_style=False, allow_unicode=True)
|
|
45
|
+
|
|
46
|
+
def get(self, key: str, default: Any = None) -> Any:
|
|
47
|
+
"""
|
|
48
|
+
Obtém valor de uma configuração.
|
|
49
|
+
|
|
50
|
+
Prioridade:
|
|
51
|
+
1. Variável de ambiente (VECTORGOV_<KEY>)
|
|
52
|
+
2. Arquivo de configuração
|
|
53
|
+
3. Valor padrão
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
key: Nome da configuração
|
|
57
|
+
default: Valor padrão se não encontrado
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Valor da configuração
|
|
61
|
+
"""
|
|
62
|
+
# Tenta variável de ambiente primeiro
|
|
63
|
+
env_key = f"VECTORGOV_{key.upper()}"
|
|
64
|
+
env_value = os.environ.get(env_key)
|
|
65
|
+
if env_value is not None:
|
|
66
|
+
return env_value
|
|
67
|
+
|
|
68
|
+
# Tenta arquivo de configuração
|
|
69
|
+
config = self._load()
|
|
70
|
+
return config.get(key, default)
|
|
71
|
+
|
|
72
|
+
def set(self, key: str, value: Any):
|
|
73
|
+
"""
|
|
74
|
+
Define valor de uma configuração.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
key: Nome da configuração
|
|
78
|
+
value: Valor a ser salvo
|
|
79
|
+
"""
|
|
80
|
+
config = self._load()
|
|
81
|
+
config[key] = value
|
|
82
|
+
self._config = config
|
|
83
|
+
self._save()
|
|
84
|
+
|
|
85
|
+
def delete(self, key: str):
|
|
86
|
+
"""
|
|
87
|
+
Remove uma configuração.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
key: Nome da configuração
|
|
91
|
+
"""
|
|
92
|
+
config = self._load()
|
|
93
|
+
if key in config:
|
|
94
|
+
del config[key]
|
|
95
|
+
self._config = config
|
|
96
|
+
self._save()
|
|
97
|
+
|
|
98
|
+
def list_all(self) -> Dict[str, Any]:
|
|
99
|
+
"""
|
|
100
|
+
Lista todas as configurações.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
Dicionário com todas as configurações
|
|
104
|
+
"""
|
|
105
|
+
return self._load().copy()
|
|
106
|
+
|
|
107
|
+
def clear(self):
|
|
108
|
+
"""Remove todas as configurações."""
|
|
109
|
+
self._config = {}
|
|
110
|
+
self._save()
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Utilitários de formatação de saída do CLI VectorGov.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from rich.console import Console
|
|
10
|
+
from rich.table import Table
|
|
11
|
+
from rich.panel import Panel
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class OutputFormat(str, Enum):
|
|
15
|
+
"""Formatos de saída suportados."""
|
|
16
|
+
table = "table"
|
|
17
|
+
json = "json"
|
|
18
|
+
text = "text"
|
|
19
|
+
markdown = "markdown"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def format_search_results(console: Console, results: Any, output_format: OutputFormat, query: str):
|
|
23
|
+
"""
|
|
24
|
+
Formata e exibe resultados de busca.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
console: Console Rich para output
|
|
28
|
+
results: Objeto SearchResult da API
|
|
29
|
+
output_format: Formato desejado
|
|
30
|
+
query: Query original
|
|
31
|
+
"""
|
|
32
|
+
if output_format == OutputFormat.json:
|
|
33
|
+
data = {
|
|
34
|
+
"query": query,
|
|
35
|
+
"total": results.total,
|
|
36
|
+
"cached": results.cached,
|
|
37
|
+
"latency_ms": results.latency_ms,
|
|
38
|
+
"query_id": results.query_id,
|
|
39
|
+
"hits": [
|
|
40
|
+
{
|
|
41
|
+
"text": h.text,
|
|
42
|
+
"article_number": getattr(h, "article_number", None),
|
|
43
|
+
"document_id": getattr(h, "document_id", None),
|
|
44
|
+
"score": h.score,
|
|
45
|
+
}
|
|
46
|
+
for h in results.hits
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
console.print_json(json.dumps(data, ensure_ascii=False))
|
|
50
|
+
|
|
51
|
+
elif output_format == OutputFormat.table:
|
|
52
|
+
# Cabeçalho
|
|
53
|
+
console.print()
|
|
54
|
+
console.print(f"[bold]Resultados para:[/bold] {query}")
|
|
55
|
+
console.print(f"[dim]Total: {results.total} | Latência: {results.latency_ms:.0f}ms | Cache: {'Sim' if results.cached else 'Não'}[/dim]")
|
|
56
|
+
console.print()
|
|
57
|
+
|
|
58
|
+
# Tabela
|
|
59
|
+
table = Table(show_header=True, header_style="bold cyan")
|
|
60
|
+
table.add_column("#", justify="right", style="dim", width=3)
|
|
61
|
+
table.add_column("Artigo", style="green", width=10)
|
|
62
|
+
table.add_column("Texto", width=60)
|
|
63
|
+
table.add_column("Score", justify="right", width=8)
|
|
64
|
+
|
|
65
|
+
for i, hit in enumerate(results.hits, 1):
|
|
66
|
+
article = getattr(hit, "article_number", "-") or "-"
|
|
67
|
+
text = hit.text[:100] + "..." if len(hit.text) > 100 else hit.text
|
|
68
|
+
text = text.replace("\n", " ")
|
|
69
|
+
table.add_row(str(i), str(article), text, f"{hit.score:.3f}")
|
|
70
|
+
|
|
71
|
+
console.print(table)
|
|
72
|
+
|
|
73
|
+
# Footer
|
|
74
|
+
console.print(f"\n[dim]Query ID: {results.query_id}[/dim]")
|
|
75
|
+
console.print("[dim]Use 'vectorgov feedback <query_id> --like' para avaliar[/dim]")
|
|
76
|
+
|
|
77
|
+
else: # text
|
|
78
|
+
console.print()
|
|
79
|
+
console.print(Panel(f"[bold]{query}[/bold]", title="Busca", border_style="blue"))
|
|
80
|
+
|
|
81
|
+
for i, hit in enumerate(results.hits, 1):
|
|
82
|
+
article = getattr(hit, "article_number", None)
|
|
83
|
+
header = f"[{i}] Art. {article}" if article else f"[{i}]"
|
|
84
|
+
|
|
85
|
+
console.print(f"\n[bold cyan]{header}[/bold cyan] (score: {hit.score:.3f})")
|
|
86
|
+
console.print(hit.text[:300] + "..." if len(hit.text) > 300 else hit.text)
|
|
87
|
+
|
|
88
|
+
console.print(f"\n[dim]Total: {results.total} | Latência: {results.latency_ms:.0f}ms[/dim]")
|
|
89
|
+
console.print(f"[dim]Query ID: {results.query_id}[/dim]")
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def format_code_block(console: Console, code: str, language: str = "python"):
|
|
93
|
+
"""
|
|
94
|
+
Formata e exibe um bloco de código.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
console: Console Rich
|
|
98
|
+
code: Código a exibir
|
|
99
|
+
language: Linguagem para syntax highlighting
|
|
100
|
+
"""
|
|
101
|
+
from rich.syntax import Syntax
|
|
102
|
+
syntax = Syntax(code, language, theme="monokai", line_numbers=True)
|
|
103
|
+
console.print(syntax)
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vectorgov-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: CLI para a API VectorGov - Busca semântica em legislação brasileira
|
|
5
|
+
Project-URL: Homepage, https://vectorgov.io
|
|
6
|
+
Project-URL: Documentation, https://vectorgov.io/documentacao
|
|
7
|
+
Project-URL: Repository, https://github.com/euteajudo/vectorgov-cli
|
|
8
|
+
Project-URL: Issues, https://github.com/euteajudo/vectorgov-cli/issues
|
|
9
|
+
Author-email: VectorGov <contato@vectorgov.io>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
Keywords: brazil,cli,legal,legislation,licitacao,rag,semantic-search,vectorgov
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Topic :: Text Processing :: Linguistic
|
|
24
|
+
Requires-Python: >=3.9
|
|
25
|
+
Requires-Dist: pyyaml>=6.0.0
|
|
26
|
+
Requires-Dist: rich>=13.0.0
|
|
27
|
+
Requires-Dist: typer>=0.9.0
|
|
28
|
+
Requires-Dist: vectorgov>=0.13.0
|
|
29
|
+
Provides-Extra: all
|
|
30
|
+
Requires-Dist: anthropic>=0.18.0; extra == 'all'
|
|
31
|
+
Requires-Dist: google-generativeai>=0.3.0; extra == 'all'
|
|
32
|
+
Requires-Dist: langchain-core>=0.1.0; extra == 'all'
|
|
33
|
+
Requires-Dist: langchain>=0.1.0; extra == 'all'
|
|
34
|
+
Requires-Dist: openai>=1.0.0; extra == 'all'
|
|
35
|
+
Provides-Extra: anthropic
|
|
36
|
+
Requires-Dist: anthropic>=0.18.0; extra == 'anthropic'
|
|
37
|
+
Provides-Extra: dev
|
|
38
|
+
Requires-Dist: black>=23.0.0; extra == 'dev'
|
|
39
|
+
Requires-Dist: isort>=5.12.0; extra == 'dev'
|
|
40
|
+
Requires-Dist: mypy>=1.0.0; extra == 'dev'
|
|
41
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
42
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
43
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
44
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
45
|
+
Provides-Extra: google
|
|
46
|
+
Requires-Dist: google-generativeai>=0.3.0; extra == 'google'
|
|
47
|
+
Provides-Extra: langchain
|
|
48
|
+
Requires-Dist: langchain-core>=0.1.0; extra == 'langchain'
|
|
49
|
+
Requires-Dist: langchain>=0.1.0; extra == 'langchain'
|
|
50
|
+
Provides-Extra: openai
|
|
51
|
+
Requires-Dist: openai>=1.0.0; extra == 'openai'
|
|
52
|
+
Description-Content-Type: text/markdown
|
|
53
|
+
|
|
54
|
+
# VectorGov CLI
|
|
55
|
+
|
|
56
|
+
Cliente de linha de comando para a API VectorGov - Busca semântica em legislação brasileira.
|
|
57
|
+
|
|
58
|
+
[](https://badge.fury.io/py/vectorgov-cli)
|
|
59
|
+
[](https://opensource.org/licenses/MIT)
|
|
60
|
+
|
|
61
|
+
## Instalação
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install vectorgov-cli
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Configuração
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
# Configure sua API key
|
|
71
|
+
vectorgov auth login
|
|
72
|
+
|
|
73
|
+
# Ou via variável de ambiente
|
|
74
|
+
export VECTORGOV_API_KEY="vg_sua_chave"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Uso
|
|
78
|
+
|
|
79
|
+
### Busca
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Busca simples
|
|
83
|
+
vectorgov search "O que é ETP?"
|
|
84
|
+
|
|
85
|
+
# Com opções
|
|
86
|
+
vectorgov search "pesquisa de preços" --top-k 10 --mode precise
|
|
87
|
+
|
|
88
|
+
# Saída em JSON
|
|
89
|
+
vectorgov search "licitação" --output json
|
|
90
|
+
|
|
91
|
+
# JSON bruto (para pipes)
|
|
92
|
+
vectorgov search "licitação" --raw | jq '.hits[0].text'
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Perguntas (contexto para LLM)
|
|
96
|
+
|
|
97
|
+
O comando `ask` busca contexto relevante para você usar com seu próprio LLM (OpenAI, Anthropic, Google, etc).
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# Busca contexto para pergunta
|
|
101
|
+
vectorgov ask "O que é ETP?"
|
|
102
|
+
|
|
103
|
+
# Com mais contexto
|
|
104
|
+
vectorgov ask "Quando o ETP pode ser dispensado?" --top-k 10 --mode precise
|
|
105
|
+
|
|
106
|
+
# Saída em formato messages (pronto para LLM)
|
|
107
|
+
vectorgov ask "critérios de julgamento" --output json
|
|
108
|
+
|
|
109
|
+
# Mostrar código de exemplo para integração
|
|
110
|
+
vectorgov ask "O que é ETP?" --code
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Exemplo de integração com OpenAI:**
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from vectorgov import VectorGov
|
|
117
|
+
from openai import OpenAI
|
|
118
|
+
|
|
119
|
+
vg = VectorGov(api_key="vg_xxx")
|
|
120
|
+
openai = OpenAI()
|
|
121
|
+
|
|
122
|
+
results = vg.search("O que é ETP?", top_k=5)
|
|
123
|
+
|
|
124
|
+
response = openai.chat.completions.create(
|
|
125
|
+
model="gpt-4o",
|
|
126
|
+
messages=results.to_messages("O que é ETP?")
|
|
127
|
+
)
|
|
128
|
+
print(response.choices[0].message.content)
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Feedback
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# Após uma busca, use o query_id para feedback
|
|
135
|
+
vectorgov feedback abc123def456 --like
|
|
136
|
+
vectorgov feedback abc123def456 --dislike
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Documentos
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# Lista documentos disponíveis
|
|
143
|
+
vectorgov docs list
|
|
144
|
+
|
|
145
|
+
# Informações de um documento
|
|
146
|
+
vectorgov docs info LEI-14133-2021
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Configuração
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
# Ver configuração atual
|
|
153
|
+
vectorgov config list
|
|
154
|
+
|
|
155
|
+
# Definir configuração
|
|
156
|
+
vectorgov config set default_mode precise
|
|
157
|
+
vectorgov config set default_top_k 10
|
|
158
|
+
|
|
159
|
+
# Ver valor específico
|
|
160
|
+
vectorgov config get api_key
|
|
161
|
+
|
|
162
|
+
# Remover configuração
|
|
163
|
+
vectorgov config delete default_mode
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### Autenticação
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
# Login (salva API key)
|
|
170
|
+
vectorgov auth login
|
|
171
|
+
|
|
172
|
+
# Status da autenticação
|
|
173
|
+
vectorgov auth status
|
|
174
|
+
|
|
175
|
+
# Logout (remove API key)
|
|
176
|
+
vectorgov auth logout
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Formatos de Saída
|
|
180
|
+
|
|
181
|
+
### Tabela (padrão para search)
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
vectorgov search "O que é ETP?" --output table
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
```
|
|
188
|
+
Resultados para: O que é ETP?
|
|
189
|
+
Total: 5 | Latência: 1234ms | Cache: Não
|
|
190
|
+
|
|
191
|
+
┏━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┓
|
|
192
|
+
┃ # ┃ Artigo ┃ Texto ┃ Score ┃
|
|
193
|
+
┡━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━┩
|
|
194
|
+
│ 1 │ Art. 3 │ ETP - Estudo Técnico Preliminar: documento constitutivo... │ 0.892 │
|
|
195
|
+
│ 2 │ Art. 1 │ Esta Instrução Normativa dispõe sobre a elaboração... │ 0.856 │
|
|
196
|
+
└───┴───────────┴────────────────────────────────────────────────────────────────┴─────────┘
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### JSON
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
vectorgov search "O que é ETP?" --output json
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
```json
|
|
206
|
+
{
|
|
207
|
+
"query": "O que é ETP?",
|
|
208
|
+
"total": 5,
|
|
209
|
+
"cached": false,
|
|
210
|
+
"latency_ms": 1234,
|
|
211
|
+
"hits": [
|
|
212
|
+
{
|
|
213
|
+
"text": "ETP - Estudo Técnico Preliminar...",
|
|
214
|
+
"article_number": "3",
|
|
215
|
+
"score": 0.892
|
|
216
|
+
}
|
|
217
|
+
]
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## Integração com Outros Comandos
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
# Buscar e processar com jq
|
|
225
|
+
vectorgov search "ETP" --raw | jq '.hits[0].text'
|
|
226
|
+
|
|
227
|
+
# Buscar e salvar
|
|
228
|
+
vectorgov search "licitação" --output json > resultados.json
|
|
229
|
+
|
|
230
|
+
# Usar em scripts
|
|
231
|
+
QUERY_ID=$(vectorgov search "ETP" --raw | jq -r '.query_id')
|
|
232
|
+
vectorgov feedback $QUERY_ID --like
|
|
233
|
+
|
|
234
|
+
# Obter contexto para LLM
|
|
235
|
+
vectorgov ask "O que é ETP?" --raw | jq '.messages'
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Variáveis de Ambiente
|
|
239
|
+
|
|
240
|
+
| Variável | Descrição |
|
|
241
|
+
|----------|-----------|
|
|
242
|
+
| `VECTORGOV_API_KEY` | API key para autenticação |
|
|
243
|
+
| `VECTORGOV_DEFAULT_MODE` | Modo de busca padrão (fast, balanced, precise) |
|
|
244
|
+
| `VECTORGOV_DEFAULT_TOP_K` | Número padrão de resultados |
|
|
245
|
+
|
|
246
|
+
## Arquivo de Configuração
|
|
247
|
+
|
|
248
|
+
Localização: `~/.vectorgov/config.yaml`
|
|
249
|
+
|
|
250
|
+
```yaml
|
|
251
|
+
api_key: vg_sua_chave
|
|
252
|
+
default_mode: balanced
|
|
253
|
+
default_top_k: 5
|
|
254
|
+
output_format: table
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Ajuda
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
# Ajuda geral
|
|
261
|
+
vectorgov --help
|
|
262
|
+
|
|
263
|
+
# Ajuda de comando específico
|
|
264
|
+
vectorgov search --help
|
|
265
|
+
vectorgov ask --help
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## Links
|
|
269
|
+
|
|
270
|
+
- [Documentação](https://vectorgov.io/documentacao)
|
|
271
|
+
- [Playground](https://vectorgov.io/playground)
|
|
272
|
+
- [SDK Python](https://pypi.org/project/vectorgov/)
|
|
273
|
+
- [SDK TypeScript](https://www.npmjs.com/package/vectorgov)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
vectorgov/cli/__init__.py,sha256=dgdWdxMKLu2ysK2cicVF1oB38j52q90oh4xuLZKQHz8,250
|
|
2
|
+
vectorgov/cli/main.py,sha256=5hVUoLm4DTwnxSXZBEYt_k3wo7GEa8-dwFLdyiBDgN8,1485
|
|
3
|
+
vectorgov/cli/commands/__init__.py,sha256=1t9iUOTIBF_3_y4k1KmhPSWGgB9v7GtKohxV8wzxIlU,166
|
|
4
|
+
vectorgov/cli/commands/ask.py,sha256=c2eQdQzJhk85Xq74gFf0vhiC1lAyGf2o2K7xeXCWIrE,5630
|
|
5
|
+
vectorgov/cli/commands/auth.py,sha256=MZYeo1_R6JqIXvHvM2rOiwGlpNpuF79kOFdYAYf1Y4E,2933
|
|
6
|
+
vectorgov/cli/commands/config.py,sha256=6J5bihAIrBi1kfaVnFxN9Y8uD55osHuzfCZxNdz3XWg,3057
|
|
7
|
+
vectorgov/cli/commands/docs.py,sha256=eRMmv7m2SYzV3szq1WTj7pDDJ_x8dpHzpFFuGcxJ97U,3373
|
|
8
|
+
vectorgov/cli/commands/feedback.py,sha256=RInF4K5hXY_580qSwwmT7o3MZS_TG05lAndwa6NEjeI,1827
|
|
9
|
+
vectorgov/cli/commands/search.py,sha256=gf_QmciLBQmzOy_8ZO0QO854ydNoTKmu5vyWfVPzoC8,3155
|
|
10
|
+
vectorgov/cli/utils/__init__.py,sha256=QhieGpT2tysFWQc6647tsctJ4O2WAJMPrwHFcLQE0HI,208
|
|
11
|
+
vectorgov/cli/utils/config.py,sha256=R_WPLTKidn1pXftKWWpAB3ikCJeayEoWqkX6i8K6NxI,3096
|
|
12
|
+
vectorgov/cli/utils/output.py,sha256=fTvvol_HAFLIm_SX8bEEoL0eV8ZSAAvt8fd1q3vYGGE,3669
|
|
13
|
+
vectorgov_cli-0.1.0.dist-info/METADATA,sha256=MsAU7KTuN1n6uTu0ETXLFQjWTuNTpJGk331pNqWJL54,7662
|
|
14
|
+
vectorgov_cli-0.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
15
|
+
vectorgov_cli-0.1.0.dist-info/entry_points.txt,sha256=F-9wuWEqDFIrwi2B5_JkGDvUM1jjwzQod598JUs59YE,54
|
|
16
|
+
vectorgov_cli-0.1.0.dist-info/RECORD,,
|