laminate-cli 0.1.2__tar.gz → 0.1.4__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: laminate-cli
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Generate release-ready changelogs from git history using a local LLM
5
5
  Author-email: Apleut <me@apleut.dev>
6
6
  License-Expression: MIT
@@ -20,6 +20,7 @@ Requires-Dist: llama-cpp-python
20
20
  Requires-Dist: pydantic
21
21
  Requires-Dist: typer
22
22
  Requires-Dist: rich
23
+ Requires-Dist: platformdirs
23
24
  Dynamic: license-file
24
25
 
25
26
  <div style="text-align: center;">
@@ -97,25 +98,35 @@ pip install llama-cpp-python --extra-index-url https://abetlen.github.io/llama-c
97
98
  Then install Laminate:
98
99
 
99
100
  ```bash
100
- pip install .
101
+ pip install laminate-cli
101
102
  ```
102
103
 
103
104
  ## Model
104
105
 
105
106
  Laminate runs a **local GGUF model** using [`llama-cpp-python`](https://github.com/abetlen/llama-cpp-python).
106
107
 
107
- Place exactly one `.gguf` model file in:
108
+ [Phi-4-mini-instruct](https://huggingface.co/unsloth/Phi-4-mini-instruct-GGUF) is a good pick, and is the model used for Laminate's development.
108
109
 
109
- ```text
110
- models/
111
- └── your-model.gguf
112
- ```
110
+ Laminate looks for exactly one `.gguf` file in two places, in this order:
113
111
 
114
- [Phi-4-mini-instruct](https://huggingface.co/unsloth/Phi-4-mini-instruct-GGUF) is a good pick, and is the model used for Laminate's development.
112
+ 1. **A `models/` folder in your current directory**, which the recommended location if you're running Laminate from a cloned repo:
113
+
114
+ ```text
115
+ models/
116
+ └── your-model.gguf
117
+ ```
118
+
119
+ 2. **Your OS's standard application data folder**, under `Laminate/models/`, used automatically if no local `models/` folder is found. This is the normal location if you installed via `pip install laminate-cli`:
120
+
121
+ | OS | Location |
122
+ |---|---|
123
+ | Windows | `%LOCALAPPDATA%\Apleut\Laminate\models\` |
124
+ | macOS | `~/Library/Application Support/Laminate/models/` |
125
+ | Linux | `~/.local/share/Laminate/models/` |
115
126
 
116
- Laminate automatically finds and loads the model when it runs.
127
+ Create the folder if it doesn't already exist, and place your `.gguf` file inside.
117
128
 
118
- If the `models/` directory does not exist, or contains zero or multiple `.gguf` files, Laminate will stop and explain what needs to be fixed.
129
+ If Laminate can't find a model, or finds more than one `.gguf` file in whichever folder it checks, it will stop and tell you exactly which locations it looked in and what to fix.
119
130
 
120
131
  The model is intentionally kept separate from the package because GGUF models can be large and have different licensing requirements.
121
132
 
@@ -73,25 +73,35 @@ pip install llama-cpp-python --extra-index-url https://abetlen.github.io/llama-c
73
73
  Then install Laminate:
74
74
 
75
75
  ```bash
76
- pip install .
76
+ pip install laminate-cli
77
77
  ```
78
78
 
79
79
  ## Model
80
80
 
81
81
  Laminate runs a **local GGUF model** using [`llama-cpp-python`](https://github.com/abetlen/llama-cpp-python).
82
82
 
83
- Place exactly one `.gguf` model file in:
83
+ [Phi-4-mini-instruct](https://huggingface.co/unsloth/Phi-4-mini-instruct-GGUF) is a good pick, and is the model used for Laminate's development.
84
84
 
85
- ```text
86
- models/
87
- └── your-model.gguf
88
- ```
85
+ Laminate looks for exactly one `.gguf` file in two places, in this order:
89
86
 
90
- [Phi-4-mini-instruct](https://huggingface.co/unsloth/Phi-4-mini-instruct-GGUF) is a good pick, and is the model used for Laminate's development.
87
+ 1. **A `models/` folder in your current directory**, which the recommended location if you're running Laminate from a cloned repo:
88
+
89
+ ```text
90
+ models/
91
+ └── your-model.gguf
92
+ ```
93
+
94
+ 2. **Your OS's standard application data folder**, under `Laminate/models/`, used automatically if no local `models/` folder is found. This is the normal location if you installed via `pip install laminate-cli`:
95
+
96
+ | OS | Location |
97
+ |---|---|
98
+ | Windows | `%LOCALAPPDATA%\Apleut\Laminate\models\` |
99
+ | macOS | `~/Library/Application Support/Laminate/models/` |
100
+ | Linux | `~/.local/share/Laminate/models/` |
91
101
 
92
- Laminate automatically finds and loads the model when it runs.
102
+ Create the folder if it doesn't already exist, and place your `.gguf` file inside.
93
103
 
94
- If the `models/` directory does not exist, or contains zero or multiple `.gguf` files, Laminate will stop and explain what needs to be fixed.
104
+ If Laminate can't find a model, or finds more than one `.gguf` file in whichever folder it checks, it will stop and tell you exactly which locations it looked in and what to fix.
95
105
 
96
106
  The model is intentionally kept separate from the package because GGUF models can be large and have different licensing requirements.
97
107
 
@@ -287,4 +297,4 @@ For changes to Laminate itself, pull requests are welcome.
287
297
 
288
298
  ## License
289
299
 
290
- License information will be added before the first stable release.
300
+ License information will be added before the first stable release.
@@ -1,6 +1,7 @@
1
1
  import typer
2
2
 
3
3
  from concurrent.futures import ThreadPoolExecutor
4
+ from importlib.metadata import version as get_version, PackageNotFoundError
4
5
 
5
6
  import sys
6
7
 
@@ -17,6 +18,17 @@ app = typer.Typer(add_completion=False)
17
18
  console = Console()
18
19
 
19
20
 
21
+ def _version_callback(value: bool):
22
+ if not value:
23
+ return
24
+ try:
25
+ v = get_version("laminate-cli")
26
+ except PackageNotFoundError:
27
+ v = "unknown (not installed as a package)"
28
+ typer.echo(f"laminate {v}")
29
+ raise typer.Exit()
30
+
31
+
20
32
  @app.command()
21
33
  def generate(
22
34
  repo: str = typer.Option(".", help="Path to the git repository."),
@@ -26,6 +38,13 @@ def generate(
26
38
  output: str = typer.Option("CHANGELOG.md", help="Path to write the generated changelog to."),
27
39
  batch_size: int = typer.Option(15, "--batch-size", help="Number of commits sent to the LLM per batch."),
28
40
  release: str = typer.Option(None, "--release", help="Version number for this release, e.g. 1.1.0. If omitted, the changelog is headed [Unreleased]."),
41
+ version: bool = typer.Option(
42
+ False,
43
+ "--version",
44
+ callback=_version_callback,
45
+ is_eager=True,
46
+ help="Show Laminate's version and exit.",
47
+ ),
29
48
  ):
30
49
  if repo != ".":
31
50
  typer.echo(f"Reading commits from '{repo}'...")
@@ -1,9 +1,13 @@
1
1
  from pathlib import Path
2
2
  from llama_cpp import Llama
3
+ from platformdirs import user_data_dir
3
4
 
4
- MODELS_DIR = Path(__file__).resolve().parent.parent / "models"
5
+ _CANDIDATE_DIRS = [
6
+ Path.cwd() / "models",
7
+ Path(user_data_dir("Laminate", "Apleut")) / "models",
8
+ ]
5
9
 
6
- DEFAULT_N_CTX = 4096
10
+ DEFAULT_N_CTX = 4096
7
11
  _llm: Llama | None = None
8
12
 
9
13
 
@@ -12,29 +16,33 @@ class LLMError(Exception):
12
16
 
13
17
 
14
18
  def _find_model_file() -> Path:
15
- if not MODELS_DIR.exists():
16
- raise LLMError(
17
- f"Models folder not found at {MODELS_DIR}. Create it and "
18
- "place a .gguf model file inside (see README for a "
19
- "recommended model and download link)."
20
- )
21
-
22
- gguf_files = list(MODELS_DIR.glob("*.gguf"))
23
-
24
- if not gguf_files:
25
- raise LLMError(
26
- f"No .gguf model file found in {MODELS_DIR}. Download a "
27
- "compatible model (see README) and place it in that folder."
28
- )
29
-
30
- if len(gguf_files) > 1:
31
- names = ", ".join(f.name for f in gguf_files)
32
- raise LLMError(
33
- f"Multiple .gguf files found in {MODELS_DIR} ({names}) - "
34
- "keep only one so Laminate knows which to load."
35
- )
36
-
37
- return gguf_files[0]
19
+ checked = []
20
+
21
+ for candidate_dir in _CANDIDATE_DIRS:
22
+ checked.append(str(candidate_dir))
23
+
24
+ if not candidate_dir.exists():
25
+ continue
26
+
27
+ gguf_files = list(candidate_dir.glob("*.gguf"))
28
+
29
+ if len(gguf_files) == 1:
30
+ return gguf_files[0]
31
+
32
+ if len(gguf_files) > 1:
33
+ names = ", ".join(f.name for f in gguf_files)
34
+ raise LLMError(
35
+ f"Multiple .gguf files found in {candidate_dir} ({names}) - "
36
+ "keep only one so Laminate knows which to load."
37
+ )
38
+
39
+ checked_str = "\n - ".join(checked)
40
+ raise LLMError(
41
+ "No .gguf model file found. Laminate checked:\n - "
42
+ f"{checked_str}\n"
43
+ "Download a compatible model (see README) and place it in one "
44
+ "of those folders (create the folder if it doesn't exist)."
45
+ )
38
46
 
39
47
 
40
48
  def get_llm(n_ctx: int = DEFAULT_N_CTX) -> Llama:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: laminate-cli
3
- Version: 0.1.2
3
+ Version: 0.1.4
4
4
  Summary: Generate release-ready changelogs from git history using a local LLM
5
5
  Author-email: Apleut <me@apleut.dev>
6
6
  License-Expression: MIT
@@ -20,6 +20,7 @@ Requires-Dist: llama-cpp-python
20
20
  Requires-Dist: pydantic
21
21
  Requires-Dist: typer
22
22
  Requires-Dist: rich
23
+ Requires-Dist: platformdirs
23
24
  Dynamic: license-file
24
25
 
25
26
  <div style="text-align: center;">
@@ -97,25 +98,35 @@ pip install llama-cpp-python --extra-index-url https://abetlen.github.io/llama-c
97
98
  Then install Laminate:
98
99
 
99
100
  ```bash
100
- pip install .
101
+ pip install laminate-cli
101
102
  ```
102
103
 
103
104
  ## Model
104
105
 
105
106
  Laminate runs a **local GGUF model** using [`llama-cpp-python`](https://github.com/abetlen/llama-cpp-python).
106
107
 
107
- Place exactly one `.gguf` model file in:
108
+ [Phi-4-mini-instruct](https://huggingface.co/unsloth/Phi-4-mini-instruct-GGUF) is a good pick, and is the model used for Laminate's development.
108
109
 
109
- ```text
110
- models/
111
- └── your-model.gguf
112
- ```
110
+ Laminate looks for exactly one `.gguf` file in two places, in this order:
113
111
 
114
- [Phi-4-mini-instruct](https://huggingface.co/unsloth/Phi-4-mini-instruct-GGUF) is a good pick, and is the model used for Laminate's development.
112
+ 1. **A `models/` folder in your current directory**, which the recommended location if you're running Laminate from a cloned repo:
113
+
114
+ ```text
115
+ models/
116
+ └── your-model.gguf
117
+ ```
118
+
119
+ 2. **Your OS's standard application data folder**, under `Laminate/models/`, used automatically if no local `models/` folder is found. This is the normal location if you installed via `pip install laminate-cli`:
120
+
121
+ | OS | Location |
122
+ |---|---|
123
+ | Windows | `%LOCALAPPDATA%\Apleut\Laminate\models\` |
124
+ | macOS | `~/Library/Application Support/Laminate/models/` |
125
+ | Linux | `~/.local/share/Laminate/models/` |
115
126
 
116
- Laminate automatically finds and loads the model when it runs.
127
+ Create the folder if it doesn't already exist, and place your `.gguf` file inside.
117
128
 
118
- If the `models/` directory does not exist, or contains zero or multiple `.gguf` files, Laminate will stop and explain what needs to be fixed.
129
+ If Laminate can't find a model, or finds more than one `.gguf` file in whichever folder it checks, it will stop and tell you exactly which locations it looked in and what to fix.
119
130
 
120
131
  The model is intentionally kept separate from the package because GGUF models can be large and have different licensing requirements.
121
132
 
@@ -2,3 +2,4 @@ llama-cpp-python
2
2
  pydantic
3
3
  typer
4
4
  rich
5
+ platformdirs
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "laminate-cli"
3
- version = "0.1.2"
3
+ version = "0.1.4"
4
4
  authors = [
5
5
  { name="Apleut", email="me@apleut.dev" },
6
6
  ]
@@ -22,6 +22,7 @@ dependencies = [
22
22
  "pydantic",
23
23
  "typer",
24
24
  "rich",
25
+ "platformdirs",
25
26
  ]
26
27
 
27
28
  license = "MIT"
@@ -42,4 +43,4 @@ requires = ["setuptools>=68"]
42
43
  build-backend = "setuptools.build_meta"
43
44
 
44
45
  [tool.setuptools.packages.find]
45
- include = ["laminate*"]
46
+ include = ["laminate*"]
File without changes
File without changes