ailtir-cli 1.0.1__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.
- ailtir_cli/__init__.py +0 -0
- ailtir_cli/app.py +3 -0
- ailtir_cli/commands/__init__.py +5 -0
- ailtir_cli/commands/analyse.py +35 -0
- ailtir_cli/commands/chat.py +37 -0
- ailtir_cli/commands/list_kbs.py +41 -0
- ailtir_cli/commands/upload.py +66 -0
- ailtir_cli/commands/version.py +13 -0
- ailtir_cli/config.py +14 -0
- ailtir_cli/main.py +7 -0
- ailtir_cli-1.0.1.dist-info/METADATA +52 -0
- ailtir_cli-1.0.1.dist-info/RECORD +16 -0
- ailtir_cli-1.0.1.dist-info/WHEEL +5 -0
- ailtir_cli-1.0.1.dist-info/entry_points.txt +2 -0
- ailtir_cli-1.0.1.dist-info/licenses/LICENSE +20 -0
- ailtir_cli-1.0.1.dist-info/top_level.txt +1 -0
ailtir_cli/__init__.py
ADDED
|
File without changes
|
ailtir_cli/app.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import httpx
|
|
2
|
+
import structlog
|
|
3
|
+
import typer
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
|
|
6
|
+
from ailtir_cli.app import app
|
|
7
|
+
from ailtir_cli.config import settings
|
|
8
|
+
|
|
9
|
+
_log = structlog.get_logger(__name__)
|
|
10
|
+
_console = Console()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@app.command()
|
|
14
|
+
def analyse(kb_id: str = typer.Argument(..., help="The knowledge base ID to analyse.")) -> None:
|
|
15
|
+
"""Trigger analysis and Knowledge Base creation for an uploaded ZIP."""
|
|
16
|
+
_console.print(f"Starting analysis for kb_id: [bold]{kb_id}[/bold]...")
|
|
17
|
+
|
|
18
|
+
token = settings.ailtir_cli_secret
|
|
19
|
+
|
|
20
|
+
with httpx.Client(base_url=settings.cli_api_url, timeout=30.0) as http:
|
|
21
|
+
try:
|
|
22
|
+
resp = http.post(
|
|
23
|
+
f"/kb/{kb_id}/analyse",
|
|
24
|
+
headers={"Authorization": f"Bearer {token}"},
|
|
25
|
+
)
|
|
26
|
+
resp.raise_for_status()
|
|
27
|
+
except httpx.HTTPStatusError as exc:
|
|
28
|
+
_console.print(f"[red]Error: {exc.response.status_code}[/red]")
|
|
29
|
+
raise typer.Exit(1) from exc
|
|
30
|
+
|
|
31
|
+
_log.info("analyse.started", kb_id=kb_id)
|
|
32
|
+
_console.print(
|
|
33
|
+
f"[green]Analysis started[/green] for kb_id: [bold]{kb_id}[/bold]. "
|
|
34
|
+
"This typically takes a few minutes. Use [bold]ailtir list[/bold] to check status."
|
|
35
|
+
)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import httpx
|
|
2
|
+
import structlog
|
|
3
|
+
import typer
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
|
|
6
|
+
from ailtir_cli.app import app
|
|
7
|
+
from ailtir_cli.config import settings
|
|
8
|
+
|
|
9
|
+
_log = structlog.get_logger(__name__)
|
|
10
|
+
_console = Console()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@app.command()
|
|
14
|
+
def chat(
|
|
15
|
+
kb_id: str = typer.Argument(..., help="The knowledge base ID to query."),
|
|
16
|
+
question: str = typer.Argument(..., help="Your natural-language question."),
|
|
17
|
+
) -> None:
|
|
18
|
+
"""Ask a question answered using documents in a knowledge base (RAG)."""
|
|
19
|
+
_console.print(f"Querying kb_id: [bold]{kb_id}[/bold]...")
|
|
20
|
+
|
|
21
|
+
token = settings.ailtir_cli_secret
|
|
22
|
+
|
|
23
|
+
with httpx.Client(base_url=settings.cli_api_url, timeout=60.0) as http:
|
|
24
|
+
try:
|
|
25
|
+
resp = http.post(
|
|
26
|
+
f"/kb/{kb_id}/chat",
|
|
27
|
+
json={"question": question},
|
|
28
|
+
headers={"Authorization": f"Bearer {token}"},
|
|
29
|
+
)
|
|
30
|
+
resp.raise_for_status()
|
|
31
|
+
except httpx.HTTPStatusError as exc:
|
|
32
|
+
_console.print(f"[red]Error: {exc.response.status_code}[/red]")
|
|
33
|
+
raise typer.Exit(1) from exc
|
|
34
|
+
|
|
35
|
+
data = resp.json()
|
|
36
|
+
_log.info("chat.answered", kb_id=kb_id)
|
|
37
|
+
_console.print(data.get("answer", "No answer returned."))
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import httpx
|
|
2
|
+
import structlog
|
|
3
|
+
import typer
|
|
4
|
+
from rich.console import Console
|
|
5
|
+
from rich.table import Table
|
|
6
|
+
|
|
7
|
+
from ailtir_cli.app import app
|
|
8
|
+
from ailtir_cli.config import settings
|
|
9
|
+
|
|
10
|
+
_log = structlog.get_logger(__name__)
|
|
11
|
+
_console = Console()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@app.command(name="list")
|
|
15
|
+
def list_kbs() -> None:
|
|
16
|
+
"""List all knowledge bases in your Ailtir account."""
|
|
17
|
+
token = settings.ailtir_cli_secret
|
|
18
|
+
|
|
19
|
+
with httpx.Client(base_url=settings.cli_api_url, timeout=30.0) as http:
|
|
20
|
+
try:
|
|
21
|
+
resp = http.get("/kb", headers={"Authorization": f"Bearer {token}"})
|
|
22
|
+
resp.raise_for_status()
|
|
23
|
+
except httpx.HTTPStatusError as exc:
|
|
24
|
+
_console.print(f"[red]Error: {exc.response.status_code}[/red]")
|
|
25
|
+
raise typer.Exit(1) from exc
|
|
26
|
+
|
|
27
|
+
kbs = resp.json()
|
|
28
|
+
if not kbs:
|
|
29
|
+
_console.print("No knowledge bases found.")
|
|
30
|
+
return
|
|
31
|
+
|
|
32
|
+
table = Table(title="Knowledge Bases")
|
|
33
|
+
table.add_column("ID", style="dim")
|
|
34
|
+
table.add_column("Name")
|
|
35
|
+
table.add_column("Status")
|
|
36
|
+
|
|
37
|
+
for kb in kbs:
|
|
38
|
+
table.add_row(str(kb.get("id", "")), str(kb.get("name", "")), str(kb.get("status", "")))
|
|
39
|
+
|
|
40
|
+
_log.info("list_kbs.returned", count=len(kbs))
|
|
41
|
+
_console.print(table)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import pathlib
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
import structlog
|
|
5
|
+
import typer
|
|
6
|
+
from rich.console import Console
|
|
7
|
+
|
|
8
|
+
from ailtir_cli.app import app
|
|
9
|
+
from ailtir_cli.config import settings
|
|
10
|
+
|
|
11
|
+
_log = structlog.get_logger(__name__)
|
|
12
|
+
_console = Console()
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@app.command()
|
|
16
|
+
def upload(
|
|
17
|
+
file_path: str = typer.Argument(..., help="Absolute path to the ZIP file to upload."),
|
|
18
|
+
) -> None:
|
|
19
|
+
"""Upload a ZIP archive of documents to Ailtir storage."""
|
|
20
|
+
path = pathlib.Path(file_path)
|
|
21
|
+
if not path.is_absolute():
|
|
22
|
+
_console.print("[red]Error: file_path must be an absolute path.[/red]")
|
|
23
|
+
raise typer.Exit(1)
|
|
24
|
+
if not path.exists():
|
|
25
|
+
_console.print(f"[red]Error: file not found: {file_path}[/red]")
|
|
26
|
+
raise typer.Exit(1)
|
|
27
|
+
if not path.is_file():
|
|
28
|
+
_console.print(f"[red]Error: not a file: {file_path}[/red]")
|
|
29
|
+
raise typer.Exit(1)
|
|
30
|
+
|
|
31
|
+
_console.print(f"Uploading [bold]{path.name}[/bold]...")
|
|
32
|
+
|
|
33
|
+
content = path.read_bytes()
|
|
34
|
+
token = settings.ailtir_cli_secret
|
|
35
|
+
|
|
36
|
+
with httpx.Client(base_url=settings.cli_api_url, timeout=30.0) as http:
|
|
37
|
+
try:
|
|
38
|
+
reg_resp = http.post(
|
|
39
|
+
"/kb",
|
|
40
|
+
json={"file_name": path.name},
|
|
41
|
+
headers={"Authorization": f"Bearer {token}"},
|
|
42
|
+
)
|
|
43
|
+
reg_resp.raise_for_status()
|
|
44
|
+
except httpx.HTTPStatusError as exc:
|
|
45
|
+
_console.print(f"[red]Error registering KB: {exc.response.status_code}[/red]")
|
|
46
|
+
raise typer.Exit(1) from exc
|
|
47
|
+
|
|
48
|
+
reg = reg_resp.json()
|
|
49
|
+
kb_id: str = reg["kb_id"]
|
|
50
|
+
upload_url: str = reg["upload_url"]
|
|
51
|
+
|
|
52
|
+
# PUT directly to S3 via the presigned URL — no auth header, S3 auth is in the URL.
|
|
53
|
+
with httpx.Client(timeout=None) as s3_client: # noqa: S113
|
|
54
|
+
try:
|
|
55
|
+
s3_resp = s3_client.put(
|
|
56
|
+
upload_url,
|
|
57
|
+
content=content,
|
|
58
|
+
headers={"Content-Type": "application/zip"},
|
|
59
|
+
)
|
|
60
|
+
s3_resp.raise_for_status()
|
|
61
|
+
except httpx.HTTPStatusError as exc:
|
|
62
|
+
_console.print(f"[red]Error uploading to S3: {exc.response.status_code}[/red]")
|
|
63
|
+
raise typer.Exit(1) from exc
|
|
64
|
+
|
|
65
|
+
_log.info("upload.done", kb_id=kb_id)
|
|
66
|
+
_console.print(f"[green]Upload complete.[/green] kb_id: [bold]{kb_id}[/bold]")
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from importlib.metadata import version
|
|
2
|
+
|
|
3
|
+
from rich.console import Console
|
|
4
|
+
|
|
5
|
+
from ailtir_cli.app import app
|
|
6
|
+
|
|
7
|
+
_console = Console()
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@app.command(name="version")
|
|
11
|
+
def get_version() -> None:
|
|
12
|
+
"""Print the version of the ailtir CLI."""
|
|
13
|
+
_console.print(version("ailtir-cli"))
|
ailtir_cli/config.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from pydantic import Field
|
|
2
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Settings(BaseSettings):
|
|
6
|
+
ailtir_cli_secret: str = Field(..., min_length=1)
|
|
7
|
+
cli_api_url: str = Field(default="https://app.ailtir.ai/cli-api")
|
|
8
|
+
log_format: str = Field(default="console")
|
|
9
|
+
log_level: str = Field(default="INFO")
|
|
10
|
+
|
|
11
|
+
model_config = SettingsConfigDict(env_file=".env", extra="ignore")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
settings = Settings() # type: ignore[call-arg]
|
ailtir_cli/main.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ailtir-cli
|
|
3
|
+
Version: 1.0.1
|
|
4
|
+
Summary: Ailtir CLI — upload, analyse, list, and chat with knowledge bases
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://ailtir.ai
|
|
7
|
+
Project-URL: Repository, https://github.com/Team-Ailtir/ailtir-cli
|
|
8
|
+
Keywords: cli,ailtir,knowledge-base,rag
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
10
|
+
Requires-Python: >=3.13
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: httpx>=0.28.1
|
|
14
|
+
Requires-Dist: pydantic-settings>=2.10.1
|
|
15
|
+
Requires-Dist: rich>=14.0.0
|
|
16
|
+
Requires-Dist: structlog>=25.4.0
|
|
17
|
+
Requires-Dist: typer>=0.15.0
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# ailtir-cli
|
|
21
|
+
|
|
22
|
+
A CLI tool for interacting with Ailtir knowledge bases. Upload documents, trigger analysis, and query your knowledge bases from the terminal.
|
|
23
|
+
|
|
24
|
+
## What is ailtir-cli?
|
|
25
|
+
|
|
26
|
+
The Ailtir CLI provides commands for:
|
|
27
|
+
- **upload**: Upload a ZIP archive of documents to Ailtir storage
|
|
28
|
+
- **analyse**: Trigger knowledge base creation and analysis
|
|
29
|
+
- **list**: List all knowledge bases in your account
|
|
30
|
+
- **chat**: Ask questions answered using documents in a knowledge base (RAG)
|
|
31
|
+
- **version**: Print the CLI version
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
uv tool install ailtir-cli
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
See [docs/index.html](./docs/index.html) for the full customer-facing installation guide.
|
|
40
|
+
|
|
41
|
+
## Documentation
|
|
42
|
+
|
|
43
|
+
- See [docs/index.html](./docs/index.html) for installation and usage guide (published at GitHub Pages)
|
|
44
|
+
- See [CLAUDE.md][] for architecture and implementation details
|
|
45
|
+
- See [CONTRIBUTING.md][] for development workflow and how to contribute
|
|
46
|
+
|
|
47
|
+
## License
|
|
48
|
+
|
|
49
|
+
MIT
|
|
50
|
+
|
|
51
|
+
[CLAUDE.md]: ./CLAUDE.md
|
|
52
|
+
[CONTRIBUTING.md]: ./CONTRIBUTING.md
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
ailtir_cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
ailtir_cli/app.py,sha256=o4Mn3tRqtJmI9_DGx-pbhrr_Ouwv38XC80Bk6Zx3Buo,92
|
|
3
|
+
ailtir_cli/config.py,sha256=3zjI7rKNvaEZwAYnEKq6bUxEIYnAzXwHm3XKVFs4kBk,458
|
|
4
|
+
ailtir_cli/main.py,sha256=BeRfiMiNLMqJxAUxods96vZF2e4uo8sNFNhzndOhfCk,182
|
|
5
|
+
ailtir_cli/commands/__init__.py,sha256=Bs1u1rQqedRMWSqof928eXiLhSlGbHt_s3BQRmZ0RY8,242
|
|
6
|
+
ailtir_cli/commands/analyse.py,sha256=HvWXS-rk6q89j-w4Fp8kiud42i_hPrgh1PD0qK316fw,1189
|
|
7
|
+
ailtir_cli/commands/chat.py,sha256=hRPYcsAfCDTkSNzWkQW0lPCAvnYEyvWwDWiD_1IZJrA,1190
|
|
8
|
+
ailtir_cli/commands/list_kbs.py,sha256=5xgjTK6euwTRLxxYrWR3aHW9gu4gnnYprPNL64FKD5A,1200
|
|
9
|
+
ailtir_cli/commands/upload.py,sha256=HD4Fc0STI43-Ml3OROlWkXloE3jT34njZ-z_ok7nuP0,2244
|
|
10
|
+
ailtir_cli/commands/version.py,sha256=94-M7A_SKaW_vSVa3s9_xVeonlF06TsrfHnivLPDk3o,274
|
|
11
|
+
ailtir_cli-1.0.1.dist-info/licenses/LICENSE,sha256=qAMoBe2jj2QIBIKUzf93gZ-JBkxh03K_lru8hrSyCHw,922
|
|
12
|
+
ailtir_cli-1.0.1.dist-info/METADATA,sha256=m1KugtxP1RgETnRSbNgVQZuWXgMqoe3PMEq2jqVh55E,1621
|
|
13
|
+
ailtir_cli-1.0.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
14
|
+
ailtir_cli-1.0.1.dist-info/entry_points.txt,sha256=y-rMue-jrKX0h1AdnJPU15mfTOZjpVHYD9T9CjM4Qs0,47
|
|
15
|
+
ailtir_cli-1.0.1.dist-info/top_level.txt,sha256=4w455lK_b-sAdT_FA4bxWam9WZj-YMVSQaW6Ds7_77I,11
|
|
16
|
+
ailtir_cli-1.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2025 Ailtir
|
|
2
|
+
|
|
3
|
+
All rights reserved.
|
|
4
|
+
|
|
5
|
+
This software and associated documentation files (the "Software") are proprietary
|
|
6
|
+
and confidential to Ailtir.
|
|
7
|
+
|
|
8
|
+
Permission is hereby granted to employees and authorized contractors of Ailtir
|
|
9
|
+
to use, copy, and modify the Software for internal business purposes only.
|
|
10
|
+
|
|
11
|
+
Redistribution, publication, or disclosure of the Software to third parties
|
|
12
|
+
is strictly prohibited without prior written permission from Ailtir.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ailtir_cli
|