From 8bd48cf1669cb9aa26cf602df84af0f3a2ebbd97 Mon Sep 17 00:00:00 2001 From: dschlueter Date: Tue, 28 Apr 2026 22:22:10 +0200 Subject: [PATCH] Include albumartist in filename; remove Claude API from LLM chain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Filename schema now: TT - AlbumArtist - TrackArtist - Title when albumartist differs from track artist (e.g. pianist vs. composer). Identical artist → old two-part format unchanged. metadata_resolver: removed Claude API fallback entirely from _claude_resolve. Chain is now Ollama (local, free) → OpenRouter (DeepSeek V3, cheap) only. music_enricher: updated status line and use_claude flag accordingly. Co-Authored-By: Claude Sonnet 4.6 --- executor.py | 12 ++++++++---- metadata_resolver.py | 19 ++----------------- music_enricher.py | 6 +++--- 3 files changed, 13 insertions(+), 24 deletions(-) diff --git a/executor.py b/executor.py index f13c808..3bff22e 100644 --- a/executor.py +++ b/executor.py @@ -36,12 +36,16 @@ def _safe_name(s: str) -> str: return _SAFE_RE.sub("_", s).strip(". ") -def _proposed_filename(proposal: TrackProposal, ext: str) -> str: +def _proposed_filename(proposal: TrackProposal, ext: str, albumartist: str = "") -> str: tn = f"{proposal.track_number:02d}" if proposal.track_number else "00" prefix = f"{proposal.disc_number}-{tn}" if proposal.disc_number and proposal.disc_number > 1 else tn - artist = _safe_name(proposal.artist or "Unknown") + track_artist = _safe_name(proposal.artist or "Unknown") + aa = _safe_name(albumartist) title = _safe_name(proposal.title or "Unknown") - return f"{prefix} - {artist} - {title}{ext}" + # Include albumartist when it differs from track artist (e.g. pianist vs. composer) + if aa and aa.casefold() != track_artist.casefold() and aa.casefold() not in ("various artists", "unknown"): + return f"{prefix} - {aa} - {track_artist} - {title}{ext}" + return f"{prefix} - {track_artist} - {title}{ext}" def backup_file(path: Path, backup_dir: Path) -> bool: @@ -194,7 +198,7 @@ def execute_album( cover_embedded = True if do_rename: - new_name = _proposed_filename(tp, tp.path.suffix) + new_name = _proposed_filename(tp, tp.path.suffix, proposal.albumartist or "") candidate = tp.path.parent / new_name if candidate != tp.path: try: diff --git a/metadata_resolver.py b/metadata_resolver.py index 56a8ccc..bd6b17a 100644 --- a/metadata_resolver.py +++ b/metadata_resolver.py @@ -272,8 +272,8 @@ def _resolve_via_openrouter(hints: AlbumHints, partial: Dict) -> Optional[Dict]: def _claude_resolve(hints: AlbumHints, partial: Dict) -> Optional[Dict]: """ - Reihenfolge: Ollama (lokal, kostenlos) → OpenRouter (günstig) → Claude API. - Ollama wird versucht wenn OLLAMA_HOST erreichbar; kein Key nötig. + Reihenfolge: Ollama (lokal, kostenlos) → OpenRouter (günstig). + Claude API wird bewusst nicht genutzt (zu teuer). """ # 1. Ollama lokal (bevorzugt — kostenlos, RTX 3090) result = _resolve_via_ollama(hints, partial) @@ -286,21 +286,6 @@ def _claude_resolve(hints: AlbumHints, partial: Dict) -> Optional[Dict]: if result: return result - # 3. Claude API als letzter Fallback - if not HAS_ANTHROPIC or not ANTHROPIC_API_KEY: - return None - try: - client = anthropic.Anthropic(api_key=ANTHROPIC_API_KEY) - prompt = _build_resolve_prompt(hints, partial) - message = client.messages.create( - model="claude-haiku-4-5-20251001", - max_tokens=300, - messages=[{"role": "user", "content": prompt}], - ) - text = message.content[0].text.strip() - return _parse_json_response(text) - except Exception as e: - print(f" ⚠️ Claude-API-Fehler: {e}", file=sys.stderr) return None diff --git a/music_enricher.py b/music_enricher.py index aabd5ae..30387cc 100644 --- a/music_enricher.py +++ b/music_enricher.py @@ -96,7 +96,7 @@ def process_album( hints, use_fingerprint=not args.no_fingerprint, use_api=not args.no_api, - use_claude=bool(os.getenv("ANTHROPIC_API_KEY")), + use_claude=not args.no_api, ) # Cover art @@ -235,8 +235,8 @@ def main() -> None: sys.exit(1) print(f"🎵 {len(album_dirs)} Album-Verzeichnisse gefunden.") - if os.getenv("ANTHROPIC_API_KEY"): - print("🤖 Claude API aktiv.") + if os.getenv("OLLAMA_HOST") or True: # Ollama always attempted + print("🤖 LLM-Resolve: Ollama → OpenRouter (kein Claude)") if not args.no_api: print("🔍 MusicBrainz-Lookup aktiv.") if args.dry_run: