added generation prompt tracking and viewing in persona detail view (new tab) for audience brief and research objective

This commit is contained in:
michael 2025-08-26 14:15:50 -05:00
parent 7da03a4706
commit 8a750ed072
10 changed files with 119 additions and 738 deletions

6
.gitignore vendored
View file

@ -1,2 +1,6 @@
venv/
*pycache*/
dist/
# Ignore Python cache files
__pycache__/
*.py[cod]

View file

@ -192,9 +192,23 @@ def complete_and_save_persona():
customer_data_session_id = data.get('customer_data_session_id') # Optional parameter
llm_model = data.get('llm_model', 'gemini-2.5-pro') # Optional parameter with default
# Get persona name for logging
persona_name = basic_profile.get('name', 'Unknown')
# Capture generation prompts for storage
audience_brief = data.get('audience_brief') # Optional parameter
research_objective = data.get('research_objective') # Optional parameter
# Debug logging for generation prompts
if audience_brief or research_objective:
print(f"🔍 Backend: Generation prompts received for '{persona_name}':")
print(f" - Audience Brief: {'Present' if audience_brief else 'Missing'} ({'~' + str(len(audience_brief)) + ' chars' if audience_brief else 'N/A'})")
print(f" - Research Objective: {'Present' if research_objective else 'Missing'} ({'~' + str(len(research_objective)) + ' chars' if research_objective else 'N/A'})")
else:
print(f"🔍 Backend: No generation prompts received for '{persona_name}'")
try:
# Log the request with model information
persona_name = basic_profile.get('name', 'Unknown')
print(f"🔄 Backend: Received complete-and-save-persona request for '{persona_name}' with model: {llm_model}")
current_app.logger.info(f"Completing persona '{persona_name}' using model: {llm_model}")
@ -230,6 +244,14 @@ def complete_and_save_persona():
if 'id' in complete_persona_data:
del complete_persona_data['id']
# Add generation prompts to persona data if provided
if audience_brief:
complete_persona_data['audience_brief'] = audience_brief
print(f"📝 Backend: Added audience_brief to persona data (~{len(audience_brief)} chars)")
if research_objective:
complete_persona_data['research_objective'] = research_objective
print(f"📝 Backend: Added research_objective to persona data (~{len(research_objective)} chars)")
# Save to database
persona_id = Persona.create(complete_persona_data, user_id)

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
dist/index.html vendored
View file

@ -7,8 +7,8 @@
<meta name="description" content="Lovable Generated Project" />
<meta name="author" content="Lovable" />
<meta property="og:image" content="/og-image.png" />
<script type="module" crossorigin src="/semblance/assets/index-D1F9eUHr.js"></script>
<link rel="stylesheet" crossorigin href="/semblance/assets/index-QYazl09u.css">
<script type="module" crossorigin src="/semblance/assets/index-BXPouqjR.js"></script>
<link rel="stylesheet" crossorigin href="/semblance/assets/index-8o0iGAjY.css">
</head>
<body>

View file

@ -0,0 +1,62 @@
import { FileText, Target } from 'lucide-react';
import { Card, CardContent } from '@/components/ui/card';
import { Persona } from '@/types/persona';
interface PersonaGenerationPromptsProps {
persona: Persona;
}
export function PersonaGenerationPrompts({ persona }: PersonaGenerationPromptsProps) {
// Check if generation prompts are available
const hasPrompts = persona.audience_brief || persona.research_objective;
if (!hasPrompts) {
return (
<div className="flex items-center justify-center h-64">
<div className="text-center text-slate-500">
<FileText className="h-12 w-12 mx-auto mb-4 text-slate-400" />
<h3 className="font-sf text-lg font-medium mb-2">Generation prompts not available</h3>
<p className="text-sm">Generation prompts are not available for this persona.</p>
</div>
</div>
);
}
return (
<div className="space-y-6">
{persona.audience_brief && (
<Card>
<CardContent className="p-6">
<div className="flex items-center mb-4">
<FileText className="h-5 w-5 text-primary mr-2" />
<h3 className="font-sf text-lg font-medium">Audience Brief</h3>
</div>
<div className="bg-slate-50 rounded-lg p-4 max-h-80 overflow-y-auto">
<p className="text-sm whitespace-pre-wrap leading-relaxed">
{persona.audience_brief}
</p>
</div>
</CardContent>
</Card>
)}
{persona.research_objective && (
<Card>
<CardContent className="p-6">
<div className="flex items-center mb-4">
<Target className="h-5 w-5 text-emerald-500 mr-2" />
<h3 className="font-sf text-lg font-medium">Research Objective</h3>
</div>
<div className="bg-slate-50 rounded-lg p-4 max-h-80 overflow-y-auto">
<p className="text-sm whitespace-pre-wrap leading-relaxed">
{persona.research_objective}
</p>
</div>
</CardContent>
</Card>
)}
</div>
);
}

View file

@ -20,6 +20,7 @@ import { PersonaSidebar } from './PersonaSidebar';
import { PersonaCooperProfile } from './PersonaCooperProfile';
import { PersonaPersonality } from './PersonaPersonality';
import { PersonaScenarios } from './PersonaScenarios';
import { PersonaGenerationPrompts } from './PersonaGenerationPrompts';
import { PersonaNotFound } from './PersonaNotFound';
import { PersonaProfileSkeleton } from './PersonaProfileSkeleton';
import PersonaEditor from './PersonaEditor';
@ -203,7 +204,7 @@ export default function PersonaProfile() {
>
<ArrowLeft className="h-5 w-5" />
</Button>
<h1 className="font-sf text-3xl font-bold text-slate-900 mx-auto">Persona Profile</h1>
<h1 className="font-sf text-3xl font-bold text-slate-900 ml-16">Persona Profile</h1>
<div className="absolute right-0 top-0 flex items-center gap-3">
<Button
variant="outline"
@ -236,10 +237,11 @@ export default function PersonaProfile() {
<div className="lg:col-span-2">
<Tabs defaultValue="cooper-profile">
<TabsList className="grid w-full grid-cols-3">
<TabsList className="grid w-full grid-cols-4">
<TabsTrigger value="cooper-profile">Cooper Profile</TabsTrigger>
<TabsTrigger value="personality">Personality</TabsTrigger>
<TabsTrigger value="scenarios">Scenarios</TabsTrigger>
<TabsTrigger value="generation-prompts">Generation Prompts</TabsTrigger>
</TabsList>
<TabsContent value="cooper-profile" className="mt-6">
@ -253,6 +255,10 @@ export default function PersonaProfile() {
<TabsContent value="scenarios" className="mt-6">
<PersonaScenarios persona={currentPersona} />
</TabsContent>
<TabsContent value="generation-prompts" className="mt-6">
<PersonaGenerationPrompts persona={currentPersona} />
</TabsContent>
</Tabs>
</div>
</div>

View file

@ -221,10 +221,21 @@ export const aiPersonasApi = {
}),
// Second stage: Complete a single persona and save to database
completeAndSavePersona: (basicProfile: any, temperature: number = 0.7) =>
completeAndSavePersona: (
basicProfile: any,
temperature: number = 0.7,
audienceBrief?: string,
researchObjective?: string,
customerDataSessionId?: string,
llmModel?: string
) =>
api.post('/ai-personas/complete-and-save-persona', {
basic_profile: basicProfile,
temperature
temperature,
audience_brief: audienceBrief,
research_objective: researchObjective,
customer_data_session_id: customerDataSessionId,
llm_model: llmModel
}, {
timeout: 600000 // 10 minutes for detailed persona generation and saving
}),
@ -276,6 +287,8 @@ export const aiPersonasApi = {
api.post('/ai-personas/complete-and-save-persona', {
basic_profile: profile,
temperature,
audience_brief: audienceBrief,
research_objective: researchObjective,
customer_data_session_id: customerDataSessionId,
llm_model: llmModel || 'gemini-2.5-pro'
}, {

View file

@ -78,4 +78,8 @@ export interface Persona {
folder_ids?: string[]; // Array of folder IDs this persona belongs to
folderId?: string; // Legacy: single folder ID (kept for backwards compatibility)
folder_id?: string; // Alternative single folder field
// Generation prompts (for personas created after this feature)
audience_brief?: string; // The audience brief used to generate this persona
research_objective?: string; // The research objective used to generate this persona
}