Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions graphify/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,7 @@ def dispatch_command(cmd: str) -> None:
co_exclude_hubs: float | None = None
label_max_concurrency: int = 4
label_batch_size: int = 100
label_language: str | None = None
i_arg = 0
while i_arg < len(args):
a = args[i_arg]
Expand Down Expand Up @@ -980,6 +981,10 @@ def dispatch_command(cmd: str) -> None:
label_batch_size = int(args[i_arg + 1]); i_arg += 2
elif a.startswith("--batch-size="):
label_batch_size = int(a.split("=", 1)[1]); i_arg += 1
elif a == "--label-language" and i_arg + 1 < len(args):
label_language = args[i_arg + 1]; i_arg += 2
elif a.startswith("--label-language="):
label_language = a.split("=", 1)[1]; i_arg += 1
elif a in ("--no-viz", "--missing-only") or a.startswith("--min-community-size="):
i_arg += 1
elif a.startswith("--"):
Expand Down Expand Up @@ -1165,7 +1170,7 @@ def dispatch_command(cmd: str) -> None:
generated_labels, _ = generate_community_labels(
G, label_communities_input, backend=label_backend, model=label_model, gods=gods,
max_concurrency=label_max_concurrency, batch_size=label_batch_size,
usage_out=label_token_usage,
usage_out=label_token_usage, label_language=label_language,
)
# Only let the LLM OVERRIDE where it produced a real name — its no-backend
# fallback returns "Community {cid}" placeholders, which must not clobber
Expand Down Expand Up @@ -2769,4 +2774,4 @@ def _progress(idx: int, total: int, _result: dict) -> None:
else:
print(f"error: unknown command '{cmd}'", file=sys.stderr)
print("Run 'graphify --help' for usage.", file=sys.stderr)
sys.exit(1)
sys.exit(1)
20 changes: 13 additions & 7 deletions graphify/llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -2373,6 +2373,7 @@ def _label_batch_with_retry(
depth: int = 0,
max_depth: int = 3,
usage_out: dict | None = None,
label_language: str | None = None,
) -> dict[int, str]:
"""Label a batch of communities, splitting in half and retrying on parse failure.

Expand All @@ -2389,11 +2390,14 @@ def _label_batch_with_retry(
missing config, programming bug) propagates unchanged — those are never
split-retried.
"""
_lang = label_language or os.environ.get("GRAPHIFY_LABEL_LANGUAGE", "")
_lang_clause = f" Respond in {_lang}." if _lang else ""
prompt = (
"You are naming clusters in a knowledge graph. For each community below, "
"return a concise 2-5 word plain-language name describing what it is about "
"(e.g. \"Order Management\", \"Payment Flow\", \"Auth Middleware\"). "
"Respond ONLY with a JSON object mapping the community id (as a string) to "
"(e.g. \"Order Management\", \"Payment Flow\", \"Auth Middleware\")."
+ _lang_clause
+ " Respond ONLY with a JSON object mapping the community id (as a string) to "
"its name - no prose, no markdown fences.\n\n" + "\n".join(batch_lines)
)
# Budget generously: a 2-5 word name is ~10 tokens, but models (notably
Expand Down Expand Up @@ -2428,12 +2432,12 @@ def _label_batch_with_retry(
left = _label_batch_with_retry(
batch_cids[:mid], batch_lines[:mid],
backend=backend, model=model, depth=depth + 1, max_depth=max_depth,
usage_out=usage_out,
usage_out=usage_out, label_language=label_language,
)
right = _label_batch_with_retry(
batch_cids[mid:], batch_lines[mid:],
backend=backend, model=model, depth=depth + 1, max_depth=max_depth,
usage_out=usage_out,
usage_out=usage_out, label_language=label_language,
)
return left | right

Expand All @@ -2450,6 +2454,7 @@ def label_communities(
batch_size: int = _LABEL_BATCH_SIZE,
max_concurrency: int = 4,
usage_out: dict | None = None,
label_language: str | None = None,
) -> dict[int, str]:
"""Return a complete ``{cid: name}`` map using ``backend`` for naming.

Expand Down Expand Up @@ -2500,7 +2505,7 @@ def _run_batch(batch_idx: int):
try:
parsed = _label_batch_with_retry(
labeled_cids[start:end], lines[start:end], backend=backend, model=model,
**batch_kwargs,
label_language=label_language, **batch_kwargs,
)
return batch_idx, parsed, None, batch_usage
except Exception as exc: # noqa: BLE001 - reported per-batch; surfaced below
Expand Down Expand Up @@ -2558,6 +2563,7 @@ def generate_community_labels(
max_concurrency: int = 4,
batch_size: int = _LABEL_BATCH_SIZE,
usage_out: dict | None = None,
label_language: str | None = None,
) -> tuple[dict[int, str], str]:
"""CLI entry point: resolve a backend, name communities, and degrade to
``Community N`` placeholders on any failure (no backend, API error, malformed
Expand All @@ -2580,7 +2586,7 @@ def generate_community_labels(
labels = label_communities(
G, communities, backend=backend, model=model, gods=gods,
max_concurrency=max_concurrency, batch_size=batch_size,
usage_out=usage_out,
usage_out=usage_out, label_language=label_language,
)
return labels, "llm"
except Exception as exc:
Expand All @@ -2590,4 +2596,4 @@ def generate_community_labels(
"using Community N placeholders.",
file=sys.stderr,
)
return _placeholder_community_labels(communities), "placeholder"
return _placeholder_community_labels(communities), "placeholder"