import asyncio import logging from yuxi.channel.extensions.confluence.format import ADFBuilder from yuxi.channel.extensions.confluence.gateway import ConfluenceGateway from yuxi.channel.extensions.confluence.types import OutboundResult logger = logging.getLogger(__name__) MAX_VERSION_RETRY = 3 RETRY_BASE_DELAY = 1.0 class ConfluencePageWriter: def __init__(self, gateway: ConfluenceGateway): self._gateway = gateway async def create_page( self, space_id: str, title: str, content: str, parent_page_id: str | None = None, account_id: str = "default", ) -> OutboundResult: client = self._gateway.get_client(account_id) if client is None: return OutboundResult(success=False, error="Client not found") adf_body = ADFBuilder.from_markdown(content) payload = { "spaceId": space_id, "status": "current", "title": title, "body": { "representation": "atlas_doc_format", "value": adf_body, }, } if parent_page_id: payload["parentId"] = parent_page_id try: result = await client._request("POST", "/wiki/api/v2/pages", json=payload) return OutboundResult(success=True, comment_id=result.get("id", "")) except Exception as e: return OutboundResult(success=False, error=str(e)) async def update_page_with_conflict_retry( self, page_id: str, title: str, content: str, space_id: str, version_comment: str = "AI 自动更新", account_id: str = "default", ) -> OutboundResult: client = self._gateway.get_client(account_id) if client is None: return OutboundResult(success=False, error="Client not found") for attempt in range(MAX_VERSION_RETRY): try: page = await client.get_page(page_id) except Exception as e: return OutboundResult(success=False, error=f"Read page failed: {e}") current_version = page.get("version", {}).get("number", 1) adf_body = ADFBuilder.from_markdown(content) payload = { "id": page_id, "status": "current", "title": title, "spaceId": space_id, "body": { "representation": "atlas_doc_format", "value": adf_body, }, "version": { "number": current_version + 1, "message": version_comment, }, } try: result = await client._request( "PUT", f"/wiki/api/v2/pages/{page_id}", json=payload ) return OutboundResult(success=True, comment_id=result.get("id", "")) except Exception as e: status = getattr(getattr(e, "response", None), "status_code", 0) if status == 409 and attempt < MAX_VERSION_RETRY - 1: delay = RETRY_BASE_DELAY * (2 ** attempt) logger.info( "Page version conflict, retry %d/%d after %.1fs", attempt + 1, MAX_VERSION_RETRY, delay, ) await asyncio.sleep(delay) continue return OutboundResult(success=False, error=str(e)) return OutboundResult(success=False, error="Max retries exceeded") async def generate_meeting_notes( self, space_id: str, title: str, transcript: str, account_id: str = "default", ) -> OutboundResult: prompt = f"""请根据以下会议记录生成结构化的会议纪要: {transcript} 格式要求: - 标题使用会议纪要标题 - 分节:参会人员、会议摘要、讨论要点、决议事项、待办事项 - 每个待办事项标注负责人和截止时间""" return await self.create_page(space_id, title, prompt, account_id=account_id)