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.
@@ -0,0 +1,12 @@
1
+ """
2
+ VectorGov CLI - Cliente de linha de comando para a API VectorGov.
3
+
4
+ Uso:
5
+ vectorgov search "O que é ETP?"
6
+ vectorgov ask "Quando o ETP pode ser dispensado?"
7
+ vectorgov auth login
8
+ """
9
+
10
+ from .main import app
11
+
12
+ __all__ = ["app"]
@@ -0,0 +1,7 @@
1
+ """
2
+ Comandos do CLI VectorGov.
3
+ """
4
+
5
+ from . import auth, search, ask, feedback, docs, config
6
+
7
+ __all__ = ["auth", "search", "ask", "feedback", "docs", "config"]
@@ -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,8 @@
1
+ """
2
+ Utilitários do CLI VectorGov.
3
+ """
4
+
5
+ from .config import ConfigManager
6
+ from .output import OutputFormat, format_search_results
7
+
8
+ __all__ = ["ConfigManager", "OutputFormat", "format_search_results"]
@@ -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
+ [![PyPI version](https://badge.fury.io/py/vectorgov-cli.svg)](https://badge.fury.io/py/vectorgov-cli)
59
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ vectorgov = vectorgov.cli.main:main