Chat optimizations
This commit is contained in:
@@ -3,6 +3,32 @@
|
||||
{% block title %}Chat Assistent{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<!-- Posts Sidebar -->
|
||||
<div class="posts-sidebar">
|
||||
<div class="posts-sidebar-header">
|
||||
<button onclick="startNewPost()">
|
||||
+ Neuer Post
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="posts-sidebar-list">
|
||||
{% if saved_posts %}
|
||||
{% for post in saved_posts %}
|
||||
<div class="post-sidebar-item"
|
||||
data-post-id="{{ post.id }}"
|
||||
onclick="loadPostHistory('{{ post.id }}')">
|
||||
<div class="post-sidebar-title">{{ post.topic_title }}</div>
|
||||
<span class="post-sidebar-status status-{{ post.status }}">{{ post.status }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="posts-sidebar-empty">
|
||||
Noch keine Posts vorhanden
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* Make chat page full height and remove padding */
|
||||
#mainContent > div {
|
||||
@@ -35,6 +61,168 @@ aside.collapsed ~ main .chat-fixed-input {
|
||||
0%, 80%, 100% { transform: translateY(0); }
|
||||
40% { transform: translateY(-8px); }
|
||||
}
|
||||
|
||||
/* Posts Sidebar */
|
||||
.posts-sidebar {
|
||||
position: fixed;
|
||||
left: 256px;
|
||||
top: 0;
|
||||
width: 280px;
|
||||
height: 100vh;
|
||||
background-color: #2d3838;
|
||||
border-right: 1px solid #5a6868;
|
||||
z-index: 15;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
transition: left 0.3s ease;
|
||||
}
|
||||
|
||||
/* When main sidebar is collapsed */
|
||||
aside.collapsed ~ main .posts-sidebar {
|
||||
left: 64px;
|
||||
}
|
||||
|
||||
/* Hide on smaller screens */
|
||||
@media (max-width: 1280px) {
|
||||
.posts-sidebar {
|
||||
display: none !important;
|
||||
}
|
||||
#chat-messages {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
.chat-fixed-header,
|
||||
.chat-fixed-input {
|
||||
left: 256px !important;
|
||||
}
|
||||
aside.collapsed ~ main .chat-fixed-header,
|
||||
aside.collapsed ~ main .chat-fixed-input {
|
||||
left: 64px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sidebar Header */
|
||||
.posts-sidebar-header {
|
||||
padding: 1rem;
|
||||
border-bottom: 1px solid #5a6868;
|
||||
}
|
||||
|
||||
.posts-sidebar-header button {
|
||||
width: 100%;
|
||||
padding: 0.625rem 1rem;
|
||||
background-color: #ffc700;
|
||||
color: #2d3838;
|
||||
border-radius: 0.5rem;
|
||||
font-weight: 600;
|
||||
font-size: 0.875rem;
|
||||
transition: background-color 0.2s;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.posts-sidebar-header button:hover {
|
||||
background-color: #e6b300;
|
||||
}
|
||||
|
||||
/* Posts List */
|
||||
.posts-sidebar-list {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
/* Post Item */
|
||||
.post-sidebar-item {
|
||||
padding: 0.75rem 1rem;
|
||||
margin-bottom: 0.25rem;
|
||||
background-color: #3d4848;
|
||||
border-left: 3px solid transparent;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.post-sidebar-item:hover {
|
||||
background-color: #4a5858;
|
||||
border-left-color: #ffc700;
|
||||
}
|
||||
|
||||
.post-sidebar-item.active {
|
||||
background-color: #4a5858;
|
||||
border-left-color: #ffc700;
|
||||
}
|
||||
|
||||
.post-sidebar-title {
|
||||
font-size: 0.875rem;
|
||||
color: #e5e5e5;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.post-sidebar-status {
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 500;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.status-draft {
|
||||
background-color: rgba(107, 114, 128, 0.3);
|
||||
color: #d1d5db;
|
||||
}
|
||||
|
||||
.status-approved {
|
||||
background-color: rgba(16, 185, 129, 0.2);
|
||||
color: #6ee7b7;
|
||||
}
|
||||
|
||||
.status-ready {
|
||||
background-color: rgba(59, 130, 246, 0.2);
|
||||
color: #93c5fd;
|
||||
}
|
||||
|
||||
.status-scheduled {
|
||||
background-color: rgba(251, 146, 60, 0.2);
|
||||
color: #fdba74;
|
||||
}
|
||||
|
||||
.status-published {
|
||||
background-color: rgba(16, 185, 129, 0.2);
|
||||
color: #6ee7b7;
|
||||
}
|
||||
|
||||
.status-rejected {
|
||||
background-color: rgba(239, 68, 68, 0.2);
|
||||
color: #fca5a5;
|
||||
}
|
||||
|
||||
/* Empty state */
|
||||
.posts-sidebar-empty {
|
||||
padding: 2rem 1rem;
|
||||
text-align: center;
|
||||
color: #9ca3af;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
/* Adjust chat area for sidebar */
|
||||
#chat-messages {
|
||||
margin-left: 280px;
|
||||
}
|
||||
|
||||
.chat-fixed-header,
|
||||
.chat-fixed-input {
|
||||
left: 536px; /* 256px (main sidebar) + 280px (posts sidebar) */
|
||||
}
|
||||
|
||||
aside.collapsed ~ main .chat-fixed-header,
|
||||
aside.collapsed ~ main .chat-fixed-input {
|
||||
left: 344px; /* 64px (collapsed main sidebar) + 280px (posts sidebar) */
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Header (Fixed at top) -->
|
||||
@@ -121,6 +309,7 @@ let chatHistory = [];
|
||||
let currentPost = null;
|
||||
let conversationId = null;
|
||||
let selectedPostTypeId = null;
|
||||
let currentLoadedPostId = null; // Track active post
|
||||
|
||||
// User profile data
|
||||
const userProfilePicture = "{{ profile_picture or '' }}";
|
||||
@@ -231,17 +420,22 @@ async function sendMessage() {
|
||||
// Add AI response to chat
|
||||
addMessageToChat('ai', result.explanation || 'Hier ist dein Post:', result.post);
|
||||
|
||||
// Show save button
|
||||
const saveBtn = document.getElementById('save-btn');
|
||||
saveBtn.classList.remove('hidden');
|
||||
saveBtn.classList.add('flex');
|
||||
|
||||
// Store in history
|
||||
chatHistory.push({
|
||||
user: message,
|
||||
ai: result.post,
|
||||
explanation: result.explanation
|
||||
});
|
||||
|
||||
// Auto-save if this is a loaded post, otherwise show save button
|
||||
if (currentLoadedPostId) {
|
||||
await autoSaveLoadedPost();
|
||||
} else {
|
||||
// Show save button only for new posts
|
||||
const saveBtn = document.getElementById('save-btn');
|
||||
saveBtn.classList.remove('hidden');
|
||||
saveBtn.classList.add('flex');
|
||||
}
|
||||
} else {
|
||||
showToast('Fehler: ' + (result.error || 'Unbekannter Fehler'), 'error');
|
||||
addMessageToChat('ai', '❌ Entschuldigung, es gab einen Fehler. Bitte versuche es erneut.');
|
||||
@@ -340,30 +534,55 @@ async function savePost() {
|
||||
saveBtn.innerHTML = '<svg class="w-5 h-5 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg>';
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/employee/chat/save', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
post_content: currentPost,
|
||||
post_type_id: selectedPostTypeId,
|
||||
conversation_id: conversationId,
|
||||
chat_history: chatHistory
|
||||
})
|
||||
});
|
||||
// If this is a loaded post, update it instead of creating a new one
|
||||
if (currentLoadedPostId) {
|
||||
const response = await fetch(`/api/employee/chat/update/${currentLoadedPostId}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
post_content: currentPost,
|
||||
chat_history: chatHistory
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showToast('Post erfolgreich gespeichert!', 'success');
|
||||
|
||||
// Redirect to post details after short delay
|
||||
setTimeout(() => {
|
||||
window.location.href = `/posts/${result.post_id}`;
|
||||
}, 1000);
|
||||
if (result.success) {
|
||||
showToast('Post erfolgreich aktualisiert!', 'success');
|
||||
saveBtn.disabled = false;
|
||||
saveBtn.innerHTML = originalHTML;
|
||||
} else {
|
||||
showToast('Fehler beim Aktualisieren: ' + (result.error || 'Unbekannter Fehler'), 'error');
|
||||
saveBtn.disabled = false;
|
||||
saveBtn.innerHTML = originalHTML;
|
||||
}
|
||||
} else {
|
||||
showToast('Fehler beim Speichern: ' + (result.error || 'Unbekannter Fehler'), 'error');
|
||||
saveBtn.disabled = false;
|
||||
saveBtn.innerHTML = originalHTML;
|
||||
// Create new post
|
||||
const response = await fetch('/api/employee/chat/save', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
post_content: currentPost,
|
||||
post_type_id: selectedPostTypeId,
|
||||
conversation_id: conversationId,
|
||||
chat_history: chatHistory
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showToast('Post erfolgreich gespeichert!', 'success');
|
||||
|
||||
// Redirect to post details after short delay
|
||||
setTimeout(() => {
|
||||
window.location.href = `/posts/${result.post_id}`;
|
||||
}, 1000);
|
||||
} else {
|
||||
showToast('Fehler beim Speichern: ' + (result.error || 'Unbekannter Fehler'), 'error');
|
||||
saveBtn.disabled = false;
|
||||
saveBtn.innerHTML = originalHTML;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error);
|
||||
@@ -379,6 +598,202 @@ function escapeHtml(text) {
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
function startNewPost() {
|
||||
// Reset state
|
||||
chatHistory = [];
|
||||
currentPost = null;
|
||||
conversationId = null;
|
||||
currentLoadedPostId = null;
|
||||
|
||||
// Remove active class from all sidebar items
|
||||
document.querySelectorAll('.post-sidebar-item').forEach(item => {
|
||||
item.classList.remove('active');
|
||||
});
|
||||
|
||||
// Clear chat area (keep only welcome message)
|
||||
const container = document.getElementById('chat-messages');
|
||||
container.innerHTML = `
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="w-8 h-8 bg-brand-highlight/20 rounded-full flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-lg">🤖</span>
|
||||
</div>
|
||||
<div class="max-w-[70%]">
|
||||
<div class="bg-brand-bg-dark rounded-2xl p-4 border border-gray-600">
|
||||
<p class="text-gray-300">
|
||||
Hallo! Ich helfe dir beim Erstellen deines LinkedIn-Posts.
|
||||
Beschreibe mir einfach, worüber du schreiben möchtest, und ich erstelle einen ersten Entwurf für dich.
|
||||
</p>
|
||||
<p class="text-gray-400 text-sm mt-2">
|
||||
Du kannst mich danach bitten, den Post anzupassen, umzuschreiben oder zu verbessern.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Hide save button
|
||||
const saveBtn = document.getElementById('save-btn');
|
||||
saveBtn.classList.add('hidden');
|
||||
saveBtn.classList.remove('flex');
|
||||
}
|
||||
|
||||
async function loadPostHistory(postId) {
|
||||
// Mark sidebar item as active
|
||||
document.querySelectorAll('.post-sidebar-item').forEach(item => {
|
||||
item.classList.remove('active');
|
||||
if (item.dataset.postId === postId) {
|
||||
item.classList.add('active');
|
||||
}
|
||||
});
|
||||
|
||||
// Show loading in chat area
|
||||
const container = document.getElementById('chat-messages');
|
||||
container.innerHTML = `
|
||||
<div class="flex items-center justify-center h-64">
|
||||
<div class="text-gray-400">
|
||||
<svg class="w-8 h-8 animate-spin mx-auto mb-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
|
||||
</svg>
|
||||
<p>Lade Chat-Verlauf...</p>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/employee/chat/history/${postId}`);
|
||||
const result = await response.json();
|
||||
|
||||
if (!result.success) {
|
||||
showToast('Fehler: ' + (result.error || 'Konnte Post nicht laden'), 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Update state
|
||||
currentLoadedPostId = postId;
|
||||
chatHistory = result.chat_history;
|
||||
currentPost = result.post;
|
||||
selectedPostTypeId = result.post_type_id;
|
||||
|
||||
// Clear chat area
|
||||
container.innerHTML = '';
|
||||
|
||||
// Add welcome message
|
||||
const welcomeDiv = document.createElement('div');
|
||||
welcomeDiv.className = 'flex items-start gap-3';
|
||||
welcomeDiv.innerHTML = `
|
||||
<div class="w-8 h-8 bg-brand-highlight/20 rounded-full flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-lg">🤖</span>
|
||||
</div>
|
||||
<div class="max-w-[70%]">
|
||||
<div class="bg-brand-bg-dark rounded-2xl p-4 border border-gray-600">
|
||||
<p class="text-gray-300">
|
||||
Hallo! Ich helfe dir beim Erstellen deines LinkedIn-Posts.
|
||||
Beschreibe mir einfach, worüber du schreiben möchtest, und ich erstelle einen ersten Entwurf für dich.
|
||||
</p>
|
||||
<p class="text-gray-400 text-sm mt-2">
|
||||
Du kannst mich danach bitten, den Post anzupassen, umzuschreiben oder zu verbessern.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
container.appendChild(welcomeDiv);
|
||||
|
||||
// Rebuild chat from history
|
||||
chatHistory.forEach(item => {
|
||||
// Add user message if exists
|
||||
if (item.user && item.user.trim()) {
|
||||
addMessageToChat('user', item.user);
|
||||
}
|
||||
|
||||
// Add AI message if exists
|
||||
if (item.ai) {
|
||||
addMessageToChat('ai', item.explanation || 'Hier ist dein Post:', item.ai);
|
||||
}
|
||||
});
|
||||
|
||||
// Update post type selection
|
||||
if (selectedPostTypeId) {
|
||||
updatePostTypeSelection(selectedPostTypeId);
|
||||
}
|
||||
|
||||
// Scroll to bottom
|
||||
setTimeout(() => {
|
||||
container.scrollTo({
|
||||
top: container.scrollHeight,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}, 100);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error loading post history:', error);
|
||||
showToast('Netzwerkfehler beim Laden', 'error');
|
||||
|
||||
// Restore welcome message on error
|
||||
container.innerHTML = `
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="w-8 h-8 bg-brand-highlight/20 rounded-full flex items-center justify-center flex-shrink-0">
|
||||
<span class="text-lg">🤖</span>
|
||||
</div>
|
||||
<div class="max-w-[70%]">
|
||||
<div class="bg-brand-bg-dark rounded-2xl p-4 border border-gray-600">
|
||||
<p class="text-gray-300">
|
||||
Hallo! Ich helfe dir beim Erstellen deines LinkedIn-Posts.
|
||||
Beschreibe mir einfach, worüber du schreiben möchtest, und ich erstelle einen ersten Entwurf für dich.
|
||||
</p>
|
||||
<p class="text-gray-400 text-sm mt-2">
|
||||
Du kannst mich danach bitten, den Post anzupassen, umzuschreiben oder zu verbessern.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
function updatePostTypeSelection(postTypeId) {
|
||||
// Remove active state from all chips
|
||||
document.querySelectorAll('.post-type-chip').forEach(chip => {
|
||||
chip.classList.remove('bg-brand-highlight', 'text-black');
|
||||
chip.classList.add('bg-brand-bg-dark', 'text-gray-400');
|
||||
chip.removeAttribute('data-selected');
|
||||
});
|
||||
|
||||
// Add active state to matching chip
|
||||
const targetChip = document.querySelector(`.post-type-chip[data-post-type-id="${postTypeId}"]`);
|
||||
if (targetChip) {
|
||||
targetChip.classList.remove('bg-brand-bg-dark', 'text-gray-400');
|
||||
targetChip.classList.add('bg-brand-highlight', 'text-black');
|
||||
targetChip.setAttribute('data-selected', 'true');
|
||||
}
|
||||
}
|
||||
|
||||
async function autoSaveLoadedPost() {
|
||||
if (!currentLoadedPostId || !currentPost) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/employee/chat/update/${currentLoadedPostId}`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
post_content: currentPost,
|
||||
chat_history: chatHistory
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (!result.success) {
|
||||
showToast('Fehler beim Auto-Speichern: ' + (result.error || 'Unbekannter Fehler'), 'error');
|
||||
}
|
||||
// Silent success - no toast for successful auto-save
|
||||
} catch (error) {
|
||||
console.error('Error auto-saving post:', error);
|
||||
showToast('Netzwerkfehler beim Auto-Speichern', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
function showToast(message, type = 'info') {
|
||||
const toast = document.createElement('div');
|
||||
const colors = {
|
||||
|
||||
@@ -1714,12 +1714,17 @@ async def chat_create_page(request: Request):
|
||||
|
||||
profile_picture = await get_user_avatar(session, user_id)
|
||||
|
||||
# Load all saved posts for sidebar (exclude scheduled and published)
|
||||
all_posts = await db.get_generated_posts(user_id)
|
||||
saved_posts = [post for post in all_posts if post.status not in ['scheduled', 'published']]
|
||||
|
||||
return templates.TemplateResponse("chat_create.html", {
|
||||
"request": request,
|
||||
"page": "chat-create",
|
||||
"session": session,
|
||||
"post_types": post_types,
|
||||
"profile_picture": profile_picture
|
||||
"profile_picture": profile_picture,
|
||||
"saved_posts": saved_posts
|
||||
})
|
||||
|
||||
|
||||
@@ -3550,6 +3555,139 @@ async def chat_save_post(request: Request):
|
||||
return JSONResponse({"success": False, "error": str(e)}, status_code=500)
|
||||
|
||||
|
||||
@user_router.get("/api/employee/chat/history/{post_id}")
|
||||
async def get_chat_history(request: Request, post_id: str):
|
||||
"""Get chat history for a saved post."""
|
||||
session = require_user_session(request)
|
||||
if not session:
|
||||
raise HTTPException(status_code=401, detail="Not authenticated")
|
||||
|
||||
try:
|
||||
user_id = UUID(session.user_id)
|
||||
post_uuid = UUID(post_id)
|
||||
|
||||
# Fetch post
|
||||
post = await db.get_generated_post(post_uuid)
|
||||
if not post:
|
||||
return JSONResponse({"success": False, "error": "Post nicht gefunden"}, status_code=404)
|
||||
|
||||
# Verify ownership
|
||||
if post.user_id != user_id:
|
||||
return JSONResponse({"success": False, "error": "Nicht autorisiert"}, status_code=403)
|
||||
|
||||
# Reconstruct chat history from writer_versions and critic_feedback
|
||||
chat_history = []
|
||||
|
||||
# First version: AI generates initial post (no user message)
|
||||
if post.writer_versions and len(post.writer_versions) > 0:
|
||||
first_explanation = "Hier ist dein erster Entwurf:"
|
||||
# Check if first critic feedback has explanation (from AI)
|
||||
if post.critic_feedback and len(post.critic_feedback) > 0:
|
||||
first_explanation = post.critic_feedback[0].get('explanation', first_explanation)
|
||||
|
||||
chat_history.append({
|
||||
"user": "", # No user message for first generation
|
||||
"ai": post.writer_versions[0],
|
||||
"explanation": first_explanation
|
||||
})
|
||||
|
||||
# Subsequent versions: User feedback → AI refined version
|
||||
for i in range(1, len(post.writer_versions)):
|
||||
user_message = ""
|
||||
explanation = "Hier ist die überarbeitete Version:"
|
||||
|
||||
# Get user feedback from critic_feedback (offset by 1, since first is for initial)
|
||||
if i <= len(post.critic_feedback):
|
||||
feedback_item = post.critic_feedback[i - 1]
|
||||
user_message = feedback_item.get('feedback', '')
|
||||
explanation = feedback_item.get('explanation', explanation)
|
||||
|
||||
chat_history.append({
|
||||
"user": user_message,
|
||||
"ai": post.writer_versions[i],
|
||||
"explanation": explanation
|
||||
})
|
||||
|
||||
return JSONResponse({
|
||||
"success": True,
|
||||
"chat_history": chat_history,
|
||||
"post": post.post_content,
|
||||
"post_type_id": str(post.post_type_id) if post.post_type_id else None,
|
||||
"topic_title": post.topic_title
|
||||
})
|
||||
|
||||
except ValueError:
|
||||
return JSONResponse({"success": False, "error": "Ungültige Post-ID"}, status_code=400)
|
||||
except Exception as e:
|
||||
logger.error(f"Error fetching chat history: {e}")
|
||||
return JSONResponse({"success": False, "error": str(e)}, status_code=500)
|
||||
|
||||
|
||||
@user_router.put("/api/employee/chat/update/{post_id}")
|
||||
async def update_chat_post(request: Request, post_id: str):
|
||||
"""Update an existing post with new chat conversation."""
|
||||
session = require_user_session(request)
|
||||
if not session:
|
||||
raise HTTPException(status_code=401, detail="Not authenticated")
|
||||
|
||||
try:
|
||||
user_id = UUID(session.user_id)
|
||||
post_uuid = UUID(post_id)
|
||||
|
||||
data = await request.json()
|
||||
post_content = data.get("post_content", "").strip()
|
||||
chat_history = data.get("chat_history", [])
|
||||
|
||||
if not post_content:
|
||||
return JSONResponse({"success": False, "error": "Post-Inhalt erforderlich"})
|
||||
|
||||
# Fetch existing post
|
||||
post = await db.get_generated_post(post_uuid)
|
||||
if not post:
|
||||
return JSONResponse({"success": False, "error": "Post nicht gefunden"}, status_code=404)
|
||||
|
||||
# Verify ownership
|
||||
if post.user_id != user_id:
|
||||
return JSONResponse({"success": False, "error": "Nicht autorisiert"}, status_code=403)
|
||||
|
||||
# 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', '')
|
||||
})
|
||||
|
||||
# Prepare update data
|
||||
updates = {
|
||||
'post_content': post_content,
|
||||
'writer_versions': writer_versions,
|
||||
'critic_feedback': critic_feedback_list,
|
||||
'iterations': len(writer_versions)
|
||||
}
|
||||
|
||||
# Update the post using the correct method
|
||||
updated_post = await db.update_generated_post(post_uuid, updates)
|
||||
|
||||
return JSONResponse({
|
||||
"success": True,
|
||||
"post_id": str(updated_post.id),
|
||||
"message": "Post erfolgreich aktualisiert"
|
||||
})
|
||||
|
||||
except ValueError:
|
||||
return JSONResponse({"success": False, "error": "Ungültige Post-ID"}, status_code=400)
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating 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