diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml new file mode 100644 index 00000000..d19dbb87 --- /dev/null +++ b/.github/workflows/deploy-docs.yml @@ -0,0 +1,98 @@ +name: Deploy Docs + +on: + push: + branches: [main] + pull_request: + branches: [main] + workflow_dispatch: + inputs: + branch: + description: '要部署文档的分支' + required: false + default: 'main' + type: string + deploy_to_pages: + description: '是否部署到 GitHub Pages' + required: false + default: true + type: boolean + +# 设置 GITHUB_TOKEN 权限以部署到 GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# 只允许一个并发部署,跳过正在进行和最新排队之间的运行 +# 但是不取消正在进行的运行,因为我们希望允许这些生产部署完成 +concurrency: + group: 'pages' + cancel-in-progress: false + +jobs: + # Build documentation + build: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.branch || github.ref }} + + - name: Setup Python environment + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y pandoc + + - name: Install Python dependencies + run: | + python -m pip install --upgrade pip + # Install package in development mode to get version info + pip install -e . + # Install documentation dependencies + pip install -r docs/requirements.txt + + - name: Setup Pages + id: pages + uses: actions/configure-pages@v4 + if: github.ref == 'refs/heads/main' || (github.event_name == 'workflow_dispatch' && github.event.inputs.deploy_to_pages == 'true') + + - name: Build Sphinx documentation + run: | + cd docs + # Clean previous builds + rm -rf _build + # Build HTML documentation + python -m sphinx -b html . _build/html -v + + - name: Check build results + run: | + echo "Documentation build completed, checking output directory:" + ls -la docs/_build/html/ + echo "Checking for index.html:" + test -f docs/_build/html/index.html && echo "✓ index.html exists" || echo "✗ index.html missing" + + - name: Upload build artifacts + uses: actions/upload-pages-artifact@v3 + if: github.ref == 'refs/heads/main' || (github.event_name == 'workflow_dispatch' && github.event.inputs.deploy_to_pages == 'true') + with: + path: docs/_build/html + + # Deploy to GitHub Pages + deploy: + if: github.ref == 'refs/heads/main' || (github.event_name == 'workflow_dispatch' && github.event.inputs.deploy_to_pages == 'true') + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/README.md b/README.md index 93f2fcbe..7d9cb64c 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Join the [Intelligent Organic Chemistry Synthesis Competition](https://bohrium.d Detailed documentation can be found at: -- [Online Documentation](https://readthedocs.dp.tech/Uni-Lab/v0.8.0/) +- [Online Documentation](https://dptech-corp.github.io/Uni-Lab-OS/) ## Quick Start @@ -55,7 +55,7 @@ pip install . 3. Start Uni-Lab System: -Please refer to [Documentation - Boot Examples](https://readthedocs.dp.tech/Uni-Lab/v0.8.0/boot_examples/index.html) +Please refer to [Documentation - Boot Examples](https://dptech-corp.github.io/Uni-Lab-OS/boot_examples/index.html) ## Message Format diff --git a/README_zh.md b/README_zh.md index 07b400db..2fe346fa 100644 --- a/README_zh.md +++ b/README_zh.md @@ -31,7 +31,7 @@ Uni-Lab-OS 是一个用于实验室自动化的综合平台,旨在连接和控 详细文档可在以下位置找到: -- [在线文档](https://readthedocs.dp.tech/Uni-Lab/v0.8.0/) +- [在线文档](https://dptech-corp.github.io/Uni-Lab-OS/) ## 快速开始 @@ -57,7 +57,7 @@ pip install . 3. 启动 Uni-Lab 系统: -请见[文档-启动样例](https://readthedocs.dp.tech/Uni-Lab/v0.8.0/boot_examples/index.html) +请见[文档-启动样例](https://dptech-corp.github.io/Uni-Lab-OS/boot_examples/index.html) ## 消息格式 diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 00000000..36809637 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,13 @@ +# Sphinx文档构建依赖 +sphinx>=7.0.0 +sphinx-rtd-theme>=2.0.0 +myst-parser>=2.0.0 + +# 用于支持Jupyter notebook文档 +myst-nb>=1.0.0 + +# 用于代码复制按钮 +sphinx-copybutton>=0.5.0 + +# 用于自动摘要生成 +sphinx-autobuild>=2024.2.4 diff --git a/unilabos/registry/devices/virtual_device.yaml b/unilabos/registry/devices/virtual_device.yaml index 18575821..22cbe819 100644 --- a/unilabos/registry/devices/virtual_device.yaml +++ b/unilabos/registry/devices/virtual_device.yaml @@ -4741,7 +4741,6 @@ virtual_stirrer: status_types: current_speed: float current_vessel: str - device_info: dict is_stirring: bool max_speed: float min_speed: float @@ -4776,8 +4775,6 @@ virtual_stirrer: type: number current_vessel: type: string - device_info: - type: object is_stirring: type: boolean max_speed: @@ -4799,7 +4796,6 @@ virtual_stirrer: - remaining_time - max_speed - min_speed - - device_info type: object version: 1.0.0 virtual_transfer_pump: diff --git a/unilabos/ros/nodes/presets/workstation.py b/unilabos/ros/nodes/presets/workstation.py index 07e35ee6..b943b5a2 100644 --- a/unilabos/ros/nodes/presets/workstation.py +++ b/unilabos/ros/nodes/presets/workstation.py @@ -1,8 +1,13 @@ import json import time import traceback +<<<<<<<< HEAD:unilabos/ros/nodes/presets/workstation.py from pprint import pformat from typing import List, Dict, Any, Optional, TYPE_CHECKING +======== +from pprint import pprint, saferepr, pformat +from typing import Union +>>>>>>>> main:unilabos/ros/nodes/presets/protocol_node.py import rclpy from rosidl_runtime_py import message_to_ordereddict @@ -193,8 +198,13 @@ class ROS2WorkstationNode(BaseROS2DeviceNode): execute_callback=self._create_protocol_execute_callback(action_name, protocol_steps_generator), callback_group=ReentrantCallbackGroup(), ) +<<<<<<<< HEAD:unilabos/ros/nodes/presets/workstation.py self.lab_logger().trace(f"发布动作: {action_name}, 类型: {str_action_type}") return +======== + + self.lab_logger().trace(f"发布动作: {action_name}, 类型: {str_action_type}") +>>>>>>>> main:unilabos/ros/nodes/presets/protocol_node.py def _create_protocol_execute_callback(self, protocol_name, protocol_steps_generator): async def execute_protocol(goal_handle: ServerGoalHandle): @@ -245,10 +255,15 @@ class ROS2WorkstationNode(BaseROS2DeviceNode): logs.append(step) elif isinstance(step, list): logs.append(step) +<<<<<<<< HEAD:unilabos/ros/nodes/presets/workstation.py self.lab_logger().info( f"Goal received: {protocol_kwargs}, running steps: " f"{json.dumps(logs, indent=4, ensure_ascii=False)}" ) +======== + self.lab_logger().info(f"Goal received: {protocol_kwargs}, running steps: " + f"{json.dumps(logs, indent=4, ensure_ascii=False)}") +>>>>>>>> main:unilabos/ros/nodes/presets/protocol_node.py time_start = time.time() time_overall = 100 @@ -263,6 +278,7 @@ class ROS2WorkstationNode(BaseROS2DeviceNode): time.sleep(action["action_kwargs"]["time"]) step_results.append({"step": i + 1, "action": "wait", "result": "completed"}) else: +<<<<<<<< HEAD:unilabos/ros/nodes/presets/workstation.py try: result = await self.execute_single_action(**action) step_results.append({"step": i + 1, "action": action["action_name"], "result": result}) @@ -273,6 +289,13 @@ class ROS2WorkstationNode(BaseROS2DeviceNode): step_results.append( {"step": i + 1, "action": action["action_name"], "result": ex.args[0]} ) +======== + result = await self.execute_single_action(**action) + step_results.append({"step": i + 1, "action": action["action_name"], "result": result}) + ret_info = json.loads(getattr(result, "return_info", "{}")) + if not ret_info.get("suc", False): + raise RuntimeError(f"Step {i + 1} failed.") +>>>>>>>> main:unilabos/ros/nodes/presets/protocol_node.py elif isinstance(action, list): # 如果是并行动作,同时执行 actions = action @@ -310,6 +333,7 @@ class ROS2WorkstationNode(BaseROS2DeviceNode): except Exception as e: # 捕获并记录错误信息 +<<<<<<<< HEAD:unilabos/ros/nodes/presets/workstation.py str_step_results = [ { k: dict(message_to_ordereddict(v)) if k == "result" and hasattr(v, "SLOT_TYPES") else v @@ -317,6 +341,9 @@ class ROS2WorkstationNode(BaseROS2DeviceNode): } for i in step_results ] +======== + str_step_results = [{k: dict(message_to_ordereddict(v)) if k == "result" and hasattr(v, "SLOT_TYPES") else v for k, v in i.items()} for i in step_results] +>>>>>>>> main:unilabos/ros/nodes/presets/protocol_node.py execution_error = f"{traceback.format_exc()}\n\nStep Result: {pformat(str_step_results)}" execution_success = False self.lab_logger().error(f"协议 {protocol_name} 执行出错: {str(e)} \n{traceback.format_exc()}")