feat: Add AI-generated content indicators

- Add is_ai_generated column to ForumTopic, ForumReply, NordaEvent, Classified
- Display AI badge next to author name for AI-generated content
- Purple gradient badge with tooltip 'Wygenerowano przez AI'
This commit is contained in:
Maciej Pienczyn 2026-01-11 06:16:35 +01:00
parent ffadcb16e8
commit e8714ac6b0
3 changed files with 61 additions and 0 deletions

View File

@ -801,6 +801,7 @@ class ForumTopic(Base):
# Moderation flags
is_pinned = Column(Boolean, default=False)
is_locked = Column(Boolean, default=False)
is_ai_generated = Column(Boolean, default=False)
views_count = Column(Integer, default=0)
# Timestamps
@ -859,6 +860,7 @@ class ForumReply(Base):
topic_id = Column(Integer, ForeignKey('forum_topics.id'), nullable=False)
author_id = Column(Integer, ForeignKey('users.id'), nullable=False)
content = Column(Text, nullable=False)
is_ai_generated = Column(Boolean, default=False)
# Timestamps
created_at = Column(DateTime, default=datetime.now)
@ -989,6 +991,7 @@ class NordaEvent(Base):
# Metadane
is_featured = Column(Boolean, default=False)
is_ai_generated = Column(Boolean, default=False)
max_attendees = Column(Integer)
created_by = Column(Integer, ForeignKey('users.id'))
created_at = Column(DateTime, default=datetime.now)
@ -1075,6 +1078,7 @@ class Classified(Base):
# Status
is_active = Column(Boolean, default=True)
is_ai_generated = Column(Boolean, default=False)
expires_at = Column(DateTime) # Auto-wygaśnięcie po 30 dniach
views_count = Column(Integer, default=0)

View File

@ -189,6 +189,25 @@
color: #991b1b;
}
/* AI generated indicator */
.ai-indicator {
display: inline-flex;
align-items: center;
gap: 2px;
padding: 2px 6px;
background: linear-gradient(135deg, #e0e7ff, #c7d2fe);
border-radius: var(--radius-sm);
font-size: 10px;
font-weight: 500;
color: #4338ca;
cursor: help;
}
.ai-indicator svg {
width: 12px;
height: 12px;
}
.topic-meta {
display: flex;
gap: var(--spacing-lg);
@ -354,6 +373,12 @@
<circle cx="12" cy="7" r="4"></circle>
</svg>
{{ topic.author.name or topic.author.email.split('@')[0] }}
{% if topic.is_ai_generated %}
<span class="ai-indicator" title="Wygenerowano przez AI">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/></svg>
AI
</span>
{% endif %}
</span>
<span>
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">

View File

@ -231,6 +231,26 @@
font-size: var(--font-size-sm);
}
/* AI generated indicator */
.ai-indicator {
display: inline-flex;
align-items: center;
gap: 2px;
padding: 2px 6px;
background: linear-gradient(135deg, #e0e7ff, #c7d2fe);
border-radius: var(--radius-sm);
font-size: 10px;
font-weight: 500;
color: #4338ca;
cursor: help;
margin-left: var(--spacing-xs);
}
.ai-indicator svg {
width: 12px;
height: 12px;
}
.reply-content {
line-height: 1.7;
white-space: pre-wrap;
@ -550,6 +570,12 @@
<circle cx="12" cy="7" r="4"></circle>
</svg>
{{ topic.author.name or topic.author.email.split('@')[0] }}
{% if topic.is_ai_generated %}
<span class="ai-indicator" title="Wygenerowano przez AI">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/></svg>
AI
</span>
{% endif %}
</span>
<span>
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
@ -599,6 +625,12 @@
{{ (reply.author.name or reply.author.email)[0].upper() }}
</div>
{{ reply.author.name or reply.author.email.split('@')[0] }}
{% if reply.is_ai_generated %}
<span class="ai-indicator" title="Wygenerowano przez AI">
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/></svg>
AI
</span>
{% endif %}
</div>
<span>{{ reply.created_at.strftime('%d.%m.%Y %H:%M') }}</span>
</div>