diff --git a/soup_cli/utils/quality.py b/soup_cli/utils/quality.py index f72d9a8..8bfc09d 100644 --- a/soup_cli/utils/quality.py +++ b/soup_cli/utils/quality.py @@ -63,7 +63,10 @@ def compute_perplexity_scores( shift_labels = input_ids[:, 1:].contiguous() shift_mask = attention_mask[:, 1:].contiguous() - loss_fct = torch.nn.CrossEntropyLoss(reduction="none") + # Set pad positions to -100 so CrossEntropyLoss skips them + shift_labels = shift_labels.masked_fill(shift_mask == 0, -100) + + loss_fct = torch.nn.CrossEntropyLoss(reduction="none", ignore_index=-100) per_token_loss = loss_fct( shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1), diff --git a/soup_cli/utils/sglang.py b/soup_cli/utils/sglang.py index 1b6ec90..1d5dcff 100644 --- a/soup_cli/utils/sglang.py +++ b/soup_cli/utils/sglang.py @@ -47,8 +47,18 @@ def create_sglang_runtime( Returns: (runtime, runtime_model_name) tuple. """ + import re + import sglang as sgl + # SSRF protection: block URL-based model paths + for path_val in (model_path, base_model): + if path_val and re.match(r'^https?://', path_val): + raise ValueError( + "model_path/base_model must be a local path or HuggingFace model ID, " + "not a URL" + ) + # For LoRA adapters, load the base model if is_adapter and base_model: runtime = sgl.Runtime(