Chat assistant
This commit is contained in:
@@ -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."""
|
||||
|
||||
Reference in New Issue
Block a user