hyf-backend/utils/general.py

219 lines
6.3 KiB
Python
Raw Permalink Normal View History

2026-01-21 13:45:39 +08:00
import os
import re
import shutil
import math
import textwrap
import platform
import subprocess
import webbrowser
from difflib import SequenceMatcher
from importlib_metadata import version as get_package_version
from typing import Iterator, Tuple
try:
import psutil
except ImportError:
psutil = None
def format_bold(text):
return f"\033[1m{text}\033[0m"
def format_color(text, color_code):
return f"\033[{color_code}m{text}\033[0m"
def gradient_text(
text: str,
start_color: Tuple[int, int, int] = (0, 0, 255),
end_color: Tuple[int, int, int] = (255, 0, 255),
frequency: float = 1.0,
) -> str:
def color_function(t: float) -> Tuple[int, int, int]:
def interpolate(start: float, end: float, t: float) -> float:
# Use a sine wave for smooth, periodic interpolation
return (
start
+ (end - start) * (math.sin(math.pi * t * frequency) + 1) / 2
)
return tuple(
round(interpolate(s, e, t)) for s, e in zip(start_color, end_color)
)
def gradient_gen(length: int) -> Iterator[Tuple[int, int, int]]:
return (color_function(i / (length - 1)) for i in range(length))
gradient = gradient_gen(len(text))
return "".join(
f"\033[38;2;{r};{g};{b}m{char}\033[0m"
for char, (r, g, b) in zip(text, gradient)
) # noqa: E501
def hex_to_rgb(hex_color):
hex_color = hex_color.lstrip("#")
return tuple(int(hex_color[i : i + 2], 16) for i in (0, 2, 4))
def indent_text(text, indent=4):
return textwrap.indent(text, " " * indent)
def is_chinese(s="人工智能"):
# Is string composed of any Chinese characters?
return bool(re.search("[\u4e00-\u9fff]", str(s)))
def is_possible_rectangle(points):
if len(points) != 4:
return False
# Check if four points form a rectangle
# The points are expected to be in the format:
# [[x1, y1], [x2, y2], [x3, y3], [x4, y4]]
dists = [square_dist(points[i], points[(i + 1) % 4]) for i in range(4)]
dists.sort()
# For a rectangle, the two smallest distances
# should be equal and the two largest should be equal
return dists[0] == dists[1] and dists[2] == dists[3]
def square_dist(p, q):
# Calculate the square distance between two points
return (p[0] - q[0]) ** 2 + (p[1] - q[1]) ** 2
def collect_system_info():
os_info = platform.platform()
cpu_info = platform.processor()
cpu_count = os.cpu_count()
if psutil:
gib = 1 << 30
ram = psutil.virtual_memory().total
ram_info = f"{ram / gib:.1f} GB"
total, used, free = shutil.disk_usage("/")
disk_info = f"{(total - free) / gib:.1f}/{total / gib:.1f} GB"
else:
ram_info = "N/A (psutil not installed)"
disk_info = "N/A (psutil not installed)"
gpu_info = get_gpu_info()
cuda_info = get_cuda_version()
python_info = platform.python_version()
pyqt5_info = get_installed_package_version("PyQt5")
onnx_info = get_installed_package_version("onnx")
ort_info = get_installed_package_version("onnxruntime")
ort_gpu_info = get_installed_package_version("onnxruntime-gpu")
opencv_contrib_info = get_installed_package_version(
"opencv-contrib-python-headless"
)
system_info = {
"Operating System": os_info,
"CPU": cpu_info,
"CPU Count": cpu_count,
"RAM": ram_info,
"Disk": disk_info,
"GPU": gpu_info,
"CUDA": cuda_info,
"Python Version": python_info,
}
pkg_info = {
"PyQt5 Version": pyqt5_info,
"ONNX Version": onnx_info,
"ONNX Runtime Version": ort_info,
"ONNX Runtime GPU Version": ort_gpu_info,
"OpenCV Contrib Python Headless Version": opencv_contrib_info,
}
return system_info, pkg_info
def find_most_similar_label(text, valid_labels):
max_similarity = 0
most_similar_label = valid_labels[0]
for label in valid_labels:
similarity = SequenceMatcher(None, text, label).ratio()
if similarity > max_similarity:
max_similarity = similarity
most_similar_label = label
return most_similar_label
def get_installed_package_version(package_name):
try:
return get_package_version(package_name)
except Exception:
return None
def get_cuda_version():
try:
nvcc_output = subprocess.check_output(["nvcc", "--version"]).decode(
"utf-8"
)
version_line = next(
(line for line in nvcc_output.split("\n") if "release" in line),
None,
)
if version_line:
return version_line.split()[-1]
except Exception:
return None
def get_gpu_info():
try:
smi_output = subprocess.check_output(
[
"nvidia-smi",
"--query-gpu=index,name,memory.total",
"--format=csv,noheader,nounits",
],
encoding="utf-8",
)
gpu_info_lines = []
for line in smi_output.strip().split("\n"):
parts = line.split(",")
if len(parts) == 3:
index = parts[0].strip()
name = parts[1].strip()
memory = parts[2].strip() + "MiB"
gpu_info_lines.append(f"CUDA:{index} ({name}, {memory})")
return ", ".join(gpu_info_lines)
except Exception:
return None
def open_url(url: str) -> None:
"""Open URL in browser while suppressing TTY warnings"""
try:
if platform.system() == "Linux":
# Check if running in WSL
with open("/proc/version", "r") as f:
if "microsoft" in f.read().lower():
# Use powershell.exe for WSL
subprocess.run(
[
"powershell.exe",
"-Command",
f'Start-Process "{url}"',
]
)
else:
# For native Linux, use xdg-open
subprocess.run(
["xdg-open", url], stderr=subprocess.DEVNULL
)
else:
webbrowser.open(url)
except Exception:
# Fallback to regular webbrowser.open
webbrowser.open(url)