Files
geutebruck/parse_all_actions.py
Administrator 14893e62a5 feat: Geutebruck GeViScope/GeViSoft Action Mapping System - MVP
This MVP release provides a complete full-stack solution for managing action mappings
in Geutebruck's GeViScope and GeViSoft video surveillance systems.

## Features

### Flutter Web Application (Port 8081)
- Modern, responsive UI for managing action mappings
- Action picker dialog with full parameter configuration
- Support for both GSC (GeViScope) and G-Core server actions
- Consistent UI for input and output actions with edit/delete capabilities
- Real-time action mapping creation, editing, and deletion
- Server categorization (GSC: prefix for GeViScope, G-Core: prefix for G-Core servers)

### FastAPI REST Backend (Port 8000)
- RESTful API for action mapping CRUD operations
- Action template service with comprehensive action catalog (247 actions)
- Server management (G-Core and GeViScope servers)
- Configuration tree reading and writing
- JWT authentication with role-based access control
- PostgreSQL database integration

### C# SDK Bridge (gRPC, Port 50051)
- Native integration with GeViSoft SDK (GeViProcAPINET_4_0.dll)
- Action mapping creation with correct binary format
- Support for GSC and G-Core action types
- Proper Camera parameter inclusion in action strings (fixes CrossSwitch bug)
- Action ID lookup table with server-specific action IDs
- Configuration reading/writing via SetupClient

## Bug Fixes
- **CrossSwitch Bug**: GSC and G-Core actions now correctly display camera/PTZ head parameters in GeViSet
- Action strings now include Camera parameter: `@ PanLeft (Comment: "", Camera: 101028)`
- Proper filter flags and VideoInput=0 for action mappings
- Correct action ID assignment (4198 for GSC, 9294 for G-Core PanLeft)

## Technical Stack
- **Frontend**: Flutter Web, Dart, Dio HTTP client
- **Backend**: Python FastAPI, PostgreSQL, Redis
- **SDK Bridge**: C# .NET 8.0, gRPC, GeViSoft SDK
- **Authentication**: JWT tokens
- **Configuration**: GeViSoft .set files (binary format)

## Credentials
- GeViSoft/GeViScope: username=sysadmin, password=masterkey
- Default admin: username=admin, password=admin123

## Deployment
All services run on localhost:
- Flutter Web: http://localhost:8081
- FastAPI: http://localhost:8000
- SDK Bridge gRPC: localhost:50051
- GeViServer: localhost (default port)

Generated with Claude Code (https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-31 18:10:54 +01:00

165 lines
5.7 KiB
Python

"""
Parse all action documentation HTML files to extract complete action catalog
"""
import re
import json
from pathlib import Path
from bs4 import BeautifulSoup
# Base path for action documentation
ACTION_DOCS_PATH = Path(r"C:\DEV\COPILOT\SOURCES\CODEX\GeViScope\GeViScopeSDK_HTML5\Content\ActionDoku")
# Category mapping from filename to display name
CATEGORY_MAPPING = {
"ATMActions.htm": "ATM",
"AudioActions.htm": "Audio",
"BackupActions.htm": "Backup",
"CameraControlActions.htm": "Camera Control",
"CashManagementActions.htm": "Cash Management",
"DeviceActions.htm": "Device",
"DigitalContactsActions.htm": "Digital Contacts",
"LogisticActions.htm": "Logistics",
"LPSActions.htm": "License Plate System",
"POSActions.htm": "Point of Sale",
"RemoteExportActions.htm": "Remote Export",
"SkiDataActions.htm": "Ski Data",
"SystemActions.htm": "System",
"VideoActions.htm": "Video",
"ViewerActions.htm": "Viewer",
"ViewerNotificationActions.htm": "Viewer Notification",
"Lenelactions.htm": "Lenel Access Control"
}
def extract_action_name(action_name_str):
"""
Extract action name and parameters from string like:
'CustomAction(Int, String)' -> ('CustomAction', ['Int', 'String'])
"""
match = re.match(r'([A-Za-z0-9_]+)\((.*?)\)', action_name_str)
if match:
name = match.group(1)
params_str = match.group(2)
if params_str.strip():
params = [p.strip() for p in params_str.split(',')]
else:
params = []
return name, params
return action_name_str, []
def parse_action_html(html_file, category):
"""Parse a single HTML file and extract all actions"""
actions = {}
try:
with open(html_file, 'r', encoding='utf-8') as f:
soup = BeautifulSoup(f.read(), 'html.parser')
# Find all h2 headers (each action starts with h2)
for h2 in soup.find_all('h2'):
# Get the next p tag which should contain "Action name:"
action_name_p = h2.find_next('p')
if not action_name_p:
continue
action_name_text = action_name_p.get_text()
if not action_name_text.startswith('Action name:'):
continue
# Extract action name
action_full_name = action_name_text.replace('Action name:', '').strip()
action_name, param_types = extract_action_name(action_full_name)
# Get action category (logical, notification, command)
category_p = action_name_p.find_next('p')
action_category = "unknown"
if category_p and 'Action category:' in category_p.get_text():
action_category = category_p.get_text().replace('Action category:', '').strip()
# Get description
desc_p = category_p.find_next('p') if category_p else h2.find_next('p', class_=None)
description = desc_p.get_text().strip() if desc_p else ""
# Find parameter table
param_table = None
current = h2.find_next_sibling()
while current and current.name != 'h2':
if current.name == 'table':
param_table = current
break
current = current.find_next_sibling()
# Extract parameters from table
parameters = []
if param_table:
rows = param_table.find_all('tr')
for row in rows[1:]: # Skip header row
cols = row.find_all('td')
if len(cols) >= 2:
param_name = cols[0].get_text().strip()
param_type = cols[1].get_text().strip()
if param_name and param_type:
parameters.append(param_name)
# Store action info
actions[action_name] = {
"parameters": parameters,
"description": description,
"category": category,
"action_category": action_category,
"required_caption": True, # Default, can be refined
"supports_delay": True # Default, can be refined
}
print(f" Found: {action_name} ({len(parameters)} params)")
except Exception as e:
print(f"Error parsing {html_file}: {e}")
return actions
def main():
"""Parse all action HTML files and create comprehensive action catalog"""
all_actions = {}
print("Parsing action documentation files...")
print("=" * 60)
for filename, category_name in CATEGORY_MAPPING.items():
html_file = ACTION_DOCS_PATH / filename
if not html_file.exists():
print(f"⚠ Skipping {filename} (not found)")
continue
print(f"\n{category_name} ({filename})")
print("-" * 60)
actions = parse_action_html(html_file, category_name)
all_actions.update(actions)
print(f" Total: {len(actions)} actions")
print("\n" + "=" * 60)
print(f"TOTAL ACTIONS FOUND: {len(all_actions)}")
print("=" * 60)
# Save to JSON
output_file = Path(r"C:\DEV\COPILOT\all_actions_catalog.json")
with open(output_file, 'w', encoding='utf-8') as f:
json.dump(all_actions, f, indent=2, ensure_ascii=False)
print(f"\nSaved to: {output_file}")
# Print category breakdown
print("\nActions by category:")
category_counts = {}
for action_name, action_info in all_actions.items():
cat = action_info['category']
category_counts[cat] = category_counts.get(cat, 0) + 1
for cat, count in sorted(category_counts.items(), key=lambda x: x[1], reverse=True):
print(f" {cat}: {count} actions")
if __name__ == "__main__":
main()