Initial commit
This commit is contained in:
244
scripts/analyze_requirements.py
Normal file
244
scripts/analyze_requirements.py
Normal file
@@ -0,0 +1,244 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Requirement analyzer for Bubble Tea TUIs.
|
||||
Extracts structured requirements from natural language.
|
||||
"""
|
||||
|
||||
import re
|
||||
from typing import Dict, List
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).parent))
|
||||
|
||||
from utils.validators import RequirementValidator
|
||||
|
||||
|
||||
# TUI archetype keywords
|
||||
ARCHETYPE_KEYWORDS = {
|
||||
'file-manager': ['file', 'directory', 'browse', 'navigator', 'ranger', 'three-column'],
|
||||
'installer': ['install', 'package', 'progress', 'setup', 'installation'],
|
||||
'dashboard': ['dashboard', 'monitor', 'real-time', 'metrics', 'status'],
|
||||
'form': ['form', 'input', 'wizard', 'configuration', 'settings'],
|
||||
'viewer': ['view', 'display', 'log', 'text', 'document', 'reader'],
|
||||
'chat': ['chat', 'message', 'conversation', 'messaging'],
|
||||
'table-viewer': ['table', 'data', 'spreadsheet', 'grid'],
|
||||
'menu': ['menu', 'select', 'choose', 'options'],
|
||||
'editor': ['edit', 'editor', 'compose', 'write']
|
||||
}
|
||||
|
||||
|
||||
def extract_requirements(description: str) -> Dict:
|
||||
"""
|
||||
Extract structured requirements from description.
|
||||
|
||||
Args:
|
||||
description: Natural language TUI description
|
||||
|
||||
Returns:
|
||||
Dictionary with structured requirements
|
||||
|
||||
Example:
|
||||
>>> reqs = extract_requirements("Build a log viewer with search")
|
||||
>>> reqs['archetype']
|
||||
'viewer'
|
||||
"""
|
||||
# Validate input
|
||||
validator = RequirementValidator()
|
||||
validation = validator.validate_description(description)
|
||||
|
||||
desc_lower = description.lower()
|
||||
|
||||
# Extract archetype
|
||||
archetype = classify_tui_type(description)
|
||||
|
||||
# Extract features
|
||||
features = identify_features(description)
|
||||
|
||||
# Extract interactions
|
||||
interactions = identify_interactions(description)
|
||||
|
||||
# Extract data types
|
||||
data_types = identify_data_types(description)
|
||||
|
||||
# Determine view type
|
||||
views = determine_view_type(description)
|
||||
|
||||
# Special requirements
|
||||
special = identify_special_requirements(description)
|
||||
|
||||
requirements = {
|
||||
'archetype': archetype,
|
||||
'features': features,
|
||||
'interactions': interactions,
|
||||
'data_types': data_types,
|
||||
'views': views,
|
||||
'special_requirements': special,
|
||||
'original_description': description,
|
||||
'validation': validation.to_dict()
|
||||
}
|
||||
|
||||
return requirements
|
||||
|
||||
|
||||
def classify_tui_type(description: str) -> str:
|
||||
"""Classify TUI archetype from description."""
|
||||
desc_lower = description.lower()
|
||||
|
||||
# Score each archetype
|
||||
scores = {}
|
||||
for archetype, keywords in ARCHETYPE_KEYWORDS.items():
|
||||
score = sum(1 for kw in keywords if kw in desc_lower)
|
||||
if score > 0:
|
||||
scores[archetype] = score
|
||||
|
||||
if not scores:
|
||||
return 'general'
|
||||
|
||||
# Return highest scoring archetype
|
||||
return max(scores.items(), key=lambda x: x[1])[0]
|
||||
|
||||
|
||||
def identify_features(description: str) -> List[str]:
|
||||
"""Identify features from description."""
|
||||
features = []
|
||||
desc_lower = description.lower()
|
||||
|
||||
feature_keywords = {
|
||||
'navigation': ['navigate', 'move', 'browse', 'arrow'],
|
||||
'selection': ['select', 'choose', 'pick'],
|
||||
'search': ['search', 'find', 'filter', 'query'],
|
||||
'editing': ['edit', 'modify', 'change', 'update'],
|
||||
'display': ['display', 'show', 'view', 'render'],
|
||||
'input': ['input', 'enter', 'type'],
|
||||
'progress': ['progress', 'loading', 'install'],
|
||||
'preview': ['preview', 'peek', 'preview pane'],
|
||||
'scrolling': ['scroll', 'scrollable'],
|
||||
'sorting': ['sort', 'order', 'rank'],
|
||||
'filtering': ['filter', 'narrow'],
|
||||
'highlighting': ['highlight', 'emphasize', 'mark']
|
||||
}
|
||||
|
||||
for feature, keywords in feature_keywords.items():
|
||||
if any(kw in desc_lower for kw in keywords):
|
||||
features.append(feature)
|
||||
|
||||
return features if features else ['display']
|
||||
|
||||
|
||||
def identify_interactions(description: str) -> Dict[str, List[str]]:
|
||||
"""Identify user interaction types."""
|
||||
desc_lower = description.lower()
|
||||
|
||||
keyboard = []
|
||||
mouse = []
|
||||
|
||||
# Keyboard interactions
|
||||
kbd_keywords = {
|
||||
'navigation': ['arrow', 'hjkl', 'navigate', 'move'],
|
||||
'selection': ['enter', 'select', 'choose'],
|
||||
'search': ['/', 'search', 'find'],
|
||||
'quit': ['q', 'quit', 'exit', 'esc'],
|
||||
'help': ['?', 'help']
|
||||
}
|
||||
|
||||
for interaction, keywords in kbd_keywords.items():
|
||||
if any(kw in desc_lower for kw in keywords):
|
||||
keyboard.append(interaction)
|
||||
|
||||
# Default keyboard interactions
|
||||
if not keyboard:
|
||||
keyboard = ['navigation', 'selection', 'quit']
|
||||
|
||||
# Mouse interactions
|
||||
if any(word in desc_lower for word in ['mouse', 'click', 'drag']):
|
||||
mouse = ['click', 'scroll']
|
||||
|
||||
return {
|
||||
'keyboard': keyboard,
|
||||
'mouse': mouse
|
||||
}
|
||||
|
||||
|
||||
def identify_data_types(description: str) -> List[str]:
|
||||
"""Identify data types being displayed."""
|
||||
desc_lower = description.lower()
|
||||
|
||||
data_type_keywords = {
|
||||
'files': ['file', 'directory', 'folder'],
|
||||
'text': ['text', 'log', 'document'],
|
||||
'tabular': ['table', 'data', 'rows', 'columns'],
|
||||
'messages': ['message', 'chat', 'conversation'],
|
||||
'packages': ['package', 'dependency', 'module'],
|
||||
'metrics': ['metric', 'stat', 'data point'],
|
||||
'config': ['config', 'setting', 'option']
|
||||
}
|
||||
|
||||
data_types = []
|
||||
for dtype, keywords in data_type_keywords.items():
|
||||
if any(kw in desc_lower for kw in keywords):
|
||||
data_types.append(dtype)
|
||||
|
||||
return data_types if data_types else ['text']
|
||||
|
||||
|
||||
def determine_view_type(description: str) -> str:
|
||||
"""Determine if single or multi-view."""
|
||||
desc_lower = description.lower()
|
||||
|
||||
multi_keywords = ['multi-view', 'multiple view', 'tabs', 'tabbed', 'switch', 'views']
|
||||
three_pane_keywords = ['three', 'three-column', 'three pane']
|
||||
|
||||
if any(kw in desc_lower for kw in three_pane_keywords):
|
||||
return 'three-pane'
|
||||
elif any(kw in desc_lower for kw in multi_keywords):
|
||||
return 'multi'
|
||||
else:
|
||||
return 'single'
|
||||
|
||||
|
||||
def identify_special_requirements(description: str) -> List[str]:
|
||||
"""Identify special requirements."""
|
||||
desc_lower = description.lower()
|
||||
special = []
|
||||
|
||||
special_keywords = {
|
||||
'validation': ['validate', 'validation', 'check'],
|
||||
'real-time': ['real-time', 'live', 'streaming'],
|
||||
'async': ['async', 'background', 'concurrent'],
|
||||
'persistence': ['save', 'persist', 'store'],
|
||||
'theming': ['theme', 'color', 'style']
|
||||
}
|
||||
|
||||
for req, keywords in special_keywords.items():
|
||||
if any(kw in desc_lower for kw in keywords):
|
||||
special.append(req)
|
||||
|
||||
return special
|
||||
|
||||
|
||||
def main():
|
||||
"""Test requirement analyzer."""
|
||||
print("Testing Requirement Analyzer\n" + "=" * 50)
|
||||
|
||||
test_cases = [
|
||||
"Build a log viewer with search and highlighting",
|
||||
"Create a file manager with three-column view",
|
||||
"Design an installer with progress bars",
|
||||
"Make a form wizard with validation"
|
||||
]
|
||||
|
||||
for i, desc in enumerate(test_cases, 1):
|
||||
print(f"\n{i}. Testing: '{desc}'")
|
||||
reqs = extract_requirements(desc)
|
||||
print(f" Archetype: {reqs['archetype']}")
|
||||
print(f" Features: {', '.join(reqs['features'])}")
|
||||
print(f" Data types: {', '.join(reqs['data_types'])}")
|
||||
print(f" View type: {reqs['views']}")
|
||||
print(f" Validation: {reqs['validation']['summary']}")
|
||||
|
||||
print("\n✅ All tests passed!")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user