Skip to content

Commit 28cd840

Browse files
committed
chore: Add UI components and migration utilities
Additional utilities: src/llmkit/ui/: - Terminal UI components - Design tokens and patterns - Console helpers - ASCII logo migrate.sh: - Migration script for upgrades src/llmkit/vector_stores_old.py: - Legacy vector store implementation Supporting files for enhanced user experience and development
1 parent 4b0d18b commit 28cd840

File tree

9 files changed

+1972
-0
lines changed

9 files changed

+1972
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,4 @@ dmypy.json
6161

6262
# Ruff
6363
.ruff_cache/
64+
.claude/settings.local.json

migrate.sh

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/bin/bash
2+
3+
cd "$(dirname "$0")"
4+
5+
echo "🔄 Starting migration: llm-model-manager → llmkit"
6+
echo ""
7+
8+
# 1. Rename directory
9+
echo "Step 1: Renaming llm_model_manager → llmkit..."
10+
if [ -d "llm_model_manager" ]; then
11+
mv llm_model_manager llmkit
12+
echo " ✅ Directory renamed"
13+
else
14+
echo " ⚠️ llm_model_manager not found (maybe already renamed?)"
15+
if [ -d "llmkit" ]; then
16+
echo " ✅ llmkit directory already exists"
17+
fi
18+
fi
19+
echo ""
20+
21+
# 2. Clean old cache
22+
echo "Step 2: Cleaning Python cache..."
23+
find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
24+
find . -name "*.pyc" -delete 2>/dev/null || true
25+
echo " ✅ Cache cleaned"
26+
echo ""
27+
28+
# 3. Uninstall old package
29+
echo "Step 3: Uninstalling old packages..."
30+
pip uninstall -y llm-model-manager 2>/dev/null || echo " (not installed)"
31+
pip uninstall -y llmkit 2>/dev/null || echo " (not installed)"
32+
echo ""
33+
34+
# 4. Install new package
35+
echo "Step 4: Installing llmkit in development mode..."
36+
pip install -e .
37+
echo ""
38+
39+
# 5. Verify installation
40+
echo "Step 5: Verifying installation..."
41+
python -c "from llmkit import get_registry; r = get_registry(); print(f' ✅ Import works! {len(r.get_available_models())} models found')"
42+
echo ""
43+
44+
# 6. Test CLI
45+
echo "Step 6: Testing CLI..."
46+
llmkit summary
47+
echo ""
48+
49+
echo "🎉 Migration complete!"
50+
echo ""
51+
echo "📝 Next steps:"
52+
echo " 1. Run tests: pytest"
53+
echo " 2. Try examples: python examples/basic_usage.py"
54+
echo " 3. Build package: python -m build"
55+
echo ""
56+
echo "📚 See README.md for usage guide"

src/llmkit/ui/__init__.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
"""
2+
Terminal UI Design System
3+
터미널 기반 제품의 시각 아이덴티티 + UI 패턴
4+
"""
5+
from .design_tokens import (
6+
ColorTokens,
7+
TypographyTokens,
8+
SpacingTokens,
9+
DesignTokens
10+
)
11+
from .components import (
12+
Badge,
13+
Spinner,
14+
ProgressBar,
15+
CommandBlock,
16+
OutputBlock,
17+
Divider,
18+
Prompt,
19+
StatusIcon
20+
)
21+
from .logo import Logo, print_logo
22+
from .patterns import (
23+
SuccessPattern,
24+
ErrorPattern,
25+
WarningPattern,
26+
InfoPattern,
27+
EmptyStatePattern,
28+
OnboardingPattern
29+
)
30+
from .console import get_console, styled_print
31+
32+
__all__ = [
33+
# Design Tokens
34+
"ColorTokens",
35+
"TypographyTokens",
36+
"SpacingTokens",
37+
"DesignTokens",
38+
# Components
39+
"Badge",
40+
"Spinner",
41+
"ProgressBar",
42+
"CommandBlock",
43+
"OutputBlock",
44+
"Divider",
45+
"Prompt",
46+
"StatusIcon",
47+
# Logo
48+
"Logo",
49+
"print_logo",
50+
# Patterns
51+
"SuccessPattern",
52+
"ErrorPattern",
53+
"WarningPattern",
54+
"InfoPattern",
55+
"EmptyStatePattern",
56+
"OnboardingPattern",
57+
# Console
58+
"get_console",
59+
"styled_print",
60+
]
61+

src/llmkit/ui/components.py

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
"""
2+
CLI/TUI Components
3+
터미널 UI 컴포넌트
4+
"""
5+
from typing import Optional, List, Any
6+
from rich.console import Console
7+
from rich.panel import Panel
8+
from rich.text import Text
9+
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn
10+
from rich.table import Table
11+
from rich import box
12+
from .design_tokens import tokens
13+
14+
15+
class Badge:
16+
"""배지 컴포넌트 [OK], [ERROR] 등"""
17+
18+
@staticmethod
19+
def success(text: str = "OK") -> str:
20+
"""성공 배지"""
21+
return f"[{tokens.color.bg_success} {tokens.color.success} bold][{text}][/{tokens.color.bg_success} {tokens.color.success} bold]"
22+
23+
@staticmethod
24+
def error(text: str = "ERROR") -> str:
25+
"""에러 배지"""
26+
return f"[{tokens.color.bg_error} {tokens.color.error} bold][{text}][/{tokens.color.bg_error} {tokens.color.error} bold]"
27+
28+
@staticmethod
29+
def warning(text: str = "WARN") -> str:
30+
"""경고 배지"""
31+
return f"[{tokens.color.bg_warning} {tokens.color.warning} bold][{text}][/{tokens.color.bg_warning} {tokens.color.warning} bold]"
32+
33+
@staticmethod
34+
def info(text: str = "INFO") -> str:
35+
"""정보 배지"""
36+
return f"[{tokens.color.bg_info} {tokens.color.info} bold][{text}][/{tokens.color.bg_info} {tokens.color.info} bold]"
37+
38+
@staticmethod
39+
def custom(text: str, color: str) -> str:
40+
"""커스텀 배지"""
41+
return f"[{color} bold][{text}][/{color} bold]"
42+
43+
44+
class StatusIcon:
45+
"""상태 아이콘"""
46+
47+
SUCCESS = "✓"
48+
ERROR = "✗"
49+
WARNING = "⚠"
50+
INFO = "ℹ"
51+
LOADING = "⟳"
52+
53+
@staticmethod
54+
def success() -> str:
55+
return f"[{tokens.color.success}]{StatusIcon.SUCCESS}[/{tokens.color.success}]"
56+
57+
@staticmethod
58+
def error() -> str:
59+
return f"[{tokens.color.error}]{StatusIcon.ERROR}[/{tokens.color.error}]"
60+
61+
@staticmethod
62+
def warning() -> str:
63+
return f"[{tokens.color.warning}]{StatusIcon.WARNING}[/{tokens.color.warning}]"
64+
65+
@staticmethod
66+
def info() -> str:
67+
return f"[{tokens.color.info}]{StatusIcon.INFO}[/{tokens.color.info}]"
68+
69+
70+
class Divider:
71+
"""구분선 컴포넌트"""
72+
73+
@staticmethod
74+
def thin(length: int = 50) -> str:
75+
"""얇은 구분선"""
76+
return "─" * length
77+
78+
@staticmethod
79+
def thick(length: int = 50) -> str:
80+
"""두꺼운 구분선"""
81+
return "═" * length
82+
83+
@staticmethod
84+
def double(length: int = 50) -> str:
85+
"""이중 구분선"""
86+
return "═" * length
87+
88+
@staticmethod
89+
def styled(text: str = "", style: str = "dim") -> str:
90+
"""스타일 적용 구분선"""
91+
return f"[{style}]{Divider.thin()}[/{style}]"
92+
93+
94+
class CommandBlock:
95+
"""명령어 블록 (실행 명령 강조)"""
96+
97+
@staticmethod
98+
def render(command: str, console: Optional[Console] = None) -> None:
99+
"""명령어 블록 렌더링"""
100+
if console is None:
101+
from .console import get_console
102+
console = get_console()
103+
104+
text = Text()
105+
text.append("$ ", style=f"{tokens.color.accent} bold")
106+
text.append(command, style=f"{tokens.color.primary} bold")
107+
108+
panel = Panel(
109+
text,
110+
border_style=tokens.color.accent,
111+
box=box.ROUNDED,
112+
padding=(0, 1)
113+
)
114+
console.print(panel)
115+
116+
117+
class OutputBlock:
118+
"""출력 블록 (결과 출력 영역)"""
119+
120+
@staticmethod
121+
def render(content: str, title: Optional[str] = None, console: Optional[Console] = None) -> None:
122+
"""출력 블록 렌더링"""
123+
if console is None:
124+
from .console import get_console
125+
console = get_console()
126+
127+
panel = Panel(
128+
content,
129+
title=title,
130+
border_style=tokens.color.muted,
131+
box=box.ROUNDED,
132+
padding=(0, 1)
133+
)
134+
console.print(panel)
135+
136+
137+
class Prompt:
138+
"""프롬프트 컴포넌트 ($, > 같은 입력 시작점)"""
139+
140+
@staticmethod
141+
def render(prompt_char: str = "$", style: str = None) -> str:
142+
"""프롬프트 렌더링"""
143+
if style is None:
144+
style = f"{tokens.color.accent} bold"
145+
return f"[{style}]{prompt_char}[/{style}] "
146+
147+
148+
class Spinner:
149+
"""로딩 스피너"""
150+
151+
@staticmethod
152+
def create(description: str = "Loading...") -> Progress:
153+
"""스피너 생성"""
154+
return Progress(
155+
SpinnerColumn(),
156+
TextColumn(f"[{tokens.color.info}]{description}[/{tokens.color.info}]"),
157+
console=get_console(),
158+
transient=True
159+
)
160+
161+
162+
class ProgressBar:
163+
"""진행률 표시"""
164+
165+
@staticmethod
166+
def create(total: int, description: str = "Progress") -> Progress:
167+
"""진행률 바 생성"""
168+
return Progress(
169+
TextColumn(f"[{tokens.color.info}]{description}[/{tokens.color.info}]"),
170+
BarColumn(),
171+
TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
172+
console=get_console(),
173+
transient=False
174+
)
175+
176+
177+
def get_console() -> Console:
178+
"""Console 인스턴스 반환"""
179+
from .console import get_console as _get_console
180+
return _get_console()
181+

src/llmkit/ui/console.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""
2+
Console Utilities
3+
터미널 콘솔 유틸리티
4+
"""
5+
from rich.console import Console
6+
from typing import Optional
7+
8+
# 전역 Console 인스턴스
9+
_console: Optional[Console] = None
10+
11+
12+
def get_console() -> Console:
13+
"""Console 인스턴스 반환 (싱글톤)"""
14+
global _console
15+
if _console is None:
16+
_console = Console()
17+
return _console
18+
19+
20+
def styled_print(text: str, style: str = ""):
21+
"""스타일 적용 출력"""
22+
console = get_console()
23+
if style:
24+
console.print(f"[{style}]{text}[/{style}]")
25+
else:
26+
console.print(text)
27+

0 commit comments

Comments
 (0)