diff --git a/backend/app/routers/content.py b/backend/app/routers/content.py index b5e200f..476114c 100644 --- a/backend/app/routers/content.py +++ b/backend/app/routers/content.py @@ -315,12 +315,28 @@ def approve_post( db: Session = Depends(get_db), current_user: User = Depends(get_current_user), ): - """Approve a post (set status to 'approved').""" + """Approve a post (set status to 'approved'). Also saves it as a reference example for the character.""" post = db.query(Post).filter(Post.id == post_id, Post.user_id == current_user.id).first() if not post: raise HTTPException(status_code=404, detail="Post not found") post.status = "approved" post.updated_at = datetime.utcnow() + + # Save as reference example for future few-shot learning (keep last 5 per character) + if post.text_content and post.character_id: + character = db.query(Character).filter(Character.id == post.character_id).first() + if character: + examples = character.content_rules or {} + approved_examples = examples.get("approved_examples", []) + approved_examples.append({ + "platform": post.platform_hint or "general", + "text": post.text_content[:500], # truncate for prompt efficiency + }) + # Keep only last 5 + examples["approved_examples"] = approved_examples[-5:] + character.content_rules = examples + character.updated_at = datetime.utcnow() + db.commit() db.refresh(post) return post diff --git a/backend/app/services/content.py b/backend/app/services/content.py index 975073f..454c506 100644 --- a/backend/app/services/content.py +++ b/backend/app/services/content.py @@ -77,6 +77,15 @@ def generate_post_text( rules_text += "\nNON FARE MAI: " + " | ".join(dont_rules) system_parts.append(rules_text) + # Few-shot: approved examples from past posts + approved_examples = content_rules.get("approved_examples", []) + if approved_examples: + examples_text = "\nESEMPI DI POST APPROVATI (usa come riferimento per stile e tono):" + for i, ex in enumerate(approved_examples[-3:], 1): # last 3 in prompt + plat = ex.get("platform", "") + examples_text += f"\n--- Esempio {i} ({plat}) ---\n{ex.get('text', '')}" + system_parts.append(examples_text) + system_parts.extend([ "\nYou create authentic, engaging content that resonates with your audience.", "Never reveal you are an AI. Write as {name} would naturally write.", diff --git a/frontend/src/components/CharacterForm.jsx b/frontend/src/components/CharacterForm.jsx index c9089f6..2402628 100644 --- a/frontend/src/components/CharacterForm.jsx +++ b/frontend/src/components/CharacterForm.jsx @@ -1,6 +1,7 @@ import { useState, useEffect } from 'react' import { useNavigate, useParams } from 'react-router-dom' import { api } from '../api' +import { useAuth } from '../AuthContext' const EMPTY_FORM = { name: '', @@ -37,6 +38,7 @@ export default function CharacterForm() { const { id } = useParams() const isEdit = Boolean(id) const navigate = useNavigate() + const { isPro } = useAuth() const [form, setForm] = useState(EMPTY_FORM) const [topicInput, setTopicInput] = useState('') @@ -291,6 +293,7 @@ export default function CharacterForm() { handleChange('hashtag_profiles', p)} + isPro={isPro} /> @@ -432,9 +435,11 @@ function RulesEditor({ doRules, dontRules, onChange }) { ) } -function HashtagProfileEditor({ profiles, onChange }) { +function HashtagProfileEditor({ profiles, onChange, isPro }) { const [activeTab, setActiveTab] = useState('instagram') const [tagInput, setTagInput] = useState('') + const availablePlatforms = isPro ? HASHTAG_PLATFORMS : HASHTAG_PLATFORMS.filter(p => ['instagram', 'facebook'].includes(p)) + const proOnlyPlatforms = ['youtube', 'tiktok'] const getProfile = (platform) => profiles[platform] || { always: [], max_generated: 12 } const setProfile = (platform, profile) => onChange({ ...profiles, [platform]: profile }) @@ -460,18 +465,22 @@ function HashtagProfileEditor({ profiles, onChange }) { return (
- {HASHTAG_PLATFORMS.map(p => ( - - ))} + ) + })}