vibe-widget 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vibe_widget-0.1.0/.claude/settings.local.json +17 -0
- vibe_widget-0.1.0/.gitignore +70 -0
- vibe_widget-0.1.0/L8_001_004_016_2014_080_2014_096_v1.1.nc +0 -0
- vibe_widget-0.1.0/MANIFEST.in +3 -0
- vibe_widget-0.1.0/PKG-INFO +135 -0
- vibe_widget-0.1.0/README.md +101 -0
- vibe_widget-0.1.0/pyproject.toml +93 -0
- vibe_widget-0.1.0/src/vibe_widget/__init__.py +4 -0
- vibe_widget-0.1.0/src/vibe_widget/code_parser.py +137 -0
- vibe_widget-0.1.0/src/vibe_widget/core.py +597 -0
- vibe_widget-0.1.0/src/vibe_widget/data_parser/PARESER.md +429 -0
- vibe_widget-0.1.0/src/vibe_widget/data_parser/data_profile.py +293 -0
- vibe_widget-0.1.0/src/vibe_widget/data_parser/extractors.py +692 -0
- vibe_widget-0.1.0/src/vibe_widget/data_parser/preprocessor.py +418 -0
- vibe_widget-0.1.0/src/vibe_widget/llm/__init__.py +4 -0
- vibe_widget-0.1.0/src/vibe_widget/llm/base.py +8 -0
- vibe_widget-0.1.0/src/vibe_widget/llm/claude.py +178 -0
- vibe_widget-0.1.0/src/vibe_widget/progress.py +154 -0
- vibe_widget-0.1.0/test.py +9 -0
- vibe_widget-0.1.0/tests/__init__.py +0 -0
- vibe_widget-0.1.0/tests/test_core.py +20 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(tree:*)",
|
|
5
|
+
"Bash(python3:*)",
|
|
6
|
+
"Bash(pip install:*)",
|
|
7
|
+
"Bash(npm run build:*)",
|
|
8
|
+
"Bash(npm install:*)",
|
|
9
|
+
"Bash(chmod:*)",
|
|
10
|
+
"Bash(./scripts/build-react-widget.sh:*)",
|
|
11
|
+
"Bash(python:*)",
|
|
12
|
+
"Bash(pkill:*)"
|
|
13
|
+
],
|
|
14
|
+
"deny": [],
|
|
15
|
+
"ask": []
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
develop-eggs/
|
|
9
|
+
dist/
|
|
10
|
+
downloads/
|
|
11
|
+
eggs/
|
|
12
|
+
.eggs/
|
|
13
|
+
lib/
|
|
14
|
+
lib64/
|
|
15
|
+
parts/
|
|
16
|
+
sdist/
|
|
17
|
+
var/
|
|
18
|
+
wheels/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
.installed.cfg
|
|
21
|
+
*.egg
|
|
22
|
+
MANIFEST
|
|
23
|
+
|
|
24
|
+
# Virtual environments
|
|
25
|
+
venv/
|
|
26
|
+
env/
|
|
27
|
+
ENV/
|
|
28
|
+
.venv
|
|
29
|
+
|
|
30
|
+
# IDEs
|
|
31
|
+
.vscode/
|
|
32
|
+
.idea/
|
|
33
|
+
*.swp
|
|
34
|
+
*.swo
|
|
35
|
+
*~
|
|
36
|
+
.DS_Store
|
|
37
|
+
|
|
38
|
+
# Testing
|
|
39
|
+
.pytest_cache/
|
|
40
|
+
.coverage
|
|
41
|
+
htmlcov/
|
|
42
|
+
.tox/
|
|
43
|
+
.mypy_cache/
|
|
44
|
+
.ruff_cache/
|
|
45
|
+
|
|
46
|
+
# Distribution
|
|
47
|
+
pip-wheel-metadata/
|
|
48
|
+
|
|
49
|
+
# Jupyter
|
|
50
|
+
.ipynb_checkpoints
|
|
51
|
+
*.ipynb
|
|
52
|
+
|
|
53
|
+
# Environment variables
|
|
54
|
+
.env
|
|
55
|
+
.env.local
|
|
56
|
+
|
|
57
|
+
# Generated widgets
|
|
58
|
+
*.html
|
|
59
|
+
output/
|
|
60
|
+
|
|
61
|
+
.meridian/
|
|
62
|
+
|
|
63
|
+
# Vibe widget cache
|
|
64
|
+
.vibe_cache/
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
/venv311/
|
|
69
|
+
**/widgets/**
|
|
70
|
+
/testdata/
|
|
Binary file
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: vibe_widget
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Create interactive visualizations using natural language and LLMs
|
|
5
|
+
Project-URL: Homepage, https://github.com/yourusername/vibe-widget
|
|
6
|
+
Project-URL: Documentation, https://github.com/yourusername/vibe-widget#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/yourusername/vibe-widget
|
|
8
|
+
Project-URL: Issues, https://github.com/yourusername/vibe-widget/issues
|
|
9
|
+
Author-email: Your Name <your.email@example.com>
|
|
10
|
+
License: MIT
|
|
11
|
+
Keywords: interactive,jupyter,llm,visualization,widgets
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Requires-Dist: anthropic>=0.40.0
|
|
24
|
+
Requires-Dist: anywidget>=0.9.0
|
|
25
|
+
Requires-Dist: pandas>=2.0.0
|
|
26
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: ipython>=8.12.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: mypy>=1.8.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
32
|
+
Requires-Dist: ruff>=0.6.0; extra == 'dev'
|
|
33
|
+
Description-Content-Type: text/markdown
|
|
34
|
+
|
|
35
|
+
# Vibe Widget
|
|
36
|
+
|
|
37
|
+
Create interactive visualizations using natural language and LLMs.
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
pip install vibe-widget
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Or with `uv`:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
uv pip install vibe-widget
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Quick Start
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
import pandas as pd
|
|
55
|
+
import vibe_widget as vw
|
|
56
|
+
|
|
57
|
+
df = pd.DataFrame({
|
|
58
|
+
'height': [150, 160, 170, 180, 190],
|
|
59
|
+
'weight': [50, 60, 70, 80, 90]
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
vw.create("an interactive scatterplot of height and weight", df)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
This will:
|
|
66
|
+
1. Analyze your data structure
|
|
67
|
+
2. Generate a React component via Claude API
|
|
68
|
+
3. Return an HTML file with the interactive visualization
|
|
69
|
+
|
|
70
|
+
## API Key Setup
|
|
71
|
+
|
|
72
|
+
Set your Anthropic API key:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
export ANTHROPIC_API_KEY='your-api-key-here'
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Or pass it directly:
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
vw.create(
|
|
82
|
+
"a bar chart of sales by region",
|
|
83
|
+
df,
|
|
84
|
+
api_key="your-api-key-here"
|
|
85
|
+
)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Saving to File
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
vw.create(
|
|
92
|
+
"an interactive line chart showing trends over time",
|
|
93
|
+
df,
|
|
94
|
+
output_path="output/visualization.html"
|
|
95
|
+
)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Development
|
|
99
|
+
|
|
100
|
+
Install with dev dependencies:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
pip install -e ".[dev]"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Run tests:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
pytest
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Lint and format:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
ruff check .
|
|
116
|
+
ruff format .
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Type checking:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
mypy src/
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Features
|
|
126
|
+
|
|
127
|
+
- 🚀 Modern Python packaging (pyproject.toml, src layout)
|
|
128
|
+
- 🤖 LLM-powered visualization generation
|
|
129
|
+
- ⚛️ React-based interactive widgets
|
|
130
|
+
- 📊 Pandas DataFrame integration
|
|
131
|
+
- 🔧 Extensible LLM provider system
|
|
132
|
+
|
|
133
|
+
## License
|
|
134
|
+
|
|
135
|
+
MIT
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Vibe Widget
|
|
2
|
+
|
|
3
|
+
Create interactive visualizations using natural language and LLMs.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install vibe-widget
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or with `uv`:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
uv pip install vibe-widget
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
import pandas as pd
|
|
21
|
+
import vibe_widget as vw
|
|
22
|
+
|
|
23
|
+
df = pd.DataFrame({
|
|
24
|
+
'height': [150, 160, 170, 180, 190],
|
|
25
|
+
'weight': [50, 60, 70, 80, 90]
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
vw.create("an interactive scatterplot of height and weight", df)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
This will:
|
|
32
|
+
1. Analyze your data structure
|
|
33
|
+
2. Generate a React component via Claude API
|
|
34
|
+
3. Return an HTML file with the interactive visualization
|
|
35
|
+
|
|
36
|
+
## API Key Setup
|
|
37
|
+
|
|
38
|
+
Set your Anthropic API key:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
export ANTHROPIC_API_KEY='your-api-key-here'
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Or pass it directly:
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
vw.create(
|
|
48
|
+
"a bar chart of sales by region",
|
|
49
|
+
df,
|
|
50
|
+
api_key="your-api-key-here"
|
|
51
|
+
)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Saving to File
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
vw.create(
|
|
58
|
+
"an interactive line chart showing trends over time",
|
|
59
|
+
df,
|
|
60
|
+
output_path="output/visualization.html"
|
|
61
|
+
)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Development
|
|
65
|
+
|
|
66
|
+
Install with dev dependencies:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pip install -e ".[dev]"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Run tests:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
pytest
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Lint and format:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
ruff check .
|
|
82
|
+
ruff format .
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Type checking:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
mypy src/
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Features
|
|
92
|
+
|
|
93
|
+
- 🚀 Modern Python packaging (pyproject.toml, src layout)
|
|
94
|
+
- 🤖 LLM-powered visualization generation
|
|
95
|
+
- ⚛️ React-based interactive widgets
|
|
96
|
+
- 📊 Pandas DataFrame integration
|
|
97
|
+
- 🔧 Extensible LLM provider system
|
|
98
|
+
|
|
99
|
+
## License
|
|
100
|
+
|
|
101
|
+
MIT
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "vibe_widget"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Create interactive visualizations using natural language and LLMs"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Your Name", email = "your.email@example.com" }
|
|
14
|
+
]
|
|
15
|
+
keywords = ["visualization", "widgets", "llm", "interactive", "jupyter"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"Intended Audience :: Science/Research",
|
|
20
|
+
"License :: OSI Approved :: MIT License",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.9",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Topic :: Scientific/Engineering :: Visualization",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
dependencies = [
|
|
30
|
+
"anywidget>=0.9.0",
|
|
31
|
+
"anthropic>=0.40.0",
|
|
32
|
+
"pandas>=2.0.0",
|
|
33
|
+
"python-dotenv>=1.0.0",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.optional-dependencies]
|
|
37
|
+
dev = [
|
|
38
|
+
"pytest>=8.0.0",
|
|
39
|
+
"pytest-cov>=4.1.0",
|
|
40
|
+
"mypy>=1.8.0",
|
|
41
|
+
"ruff>=0.6.0",
|
|
42
|
+
"ipython>=8.12.0",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
[project.urls]
|
|
46
|
+
Homepage = "https://github.com/yourusername/vibe-widget"
|
|
47
|
+
Documentation = "https://github.com/yourusername/vibe-widget#readme"
|
|
48
|
+
Repository = "https://github.com/yourusername/vibe-widget"
|
|
49
|
+
Issues = "https://github.com/yourusername/vibe-widget/issues"
|
|
50
|
+
|
|
51
|
+
[tool.hatch.build.targets.wheel]
|
|
52
|
+
packages = ["src/vibe_widget"]
|
|
53
|
+
|
|
54
|
+
[tool.ruff]
|
|
55
|
+
line-length = 100
|
|
56
|
+
target-version = "py39"
|
|
57
|
+
|
|
58
|
+
[tool.ruff.lint]
|
|
59
|
+
select = [
|
|
60
|
+
"E", # pycodestyle errors
|
|
61
|
+
"W", # pycodestyle warnings
|
|
62
|
+
"F", # pyflakes
|
|
63
|
+
"I", # isort
|
|
64
|
+
"B", # flake8-bugbear
|
|
65
|
+
"C4", # flake8-comprehensions
|
|
66
|
+
"UP", # pyupgrade
|
|
67
|
+
]
|
|
68
|
+
ignore = [
|
|
69
|
+
"E501", # line too long (handled by formatter)
|
|
70
|
+
"B008", # do not perform function calls in argument defaults
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
[tool.ruff.format]
|
|
74
|
+
quote-style = "double"
|
|
75
|
+
indent-style = "space"
|
|
76
|
+
|
|
77
|
+
[tool.mypy]
|
|
78
|
+
python_version = "3.9"
|
|
79
|
+
warn_return_any = true
|
|
80
|
+
warn_unused_configs = true
|
|
81
|
+
disallow_untyped_defs = true
|
|
82
|
+
ignore_missing_imports = true
|
|
83
|
+
|
|
84
|
+
[tool.pytest.ini_options]
|
|
85
|
+
testpaths = ["tests"]
|
|
86
|
+
python_files = ["test_*.py"]
|
|
87
|
+
python_classes = ["Test*"]
|
|
88
|
+
python_functions = ["test_*"]
|
|
89
|
+
addopts = [
|
|
90
|
+
"--strict-markers",
|
|
91
|
+
"--strict-config",
|
|
92
|
+
"--cov=vibe_widget",
|
|
93
|
+
]
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import time
|
|
3
|
+
from typing import Dict, List, Tuple
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class CodeStreamParser:
|
|
7
|
+
"""Parse streaming JavaScript code to detect landmarks and generate micro-updates."""
|
|
8
|
+
|
|
9
|
+
BUBBLE_COOLDOWN = 0.5 # 500ms between bubbles of same type
|
|
10
|
+
|
|
11
|
+
PATTERNS = {
|
|
12
|
+
"import": (
|
|
13
|
+
r'import\s+.*?\s+from\s+["\'](?:https?://)?(?:esm\.sh/)?([^"\'@]+)(?:@([^"\']+))?',
|
|
14
|
+
"📦 Importing {package}..."
|
|
15
|
+
),
|
|
16
|
+
"function_render": (
|
|
17
|
+
r'function\s+render\s*\(',
|
|
18
|
+
"⚙️ Building render function..."
|
|
19
|
+
),
|
|
20
|
+
"const_data": (
|
|
21
|
+
r'const\s+data\s*=\s*model\.get\(',
|
|
22
|
+
"📊 Loading data..."
|
|
23
|
+
),
|
|
24
|
+
"svg_create": (
|
|
25
|
+
r'\.append\(["\']svg["\']\)',
|
|
26
|
+
"🎨 Creating SVG canvas..."
|
|
27
|
+
),
|
|
28
|
+
"element_create": (
|
|
29
|
+
r'\.append\(["\'](?:div|canvas|g|circle|rect|path)["\']\)',
|
|
30
|
+
"🎨 Adding visualization elements..."
|
|
31
|
+
),
|
|
32
|
+
"scale": (
|
|
33
|
+
r'd3\.scale(?:Linear|Band|Time|Point)',
|
|
34
|
+
"📏 Setting up scales..."
|
|
35
|
+
),
|
|
36
|
+
"axis": (
|
|
37
|
+
r'd3\.axis(?:Bottom|Left|Top|Right)',
|
|
38
|
+
"📐 Creating axes..."
|
|
39
|
+
),
|
|
40
|
+
"data_binding": (
|
|
41
|
+
r'model\.on\(["\']change:',
|
|
42
|
+
"🔄 Setting up reactivity..."
|
|
43
|
+
),
|
|
44
|
+
"selection": (
|
|
45
|
+
r'\.selectAll\(["\'][^"\']+["\']\)',
|
|
46
|
+
"🎯 Binding data to elements..."
|
|
47
|
+
),
|
|
48
|
+
"transition": (
|
|
49
|
+
r'\.transition\(\)',
|
|
50
|
+
"✨ Adding animations..."
|
|
51
|
+
),
|
|
52
|
+
"event_listener": (
|
|
53
|
+
r'\.on\(["\'](?:click|mouseover|mouseout)',
|
|
54
|
+
"👆 Adding interactivity..."
|
|
55
|
+
),
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
def __init__(self):
|
|
59
|
+
self.buffer = ""
|
|
60
|
+
self.detected = set()
|
|
61
|
+
self.actions = []
|
|
62
|
+
self.last_bubble_time = {}
|
|
63
|
+
self.has_new_updates = False
|
|
64
|
+
|
|
65
|
+
def parse_chunk(self, chunk: str) -> List[Dict[str, str]]:
|
|
66
|
+
"""Parse a code chunk and return detected micro-updates."""
|
|
67
|
+
self.buffer += chunk
|
|
68
|
+
updates = []
|
|
69
|
+
self.has_new_updates = False
|
|
70
|
+
current_time = time.time()
|
|
71
|
+
|
|
72
|
+
for pattern_name, (regex, message_template) in self.PATTERNS.items():
|
|
73
|
+
if pattern_name in self.detected:
|
|
74
|
+
continue
|
|
75
|
+
|
|
76
|
+
match = re.search(regex, self.buffer)
|
|
77
|
+
if match:
|
|
78
|
+
# Check cooldown - only emit bubble if enough time has passed
|
|
79
|
+
if pattern_name in self.last_bubble_time:
|
|
80
|
+
if current_time - self.last_bubble_time[pattern_name] < self.BUBBLE_COOLDOWN:
|
|
81
|
+
continue # Skip this update, too soon
|
|
82
|
+
|
|
83
|
+
self.detected.add(pattern_name)
|
|
84
|
+
self.last_bubble_time[pattern_name] = current_time
|
|
85
|
+
self.has_new_updates = True
|
|
86
|
+
|
|
87
|
+
# Extract package name for imports
|
|
88
|
+
if pattern_name == "import" and match.groups():
|
|
89
|
+
package = match.group(1)
|
|
90
|
+
version = match.group(2) if len(match.groups()) > 1 else None
|
|
91
|
+
message = message_template.format(
|
|
92
|
+
package=f"{package}@{version}" if version else package
|
|
93
|
+
)
|
|
94
|
+
else:
|
|
95
|
+
message = message_template
|
|
96
|
+
|
|
97
|
+
updates.append({
|
|
98
|
+
"type": "micro_bubble",
|
|
99
|
+
"message": message,
|
|
100
|
+
"pattern": pattern_name,
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
# Also create action tile for imports
|
|
104
|
+
if pattern_name == "import":
|
|
105
|
+
self.actions.append({
|
|
106
|
+
"type": "action_tile",
|
|
107
|
+
"title": "Loaded dependency",
|
|
108
|
+
"message": message,
|
|
109
|
+
"icon": "📦"
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
return updates
|
|
113
|
+
|
|
114
|
+
def has_new_pattern(self) -> bool:
|
|
115
|
+
"""Check if new patterns were detected in last parse."""
|
|
116
|
+
return self.has_new_updates
|
|
117
|
+
|
|
118
|
+
def get_actions(self) -> List[Dict[str, str]]:
|
|
119
|
+
"""Get all detected actions for the timeline."""
|
|
120
|
+
return self.actions
|
|
121
|
+
|
|
122
|
+
def get_progress(self) -> float:
|
|
123
|
+
"""Get code generation progress based on detected patterns (0.0 to 1.0)."""
|
|
124
|
+
total_patterns = len(self.PATTERNS)
|
|
125
|
+
detected_count = len(self.detected)
|
|
126
|
+
return min(1.0, detected_count / total_patterns)
|
|
127
|
+
|
|
128
|
+
def get_completion_summary(self) -> Dict[str, any]:
|
|
129
|
+
"""Get summary of detected code features."""
|
|
130
|
+
return {
|
|
131
|
+
"total_patterns": len(self.detected),
|
|
132
|
+
"has_imports": "import" in self.detected,
|
|
133
|
+
"has_reactivity": "data_binding" in self.detected,
|
|
134
|
+
"has_animation": "transition" in self.detected,
|
|
135
|
+
"has_interaction": "event_listener" in self.detected,
|
|
136
|
+
"detected_patterns": list(self.detected),
|
|
137
|
+
}
|