Skip to main content
Glama
validation_tools.py12.1 kB
"""验证和预览URL相关工具 包含UML语法验证和预览URL生成的工具函数: - validate_uml_syntax: 验证UML语法 - generate_preview_url: 生成PlantUML预览URL """ import re import zlib import base64 from typing import Dict, Any, List from urllib.parse import urljoin from loguru import logger from ..config import Config from ..uml_renderer import UMLRenderer from ..metrics import RenderMetrics # 全局变量,将在register_validation_tools中初始化 config: Config = None renderer: UMLRenderer = None metrics: RenderMetrics = None async def validate_uml_syntax(uml_code: str) -> Dict[str, Any]: """ 验证 UML 语法 对 PlantUML DSL 代码进行语法验证,检查代码结构、关键字使用和语法正确性。 不执行实际渲染,仅进行静态分析,响应速度快。 Args: uml_code (str): 要验证的 PlantUML DSL 代码 应包含完整的 @startuml...@enduml 块 Returns: Dict[str, Any]: 验证结果字典,包含: - valid (bool): 语法是否有效 - errors (List[Dict]): 错误列表(如果存在) - line (int): 错误行号 - message (str): 错误描述 - severity (str): 错误级别(error/warning) - warnings (List[Dict]): 警告列表 - complexity_score (float): 图表复杂度评分 - estimated_render_time (float): 预估渲染时间(秒) - suggestions (List[str]): 优化建议 Examples: >>> # 验证有效的 UML 代码 >>> result = await validate_uml_syntax( ... "@startuml\nAlice -> Bob: Hello\n@enduml" ... ) >>> print(result["valid"]) # True >>> >>> # 验证无效的 UML 代码 >>> result = await validate_uml_syntax("invalid code") >>> print(result["errors"][0]["message"]) # 具体错误信息 Note: - 验证过程不会生成实际图像,因此速度很快 - 复杂度评分可用于预估渲染时间和资源消耗 - 建议在渲染前先进行语法验证,避免无效请求 """ try: errors = [] warnings = [] suggestions = [] # 基本结构检查 if not uml_code.strip(): errors.append({ "line": 1, "message": "UML代码不能为空", "severity": "error" }) return { "valid": False, "errors": errors, "warnings": warnings, "complexity_score": 0.0, "estimated_render_time": 0.0, "suggestions": ["请提供有效的PlantUML代码"] } lines = uml_code.split('\n') # 检查开始和结束标记 has_start = any('@startuml' in line.lower() for line in lines) has_end = any('@enduml' in line.lower() for line in lines) if not has_start: errors.append({ "line": 1, "message": "缺少@startuml开始标记", "severity": "error" }) if not has_end: errors.append({ "line": len(lines), "message": "缺少@enduml结束标记", "severity": "error" }) # 检查代码长度 if len(uml_code) > config.max_uml_size: errors.append({ "line": 1, "message": f"UML代码过长,最大允许{config.max_uml_size}字符", "severity": "error" }) # 复杂度评估 complexity_indicators = { 'participants': len(re.findall(r'participant|actor|boundary|control|entity|database', uml_code, re.IGNORECASE)), 'arrows': len(re.findall(r'->', uml_code)), 'notes': len(re.findall(r'note', uml_code, re.IGNORECASE)), 'loops': len(re.findall(r'loop|alt|opt|par', uml_code, re.IGNORECASE)), 'classes': len(re.findall(r'class|interface|abstract', uml_code, re.IGNORECASE)), } # 计算复杂度分数 (0-10) complexity_score = min(10.0, sum(complexity_indicators.values()) * 0.5) # 预估渲染时间(基于复杂度) estimated_render_time = max(0.1, complexity_score * 0.2) # 生成建议 if complexity_score > 7: suggestions.append("图表较为复杂,建议分解为多个较小的图表") if complexity_indicators['participants'] > 10: suggestions.append("参与者数量较多,考虑使用分组或简化") if len(lines) > 100: suggestions.append("代码行数较多,建议添加注释和适当的空行") # 语法警告检查 for i, line in enumerate(lines, 1): line = line.strip() if line and not line.startswith('@') and not line.startswith("'") and not line.startswith('/'): # 检查常见的语法问题 if '->' in line and not re.search(r'\w+\s*->\s*\w+', line): warnings.append({ "line": i, "message": "箭头语法可能不正确,请检查参与者名称", "severity": "warning" }) is_valid = len(errors) == 0 logger.info(f"UML语法验证完成: valid={is_valid}, errors={len(errors)}, warnings={len(warnings)}") return { "valid": is_valid, "errors": errors, "warnings": warnings, "complexity_score": complexity_score, "estimated_render_time": estimated_render_time, "suggestions": suggestions, "line_count": len(lines), "character_count": len(uml_code) } except Exception as e: logger.error(f"UML语法验证失败: {str(e)}", exc_info=True) return { "valid": False, "errors": [{ "line": 1, "message": f"验证过程中发生错误: {str(e)}", "severity": "error" }], "warnings": [], "complexity_score": 0.0, "estimated_render_time": 0.0, "suggestions": ["请检查UML代码格式"] } async def generate_preview_url( uml_code: str, server_url: str = "http://www.plantuml.com/plantuml", output_format: str = "png", use_hex: bool = False ) -> Dict[str, Any]: """ 生成 PlantUML 预览 URL 生成可以在浏览器中直接预览的 PlantUML URL,支持官方服务器和自定义服务器。 同时生成在线编辑器 URL,方便用户在浏览器中编辑和调试 UML 代码。 Args: uml_code (str): PlantUML DSL 代码,完整的 @startuml...@enduml 块 server_url (str): PlantUML 服务器 URL,默认使用官方服务器 支持自定义服务器,如本地部署的 PlantUML 服务 output_format (str): 输出格式,支持: - png: PNG 图像格式(默认) - svg: SVG 矢量格式 - uml: 返回 UML 源码 use_hex (bool): 编码方式选择: - False: 使用 Deflate 压缩编码(推荐,适用于复杂图表) - True: 使用十六进制编码(适用于简单图表) Returns: Dict[str, Any]: 预览信息字典,包含: - preview_url (str): 可直接访问的预览 URL - editor_url (str): PlantUML 在线编辑器 URL - encoded_text (str): 编码后的 UML 文本 - server_url (str): 使用的服务器 URL - format (str): 输出格式 - encoding_method (str): 编码方法(deflate/hex) - success (bool): 生成是否成功 - message (str): 成功消息或错误信息 Examples: >>> # 基本用法 - 生成 PNG 预览 >>> result = await generate_preview_url( ... uml_code="@startuml\nAlice -> Bob: Hello\n@enduml", ... output_format="png" ... ) >>> print(result["preview_url"]) # 可直接在浏览器中打开 >>> print(result["editor_url"]) # 可在线编辑的 URL >>> >>> # 使用 SVG 格式和十六进制编码 >>> result = await generate_preview_url( ... uml_code="@startuml\nclass User\n@enduml", ... output_format="svg", ... use_hex=True ... ) >>> >>> # 使用自定义服务器 >>> result = await generate_preview_url( ... uml_code="@startuml\nA -> B\n@enduml", ... server_url="http://localhost:8080/plantuml" ... ) Note: - 预览 URL 可直接在浏览器中打开查看图表 - 编辑器 URL 允许用户在线修改和调试 UML 代码 - Deflate 编码适用于复杂图表,压缩率更高 - 十六进制编码适用于简单图表,URL 更易读 - 自定义服务器需要兼容 PlantUML 服务器 API """ try: # 验证输入参数 if not uml_code.strip(): return { "success": False, "message": "UML代码不能为空", "error_type": "validation_error" } if output_format not in ["png", "svg", "uml"]: return { "success": False, "message": f"不支持的输出格式: {output_format}", "error_type": "validation_error" } # 编码UML文本 if use_hex: # 十六进制编码 encoded_text = uml_code.encode('utf-8').hex() encoding_method = "hex" else: # Deflate压缩编码 compressed = zlib.compress(uml_code.encode('utf-8')) encoded_text = base64.b64encode(compressed).decode('ascii') # PlantUML使用特殊的base64字符集 encoded_text = encoded_text.translate(str.maketrans( 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_' )) encoding_method = "deflate" # 构建预览URL format_path = { "png": "png", "svg": "svg", "uml": "uml" }[output_format] preview_url = urljoin(server_url.rstrip('/') + '/', f"{format_path}/{encoded_text}") # 构建编辑器URL(使用官方编辑器) editor_url = f"http://www.plantuml.com/plantuml/uml/{encoded_text}" logger.info(f"生成预览URL成功: format={output_format}, encoding={encoding_method}") return { "success": True, "preview_url": preview_url, "editor_url": editor_url, "encoded_text": encoded_text, "server_url": server_url, "format": output_format, "encoding_method": encoding_method, "message": "预览URL生成成功" } except Exception as e: logger.error(f"生成预览URL失败: {str(e)}", exc_info=True) return { "success": False, "message": f"生成预览URL时发生错误: {str(e)}", "error_type": "encoding_error" } def register_validation_tools(mcp, config_instance, renderer_instance, metrics_instance): """注册验证相关工具到FastMCP实例""" global config, renderer, metrics # 设置全局变量 config = config_instance renderer = renderer_instance metrics = metrics_instance # 注册工具 mcp.tool(validate_uml_syntax) mcp.tool(generate_preview_url)

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/icatw/uml-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server