feat: add tone selector for AI content generation in social publisher
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
Some checks are pending
NordaBiz Tests / Unit & Integration Tests (push) Waiting to run
NordaBiz Tests / E2E Tests (Playwright) (push) Blocked by required conditions
NordaBiz Tests / Smoke Tests (Production) (push) Blocked by required conditions
NordaBiz Tests / Send Failure Notification (push) Blocked by required conditions
6 tones: Profesjonalny (default), Przyjazny, Oficjalny, Entuzjastyczny, Informacyjny, Inspirujący. Tone instruction is appended to the AI prompt. Dropdown appears next to "Generuj AI" button. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
c59fe04572
commit
c1a8cb6183
@ -123,7 +123,7 @@ def social_publisher_list():
|
||||
@role_required(SystemRole.MANAGER)
|
||||
def social_publisher_new():
|
||||
"""Tworzenie nowego posta."""
|
||||
from services.social_publisher_service import social_publisher, POST_TYPES
|
||||
from services.social_publisher_service import social_publisher, POST_TYPES, POST_TONES, DEFAULT_TONE
|
||||
|
||||
db = SessionLocal()
|
||||
try:
|
||||
@ -149,7 +149,8 @@ def social_publisher_new():
|
||||
flash('Treść posta jest wymagana.', 'danger')
|
||||
return render_template('admin/social_publisher_form.html',
|
||||
post=None, companies=companies, events=events,
|
||||
post_types=POST_TYPES,
|
||||
post_types=POST_TYPES, post_tones=POST_TONES,
|
||||
default_tone=DEFAULT_TONE,
|
||||
configured_companies=configured_companies)
|
||||
|
||||
post = social_publisher.create_post(
|
||||
@ -172,7 +173,8 @@ def social_publisher_new():
|
||||
|
||||
return render_template('admin/social_publisher_form.html',
|
||||
post=None, companies=companies, events=events,
|
||||
post_types=POST_TYPES,
|
||||
post_types=POST_TYPES, post_tones=POST_TONES,
|
||||
default_tone=DEFAULT_TONE,
|
||||
configured_companies=configured_companies)
|
||||
finally:
|
||||
db.close()
|
||||
@ -183,7 +185,7 @@ def social_publisher_new():
|
||||
@role_required(SystemRole.MANAGER)
|
||||
def social_publisher_edit(post_id):
|
||||
"""Edycja istniejacego posta."""
|
||||
from services.social_publisher_service import social_publisher, POST_TYPES
|
||||
from services.social_publisher_service import social_publisher, POST_TYPES, POST_TONES, DEFAULT_TONE
|
||||
|
||||
db = SessionLocal()
|
||||
try:
|
||||
@ -236,7 +238,8 @@ def social_publisher_edit(post_id):
|
||||
flash('Treść posta jest wymagana.', 'danger')
|
||||
return render_template('admin/social_publisher_form.html',
|
||||
post=post, companies=companies, events=events,
|
||||
post_types=POST_TYPES,
|
||||
post_types=POST_TYPES, post_tones=POST_TONES,
|
||||
default_tone=DEFAULT_TONE,
|
||||
configured_companies=configured_companies)
|
||||
|
||||
social_publisher.update_post(
|
||||
@ -253,7 +256,8 @@ def social_publisher_edit(post_id):
|
||||
|
||||
return render_template('admin/social_publisher_form.html',
|
||||
post=post, companies=companies, events=events,
|
||||
post_types=POST_TYPES,
|
||||
post_types=POST_TYPES, post_tones=POST_TONES,
|
||||
default_tone=DEFAULT_TONE,
|
||||
configured_companies=configured_companies)
|
||||
finally:
|
||||
db.close()
|
||||
@ -341,6 +345,7 @@ def social_publisher_generate():
|
||||
post_type = request.json.get('post_type')
|
||||
company_id = request.json.get('company_id')
|
||||
event_id = request.json.get('event_id')
|
||||
tone = request.json.get('tone', '')
|
||||
custom_context = request.json.get('custom_context', {})
|
||||
|
||||
try:
|
||||
@ -363,7 +368,7 @@ def social_publisher_generate():
|
||||
for key, default in defaults.items():
|
||||
context.setdefault(key, default)
|
||||
|
||||
content, model = social_publisher.generate_content(post_type, context)
|
||||
content, model = social_publisher.generate_content(post_type, context, tone=tone)
|
||||
return jsonify({'success': True, 'content': content, 'model': model})
|
||||
except Exception as e:
|
||||
logger.error(f"AI generation failed: {e}")
|
||||
|
||||
@ -116,6 +116,36 @@ Odpowiedz WYŁĄCZNIE tekstem postu.""",
|
||||
}
|
||||
|
||||
|
||||
POST_TONES = {
|
||||
'professional': {
|
||||
'label': 'Profesjonalny',
|
||||
'instruction': 'Pisz w tonie profesjonalnym, rzeczowym i biznesowym. Zachowaj powagę, ale bądź przystępny.',
|
||||
},
|
||||
'friendly': {
|
||||
'label': 'Przyjazny',
|
||||
'instruction': 'Pisz ciepło i przyjaźnie, jakbyś rozmawiał z dobrym znajomym. Używaj bezpośredniego zwrotu do czytelnika.',
|
||||
},
|
||||
'formal': {
|
||||
'label': 'Oficjalny',
|
||||
'instruction': 'Pisz formalnie i oficjalnie, jak komunikat prasowy. Zachowaj dystans i powagę instytucji.',
|
||||
},
|
||||
'enthusiastic': {
|
||||
'label': 'Entuzjastyczny',
|
||||
'instruction': 'Pisz z energią i entuzjazmem! Używaj wykrzykników, pozytywnych emocji i dynamicznego języka.',
|
||||
},
|
||||
'informative': {
|
||||
'label': 'Informacyjny',
|
||||
'instruction': 'Pisz rzeczowo i informacyjnie, jak artykuł prasowy. Skup się na faktach, danych i konkretach.',
|
||||
},
|
||||
'inspiring': {
|
||||
'label': 'Inspirujący',
|
||||
'instruction': 'Pisz inspirująco i motywująco. Podkreślaj wartości, wizję i potencjał. Zachęcaj do działania.',
|
||||
},
|
||||
}
|
||||
|
||||
DEFAULT_TONE = 'professional'
|
||||
|
||||
|
||||
class SocialPublisherService:
|
||||
"""Service for managing social media posts with per-company FB configuration."""
|
||||
|
||||
@ -381,12 +411,13 @@ class SocialPublisherService:
|
||||
|
||||
# ---- AI Content Generation ----
|
||||
|
||||
def generate_content(self, post_type: str, context: dict) -> Tuple[str, str]:
|
||||
def generate_content(self, post_type: str, context: dict, tone: str = None) -> Tuple[str, str]:
|
||||
"""Generate post content using AI.
|
||||
|
||||
Args:
|
||||
post_type: One of POST_TYPES keys
|
||||
context: Dict with template variables
|
||||
tone: One of POST_TONES keys (default: DEFAULT_TONE)
|
||||
|
||||
Returns:
|
||||
(content: str, ai_model: str)
|
||||
@ -401,6 +432,11 @@ class SocialPublisherService:
|
||||
except KeyError as e:
|
||||
raise ValueError(f"Missing context field: {e}")
|
||||
|
||||
# Add tone instruction
|
||||
tone_key = tone if tone in POST_TONES else DEFAULT_TONE
|
||||
tone_info = POST_TONES[tone_key]
|
||||
prompt += f"\n\nTONACJA: {tone_info['instruction']}"
|
||||
|
||||
# Generate with Gemini
|
||||
from gemini_service import generate_text
|
||||
result = generate_text(prompt)
|
||||
|
||||
@ -308,8 +308,14 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Przycisk generowania AI -->
|
||||
<div class="form-group" style="text-align: right;">
|
||||
<!-- Tonacja + Przycisk generowania AI -->
|
||||
<div class="form-group" style="display: flex; align-items: center; justify-content: flex-end; gap: var(--spacing-sm); flex-wrap: wrap;">
|
||||
<label for="tone" style="margin: 0; white-space: nowrap;">Tonacja:</label>
|
||||
<select id="tone" name="tone" style="width: auto; min-width: 160px; padding: var(--spacing-xs) var(--spacing-sm); border: 1px solid var(--border); border-radius: var(--radius-md); font-size: var(--font-size-sm);">
|
||||
{% for key, tone in post_tones.items() %}
|
||||
<option value="{{ key }}" {% if key == default_tone %}selected{% endif %}>{{ tone.label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<button type="button" id="btn-generate-ai" class="btn btn-generate">
|
||||
Generuj AI
|
||||
</button>
|
||||
@ -422,9 +428,10 @@
|
||||
const postType = document.getElementById('post_type').value;
|
||||
const companyId = document.getElementById('company_id')?.value;
|
||||
const eventId = document.getElementById('event_id')?.value;
|
||||
const tone = document.getElementById('tone')?.value || '';
|
||||
|
||||
if (!postType) {
|
||||
alert('Wybierz typ posta przed generowaniem.');
|
||||
showAiError('Wybierz typ posta przed generowaniem.');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -452,6 +459,7 @@
|
||||
post_type: postType,
|
||||
company_id: companyId || null,
|
||||
event_id: eventId || null,
|
||||
tone: tone,
|
||||
custom_context: customContext
|
||||
})
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user