import asyncio from typing import Any from google import genai from ...config.model_ssot import SYSTEM_MODELS from ..librarian_service import LibrarianService from ..prompt_service import prompt_service from .content_handler import get_logger logger = get_logger(__name__) class ApprovalManager: """Handles content approval workflows and feedback suggestion generation.""" def __init__(self, supabase_client: Any): self.supabase_client = supabase_client async def process_approval(self, item_type: str, item_id: str, action: str, notes: str | None) -> bool: if item_type == "blog": new_status = "published" if action == "approve" else "changes_requested" res = ( self.supabase_client.table("blog_posts") .update({"status": new_status, "review_notes": notes}) .eq("id", item_id) .execute() ) if action != "approve" and notes and res.data: try: post_data = res.data[0] asyncio.create_task( LibrarianService().archive_style_critique( post_title=post_data.get("title", "Untitled"), original_content=post_data.get("content", ""), review_notes=notes, ) ) except Exception as e: logger.error(f"ApprovalManager: Failed to archive style critique for blog {item_id}: {e}") return True return False async def get_pending_approvals(self) -> dict: res = ( self.supabase_client.table("blog_posts") .select("*") .eq("status", "review") .order("updated_at", desc=True) .execute() ) return {"blogs": res.data or [], "leads": []} async def generate_reject_suggestion(self, item_type: str, item_id: str) -> dict: if item_type != "blog": return {"notes": "Content type not supported for AI rejection."} post = self.supabase_client.table("blog_posts").select("*").eq("id", item_id).single().execute().data if not post: return {"notes": "Item not found."} from ..credential_service import credential_service api_key = await credential_service.get_credential("GEMINI_API_KEY") if not api_key: return {"notes": "Cannot generate AI reason: AI provider missing."} client = genai.Client(api_key=api_key) default_prompt = ( "You are a marketing director reviewing a blog post draft.\n" "The draft is slightly off-brand or has quality issues.\n" "Content:\n{content}\n\n" "Provide exactly ONE brief, constructive paragraph (max 50 words) explaining why this is rejected and what needs to be improved. Use Traditional Chinese." ) prompt_template = prompt_service.get_prompt("REJECT_SUGGESTION", default=default_prompt) prompt = prompt_template.format(content=post.get("content", "")) try: response = await client.aio.models.generate_content(model=SYSTEM_MODELS["DEFAULT_TEXT"], contents=prompt) return {"notes": response.text.strip() if response.text else "Failed to generate reason."} except Exception as e: return {"notes": f"AI Generation Failed: {str(e)}"}