reddit_hack / api /moderation.py
GitHub Actions Bot
Deploy backend from GitHub Actions
7f99b5c
Raw
History Blame Contribute Delete
4.89 kB
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))