@@ -943,10 +943,12 @@
Version {{ i + 1 }}
{% if post.critic_feedback and i < post.critic_feedback | length %}
-
- Score: {{ post.critic_feedback[i].overall_score }}/100
+ {% if post.critic_feedback[i].get('overall_score') is not none %}
+
+ Score: {{ post.critic_feedback[i].get('overall_score', 0) }}/100
- {% if post.critic_feedback[i].approved %}
+ {% endif %}
+ {% if post.critic_feedback[i].get('approved') %}
Approved
{% endif %}
diff --git a/src/web/templates/user/posts.html b/src/web/templates/user/posts.html
index 6690a6b..c4139b1 100644
--- a/src/web/templates/user/posts.html
+++ b/src/web/templates/user/posts.html
@@ -10,8 +10,8 @@
onclick="window.location.href='/posts/{{ post.id }}'">
{{ post.topic_title or 'Untitled' }}
- {% if post.critic_feedback and post.critic_feedback | length > 0 %}
- {% set score = post.critic_feedback[-1].overall_score %}
+ {% if post.critic_feedback and post.critic_feedback | length > 0 and post.critic_feedback[-1].get('overall_score') is not none %}
+ {% set score = post.critic_feedback[-1].get('overall_score', 0) %}
{{ score }}
diff --git a/src/web/user/routes.py b/src/web/user/routes.py
index 6271f8a..9058ecd 100644
--- a/src/web/user/routes.py
+++ b/src/web/user/routes.py
@@ -1354,7 +1354,9 @@ async def posts_page(request: Request):
"profile_picture": profile_picture
})
except Exception as e:
+ import traceback
logger.error(f"Error loading posts: {e}")
+ logger.error(f"Traceback: {traceback.format_exc()}")
return templates.TemplateResponse("posts.html", {
"request": request,
"page": "posts",
@@ -1628,7 +1630,9 @@ async def post_detail_page(request: Request, post_id: str):
"media_items_dict": media_items_dict
})
except Exception as e:
+ import traceback
logger.error(f"Error loading post detail: {e}")
+ logger.error(f"Traceback: {traceback.format_exc()}")
return RedirectResponse(url="/posts", status_code=302)
@@ -1690,6 +1694,35 @@ async def create_post_page(request: Request):
})
+@user_router.get("/chat-create", response_class=HTMLResponse)
+async def chat_create_page(request: Request):
+ """Chat-based post creation page."""
+ session = require_user_session(request)
+ if not session:
+ return RedirectResponse(url="/login", status_code=302)
+
+ user_id = UUID(session.user_id)
+
+ # Get post types
+ post_types = await db.get_post_types(user_id)
+ if not post_types:
+ return templates.TemplateResponse("error.html", {
+ "request": request,
+ "session": session,
+ "error": "Keine Post-Typen gefunden. Bitte erstelle zuerst Post-Typen."
+ })
+
+ profile_picture = await get_user_avatar(session, user_id)
+
+ return templates.TemplateResponse("chat_create.html", {
+ "request": request,
+ "page": "chat-create",
+ "session": session,
+ "post_types": post_types,
+ "profile_picture": profile_picture
+ })
+
+
@user_router.get("/status", response_class=HTMLResponse)
async def status_page(request: Request):
"""User's status page."""
@@ -3252,6 +3285,271 @@ async def save_all_and_reanalyze(request: Request, background_tasks: BackgroundT
return JSONResponse({"error": str(e)}, status_code=500)
+@user_router.post("/api/employee/chat/generate")
+async def chat_generate_post(request: Request):
+ """Generate initial post from chat message."""
+ session = require_user_session(request)
+ if not session:
+ raise HTTPException(status_code=401, detail="Not authenticated")
+
+ try:
+ data = await request.json()
+ message = data.get("message", "").strip()
+ post_type_id = data.get("post_type_id")
+
+ if not message:
+ return JSONResponse({"success": False, "error": "Nachricht erforderlich"})
+
+ if not post_type_id:
+ return JSONResponse({"success": False, "error": "Post-Typ erforderlich"})
+
+ user_id = UUID(session.user_id)
+
+ # Get post type info
+ post_type = await db.get_post_type(UUID(post_type_id))
+ if not post_type:
+ return JSONResponse({"success": False, "error": "Post-Typ nicht gefunden"})
+
+ # Get profile analysis
+ profile_analysis = await db.get_profile_analysis(user_id)
+ if not profile_analysis:
+ return JSONResponse({"success": False, "error": "Profil-Analyse nicht gefunden"})
+
+ # Get company strategy if available
+ company_strategy = None
+ profile = await db.get_profile(user_id)
+ if profile and profile.company_id:
+ company = await db.get_company(profile.company_id)
+ if company and company.company_strategy:
+ company_strategy = company.company_strategy
+
+ # Get example posts for style reference
+ linkedin_posts = await db.get_posts_by_type(user_id, UUID(post_type_id))
+ if len(linkedin_posts) < 3:
+ linkedin_posts = await db.get_linkedin_posts(user_id)
+
+ example_post_texts = [
+ post.post_text for post in linkedin_posts
+ if post.post_text and len(post.post_text) > 100
+ ][:10]
+
+ # Generate post using writer agent with user's content as primary focus
+ from src.agents.writer import WriterAgent
+ writer = WriterAgent()
+
+ # Create a topic structure from user's message
+ topic = {
+ "title": message[:100],
+ "fact": message,
+ "relevance": "User-specified content"
+ }
+
+ # Generate post
+ post_content = await writer.process(
+ topic=topic,
+ profile_analysis=profile_analysis.full_analysis,
+ example_posts=example_post_texts,
+ post_type=post_type,
+ user_thoughts=message, # CRITICAL: User's input as primary content
+ company_strategy=company_strategy,
+ strategy_weight=post_type.strategy_weight
+ )
+
+ # Generate conversation ID
+ import uuid
+ conversation_id = str(uuid.uuid4())
+
+ return JSONResponse({
+ "success": True,
+ "post": post_content,
+ "conversation_id": conversation_id,
+ "explanation": "Hier ist dein erster Entwurf basierend auf deiner Beschreibung:"
+ })
+
+ except Exception as e:
+ logger.error(f"Error generating chat post: {e}")
+ return JSONResponse({"success": False, "error": str(e)}, status_code=500)
+
+
+@user_router.post("/api/employee/chat/refine")
+async def chat_refine_post(request: Request):
+ """Refine existing post based on user feedback."""
+ session = require_user_session(request)
+ if not session:
+ raise HTTPException(status_code=401, detail="Not authenticated")
+
+ try:
+ data = await request.json()
+ message = data.get("message", "").strip()
+ current_post = data.get("current_post", "")
+ post_type_id = data.get("post_type_id")
+ chat_history = data.get("chat_history", [])
+
+ if not message:
+ return JSONResponse({"success": False, "error": "Nachricht erforderlich"})
+
+ if not current_post:
+ return JSONResponse({"success": False, "error": "Kein Post zum Verfeinern vorhanden"})
+
+ if not post_type_id:
+ return JSONResponse({"success": False, "error": "Post-Typ erforderlich"})
+
+ user_id = UUID(session.user_id)
+
+ # Get post type info
+ post_type = await db.get_post_type(UUID(post_type_id))
+ if not post_type:
+ return JSONResponse({"success": False, "error": "Post-Typ nicht gefunden"})
+
+ # Get profile analysis
+ profile_analysis = await db.get_profile_analysis(user_id)
+ if not profile_analysis:
+ return JSONResponse({"success": False, "error": "Profil-Analyse nicht gefunden"})
+
+ # Ensure full_analysis is a dict
+ full_analysis = profile_analysis.full_analysis if profile_analysis.full_analysis else {}
+ if not isinstance(full_analysis, dict):
+ logger.warning(f"full_analysis is not a dict: {type(full_analysis)}")
+ full_analysis = {}
+
+ # Get company strategy if available
+ company_strategy = None
+ profile = await db.get_profile(user_id)
+ if profile and profile.company_id:
+ company = await db.get_company(profile.company_id)
+ if company and company.company_strategy:
+ company_strategy = company.company_strategy
+ # Ensure it's a dict
+ if not isinstance(company_strategy, dict):
+ logger.warning(f"company_strategy is not a dict: {type(company_strategy)}")
+ company_strategy = None
+
+ # Get example posts
+ linkedin_posts = await db.get_posts_by_type(user_id, UUID(post_type_id))
+ if len(linkedin_posts) < 3:
+ linkedin_posts = await db.get_linkedin_posts(user_id)
+
+ example_post_texts = [
+ post.post_text for post in linkedin_posts
+ if post.post_text and len(post.post_text) > 100
+ ][:10]
+
+ # Refine post using writer with feedback
+ from src.agents.writer import WriterAgent
+ writer = WriterAgent()
+
+ topic = {
+ "title": "Chat refinement",
+ "fact": message,
+ "relevance": "User refinement request"
+ }
+
+ # Use writer's revision capability
+ refined_post = await writer.process(
+ topic=topic,
+ profile_analysis=full_analysis,
+ example_posts=example_post_texts,
+ feedback=message, # User's refinement instruction
+ previous_version=current_post,
+ post_type=post_type,
+ user_thoughts=message,
+ company_strategy=company_strategy,
+ strategy_weight=getattr(post_type, 'strategy_weight', 0.5)
+ )
+
+ return JSONResponse({
+ "success": True,
+ "post": refined_post,
+ "conversation_id": data.get("conversation_id"),
+ "explanation": "Ich habe den Post angepasst:"
+ })
+
+ except Exception as e:
+ import traceback
+ logger.error(f"Error refining chat post: {e}")
+ logger.error(f"Traceback: {traceback.format_exc()}")
+ return JSONResponse({"success": False, "error": str(e)}, status_code=500)
+
+
+@user_router.post("/api/employee/chat/save")
+async def chat_save_post(request: Request):
+ """Save chat-generated post to database."""
+ session = require_user_session(request)
+ if not session:
+ raise HTTPException(status_code=401, detail="Not authenticated")
+
+ try:
+ data = await request.json()
+ post_content = data.get("post_content", "").strip()
+ post_type_id = data.get("post_type_id")
+ chat_history = data.get("chat_history", [])
+
+ if not post_content:
+ return JSONResponse({"success": False, "error": "Post-Inhalt erforderlich"})
+
+ if not post_type_id:
+ return JSONResponse({"success": False, "error": "Post-Typ erforderlich"})
+
+ user_id = UUID(session.user_id)
+
+ # Extract title from first sentence of post
+ first_sentence = post_content.split('\n')[0].strip()
+ if len(first_sentence) > 100:
+ title = first_sentence[:97] + "..."
+ else:
+ title = first_sentence if first_sentence else "Chat-generierter Post"
+
+ # Create GeneratedPost with status draft
+ from src.database.models import GeneratedPost
+ import uuid as uuid_lib
+
+ post_id = uuid_lib.uuid4()
+
+ # Extract all AI-generated versions from chat history
+ writer_versions = []
+ critic_feedback_list = []
+
+ for item in chat_history:
+ if 'ai' in item and item['ai']:
+ writer_versions.append(item['ai'])
+ # Store user feedback as "critic feedback"
+ if 'user' in item and item['user']:
+ critic_feedback_list.append({
+ 'feedback': item['user'],
+ 'explanation': item.get('explanation', '')
+ })
+
+ # Add final version
+ writer_versions.append(post_content)
+
+ num_iterations = len(writer_versions)
+
+ generated_post = GeneratedPost(
+ id=post_id,
+ user_id=user_id,
+ post_content=post_content,
+ post_type_id=UUID(post_type_id),
+ status="draft",
+ iterations=num_iterations,
+ writer_versions=writer_versions, # All iterations saved here
+ critic_feedback=critic_feedback_list, # User feedback saved here
+ topic_title=title,
+ created_at=datetime.now(timezone.utc)
+ )
+
+ saved_post = await db.save_generated_post(generated_post)
+
+ return JSONResponse({
+ "success": True,
+ "post_id": str(saved_post.id),
+ "message": "Post erfolgreich gespeichert"
+ })
+
+ except Exception as e:
+ logger.error(f"Error saving chat post: {e}")
+ return JSONResponse({"success": False, "error": str(e)}, status_code=500)
+
+
@user_router.post("/api/company/invite")
async def send_company_invitation(request: Request):
"""Send invitation to a new employee."""