Spaces:
Sleeping
Sleeping
File size: 4,887 Bytes
7f99b5c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | import logging
from datetime import datetime, timezone
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlmodel import select, desc
from sqlmodel.ext.asyncio.session import AsyncSession
from db import get_session
from models import (
ContentSubmission,
ResolutionRequest,
FeedbackRequest,
ModerationLog,
QueueResponse
)
from moderation.detector import ModerationDetector
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/moderation", tags=["moderation"])
@router.post("/check", response_model=QueueResponse)
async def check_submission(
submission: ContentSubmission,
db: AsyncSession = Depends(get_session)
):
"""Checks a post or comment submission, runs AI moderation, and stores logs."""
try:
# Check if already processed
existing = await db.get(ModerationLog, submission.id)
if existing:
# If already processed, return existing log (or re-evaluate)
return existing
# Run detection pipeline
log = await ModerationDetector.analyze_submission(db, submission)
# Add to database
db.add(log)
await db.commit()
await db.refresh(log)
return log
except Exception as e:
logger.error(f"Error checking submission {submission.id}: {e}")
raise HTTPException(status_code=500, detail=f"Moderation check failed: {str(e)}")
@router.get("/queue", response_model=List[QueueResponse])
async def get_moderation_queue(
subreddit: str,
db: AsyncSession = Depends(get_session)
):
"""Fetches the prioritized moderation queue for a specific subreddit."""
try:
# Select flagged items that have not been resolved
stmt = (
select(ModerationLog)
.where(ModerationLog.subreddit == subreddit)
.where(ModerationLog.status == "flagged")
)
result = await db.execute(stmt)
items = result.scalars().all()
# Priority mapping for sorting
priority_map = {"high": 3, "medium": 2, "low": 1}
# Sort by priority level (high -> medium -> low), then by created_at desc
sorted_items = sorted(
items,
key=lambda x: (priority_map.get(x.priority, 0), x.created_at),
reverse=True
)
return sorted_items
except Exception as e:
logger.error(f"Error fetching queue for subreddit {subreddit}: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.post("/resolve")
async def resolve_item(
request: ResolutionRequest,
db: AsyncSession = Depends(get_session)
):
"""Resolves a flagged queue item (approves, removes, ignores, warns)."""
try:
log = await db.get(ModerationLog, request.id)
if not log:
raise HTTPException(status_code=404, detail="Moderation log item not found")
# Map actions to log statuses
action_map = {
"approve": "approved",
"remove": "removed",
"ignore": "ignored",
"warn": "warned"
}
new_status = action_map.get(request.action.lower())
if not new_status:
raise HTTPException(status_code=400, detail=f"Invalid resolution action: {request.action}")
log.status = new_status
log.resolved_at = datetime.now(timezone.utc)
log.resolved_by = request.moderator
db.add(log)
await db.commit()
logger.info(f"Subreddit item {request.id} resolved as '{new_status}' by mod {request.moderator}")
return {"status": "success", "resolved_id": request.id, "new_status": new_status}
except HTTPException:
raise
except Exception as e:
logger.error(f"Error resolving item {request.id}: {e}")
raise HTTPException(status_code=500, detail=str(e))
@router.post("/feedback")
async def submit_feedback(
request: FeedbackRequest,
db: AsyncSession = Depends(get_session)
):
"""Allows moderators to flag false positives and rate AI accuracy."""
try:
log = await db.get(ModerationLog, request.id)
if not log:
raise HTTPException(status_code=404, detail="Moderation log item not found")
log.feedback_correct = request.is_correct
log.feedback_reason = request.reason
db.add(log)
await db.commit()
logger.info(f"Feedback logged for item {request.id}. Correctness: {request.is_correct}")
return {"status": "success", "item_id": request.id}
except HTTPException:
raise
except Exception as e:
logger.error(f"Error saving feedback for item {request.id}: {e}")
raise HTTPException(status_code=500, detail=str(e))
|