cohorta/backend/app/services/persona_export_service.py
Vadym Samoilenko e01569c412
All checks were successful
Deploy to Production / deploy (push) Successful in 2m23s
feat: commit all app changes — billing API, new auth, design overhaul
Includes frontend redesign (Navigation, billingApi), backend updates
(auth routes, admin routes, LLM service refactor), MSAL removal,
and dependency updates.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 19:04:43 +01:00

171 lines
No EOL
6.4 KiB
Python
Executable file

"""
Persona Profile Export Service
Generates beautifully formatted markdown profiles for individual personas using LLM processing.
"""
import os
import json
import logging
from typing import Dict, Any, Optional
from app.services.llm_service import LLMService
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class PersonaExportService:
"""Service for exporting individual persona profiles as formatted markdown."""
def __init__(self):
"""Initialize the persona export service."""
self.llm_service = LLMService()
self.prompt_template = self._load_prompt_template()
def _load_prompt_template(self) -> str:
"""Load the persona profile export prompt template."""
try:
prompt_path = os.path.join(
os.path.dirname(__file__),
"..",
"..",
"prompts",
"persona-profile-export.md"
)
with open(prompt_path, 'r', encoding='utf-8') as f:
return f.read()
except Exception as e:
logger.error(f"Failed to load persona export prompt template: {e}")
# Fallback prompt if file loading fails
return """
You are a professional documentation specialist. Transform the provided persona JSON data
into a well-structured, professional markdown document with proper headers, tables, lists,
and formatting. Include all available information organized logically with sections for
demographics, goals, personality traits, scenarios, and additional data.
"""
async def generate_profile_markdown(
self,
persona_data: Dict[str, Any],
llm_model: str = "gpt-5.4",
temperature: float = 0.3
) -> Dict[str, Any]:
"""
Generate a formatted markdown profile for a persona using LLM processing.
Args:
persona_data: Complete persona data as dictionary
llm_model: LLM model to use (default: gpt-5.4 for speed)
temperature: Temperature for LLM generation (lower for consistency)
Returns:
Dictionary containing:
- success: Boolean indicating success
- markdown_content: Generated markdown string
- error: Error message if failed
- persona_name: Name of the persona
"""
try:
# Validate input data
if not persona_data:
return {
"success": False,
"error": "No persona data provided",
"markdown_content": None,
"persona_name": None
}
persona_name = persona_data.get('name', 'Unknown Persona')
logger.info(f"🤖 Backend: Generating profile markdown for persona: {persona_name} using {llm_model}")
# Prepare the full prompt
persona_json = json.dumps(persona_data, indent=2, ensure_ascii=False)
full_prompt = f"{self.prompt_template}\n\n## Persona Data\n```json\n{persona_json}\n```"
# Generate markdown using LLM
markdown_content = await LLMService.generate_content(
prompt=full_prompt,
model_name=llm_model,
temperature=temperature,
max_tokens=4000 # Allow for comprehensive profiles
)
if not markdown_content:
return {
"success": False,
"error": "LLM failed to generate markdown content",
"markdown_content": None,
"persona_name": persona_name
}
markdown_content = markdown_content.strip()
# Basic validation of generated content
if len(markdown_content) < 100: # Too short, likely an error
logger.warning(f"Generated markdown seems too short for {persona_name}")
return {
"success": False,
"error": "Generated markdown content appears incomplete",
"markdown_content": None,
"persona_name": persona_name
}
logger.info(f"✅ Successfully generated profile markdown for {persona_name} ({len(markdown_content)} characters)")
return {
"success": True,
"markdown_content": markdown_content,
"persona_name": persona_name,
"model_used": llm_model,
"content_length": len(markdown_content)
}
except Exception as e:
logger.error(f"Error generating persona profile markdown: {str(e)}")
return {
"success": False,
"error": f"Failed to generate markdown profile: {str(e)}",
"markdown_content": None,
"persona_name": persona_data.get('name', 'Unknown') if persona_data else None
}
def generate_fallback_markdown(self, persona_data: Dict[str, Any]) -> str:
"""
Generate a basic fallback markdown if LLM processing fails.
Args:
persona_data: Complete persona data as dictionary
Returns:
Basic markdown string
"""
try:
name = persona_data.get('name', 'Unknown Persona')
occupation = persona_data.get('occupation', 'Unknown')
age = persona_data.get('age', 'Unknown')
location = persona_data.get('location', 'Unknown')
# Create basic markdown structure
markdown = f"""# {name} - Complete Profile
## Overview
{name} is a {age} year old {occupation} based in {location}.
## Basic Information
- **Name:** {name}
- **Age:** {age}
- **Occupation:** {occupation}
- **Location:** {location}
## Raw Data
```json
{json.dumps(persona_data, indent=2, ensure_ascii=False)}
```
*This is a basic export. For enhanced formatting, please try again later.*
"""
return markdown
except Exception as e:
logger.error(f"Failed to generate fallback markdown: {e}")
return f"# Persona Profile Export\n\nError generating profile. Raw data:\n\n```json\n{json.dumps(persona_data, indent=2)}\n```"