diffron 0.1.4__tar.gz → 0.1.6__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.
Files changed (48) hide show
  1. {diffron-0.1.4/diffron.egg-info → diffron-0.1.6}/PKG-INFO +2 -2
  2. {diffron-0.1.4 → diffron-0.1.6}/README.md +1 -1
  3. {diffron-0.1.4 → diffron-0.1.6}/diffron/lemonade.py +4 -1
  4. {diffron-0.1.4 → diffron-0.1.6/diffron.egg-info}/PKG-INFO +2 -2
  5. {diffron-0.1.4 → diffron-0.1.6}/diffron.egg-info/SOURCES.txt +0 -3
  6. {diffron-0.1.4 → diffron-0.1.6}/diffron.egg-info/top_level.txt +0 -2
  7. {diffron-0.1.4 → diffron-0.1.6}/pyproject.toml +1 -1
  8. diffron-0.1.4/docs/LEMONADE_PORT_VERIFICATION_FIX.md +0 -105
  9. diffron-0.1.4/docs/LEMONADE_UNRESPONSIVE_FIX.md +0 -100
  10. diffron-0.1.4/docs/MODEL_NAME_CASE_FIX.md +0 -88
  11. {diffron-0.1.4 → diffron-0.1.6}/CHANGELOG.md +0 -0
  12. {diffron-0.1.4 → diffron-0.1.6}/LICENSE +0 -0
  13. {diffron-0.1.4 → diffron-0.1.6}/MANIFEST.in +0 -0
  14. {diffron-0.1.4 → diffron-0.1.6}/diffron/__init__.py +0 -0
  15. {diffron-0.1.4 → diffron-0.1.6}/diffron/__init__.pyi +0 -0
  16. {diffron-0.1.4 → diffron-0.1.6}/diffron/__main__.py +0 -0
  17. {diffron-0.1.4 → diffron-0.1.6}/diffron/cli.py +0 -0
  18. {diffron-0.1.4 → diffron-0.1.6}/diffron/cli.pyi +0 -0
  19. {diffron-0.1.4 → diffron-0.1.6}/diffron/client.py +0 -0
  20. {diffron-0.1.4 → diffron-0.1.6}/diffron/client.pyi +0 -0
  21. {diffron-0.1.4 → diffron-0.1.6}/diffron/commit_gen.py +0 -0
  22. {diffron-0.1.4 → diffron-0.1.6}/diffron/commit_gen.pyi +0 -0
  23. {diffron-0.1.4 → diffron-0.1.6}/diffron/git_hooks.py +0 -0
  24. {diffron-0.1.4 → diffron-0.1.6}/diffron/git_hooks.pyi +0 -0
  25. {diffron-0.1.4 → diffron-0.1.6}/diffron/hooks/aipr.py +0 -0
  26. {diffron-0.1.4 → diffron-0.1.6}/diffron/hooks/prepare-commit-msg +0 -0
  27. {diffron-0.1.4 → diffron-0.1.6}/diffron/hooks/prepare-commit-msg-global.py +0 -0
  28. {diffron-0.1.4 → diffron-0.1.6}/diffron/hooks/prepare-commit-msg.py +0 -0
  29. {diffron-0.1.4 → diffron-0.1.6}/diffron/lemonade.pyi +0 -0
  30. {diffron-0.1.4 → diffron-0.1.6}/diffron/models.py +0 -0
  31. {diffron-0.1.4 → diffron-0.1.6}/diffron/models.pyi +0 -0
  32. {diffron-0.1.4 → diffron-0.1.6}/diffron/pr_gen.py +0 -0
  33. {diffron-0.1.4 → diffron-0.1.6}/diffron/pr_gen.pyi +0 -0
  34. {diffron-0.1.4 → diffron-0.1.6}/diffron/py.typed +0 -0
  35. {diffron-0.1.4 → diffron-0.1.6}/diffron/utils.py +0 -0
  36. {diffron-0.1.4 → diffron-0.1.6}/diffron/utils.pyi +0 -0
  37. {diffron-0.1.4 → diffron-0.1.6}/diffron.egg-info/dependency_links.txt +0 -0
  38. {diffron-0.1.4 → diffron-0.1.6}/diffron.egg-info/entry_points.txt +0 -0
  39. {diffron-0.1.4 → diffron-0.1.6}/diffron.egg-info/requires.txt +0 -0
  40. {diffron-0.1.4 → diffron-0.1.6}/docs/HOOKS.md +0 -0
  41. {diffron-0.1.4 → diffron-0.1.6}/docs/SETUP.md +0 -0
  42. {diffron-0.1.4 → diffron-0.1.6}/docs/USAGE.md +0 -0
  43. {diffron-0.1.4 → diffron-0.1.6}/hooks/aipr.py +0 -0
  44. {diffron-0.1.4 → diffron-0.1.6}/hooks/prepare-commit-msg-global.py +0 -0
  45. {diffron-0.1.4 → diffron-0.1.6}/hooks/prepare-commit-msg.py +0 -0
  46. {diffron-0.1.4 → diffron-0.1.6}/requirements.txt +0 -0
  47. {diffron-0.1.4 → diffron-0.1.6}/setup.cfg +0 -0
  48. {diffron-0.1.4 → diffron-0.1.6}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: diffron
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Summary: Git commit message and PR description generator using Lemonade
5
5
  Home-page: https://github.com/diffron/diffron
6
6
  Author: Diffron Contributors
@@ -47,7 +47,7 @@ Git commit message and PR description generator using AMD Lemonade via lemonade-
47
47
 
48
48
  **Diffron is a production-ready reference implementation of the lemonade-python-sdk — submitted to the AMD Lemonade Developer Challenge 2026.**
49
49
 
50
- ![Version](https://img.shields.io/badge/version-0.1.3-blue)
50
+ ![Version](https://img.shields.io/badge/version-0.1.6-blue)
51
51
  ![Python](https://img.shields.io/badge/python-3.9+-blue)
52
52
  ![License](https://img.shields.io/badge/license-MIT-green)
53
53
  ![Platform](https://img.shields.io/badge/platform-Windows-lightgrey)
@@ -4,7 +4,7 @@ Git commit message and PR description generator using AMD Lemonade via lemonade-
4
4
 
5
5
  **Diffron is a production-ready reference implementation of the lemonade-python-sdk — submitted to the AMD Lemonade Developer Challenge 2026.**
6
6
 
7
- ![Version](https://img.shields.io/badge/version-0.1.3-blue)
7
+ ![Version](https://img.shields.io/badge/version-0.1.6-blue)
8
8
  ![Python](https://img.shields.io/badge/python-3.9+-blue)
9
9
  ![License](https://img.shields.io/badge/license-MIT-green)
10
10
  ![Platform](https://img.shields.io/badge/platform-Windows-lightgrey)
@@ -229,7 +229,10 @@ class LemonadeClient:
229
229
  )
230
230
  if new_port and new_port != self._port:
231
231
  self._port = new_port
232
- # Reinitialize client with new port
232
+ self.port = new_port # Update the port attribute
233
+ # Rebuild the base_url with the new port and the same host
234
+ self.base_url = f"http://{self.host}:{new_port}"
235
+ # Reinitialize client with new base_url
233
236
  self._init_client()
234
237
  except Exception:
235
238
  # Silently continue on reload failure
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: diffron
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Summary: Git commit message and PR description generator using Lemonade
5
5
  Home-page: https://github.com/diffron/diffron
6
6
  Author: Diffron Contributors
@@ -47,7 +47,7 @@ Git commit message and PR description generator using AMD Lemonade via lemonade-
47
47
 
48
48
  **Diffron is a production-ready reference implementation of the lemonade-python-sdk — submitted to the AMD Lemonade Developer Challenge 2026.**
49
49
 
50
- ![Version](https://img.shields.io/badge/version-0.1.3-blue)
50
+ ![Version](https://img.shields.io/badge/version-0.1.6-blue)
51
51
  ![Python](https://img.shields.io/badge/python-3.9+-blue)
52
52
  ![License](https://img.shields.io/badge/license-MIT-green)
53
53
  ![Platform](https://img.shields.io/badge/platform-Windows-lightgrey)
@@ -36,9 +36,6 @@ diffron/hooks/prepare-commit-msg
36
36
  diffron/hooks/prepare-commit-msg-global.py
37
37
  diffron/hooks/prepare-commit-msg.py
38
38
  docs/HOOKS.md
39
- docs/LEMONADE_PORT_VERIFICATION_FIX.md
40
- docs/LEMONADE_UNRESPONSIVE_FIX.md
41
- docs/MODEL_NAME_CASE_FIX.md
42
39
  docs/SETUP.md
43
40
  docs/USAGE.md
44
41
  hooks/aipr.py
@@ -1,6 +1,4 @@
1
- build
2
1
  diffron
3
2
  dist
4
3
  docs
5
4
  hooks
6
- internal
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "diffron"
7
- version = "0.1.4"
7
+ version = "0.1.6"
8
8
  description = "Git commit message and PR description generator using Lemonade"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -1,105 +0,0 @@
1
- # Lemonade Port Verification Fix
2
-
3
- ## Problem
4
-
5
- Diffron incorrectly connected to **port 8000** (running Axo Biomarker Analyzer) instead of **port 8020** (running Lemonade), causing:
6
-
7
- ```
8
- Error code: 404 - {'detail': 'Not Found'}
9
- ```
10
-
11
- ### Root Cause
12
-
13
- The `detect_lemonade_port()` function in `diffron/lemonade.py` only checked if a **port was open** (`is_port_open`), not whether it was actually a **Lemonade server**.
14
-
15
- When port 8000 responded (Axo Biomarker web app), Diffron mistakenly identified it as Lemonade and sent API requests to the wrong service.
16
-
17
- | Port | Service | Response |
18
- |------|---------|----------|
19
- | 8000 | Axo Biomarker Analyzer | HTML web page |
20
- | 8020 | **Lemonade** (correct) | `{"data": [...]}` API |
21
-
22
- ## Solution
23
-
24
- ### Use lemonade-python-sdk's `verify_lemonade_server`
25
-
26
- The **lemonade-python-sdk** provides `verify_lemonade_server(port, host)` which:
27
-
28
- 1. Queries the native Lemonade API endpoint `/api/v1/models`
29
- 2. Validates the response format (`{"data": [...]}` or list)
30
- 3. Distinguishes Lemonade from other services (Ollama, web apps, etc.)
31
-
32
- ### Changes
33
-
34
- **1. Added `lemonade-sdk` dependency**
35
-
36
- Updated `requirements.txt`:
37
- ```txt
38
- lemonade-sdk>=0.1.0
39
- ```
40
-
41
- **2. Updated `detect_lemonade_port()`**
42
-
43
- `diffron/lemonade.py` now:
44
-
45
- - Imports `verify_lemonade_server` and `find_available_lemonade_port` from `lemonade_sdk.port_scanner`
46
- - **Verifies** each open port is actually Lemonade before returning it
47
- - Falls back to legacy `is_port_open` behavior if SDK is not installed
48
-
49
- ```python
50
- # Import from lemonade-python-sdk for proper Lemonade verification
51
- try:
52
- from lemonade_sdk.port_scanner import verify_lemonade_server, find_available_lemonade_port
53
- HAS_LEMONADE_SDK = True
54
- except ImportError:
55
- HAS_LEMONADE_SDK = False
56
-
57
- def detect_lemonade_port(...) -> Optional[int]:
58
- # ... existing env var checks ...
59
-
60
- # Try SDK's find_available_lemonade_port first
61
- if HAS_LEMONADE_SDK:
62
- found = find_available_lemonade_port(hostname, scan_ports)
63
- if found:
64
- return found
65
-
66
- # Fallback: manual scan with SDK verification
67
- for port in ports_to_scan:
68
- if is_port_open(hostname, port):
69
- if HAS_LEMONADE_SDK:
70
- if verify_lemonade_server(port, hostname): # ← Key fix!
71
- return port
72
- else:
73
- return port # Legacy: no verification
74
- ```
75
-
76
- **3. Added graceful fallback**
77
-
78
- If `lemonade-sdk` is not installed, Diffron falls back to the original `is_port_open` behavior (first open port wins), maintaining backward compatibility.
79
-
80
- ## Testing
81
-
82
- ```bash
83
- # Before fix: returned 8000 (Axo Biomarker)
84
- # After fix: returns 8020 (Lemonade)
85
- python -c "from diffron.lemonade import detect_lemonade_port; print(detect_lemonade_port())"
86
- # Output: 8020
87
- ```
88
-
89
- ## Impact
90
-
91
- - **Fixes 404 errors** when other services run on ports 8000/8080
92
- - **No breaking changes** - existing setups continue to work
93
- - **Better diagnostics** - clear separation between Lemonade and non-Lemonade services
94
-
95
- ## Files Changed
96
-
97
- | File | Change |
98
- |------|--------|
99
- | `diffron/lemonade.py` | Use `verify_lemonade_server` for port detection |
100
- | `requirements.txt` | Add `lemonade-sdk>=0.1.0` dependency |
101
-
102
- ## Version
103
-
104
- - **Fixed in**: 0.1.3
105
- - **Date**: 2026-04-13
@@ -1,100 +0,0 @@
1
- # Lemonade Model Unresponsive Fix
2
-
3
- ## Problem
4
-
5
- Das Lemonade-Modell wurde manchmal unresponsive, was zu einem Fehler in Diffron führte:
6
-
7
- ```
8
- Diffron error: 'NoneType' object is not subscriptable
9
- ```
10
-
11
- Dies trat auf, wenn die Antwort des Modells `None` war oder `response.choices` leer war, was beim Zugriff auf `response.choices[0].message.content` zu einem Fehler führte.
12
-
13
- ## Lösung
14
-
15
- In [`diffron/lemonade.py`](../diffron/lemonade.py:170) wurde eine Retry-Logik mit automatischem Entladen und Neuladen des Modells implementiert.
16
-
17
- ### Änderungen in `LemonadeClient.chat_completion()`
18
-
19
- ```python
20
- max_retries = 3
21
- for attempt in range(1, max_retries + 1):
22
- try:
23
- response = self.client.chat.completions.create(...)
24
- # Handle None response (model unresponsive)
25
- if response is None or not response.choices:
26
- if attempt < max_retries:
27
- self._reload_model()
28
- continue
29
- raise RuntimeError("Lemonade model returned no response")
30
- return response.choices[0].message.content
31
- except Exception as e:
32
- if attempt < max_retries:
33
- self._reload_model()
34
- continue
35
- raise RuntimeError(
36
- f"Lemonade model failed after {max_retries} attempts: {e}"
37
- )
38
- ```
39
-
40
- ### Neue Methoden
41
-
42
- #### `_reload_model()`
43
-
44
- Entlädt und lädt das Lemonade-Modell neu, wenn es unresponsive ist:
45
-
46
- ```python
47
- def _reload_model(self) -> None:
48
- """Unload and reload the Lemonade model when unresponsive."""
49
- try:
50
- if HAS_LEMONADE_SDK:
51
- new_port = find_available_lemonade_port(
52
- hostname=self.host or DEFAULT_HOST,
53
- ports=DEFAULT_PORTS
54
- )
55
- if new_port and new_port != self._port:
56
- self._port = new_port
57
- self._init_client()
58
- except Exception:
59
- pass
60
- ```
61
-
62
- #### `_init_client()`
63
-
64
- Initialisiert den OpenAI-Client neu mit der aktuellen Konfiguration:
65
-
66
- ```python
67
- def _init_client(self) -> None:
68
- """Reinitialize the OpenAI client with current configuration."""
69
- self.client = OpenAI(
70
- base_url=f"{self.base_url}/api/v1",
71
- api_key=self.api_key
72
- )
73
- ```
74
-
75
- ## Ablauf bei Unresponsiveness
76
-
77
- 1. **Erster Versuch**: Modell antwortet nicht → `_reload_model()` aufgerufen
78
- 2. **Zweiter Versuch**: Modell antwortet immer noch nicht → `_reload_model()` erneut aufgerufen
79
- 3. **Dritter Versuch**: Erfolgt mit neu geladenem Modell
80
- 4. **Falls alle Versuche fehlschlagen**: `RuntimeError` mit detaillierter Fehlermeldung
81
-
82
- ## Voraussetzungen
83
-
84
- Die automatische Wiederherstellung erfordert das `lemonade-python-sdk`:
85
-
86
- ```python
87
- try:
88
- from lemonade_sdk.port_scanner import verify_lemonade_server
89
- from lemonade_sdk.port_scanner import find_available_lemonade_port
90
- HAS_LEMONADE_SDK = True
91
- except ImportError:
92
- HAS_LEMONADE_SDK = False
93
- ```
94
-
95
- Ohne das SDK wird weiterhin versucht, einen offenen Port zu finden, aber die automatische Wiederherstellung ist eingeschränkt.
96
-
97
- ## Siehe auch
98
-
99
- - [LEMONADE_PORT_VERIFICATION_FIX.md](LEMONADE_PORT_VERIFICATION_FIX.md) - Port-Erkennungsfix
100
- - [MODEL_NAME_CASE_FIX.md](MODEL_NAME_CASE_FIX.md) - Modellnamen-Fallfix
@@ -1,88 +0,0 @@
1
- # Model Name Case Sensitivity Fix
2
-
3
- ## Problem
4
-
5
- Diffron returned a **404 Not Found** error from the Lemonade server when using the `Qwen3.5-0.8B-GGUF` model.
6
-
7
- ### Root Cause
8
-
9
- The Lemonade server is **case-sensitive** when matching model names. Diffron's curated model configuration used the wrong casing:
10
-
11
- | Location | Model Name (Before) | Model Name (Expected) |
12
- |----------|---------------------|------------------------|
13
- | `diffron/models.py` | `qwen3.5-0.8b-gguf` | `Qwen3.5-0.8B-GGUF` |
14
-
15
- This caused the OpenAI SDK to send a request with the wrong model identifier, resulting in:
16
-
17
- ```
18
- Error code: 404 - {'detail': 'Not Found'}
19
- ```
20
-
21
- ## Solution
22
-
23
- ### 1. Corrected Model Name
24
-
25
- Updated the canonical model name in `diffron/models.py`:
26
-
27
- ```python
28
- # Before
29
- ModelConfig(name="qwen3.5-0.8b-gguf", ...)
30
-
31
- # After
32
- ModelConfig(name="Qwen3.5-0.8B-GGUF", ...)
33
- ```
34
-
35
- ### 2. Case-Insensitive Model Lookup
36
-
37
- Enhanced `get_model_config()` to accept case-insensitive input while always returning the **canonical name**:
38
-
39
- ```python
40
- def get_model_config(model_name: str) -> Optional[ModelConfig]:
41
- # Exact match first
42
- for model in AVAILABLE_MODELS:
43
- if model.name == model_name:
44
- return model
45
- # Case-insensitive fallback
46
- for model in AVAILABLE_MODEOLS:
47
- if model.name.lower() == model_name.lower():
48
- return model
49
- return None
50
- ```
51
-
52
- This allows users to type `qwen3.5-0.8b-gguf`, `QWEN3.5-0.8B-GGUF`, etc., but Diffron always sends the correct name to the server.
53
-
54
- ### 3. CLI Canonical Name Enforcement
55
-
56
- The `setup_model_cli()` now stores the **canonical name** from the config, not the user's raw input:
57
-
58
- ```python
59
- # Always uses config.name (canonical) instead of args.model (user input)
60
- os.environ["DIFFRON_MODEL"] = config.name
61
- subprocess.run(["setx", "DIFFRON_MODEL", config.name], check=True)
62
- ```
63
-
64
- ## Testing
65
-
66
- ```bash
67
- # All of these now work correctly:
68
- diffron-setup-model --model Qwen3.5-0.8B-GGUF # exact
69
- diffron-setup-model --model qwen3.5-0.8b-gguf # lowercase (fallback)
70
- diffron-setup-model --model QWEN3.5-0.8B-GGUF # uppercase (fallback)
71
- ```
72
-
73
- ## Impact
74
-
75
- - **No breaking changes** - existing `DIFFRON_MODEL` values with wrong casing are now resolved correctly
76
- - **Improved UX** - users don't need to memorize exact casing
77
- - **Server compatibility** - correct model name is always sent to Lemonade
78
-
79
- ## Files Changed
80
-
81
- | File | Change |
82
- |------|--------|
83
- | `diffron/models.py` | Fixed `Qwen3.5-0.8B-GGUF` name, added case-insensitive lookup |
84
-
85
- ## Version
86
-
87
- - **Fixed in**: 0.1.3
88
- - **Date**: 2026-04-13
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes