aktueller stand

This commit is contained in:
2026-02-03 12:48:43 +01:00
parent e1ecd1a38c
commit b50594dbfa
77 changed files with 19139 additions and 0 deletions

View File

@@ -0,0 +1,300 @@
"""Profile analyzer agent."""
import json
from typing import Dict, Any, List
from loguru import logger
from src.agents.base import BaseAgent
from src.database.models import LinkedInProfile, LinkedInPost
class ProfileAnalyzerAgent(BaseAgent):
"""Agent for analyzing LinkedIn profiles and extracting writing patterns."""
def __init__(self):
"""Initialize profile analyzer agent."""
super().__init__("ProfileAnalyzer")
async def process(
self,
profile: LinkedInProfile,
posts: List[LinkedInPost],
customer_data: Dict[str, Any]
) -> Dict[str, Any]:
"""
Analyze LinkedIn profile and extract writing patterns.
Args:
profile: LinkedIn profile data
posts: List of LinkedIn posts
customer_data: Additional customer data from input file
Returns:
Comprehensive profile analysis
"""
logger.info(f"Analyzing profile for: {profile.name}")
# Prepare analysis data
profile_summary = {
"name": profile.name,
"headline": profile.headline,
"summary": profile.summary,
"industry": profile.industry,
"location": profile.location
}
# Prepare posts with engagement data - use up to 30 posts
posts_with_engagement = self._prepare_posts_for_analysis(posts[:15])
# Also identify top performing posts by engagement
top_posts = self._get_top_performing_posts(posts, limit=5)
system_prompt = self._get_system_prompt()
user_prompt = self._get_user_prompt(profile_summary, posts_with_engagement, top_posts, customer_data)
response = await self.call_openai(
system_prompt=system_prompt,
user_prompt=user_prompt,
model="gpt-4o",
temperature=0.3,
response_format={"type": "json_object"}
)
# Parse JSON response
analysis = json.loads(response)
logger.info("Profile analysis completed successfully")
return analysis
def _prepare_posts_for_analysis(self, posts: List[LinkedInPost]) -> List[Dict[str, Any]]:
"""Prepare posts with engagement data for analysis."""
prepared = []
for i, post in enumerate(posts):
if not post.post_text:
continue
prepared.append({
"index": i + 1,
"text": post.post_text,
"likes": post.likes or 0,
"comments": post.comments or 0,
"shares": post.shares or 0,
"engagement_total": (post.likes or 0) + (post.comments or 0) * 2 + (post.shares or 0) * 3
})
return prepared
def _get_top_performing_posts(self, posts: List[LinkedInPost], limit: int = 5) -> List[Dict[str, Any]]:
"""Get top performing posts by engagement."""
posts_with_engagement = []
for post in posts:
if not post.post_text or len(post.post_text) < 50:
continue
engagement = (post.likes or 0) + (post.comments or 0) * 2 + (post.shares or 0) * 3
posts_with_engagement.append({
"text": post.post_text,
"likes": post.likes or 0,
"comments": post.comments or 0,
"shares": post.shares or 0,
"engagement_score": engagement
})
# Sort by engagement and return top posts
sorted_posts = sorted(posts_with_engagement, key=lambda x: x["engagement_score"], reverse=True)
return sorted_posts[:limit]
def _get_system_prompt(self) -> str:
"""Get system prompt for profile analysis."""
return """Du bist ein hochspezialisierter AI-Analyst für LinkedIn-Profile und Content-Strategie.
Deine Aufgabe ist es, aus LinkedIn-Profildaten und Posts ein umfassendes Content-Analyse-Profil zu erstellen, das als BLAUPAUSE für das Schreiben neuer Posts dient.
WICHTIG: Extrahiere ECHTE BEISPIELE aus den Posts! Keine generischen Beschreibungen.
Das Profil soll folgende Dimensionen analysieren:
1. **Schreibstil & Tonalität**
- Wie schreibt die Person? (formal, locker, inspirierend, provokativ, etc.)
- Welche Perspektive wird genutzt? (Ich, Wir, Man)
- Wie ist die Ansprache? (Du, Sie, neutral)
- Satzdynamik und Rhythmus
2. **Phrasen-Bibliothek (KRITISCH!)**
- Hook-Phrasen: Wie beginnen Posts? Extrahiere 5-10 ECHTE Beispiele!
- Übergangs-Phrasen: Wie werden Absätze verbunden?
- Emotionale Ausdrücke: Ausrufe, Begeisterung, etc.
- CTA-Phrasen: Wie werden Leser aktiviert?
- Signature Phrases: Wiederkehrende Markenzeichen
3. **Struktur-Templates**
- Analysiere die STRUKTUR der Top-Posts
- Erstelle 2-3 konkrete Templates (z.B. "Hook → Flashback → Erkenntnis → CTA")
- Typische Satzanfänge für jeden Abschnitt
4. **Visuelle Muster**
- Emoji-Nutzung (welche, wo, wie oft)
- Unicode-Formatierung (fett, kursiv)
- Strukturierung (Absätze, Listen, etc.)
5. **Audience Insights**
- Wer ist die Zielgruppe?
- Welche Probleme werden adressiert?
- Welcher Mehrwert wird geboten?
Gib deine Analyse als strukturiertes JSON zurück."""
def _get_user_prompt(
self,
profile_summary: Dict[str, Any],
posts_with_engagement: List[Dict[str, Any]],
top_posts: List[Dict[str, Any]],
customer_data: Dict[str, Any]
) -> str:
"""Get user prompt with data for analysis."""
# Format all posts with engagement data
all_posts_text = ""
for post in posts_with_engagement:
all_posts_text += f"\n--- Post {post['index']} (Likes: {post['likes']}, Comments: {post['comments']}, Shares: {post['shares']}) ---\n"
all_posts_text += post['text'][:2000] # Limit each post to 2000 chars
all_posts_text += "\n"
# Format top performing posts
top_posts_text = ""
if top_posts:
for i, post in enumerate(top_posts, 1):
top_posts_text += f"\n--- TOP POST {i} (Engagement Score: {post['engagement_score']}, Likes: {post['likes']}, Comments: {post['comments']}) ---\n"
top_posts_text += post['text'][:2000]
top_posts_text += "\n"
return f"""Bitte analysiere folgendes LinkedIn-Profil BASIEREND AUF DEN ECHTEN POSTS:
**PROFIL-INFORMATIONEN:**
- Name: {profile_summary.get('name', 'N/A')}
- Headline: {profile_summary.get('headline', 'N/A')}
- Branche: {profile_summary.get('industry', 'N/A')}
- Location: {profile_summary.get('location', 'N/A')}
- Summary: {profile_summary.get('summary', 'N/A')}
**ZUSÄTZLICHE KUNDENDATEN (Persona, Style Guide, etc.):**
{json.dumps(customer_data, indent=2, ensure_ascii=False)}
**TOP-PERFORMING POSTS (die erfolgreichsten Posts - ANALYSIERE DIESE BESONDERS GENAU!):**
{top_posts_text if top_posts_text else "Keine Engagement-Daten verfügbar"}
**ALLE POSTS ({len(posts_with_engagement)} Posts mit Engagement-Daten):**
{all_posts_text}
---
WICHTIG: Analysiere die ECHTEN POSTS sehr genau! Deine Analyse muss auf den tatsächlichen Mustern basieren, nicht auf Annahmen. Extrahiere WÖRTLICHE ZITATE wo möglich!
Achte besonders auf:
1. Die TOP-PERFORMING Posts - was macht sie erfolgreich?
2. Wiederkehrende Phrasen und Formulierungen - WÖRTLICH extrahieren!
3. Wie beginnen die Posts (Hooks)? - ECHTE BEISPIELE sammeln!
4. Wie enden die Posts (CTAs)?
5. Emoji-Verwendung (welche, wo, wie oft)
6. Länge und Struktur der Absätze
7. Typische Satzanfänge und Übergänge
Erstelle eine umfassende Analyse im folgenden JSON-Format:
{{
"writing_style": {{
"tone": "Beschreibung der Tonalität basierend auf den echten Posts",
"perspective": "Ich/Wir/Man/Gemischt - mit Beispielen aus den Posts",
"form_of_address": "Du/Sie/Neutral - wie spricht die Person die Leser an?",
"sentence_dynamics": "Kurze Sätze? Lange Sätze? Mischung? Fragen?",
"average_post_length": "Kurz/Mittel/Lang",
"average_word_count": 0
}},
"linguistic_fingerprint": {{
"energy_level": 0,
"shouting_usage": "Beschreibung mit konkreten Beispielen aus den Posts",
"punctuation_patterns": "Beschreibung (!!!, ..., ?, etc.)",
"signature_phrases": ["ECHTE Phrasen aus den Posts", "die wiederholt vorkommen"],
"narrative_anchors": ["Storytelling-Elemente", "die die Person nutzt"]
}},
"phrase_library": {{
"hook_phrases": [
"ECHTE Hook-Sätze aus den Posts wörtlich kopiert",
"Mindestens 5-8 verschiedene Beispiele",
"z.B. '𝗞𝗜-𝗦𝘂𝗰𝗵𝗲 𝗶𝘀𝘁 𝗱𝗲𝗿 𝗲𝗿𝘀𝘁𝗲 𝗦𝗰𝗵𝗿𝗶𝘁𝘁 𝗶𝗺 𝗦𝗮𝗹𝗲𝘀 𝗙𝘂𝗻𝗻𝗲𝗹.'"
],
"transition_phrases": [
"ECHTE Übergangssätze zwischen Absätzen",
"z.B. 'Und wisst ihr was?', 'Aber Moment...', 'Was das mit X zu tun hat?'"
],
"emotional_expressions": [
"Ausrufe und emotionale Marker",
"z.B. 'Halleluja!', 'Sorry to say!!', 'Galopp!!!!'"
],
"cta_phrases": [
"ECHTE Call-to-Action Formulierungen",
"z.B. 'Was denkt ihr?', 'Seid ihr dabei?', 'Lasst uns darüber sprechen.'"
],
"filler_expressions": [
"Typische Füllwörter und Ausdrücke",
"z.B. 'Ich meine...', 'Wisst ihr...', 'Ok, ok...'"
]
}},
"structure_templates": {{
"primary_structure": "Die häufigste Struktur beschreiben, z.B. 'Unicode-Hook → Persönliche Anekdote → Erkenntnis → Bullet Points → CTA'",
"template_examples": [
{{
"name": "Storytelling-Post",
"structure": ["Fetter Hook mit Zitat", "Flashback/Anekdote", "Erkenntnis/Lesson", "Praktische Tipps", "CTA-Frage"],
"example_post_index": 1
}},
{{
"name": "Insight-Post",
"structure": ["Provokante These", "Begründung", "Beispiel", "Handlungsaufforderung"],
"example_post_index": 2
}}
],
"typical_sentence_starters": [
"ECHTE Satzanfänge aus den Posts",
"z.B. 'Ich glaube, dass...', 'Was mir aufgefallen ist...', 'Das Verrückte ist...'"
],
"paragraph_transitions": [
"Wie werden Absätze eingeleitet?",
"z.B. 'Und...', 'Aber:', 'Das bedeutet:'"
]
}},
"tone_analysis": {{
"primary_tone": "Haupttonalität basierend auf den Posts",
"emotional_range": "Welche Emotionen werden angesprochen?",
"authenticity_markers": ["Was macht den Stil einzigartig?", "Erkennbare Merkmale"]
}},
"topic_patterns": {{
"main_topics": ["Hauptthemen aus den Posts"],
"content_pillars": ["Content-Säulen"],
"expertise_areas": ["Expertise-Bereiche"],
"expertise_level": "Anfänger/Fortgeschritten/Experte"
}},
"audience_insights": {{
"target_audience": "Wer wird angesprochen?",
"pain_points_addressed": ["Probleme die adressiert werden"],
"value_proposition": "Welchen Mehrwert bietet die Person?",
"industry_context": "Branchenkontext"
}},
"visual_patterns": {{
"emoji_usage": {{
"emojis": ["Liste der tatsächlich verwendeten Emojis"],
"placement": "Anfang/Ende/Inline/Zwischen Absätzen",
"frequency": "Selten/Mittel/Häufig - pro Post durchschnittlich X"
}},
"unicode_formatting": "Wird ✓, →, •, 𝗙𝗲𝘁𝘁 etc. verwendet? Wo?",
"structure_preferences": "Absätze/Listen/Einzeiler/Nummeriert"
}},
"content_strategy": {{
"hook_patterns": "Wie werden Posts KONKRET eröffnet? Beschreibung des Musters",
"cta_style": "Wie sehen die CTAs aus? Frage? Aufforderung? Keine?",
"storytelling_approach": "Persönliche Geschichten? Metaphern? Case Studies?",
"post_structure": "Hook → Body → CTA? Oder anders?"
}},
"best_performing_patterns": {{
"what_works": "Was machen die Top-Posts anders/besser?",
"successful_hooks": ["WÖRTLICHE Beispiel-Hooks aus Top-Posts"],
"engagement_drivers": ["Was treibt Engagement?"]
}}
}}
KRITISCH: Bei phrase_library und structure_templates müssen ECHTE, WÖRTLICHE Beispiele aus den Posts stehen! Keine generischen Beschreibungen!"""