llamapass 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,15 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.so
4
+ db.sqlite3
5
+ .env
6
+ staticfiles/
7
+ *.egg-info/
8
+ dist/
9
+ build/
10
+ .venv/
11
+ venv/
12
+ ollama-tunnel.sh
13
+ /*.png
14
+ !static/*.png
15
+ !screens/*.png
@@ -0,0 +1,33 @@
1
+ Metadata-Version: 2.4
2
+ Name: llamapass
3
+ Version: 0.1.0
4
+ Summary: CLI client for LlamaPass - Ollama gateway with authentication
5
+ License-Expression: MIT
6
+ Requires-Python: >=3.10
7
+ Requires-Dist: httpx>=0.27
8
+ Description-Content-Type: text/markdown
9
+
10
+ # LlamaPass CLI
11
+
12
+ CLI client for [LlamaPass](https://llamapass.org) - an Ollama gateway with authentication.
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ pip install llamapass
18
+ ```
19
+
20
+ ## Setup
21
+
22
+ ```bash
23
+ llamapass config set-url https://llamapass.org
24
+ llamapass config set-key oah_your_api_key
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ```bash
30
+ llamapass run gemma3 # interactive chat
31
+ llamapass list # list available models
32
+ llamapass config show # show current config
33
+ ```
@@ -0,0 +1,24 @@
1
+ # LlamaPass CLI
2
+
3
+ CLI client for [LlamaPass](https://llamapass.org) - an Ollama gateway with authentication.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install llamapass
9
+ ```
10
+
11
+ ## Setup
12
+
13
+ ```bash
14
+ llamapass config set-url https://llamapass.org
15
+ llamapass config set-key oah_your_api_key
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```bash
21
+ llamapass run gemma3 # interactive chat
22
+ llamapass list # list available models
23
+ llamapass config show # show current config
24
+ ```
@@ -0,0 +1 @@
1
+ __version__ = "0.1.0"
@@ -0,0 +1,3 @@
1
+ from llamapass_cli.cli import main
2
+
3
+ main()
@@ -0,0 +1,100 @@
1
+ import argparse
2
+ import sys
3
+
4
+ from llamapass_cli import __version__
5
+ from llamapass_cli.client import chat_stream, list_models
6
+ from llamapass_cli.config import get, load, set_value
7
+
8
+
9
+ def cmd_run(args):
10
+ model = args.model
11
+ messages = []
12
+ print(f"LlamaPass - {model} (type /bye to quit)\n")
13
+
14
+ while True:
15
+ try:
16
+ user_input = input(">>> ")
17
+ except (KeyboardInterrupt, EOFError):
18
+ print("\nBye!")
19
+ break
20
+
21
+ if user_input.strip().lower() in ("/bye", "/exit", "/quit"):
22
+ print("Bye!")
23
+ break
24
+
25
+ if not user_input.strip():
26
+ continue
27
+
28
+ messages.append({"role": "user", "content": user_input})
29
+ response = chat_stream(model, messages)
30
+ if response:
31
+ messages.append({"role": "assistant", "content": response})
32
+
33
+
34
+ def cmd_list(args):
35
+ list_models()
36
+
37
+
38
+ def cmd_config(args):
39
+ action = args.action
40
+
41
+ if action == "show":
42
+ cfg = load()
43
+ print(f" url: {cfg['url']}")
44
+ print(f" api_key: {cfg['api_key'][:10]}..." if cfg["api_key"] else " api_key: (not set)")
45
+
46
+ elif action == "set-url":
47
+ if not args.value:
48
+ print("Usage: llamapass config set-url <url>")
49
+ sys.exit(1)
50
+ set_value("url", args.value)
51
+ print(f"URL set to: {args.value}")
52
+
53
+ elif action == "set-key":
54
+ if not args.value:
55
+ print("Usage: llamapass config set-key <key>")
56
+ sys.exit(1)
57
+ set_value("api_key", args.value)
58
+ print(f"API key saved.")
59
+
60
+ else:
61
+ print(f"Unknown action: {action}")
62
+ print("Available: show, set-url, set-key")
63
+ sys.exit(1)
64
+
65
+
66
+ def main():
67
+ parser = argparse.ArgumentParser(
68
+ prog="llamapass",
69
+ description="CLI client for LlamaPass",
70
+ )
71
+ parser.add_argument("-v", "--version", action="version", version=f"%(prog)s {__version__}")
72
+
73
+ subparsers = parser.add_subparsers(dest="command")
74
+
75
+ # run
76
+ run_parser = subparsers.add_parser("run", help="Chat with a model")
77
+ run_parser.add_argument("model", help="Model name (e.g. gemma3)")
78
+
79
+ # list
80
+ subparsers.add_parser("list", help="List available models")
81
+ subparsers.add_parser("ls", help="List available models")
82
+
83
+ # config
84
+ config_parser = subparsers.add_parser("config", help="Manage configuration")
85
+ config_parser.add_argument("action", help="show | set-url | set-key")
86
+ config_parser.add_argument("value", nargs="?", help="Value to set")
87
+
88
+ args = parser.parse_args()
89
+
90
+ if args.command is None:
91
+ parser.print_help()
92
+ sys.exit(0)
93
+
94
+ commands = {
95
+ "run": cmd_run,
96
+ "list": cmd_list,
97
+ "ls": cmd_list,
98
+ "config": cmd_config,
99
+ }
100
+ commands[args.command](args)
@@ -0,0 +1,99 @@
1
+ import json
2
+ import sys
3
+
4
+ import httpx
5
+
6
+ from llamapass_cli.config import load
7
+
8
+
9
+ def _get_client():
10
+ cfg = load()
11
+ url = cfg["url"].rstrip("/")
12
+ api_key = cfg.get("api_key", "")
13
+ if not api_key:
14
+ print("Error: no API key configured. Run: llamapass config set-key <key>")
15
+ sys.exit(1)
16
+ headers = {
17
+ "Authorization": f"Bearer {api_key}",
18
+ "Content-Type": "application/json",
19
+ }
20
+ return url, headers
21
+
22
+
23
+ def list_models():
24
+ url, headers = _get_client()
25
+ try:
26
+ resp = httpx.get(f"{url}/ollama/api/tags", headers=headers, timeout=30)
27
+ resp.raise_for_status()
28
+ data = resp.json()
29
+ models = data.get("models", [])
30
+ if not models:
31
+ print("No models available.")
32
+ return
33
+ print(f"{'NAME':<40} {'SIZE':<12} {'MODIFIED'}")
34
+ for m in models:
35
+ name = m.get("name", "?")
36
+ size_gb = m.get("size", 0) / (1024**3)
37
+ modified = m.get("modified_at", "?")[:19]
38
+ print(f"{name:<40} {size_gb:<12.1f}GB {modified}")
39
+ except httpx.ConnectError:
40
+ print(f"Error: cannot connect to {url}")
41
+ sys.exit(1)
42
+ except httpx.HTTPStatusError as e:
43
+ _handle_http_error(e.response)
44
+
45
+
46
+ def chat_stream(model, messages):
47
+ url, headers = _get_client()
48
+ payload = {
49
+ "model": model,
50
+ "messages": messages,
51
+ "stream": True,
52
+ }
53
+ try:
54
+ with httpx.stream(
55
+ "POST",
56
+ f"{url}/ollama/api/chat",
57
+ json=payload,
58
+ headers=headers,
59
+ timeout=None,
60
+ ) as resp:
61
+ if resp.status_code != 200:
62
+ _handle_http_error(resp)
63
+ return ""
64
+ full_response = []
65
+ for line in resp.iter_lines():
66
+ if not line:
67
+ continue
68
+ try:
69
+ data = json.loads(line)
70
+ content = data.get("message", {}).get("content", "")
71
+ if content:
72
+ print(content, end="", flush=True)
73
+ full_response.append(content)
74
+ if data.get("done"):
75
+ break
76
+ except json.JSONDecodeError:
77
+ continue
78
+ print()
79
+ return "".join(full_response)
80
+ except httpx.ConnectError:
81
+ print(f"\nError: cannot connect to {url}")
82
+ sys.exit(1)
83
+
84
+
85
+ def _handle_http_error(resp):
86
+ try:
87
+ data = resp.json()
88
+ error = data.get("error", resp.status_code)
89
+ except Exception:
90
+ error = resp.status_code
91
+
92
+ messages = {
93
+ 401: "Invalid API key. Run: llamapass config set-key <key>",
94
+ 403: f"Access denied: {error}",
95
+ 429: "Rate limited. Try again later.",
96
+ 502: "LlamaPass server cannot reach upstream Ollama.",
97
+ }
98
+ print(f"Error: {messages.get(resp.status_code, f'HTTP {resp.status_code}: {error}')}")
99
+ sys.exit(1)
@@ -0,0 +1,33 @@
1
+ import json
2
+ from pathlib import Path
3
+
4
+ CONFIG_DIR = Path.home() / ".config" / "llamapass"
5
+ CONFIG_FILE = CONFIG_DIR / "config.json"
6
+
7
+ DEFAULTS = {
8
+ "url": "https://llamapass.org",
9
+ "api_key": "",
10
+ }
11
+
12
+
13
+ def load():
14
+ if CONFIG_FILE.exists():
15
+ with open(CONFIG_FILE) as f:
16
+ return {**DEFAULTS, **json.load(f)}
17
+ return dict(DEFAULTS)
18
+
19
+
20
+ def save(cfg):
21
+ CONFIG_DIR.mkdir(parents=True, exist_ok=True)
22
+ with open(CONFIG_FILE, "w") as f:
23
+ json.dump(cfg, f, indent=2)
24
+
25
+
26
+ def get(key):
27
+ return load().get(key)
28
+
29
+
30
+ def set_value(key, value):
31
+ cfg = load()
32
+ cfg[key] = value
33
+ save(cfg)
@@ -0,0 +1,20 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "llamapass"
7
+ version = "0.1.0"
8
+ description = "CLI client for LlamaPass - Ollama gateway with authentication"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = "MIT"
12
+ dependencies = [
13
+ "httpx>=0.27",
14
+ ]
15
+
16
+ [tool.hatch.build.targets.wheel]
17
+ packages = ["llamapass_cli"]
18
+
19
+ [project.scripts]
20
+ llamapass = "llamapass_cli.cli:main"