Files
ktransformers/kt-kernel/python/cli/utils/input_validators.py
Oql 56cbd69ac4 kt-cli enhancement (#1834)
* [feat]: redesign kt run interactive configuration with i18n support

- Redesign kt run with 8-step interactive flow (model selection, inference method, NUMA/CPU, GPU experts, KV cache, GPU/TP selection, parsers, host/port)
- Add configuration save/load system (~/.ktransformers/run_configs.yaml)
- Add i18n support for kt chat (en/zh translations)
- Add universal input validators with auto-retry and Chinese comma support
- Add port availability checker with auto-suggestion
- Add parser configuration (--tool-call-parser, --reasoning-parser)
- Remove tuna command and clean up redundant files
- Fix: variable reference bug in run.py, filter to show only MoE models

* [feat]: unify model selection UI and enable shared experts fusion by default

- Unify kt run model selection table with kt model list display
  * Add Total size, MoE Size, Repo, and SHA256 status columns
  * Use consistent formatting and styling
  * Improve user decision-making with more information

- Enable --disable-shared-experts-fusion by default
  * Change default value from False to True
  * Users can still override with --enable-shared-experts-fusion

* [feat]: improve kt chat with performance metrics and better CJK support

- Add performance metrics display after each response
  * Total time, TTFT (Time To First Token), TPOT (Time Per Output Token)
  * Accurate input/output token counts using model tokenizer
  * Fallback to estimation if tokenizer unavailable
  * Metrics shown in dim style (not prominent)

- Fix Chinese character input issues
  * Replace Prompt.ask() with console.input() for better CJK support
  * Fixes backspace deletion showing half-characters

- Suppress NumPy subnormal warnings
  * Filter "The value of the smallest subnormal" warnings
  * Cleaner CLI output on certain hardware environments

* [fix]: correct TTFT measurement in kt chat

- Move start_time initialization before API call
- Previously start_time was set when receiving first chunk, causing TTFT ≈ 0ms
- Now correctly measures time from request sent to first token received

* [docs]: 添加 Clawdbot 集成指南 - KTransformers 企业级 AI 助手部署方案

* [docs]: 强调推荐使用 Kimi K2.5 作为核心模型,突出企业级推理能力

* [docs]: 添加 Clawdbot 飞书接入教程链接

* [feat]: improve CLI table display, model verification, and chat experience

- Add sequence number (#) column to all model tables by default
- Filter kt edit to show only MoE GPU models (exclude AMX)
- Extend kt model verify to check *.json and *.py files in addition to weights
- Fix re-verification bug where repaired files caused false failures
- Suppress tokenizer debug output in kt chat token counting

* [fix]: fix cpu cores.

---------

Co-authored-by: skqliao <skqliao@gmail.com>
2026-02-04 16:44:54 +08:00

217 lines
6.7 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Input validation utilities with retry mechanism.
Provides robust input validation with automatic retry on failure.
"""
from typing import Optional, List, Callable, Any
from rich.console import Console
from rich.prompt import Prompt
console = Console()
def prompt_int_with_retry(
message: str,
default: Optional[int] = None,
min_val: Optional[int] = None,
max_val: Optional[int] = None,
validator: Optional[Callable[[int], bool]] = None,
validator_error_msg: Optional[str] = None,
) -> int:
"""Prompt for integer input with validation and retry.
Args:
message: Prompt message
default: Default value (optional)
min_val: Minimum allowed value (optional)
max_val: Maximum allowed value (optional)
validator: Custom validation function (optional)
validator_error_msg: Error message for custom validator (optional)
Returns:
Validated integer value
"""
while True:
# Build prompt with default
if default is not None:
prompt_text = f"{message} [{default}]"
else:
prompt_text = message
# Get input
user_input = Prompt.ask(prompt_text, default=str(default) if default is not None else None)
# Try to parse as integer
try:
value = int(user_input)
except ValueError:
console.print(f"[red]✗ Invalid input. Please enter a valid integer.[/red]")
console.print()
continue
# Validate range
if min_val is not None and value < min_val:
console.print(f"[red]✗ Value must be at least {min_val}[/red]")
console.print()
continue
if max_val is not None and value > max_val:
console.print(f"[red]✗ Value must be at most {max_val}[/red]")
console.print()
continue
# Custom validation
if validator is not None:
if not validator(value):
error_msg = validator_error_msg or "Invalid value"
console.print(f"[red]✗ {error_msg}[/red]")
console.print()
continue
# All validations passed
return value
def prompt_float_with_retry(
message: str,
default: Optional[float] = None,
min_val: Optional[float] = None,
max_val: Optional[float] = None,
) -> float:
"""Prompt for float input with validation and retry.
Args:
message: Prompt message
default: Default value (optional)
min_val: Minimum allowed value (optional)
max_val: Maximum allowed value (optional)
Returns:
Validated float value
"""
while True:
# Build prompt with default
if default is not None:
prompt_text = f"{message} [{default}]"
else:
prompt_text = message
# Get input
user_input = Prompt.ask(prompt_text, default=str(default) if default is not None else None)
# Try to parse as float
try:
value = float(user_input)
except ValueError:
console.print(f"[red]✗ Invalid input. Please enter a valid number.[/red]")
console.print()
continue
# Validate range
if min_val is not None and value < min_val:
console.print(f"[red]✗ Value must be at least {min_val}[/red]")
console.print()
continue
if max_val is not None and value > max_val:
console.print(f"[red]✗ Value must be at most {max_val}[/red]")
console.print()
continue
# All validations passed
return value
def prompt_choice_with_retry(
message: str,
choices: List[str],
default: Optional[str] = None,
) -> str:
"""Prompt for choice input with validation and retry.
Args:
message: Prompt message
choices: List of valid choices
default: Default choice (optional)
Returns:
Selected choice
"""
while True:
# Get input
user_input = Prompt.ask(message, default=default)
# Validate choice
if user_input not in choices:
console.print(f"[red]✗ Invalid choice. Please select from: {', '.join(choices)}[/red]")
console.print()
continue
return user_input
def prompt_int_list_with_retry(
message: str,
default: Optional[str] = None,
min_val: Optional[int] = None,
max_val: Optional[int] = None,
validator: Optional[Callable[[List[int]], tuple[bool, Optional[str]]]] = None,
) -> List[int]:
"""Prompt for comma-separated integer list with validation and retry.
Args:
message: Prompt message
default: Default value as string (e.g., "0,1,2,3")
min_val: Minimum allowed value for each integer (optional)
max_val: Maximum allowed value for each integer (optional)
validator: Custom validation function that returns (is_valid, error_message) (optional)
Returns:
List of validated integers
"""
while True:
# Get input
user_input = Prompt.ask(message, default=default)
# Clean input: support Chinese comma and spaces
user_input_cleaned = user_input.replace("", ",").replace(" ", "")
# Try to parse as integers
try:
values = [int(x.strip()) for x in user_input_cleaned.split(",") if x.strip()]
except ValueError:
console.print(f"[red]✗ Invalid format. Please enter numbers separated by commas.[/red]")
console.print()
continue
# Validate each value's range
invalid_values = []
for value in values:
if min_val is not None and value < min_val:
invalid_values.append(value)
elif max_val is not None and value > max_val:
invalid_values.append(value)
if invalid_values:
if min_val is not None and max_val is not None:
console.print(f"[red]✗ Invalid value(s): {invalid_values}[/red]")
console.print(f"[yellow]Valid range: {min_val}-{max_val}[/yellow]")
elif min_val is not None:
console.print(f"[red]✗ Value(s) must be at least {min_val}: {invalid_values}[/red]")
elif max_val is not None:
console.print(f"[red]✗ Value(s) must be at most {max_val}: {invalid_values}[/red]")
console.print()
continue
# Custom validation
if validator is not None:
is_valid, error_msg = validator(values)
if not is_valid:
console.print(f"[red]✗ {error_msg}[/red]")
console.print()
continue
# All validations passed
return values