Merge PR #226: Writing Persona System with platform-specific adaptations
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -354,12 +354,29 @@ async def complete_onboarding():
|
||||
detail="Cannot complete onboarding. At least one AI provider API key must be configured."
|
||||
)
|
||||
|
||||
# Generate writing persona from onboarding data
|
||||
try:
|
||||
from services.persona_analysis_service import PersonaAnalysisService
|
||||
persona_service = PersonaAnalysisService()
|
||||
|
||||
# Use user_id = 1 for now (assuming single user system)
|
||||
user_id = 1
|
||||
persona_result = persona_service.generate_persona_from_onboarding(user_id)
|
||||
|
||||
if "error" not in persona_result:
|
||||
logger.info(f"✅ Writing persona generated during onboarding completion: {persona_result.get('persona_id')}")
|
||||
else:
|
||||
logger.warning(f"⚠️ Persona generation failed during onboarding: {persona_result['error']}")
|
||||
except Exception as e:
|
||||
logger.warning(f"⚠️ Non-critical error generating persona during onboarding: {str(e)}")
|
||||
|
||||
progress.complete_onboarding()
|
||||
|
||||
return {
|
||||
"message": "Onboarding completed successfully",
|
||||
"completed_at": progress.completed_at,
|
||||
"completion_percentage": 100.0
|
||||
"completion_percentage": 100.0,
|
||||
"persona_generated": "error" not in persona_result if 'persona_result' in locals() else False
|
||||
}
|
||||
except HTTPException:
|
||||
raise
|
||||
@@ -522,9 +539,11 @@ async def get_onboarding_summary():
|
||||
from services.database import get_db
|
||||
from services.website_analysis_service import WebsiteAnalysisService
|
||||
from services.research_preferences_service import ResearchPreferencesService
|
||||
from services.persona_analysis_service import PersonaAnalysisService
|
||||
|
||||
# Get current session (assuming session ID 1 for now)
|
||||
session_id = 1
|
||||
user_id = 1 # Assuming single user system for now
|
||||
|
||||
# Get API keys
|
||||
api_manager = get_api_key_manager()
|
||||
@@ -548,18 +567,37 @@ async def get_onboarding_summary():
|
||||
'brand_voice': research_preferences.get('writing_style', {}).get('complexity', 'Trustworthy and Expert')
|
||||
}
|
||||
|
||||
# Check persona generation readiness
|
||||
persona_service = PersonaAnalysisService()
|
||||
persona_readiness = None
|
||||
try:
|
||||
# Check if persona can be generated
|
||||
onboarding_data = persona_service._collect_onboarding_data(user_id)
|
||||
if onboarding_data:
|
||||
data_sufficiency = persona_service._calculate_data_sufficiency(onboarding_data)
|
||||
persona_readiness = {
|
||||
"ready": data_sufficiency >= 50.0,
|
||||
"data_sufficiency": data_sufficiency,
|
||||
"can_generate": website_analysis is not None
|
||||
}
|
||||
except Exception as e:
|
||||
logger.warning(f"Could not check persona readiness: {str(e)}")
|
||||
persona_readiness = {"ready": False, "error": str(e)}
|
||||
|
||||
return {
|
||||
"api_keys": api_keys,
|
||||
"website_url": website_analysis.get('website_url') if website_analysis else None,
|
||||
"style_analysis": website_analysis.get('style_analysis') if website_analysis else None,
|
||||
"research_preferences": research_preferences,
|
||||
"personalization_settings": personalization_settings,
|
||||
"persona_readiness": persona_readiness,
|
||||
"integrations": {}, # TODO: Implement integrations data
|
||||
"capabilities": {
|
||||
"ai_content": len(api_keys) > 0,
|
||||
"style_analysis": website_analysis is not None,
|
||||
"research_tools": research_preferences is not None,
|
||||
"personalization": personalization_settings is not None,
|
||||
"persona_generation": persona_readiness.get("ready", False) if persona_readiness else False,
|
||||
"integrations": False # TODO: Implement
|
||||
}
|
||||
}
|
||||
@@ -607,4 +645,43 @@ async def get_research_preferences_data():
|
||||
return preferences
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting research preferences data: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
# New persona-related endpoints
|
||||
|
||||
async def check_persona_generation_readiness(user_id: int = 1):
|
||||
"""Check if user has sufficient data for persona generation."""
|
||||
try:
|
||||
from api.persona import validate_persona_generation_readiness
|
||||
return await validate_persona_generation_readiness(user_id)
|
||||
except Exception as e:
|
||||
logger.error(f"Error checking persona readiness: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
async def generate_persona_preview(user_id: int = 1):
|
||||
"""Generate a preview of the writing persona without saving."""
|
||||
try:
|
||||
from api.persona import generate_persona_preview
|
||||
return await generate_persona_preview(user_id)
|
||||
except Exception as e:
|
||||
logger.error(f"Error generating persona preview: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
async def generate_writing_persona(user_id: int = 1):
|
||||
"""Generate and save a writing persona from onboarding data."""
|
||||
try:
|
||||
from api.persona import generate_persona, PersonaGenerationRequest
|
||||
request = PersonaGenerationRequest(force_regenerate=False)
|
||||
return await generate_persona(user_id, request)
|
||||
except Exception as e:
|
||||
logger.error(f"Error generating writing persona: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
|
||||
async def get_user_writing_personas(user_id: int = 1):
|
||||
"""Get all writing personas for the user."""
|
||||
try:
|
||||
from api.persona import get_user_personas
|
||||
return await get_user_personas(user_id)
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting user personas: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail="Internal server error")
|
||||
385
backend/api/persona.py
Normal file
385
backend/api/persona.py
Normal file
@@ -0,0 +1,385 @@
|
||||
"""
|
||||
Persona API endpoints for ALwrity.
|
||||
Handles writing persona generation, management, and platform-specific adaptations.
|
||||
"""
|
||||
|
||||
from fastapi import HTTPException, Depends
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Dict, Any, List, Optional
|
||||
from datetime import datetime
|
||||
from loguru import logger
|
||||
|
||||
from services.persona_analysis_service import PersonaAnalysisService
|
||||
from services.database import get_db
|
||||
|
||||
class PersonaGenerationRequest(BaseModel):
|
||||
"""Request model for persona generation."""
|
||||
onboarding_session_id: Optional[int] = Field(None, description="Specific onboarding session ID to use")
|
||||
force_regenerate: bool = Field(False, description="Force regeneration even if persona exists")
|
||||
|
||||
class PersonaResponse(BaseModel):
|
||||
"""Response model for persona data."""
|
||||
persona_id: int
|
||||
persona_name: str
|
||||
archetype: str
|
||||
core_belief: str
|
||||
confidence_score: float
|
||||
platforms: List[str]
|
||||
created_at: str
|
||||
|
||||
class PlatformPersonaResponse(BaseModel):
|
||||
"""Response model for platform-specific persona."""
|
||||
platform_type: str
|
||||
sentence_metrics: Dict[str, Any]
|
||||
lexical_features: Dict[str, Any]
|
||||
content_format_rules: Dict[str, Any]
|
||||
engagement_patterns: Dict[str, Any]
|
||||
platform_best_practices: Dict[str, Any]
|
||||
|
||||
class PersonaGenerationResponse(BaseModel):
|
||||
"""Response model for persona generation result."""
|
||||
success: bool
|
||||
persona_id: Optional[int] = None
|
||||
message: str
|
||||
confidence_score: Optional[float] = None
|
||||
data_sufficiency: Optional[float] = None
|
||||
platforms_generated: List[str] = []
|
||||
|
||||
# Dependency to get persona service
|
||||
def get_persona_service() -> PersonaAnalysisService:
|
||||
"""Get the persona analysis service instance."""
|
||||
return PersonaAnalysisService()
|
||||
|
||||
async def generate_persona(user_id: int, request: PersonaGenerationRequest):
|
||||
"""Generate a new writing persona from onboarding data."""
|
||||
try:
|
||||
logger.info(f"Generating persona for user {user_id}")
|
||||
|
||||
persona_service = get_persona_service()
|
||||
|
||||
# Check if persona already exists and force_regenerate is False
|
||||
if not request.force_regenerate:
|
||||
existing_personas = persona_service.get_user_personas(user_id)
|
||||
if existing_personas:
|
||||
return PersonaGenerationResponse(
|
||||
success=False,
|
||||
message="Persona already exists. Use force_regenerate=true to create a new one.",
|
||||
persona_id=existing_personas[0]["id"]
|
||||
)
|
||||
|
||||
# Generate new persona
|
||||
result = persona_service.generate_persona_from_onboarding(
|
||||
user_id=user_id,
|
||||
onboarding_session_id=request.onboarding_session_id
|
||||
)
|
||||
|
||||
if "error" in result:
|
||||
return PersonaGenerationResponse(
|
||||
success=False,
|
||||
message=result["error"]
|
||||
)
|
||||
|
||||
return PersonaGenerationResponse(
|
||||
success=True,
|
||||
persona_id=result["persona_id"],
|
||||
message="Persona generated successfully",
|
||||
confidence_score=result["analysis_metadata"]["confidence_score"],
|
||||
data_sufficiency=result["analysis_metadata"].get("data_sufficiency", 0.0),
|
||||
platforms_generated=list(result["platform_personas"].keys())
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error generating persona: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"Failed to generate persona: {str(e)}")
|
||||
|
||||
async def get_user_personas(user_id: int):
|
||||
"""Get all personas for a user."""
|
||||
try:
|
||||
persona_service = get_persona_service()
|
||||
personas = persona_service.get_user_personas(user_id)
|
||||
|
||||
return {
|
||||
"personas": personas,
|
||||
"total_count": len(personas)
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting user personas: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"Failed to get personas: {str(e)}")
|
||||
|
||||
async def get_persona_details(user_id: int, persona_id: int):
|
||||
"""Get detailed information about a specific persona."""
|
||||
try:
|
||||
from services.database import get_db_session
|
||||
from models.persona_models import WritingPersona, PlatformPersona
|
||||
|
||||
session = get_db_session()
|
||||
|
||||
# Get persona
|
||||
persona = session.query(WritingPersona).filter(
|
||||
WritingPersona.id == persona_id,
|
||||
WritingPersona.user_id == user_id,
|
||||
WritingPersona.is_active == True
|
||||
).first()
|
||||
|
||||
if not persona:
|
||||
raise HTTPException(status_code=404, detail="Persona not found")
|
||||
|
||||
# Get platform adaptations
|
||||
platform_personas = session.query(PlatformPersona).filter(
|
||||
PlatformPersona.writing_persona_id == persona_id,
|
||||
PlatformPersona.is_active == True
|
||||
).all()
|
||||
|
||||
result = persona.to_dict()
|
||||
result["platform_adaptations"] = [pp.to_dict() for pp in platform_personas]
|
||||
|
||||
session.close()
|
||||
return result
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting persona details: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"Failed to get persona details: {str(e)}")
|
||||
|
||||
async def get_platform_persona(user_id: int, platform: str):
|
||||
"""Get persona adaptation for a specific platform."""
|
||||
try:
|
||||
persona_service = get_persona_service()
|
||||
platform_persona = persona_service.get_persona_for_platform(user_id, platform)
|
||||
|
||||
if not platform_persona:
|
||||
raise HTTPException(status_code=404, detail=f"No persona found for platform {platform}")
|
||||
|
||||
return platform_persona
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error getting platform persona: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"Failed to get platform persona: {str(e)}")
|
||||
|
||||
async def update_persona(user_id: int, persona_id: int, update_data: Dict[str, Any]):
|
||||
"""Update an existing persona."""
|
||||
try:
|
||||
from services.database import get_db_session
|
||||
from models.persona_models import WritingPersona
|
||||
|
||||
session = get_db_session()
|
||||
|
||||
persona = session.query(WritingPersona).filter(
|
||||
WritingPersona.id == persona_id,
|
||||
WritingPersona.user_id == user_id
|
||||
).first()
|
||||
|
||||
if not persona:
|
||||
raise HTTPException(status_code=404, detail="Persona not found")
|
||||
|
||||
# Update allowed fields
|
||||
updatable_fields = [
|
||||
'persona_name', 'archetype', 'core_belief', 'brand_voice_description',
|
||||
'linguistic_fingerprint', 'platform_adaptations'
|
||||
]
|
||||
|
||||
for field in updatable_fields:
|
||||
if field in update_data:
|
||||
setattr(persona, field, update_data[field])
|
||||
|
||||
persona.updated_at = datetime.utcnow()
|
||||
session.commit()
|
||||
session.close()
|
||||
|
||||
return {
|
||||
"message": "Persona updated successfully",
|
||||
"persona_id": persona_id,
|
||||
"updated_at": persona.updated_at.isoformat()
|
||||
}
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating persona: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"Failed to update persona: {str(e)}")
|
||||
|
||||
async def delete_persona(user_id: int, persona_id: int):
|
||||
"""Delete a persona (soft delete by setting is_active=False)."""
|
||||
try:
|
||||
from services.database import get_db_session
|
||||
from models.persona_models import WritingPersona, PlatformPersona
|
||||
|
||||
session = get_db_session()
|
||||
|
||||
persona = session.query(WritingPersona).filter(
|
||||
WritingPersona.id == persona_id,
|
||||
WritingPersona.user_id == user_id
|
||||
).first()
|
||||
|
||||
if not persona:
|
||||
raise HTTPException(status_code=404, detail="Persona not found")
|
||||
|
||||
# Soft delete persona and platform adaptations
|
||||
persona.is_active = False
|
||||
persona.updated_at = datetime.utcnow()
|
||||
|
||||
platform_personas = session.query(PlatformPersona).filter(
|
||||
PlatformPersona.writing_persona_id == persona_id
|
||||
).all()
|
||||
|
||||
for pp in platform_personas:
|
||||
pp.is_active = False
|
||||
pp.updated_at = datetime.utcnow()
|
||||
|
||||
session.commit()
|
||||
session.close()
|
||||
|
||||
return {
|
||||
"message": "Persona deleted successfully",
|
||||
"persona_id": persona_id
|
||||
}
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error deleting persona: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"Failed to delete persona: {str(e)}")
|
||||
|
||||
async def validate_persona_generation_readiness(user_id: int):
|
||||
"""Check if user has sufficient onboarding data for persona generation."""
|
||||
try:
|
||||
persona_service = get_persona_service()
|
||||
|
||||
# Get onboarding data
|
||||
onboarding_data = persona_service._collect_onboarding_data(user_id)
|
||||
|
||||
if not onboarding_data:
|
||||
return {
|
||||
"ready": False,
|
||||
"message": "No onboarding data found. Please complete onboarding first.",
|
||||
"missing_steps": ["All onboarding steps"],
|
||||
"data_sufficiency": 0.0
|
||||
}
|
||||
|
||||
data_sufficiency = persona_service._calculate_data_sufficiency(onboarding_data)
|
||||
|
||||
missing_steps = []
|
||||
if not onboarding_data.get("website_analysis"):
|
||||
missing_steps.append("Website Analysis (Step 2)")
|
||||
if not onboarding_data.get("research_preferences"):
|
||||
missing_steps.append("Research Preferences (Step 3)")
|
||||
|
||||
ready = data_sufficiency >= 50.0 # Require at least 50% data sufficiency
|
||||
|
||||
return {
|
||||
"ready": ready,
|
||||
"message": "Ready for persona generation" if ready else "Insufficient data for reliable persona generation",
|
||||
"missing_steps": missing_steps,
|
||||
"data_sufficiency": data_sufficiency,
|
||||
"recommendations": [
|
||||
"Complete website analysis for better style detection",
|
||||
"Provide research preferences for content type optimization"
|
||||
] if not ready else []
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error validating persona generation readiness: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"Failed to validate readiness: {str(e)}")
|
||||
|
||||
async def generate_persona_preview(user_id: int):
|
||||
"""Generate a preview of what the persona would look like without saving."""
|
||||
try:
|
||||
persona_service = get_persona_service()
|
||||
|
||||
# Get onboarding data
|
||||
onboarding_data = persona_service._collect_onboarding_data(user_id)
|
||||
|
||||
if not onboarding_data:
|
||||
raise HTTPException(status_code=400, detail="No onboarding data available")
|
||||
|
||||
# Generate core persona (without saving)
|
||||
core_persona = persona_service._generate_core_persona(onboarding_data)
|
||||
|
||||
if "error" in core_persona:
|
||||
raise HTTPException(status_code=400, detail=core_persona["error"])
|
||||
|
||||
# Generate sample platform adaptation (just one for preview)
|
||||
sample_platform = "linkedin"
|
||||
platform_preview = persona_service._generate_single_platform_persona(
|
||||
core_persona, sample_platform, onboarding_data
|
||||
)
|
||||
|
||||
return {
|
||||
"preview": {
|
||||
"identity": core_persona.get("identity", {}),
|
||||
"linguistic_fingerprint": core_persona.get("linguistic_fingerprint", {}),
|
||||
"tonal_range": core_persona.get("tonal_range", {}),
|
||||
"sample_platform": {
|
||||
"platform": sample_platform,
|
||||
"adaptation": platform_preview
|
||||
}
|
||||
},
|
||||
"confidence_score": core_persona.get("confidence_score", 0.0),
|
||||
"data_sufficiency": persona_service._calculate_data_sufficiency(onboarding_data)
|
||||
}
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.error(f"Error generating persona preview: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"Failed to generate preview: {str(e)}")
|
||||
|
||||
async def get_supported_platforms():
|
||||
"""Get list of supported platforms for persona generation."""
|
||||
return {
|
||||
"platforms": [
|
||||
{
|
||||
"id": "twitter",
|
||||
"name": "Twitter/X",
|
||||
"description": "Microblogging platform optimized for short, engaging content",
|
||||
"character_limit": 280,
|
||||
"optimal_length": "120-150 characters"
|
||||
},
|
||||
{
|
||||
"id": "linkedin",
|
||||
"name": "LinkedIn",
|
||||
"description": "Professional networking platform for thought leadership content",
|
||||
"character_limit": 3000,
|
||||
"optimal_length": "150-300 words"
|
||||
},
|
||||
{
|
||||
"id": "instagram",
|
||||
"name": "Instagram",
|
||||
"description": "Visual-first platform with engaging captions",
|
||||
"character_limit": 2200,
|
||||
"optimal_length": "125-150 words"
|
||||
},
|
||||
{
|
||||
"id": "facebook",
|
||||
"name": "Facebook",
|
||||
"description": "Social networking platform for community engagement",
|
||||
"character_limit": 63206,
|
||||
"optimal_length": "40-80 words"
|
||||
},
|
||||
{
|
||||
"id": "blog",
|
||||
"name": "Blog Posts",
|
||||
"description": "Long-form content optimized for SEO and engagement",
|
||||
"word_count": "800-2000 words",
|
||||
"seo_optimized": True
|
||||
},
|
||||
{
|
||||
"id": "medium",
|
||||
"name": "Medium",
|
||||
"description": "Publishing platform for storytelling and thought leadership",
|
||||
"word_count": "1000-3000 words",
|
||||
"storytelling_focus": True
|
||||
},
|
||||
{
|
||||
"id": "substack",
|
||||
"name": "Substack",
|
||||
"description": "Newsletter platform for building subscriber relationships",
|
||||
"format": "email newsletter",
|
||||
"subscription_focus": True
|
||||
}
|
||||
]
|
||||
}
|
||||
167
backend/api/persona_routes.py
Normal file
167
backend/api/persona_routes.py
Normal file
@@ -0,0 +1,167 @@
|
||||
"""
|
||||
FastAPI routes for persona management.
|
||||
Integrates persona generation and management into the main API.
|
||||
"""
|
||||
|
||||
from fastapi import APIRouter, HTTPException, Query
|
||||
from typing import Dict, Any, Optional
|
||||
|
||||
from api.persona import (
|
||||
generate_persona,
|
||||
get_user_personas,
|
||||
get_persona_details,
|
||||
get_platform_persona,
|
||||
update_persona,
|
||||
delete_persona,
|
||||
validate_persona_generation_readiness,
|
||||
generate_persona_preview,
|
||||
get_supported_platforms,
|
||||
PersonaGenerationRequest
|
||||
)
|
||||
|
||||
from services.persona_replication_engine import PersonaReplicationEngine
|
||||
|
||||
# Create router
|
||||
router = APIRouter(prefix="/api/personas", tags=["personas"])
|
||||
|
||||
@router.post("/generate")
|
||||
async def generate_persona_endpoint(
|
||||
request: PersonaGenerationRequest,
|
||||
user_id: int = Query(1, description="User ID")
|
||||
):
|
||||
"""Generate a new writing persona from onboarding data."""
|
||||
return await generate_persona(user_id, request)
|
||||
|
||||
@router.get("/user/{user_id}")
|
||||
async def get_user_personas_endpoint(user_id: int):
|
||||
"""Get all personas for a user."""
|
||||
return await get_user_personas(user_id)
|
||||
|
||||
@router.get("/{persona_id}")
|
||||
async def get_persona_details_endpoint(
|
||||
persona_id: int,
|
||||
user_id: int = Query(..., description="User ID")
|
||||
):
|
||||
"""Get detailed information about a specific persona."""
|
||||
return await get_persona_details(user_id, persona_id)
|
||||
|
||||
@router.get("/platform/{platform}")
|
||||
async def get_platform_persona_endpoint(
|
||||
platform: str,
|
||||
user_id: int = Query(1, description="User ID")
|
||||
):
|
||||
"""Get persona adaptation for a specific platform."""
|
||||
return await get_platform_persona(user_id, platform)
|
||||
|
||||
@router.put("/{persona_id}")
|
||||
async def update_persona_endpoint(
|
||||
persona_id: int,
|
||||
update_data: Dict[str, Any],
|
||||
user_id: int = Query(..., description="User ID")
|
||||
):
|
||||
"""Update an existing persona."""
|
||||
return await update_persona(user_id, persona_id, update_data)
|
||||
|
||||
@router.delete("/{persona_id}")
|
||||
async def delete_persona_endpoint(
|
||||
persona_id: int,
|
||||
user_id: int = Query(..., description="User ID")
|
||||
):
|
||||
"""Delete a persona."""
|
||||
return await delete_persona(user_id, persona_id)
|
||||
|
||||
@router.get("/check/readiness")
|
||||
async def check_persona_readiness_endpoint(
|
||||
user_id: int = Query(1, description="User ID")
|
||||
):
|
||||
"""Check if user has sufficient data for persona generation."""
|
||||
return await validate_persona_generation_readiness(user_id)
|
||||
|
||||
@router.get("/preview/generate")
|
||||
async def generate_preview_endpoint(
|
||||
user_id: int = Query(1, description="User ID")
|
||||
):
|
||||
"""Generate a preview of the writing persona without saving."""
|
||||
return await generate_persona_preview(user_id)
|
||||
|
||||
@router.get("/platforms/supported")
|
||||
async def get_supported_platforms_endpoint():
|
||||
"""Get list of supported platforms for persona generation."""
|
||||
return await get_supported_platforms()
|
||||
|
||||
@router.post("/generate-content")
|
||||
async def generate_content_with_persona_endpoint(
|
||||
request: Dict[str, Any]
|
||||
):
|
||||
"""Generate content using persona replication engine."""
|
||||
try:
|
||||
user_id = request.get("user_id", 1)
|
||||
platform = request.get("platform")
|
||||
content_request = request.get("content_request")
|
||||
content_type = request.get("content_type", "post")
|
||||
|
||||
if not platform or not content_request:
|
||||
raise HTTPException(status_code=400, detail="Platform and content_request are required")
|
||||
|
||||
engine = PersonaReplicationEngine()
|
||||
result = engine.generate_content_with_persona(
|
||||
user_id=user_id,
|
||||
platform=platform,
|
||||
content_request=content_request,
|
||||
content_type=content_type
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Content generation failed: {str(e)}")
|
||||
|
||||
@router.get("/export/{platform}")
|
||||
async def export_persona_prompt_endpoint(
|
||||
platform: str,
|
||||
user_id: int = Query(1, description="User ID")
|
||||
):
|
||||
"""Export hardened persona prompt for external use."""
|
||||
try:
|
||||
engine = PersonaReplicationEngine()
|
||||
export_package = engine.export_persona_for_external_use(user_id, platform)
|
||||
|
||||
if "error" in export_package:
|
||||
raise HTTPException(status_code=400, detail=export_package["error"])
|
||||
|
||||
return export_package
|
||||
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Export failed: {str(e)}")
|
||||
|
||||
@router.post("/validate-content")
|
||||
async def validate_content_endpoint(
|
||||
request: Dict[str, Any]
|
||||
):
|
||||
"""Validate content against persona constraints."""
|
||||
try:
|
||||
user_id = request.get("user_id", 1)
|
||||
platform = request.get("platform")
|
||||
content = request.get("content")
|
||||
|
||||
if not platform or not content:
|
||||
raise HTTPException(status_code=400, detail="Platform and content are required")
|
||||
|
||||
engine = PersonaReplicationEngine()
|
||||
persona_data = engine.persona_service.get_persona_for_platform(user_id, platform)
|
||||
|
||||
if not persona_data:
|
||||
raise HTTPException(status_code=404, detail="No persona found for platform")
|
||||
|
||||
validation_result = engine._validate_content_fidelity(content, persona_data, platform)
|
||||
|
||||
return {
|
||||
"validation_result": validation_result,
|
||||
"persona_id": persona_data["core_persona"]["id"],
|
||||
"platform": platform
|
||||
}
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Validation failed: {str(e)}")
|
||||
Reference in New Issue
Block a user