58ca4e68db
- Go backend API with full CRUD for all modules (CRM, Sales, Finance, HR, Legal, Marketing, Support, Purchase, Inventory, Projects, Automation, Analytics) - Rust analytics service with parallel report generation - C runtime with POSIX shared memory IPC - PostgreSQL schema with 30+ tables, full migrations - Redis cache, sessions, pub/sub - Kafka event streaming with Zookeeper - WebSocket hub for real-time updates - Automation engine with cron jobs, workflows, event triggers - JWT authentication, multi-tenant from start - Docker Compose with all services - Nginx reverse proxy with rate limiting - Integration tests passing - Feature gap analysis against Fortnox/Odoo/Visma Refs: BOC-001
308 lines
7.7 KiB
Python
308 lines
7.7 KiB
Python
"""
|
|
VIMS Instance Creator
|
|
|
|
Creates a new VIMS instance for any article/topic.
|
|
Usage:
|
|
python scripts/create_instance.py \
|
|
--name "street-lighting" \
|
|
--display-name "Street Lighting Monitoring" \
|
|
--classes "pole_damage,light_out,vegetation_obstruction,vandalism" \
|
|
--article-url "/insights/evidence-driven-municipal-maintenance/"
|
|
"""
|
|
|
|
import os
|
|
import argparse
|
|
from pathlib import Path
|
|
|
|
|
|
def create_instance(
|
|
name: str,
|
|
display_name: str,
|
|
classes: str,
|
|
article_url: str,
|
|
base_dir: str = "/home/bernt/.openclaw/workspace/vims-core/instances"
|
|
):
|
|
"""
|
|
Create new VIMS instance.
|
|
|
|
Args:
|
|
name: Instance name (directory name)
|
|
display_name: Human-readable name
|
|
classes: Comma-separated anomaly classes
|
|
article_url: Related Landvex article URL
|
|
base_dir: Base directory for instances
|
|
"""
|
|
instance_dir = Path(base_dir) / name
|
|
instance_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
# Create subdirectories
|
|
(instance_dir / "data" / "raw").mkdir(parents=True, exist_ok=True)
|
|
(instance_dir / "data" / "processed").mkdir(parents=True, exist_ok=True)
|
|
(instance_dir / "data" / "annotations").mkdir(parents=True, exist_ok=True)
|
|
(instance_dir / "models").mkdir(exist_ok=True)
|
|
(instance_dir / "src").mkdir(exist_ok=True)
|
|
|
|
class_list = [c.strip() for c in classes.split(",")]
|
|
|
|
# Create detector module
|
|
detector_code = f'''"""
|
|
{name} Anomaly Detector
|
|
Generated by VIMS Instance Creator
|
|
Related article: {article_url}
|
|
"""
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
sys.path.append(str(Path(__file__).parent.parent.parent / "core"))
|
|
|
|
from base_detector import VIMSBaseDetector, VIMSInstanceRegistry
|
|
|
|
|
|
class {name.title().replace("-", "")}Detector(VIMSBaseDetector):
|
|
"""
|
|
Anomaly detector for {display_name}.
|
|
|
|
Article: {article_url}
|
|
"""
|
|
|
|
TOPIC = "{name}"
|
|
CLASS_NAMES = {{
|
|
{', '.join([f'{i}: "{c}"' for i, c in enumerate(class_list)])}
|
|
}}
|
|
|
|
SEVERITY_MAP = {{
|
|
{', '.join([f'"{c}": 3' for c in class_list])}
|
|
}}
|
|
|
|
def preprocess(self, image):
|
|
"""{name}-specific preprocessing."""
|
|
# TODO: Implement specific preprocessing
|
|
return image
|
|
|
|
def postprocess(self, raw_output):
|
|
"""{name}-specific postprocessing."""
|
|
# TODO: Implement specific postprocessing
|
|
return raw_output
|
|
|
|
|
|
# Register instance
|
|
VIMSInstanceRegistry.register("{name}", {name.title().replace("-", "")}Detector)
|
|
'''
|
|
|
|
(instance_dir / "src" / "detector.py").write_text(detector_code)
|
|
|
|
# Create database setup
|
|
db_code = f'''"""
|
|
Database setup for {display_name}
|
|
"""
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
sys.path.append(str(Path(__file__).parent.parent.parent / "core"))
|
|
|
|
from database import VIMSDatabase
|
|
|
|
|
|
def setup():
|
|
"""Initialize database for {name}."""
|
|
db = VIMSDatabase("{name}")
|
|
db.create_schema(anomaly_classes={class_list})
|
|
print(f"Database initialized for {display_name}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
setup()
|
|
'''
|
|
|
|
(instance_dir / "src" / "database.py").write_text(db_code)
|
|
|
|
# Create README
|
|
readme = f'''# {display_name}
|
|
|
|
VIMS instance for {name}.
|
|
|
|
## Related Article
|
|
[{article_url}](https://landvex.com{article_url})
|
|
|
|
## Anomaly Classes
|
|
{chr(10).join([f"- {c}" for c in class_list])}
|
|
|
|
## Quick Start
|
|
|
|
1. Add training images to `data/raw/`
|
|
2. Annotate using LabelImg (YOLO format)
|
|
3. Run preprocessing: `python src/detector.py`
|
|
4. Train model: `python src/detector.py --train`
|
|
5. Run inference: `python src/detector.py --predict data/test/image.jpg`
|
|
|
|
## API
|
|
|
|
Once deployed, access via:
|
|
- REST: `POST /api/{name}/predict`
|
|
- WebSocket: `ws://host/ws/{name}/alerts`
|
|
'''
|
|
|
|
(instance_dir / "README.md").write_text(readme)
|
|
|
|
# Create config
|
|
config = f'''# {name} configuration
|
|
|
|
topic: {name}
|
|
display_name: {display_name}
|
|
article_url: {article_url}
|
|
|
|
anomaly_classes:
|
|
{chr(10).join([f" - {c}" for c in class_list])}
|
|
|
|
model:
|
|
base: yolov8n.pt
|
|
input_size: 640
|
|
|
|
training:
|
|
epochs: 100
|
|
batch_size: 16
|
|
'''
|
|
|
|
(instance_dir / "config.yaml").write_text(config)
|
|
|
|
print(f"✅ Created VIMS instance: {name}")
|
|
print(f" Location: {instance_dir}")
|
|
print(f" Classes: {', '.join(class_list)}")
|
|
print(f" Article: {article_url}")
|
|
print()
|
|
print("Next steps:")
|
|
print(f" 1. cd {instance_dir}")
|
|
print(" 2. Add training images to data/raw/")
|
|
print(" 3. python src/database.py")
|
|
print(" 4. python src/detector.py --train")
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Create VIMS Instance")
|
|
parser.add_argument("--name", required=True, help="Instance name (directory)")
|
|
parser.add_argument("--display-name", required=True, help="Human-readable name")
|
|
parser.add_argument("--classes", required=True, help="Comma-separated anomaly classes")
|
|
parser.add_argument("--article-url", required=True, help="Related article URL")
|
|
|
|
args = parser.parse_args()
|
|
|
|
create_instance(
|
|
name=args.name,
|
|
display_name=args.display_name,
|
|
classes=args.classes,
|
|
article_url=args.article_url
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
'''
|
|
|
|
(instance_dir / "src" / "detector.py").write_text(detector_code)
|
|
|
|
# Create database setup
|
|
db_code = f'''"""
|
|
Database setup for {display_name}
|
|
"""
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
sys.path.append(str(Path(__file__).parent.parent.parent / "core"))
|
|
|
|
from database import VIMSDatabase
|
|
|
|
|
|
def setup():
|
|
"""Initialize database for {name}."""
|
|
db = VIMSDatabase("{name}")
|
|
db.create_schema(anomaly_classes={class_list})
|
|
print(f"Database initialized for {display_name}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
setup()
|
|
'''
|
|
|
|
(instance_dir / "src" / "database.py").write_text(db_code)
|
|
|
|
# Create README
|
|
readme = f'''# {display_name}
|
|
|
|
VIMS instance for {name}.
|
|
|
|
## Related Article
|
|
[{article_url}](https://landvex.com{article_url})
|
|
|
|
## Anomaly Classes
|
|
{chr(10).join([f"- {c}" for c in class_list])}
|
|
|
|
## Quick Start
|
|
|
|
1. Add training images to `data/raw/`
|
|
2. Annotate using LabelImg (YOLO format)
|
|
3. Run preprocessing: `python src/detector.py`
|
|
4. Train model: `python src/detector.py --train`
|
|
5. Run inference: `python src/detector.py --predict data/test/image.jpg`
|
|
|
|
## API
|
|
|
|
Once deployed, access via:
|
|
- REST: `POST /api/{name}/predict`
|
|
- WebSocket: `ws://host/ws/{name}/alerts`
|
|
'''
|
|
|
|
(instance_dir / "README.md").write_text(readme)
|
|
|
|
# Create config
|
|
config = f'''# {name} configuration
|
|
|
|
topic: {name}
|
|
display_name: {display_name}
|
|
article_url: {article_url}
|
|
|
|
anomaly_classes:
|
|
{chr(10).join([f" - {c}" for c in class_list])}
|
|
|
|
model:
|
|
base: yolov8n.pt
|
|
input_size: 640
|
|
|
|
training:
|
|
epochs: 100
|
|
batch_size: 16
|
|
'''
|
|
|
|
(instance_dir / "config.yaml").write_text(config)
|
|
|
|
print(f"✅ Created VIMS instance: {name}")
|
|
print(f" Location: {instance_dir}")
|
|
print(f" Classes: {', '.join(class_list)}")
|
|
print(f" Article: {article_url}")
|
|
print()
|
|
print("Next steps:")
|
|
print(f" 1. cd {instance_dir}")
|
|
print(" 2. Add training images to data/raw/")
|
|
print(" 3. python src/database.py")
|
|
print(" 4. python src/detector.py --train")
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Create VIMS Instance")
|
|
parser.add_argument("--name", required=True, help="Instance name (directory)")
|
|
parser.add_argument("--display-name", required=True, help="Human-readable name")
|
|
parser.add_argument("--classes", required=True, help="Comma-separated anomaly classes")
|
|
parser.add_argument("--article-url", required=True, help="Related article URL")
|
|
|
|
args = parser.parse_args()
|
|
|
|
create_instance(
|
|
name=args.name,
|
|
display_name=args.display_name,
|
|
classes=args.classes,
|
|
article_url=args.article_url
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|