feat: add AI hashtag generation and AI engine info to 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
- New generate_hashtags() method in SocialPublisherService - New /social-publisher/generate-hashtags AJAX endpoint - "Generuj hashtagi AI" button next to hashtags field - Small print info about AI engine (Gemini 3 Flash) with note about future model selection Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
921f72f569
commit
c59fe04572
@ -370,6 +370,27 @@ def social_publisher_generate():
|
||||
return jsonify({'success': False, 'error': 'Nie udalo sie wygenerowac tresci. Sprobuj ponownie lub wpisz tresc recznie.'}), 500
|
||||
|
||||
|
||||
@bp.route('/social-publisher/generate-hashtags', methods=['POST'])
|
||||
@login_required
|
||||
@role_required(SystemRole.MANAGER)
|
||||
def social_publisher_generate_hashtags():
|
||||
"""Generuj hashtagi AI na podstawie tresci posta (AJAX endpoint)."""
|
||||
from services.social_publisher_service import social_publisher
|
||||
|
||||
content = request.json.get('content', '').strip()
|
||||
post_type = request.json.get('post_type', '')
|
||||
|
||||
if not content:
|
||||
return jsonify({'success': False, 'error': 'Wpisz najpierw tresc posta, aby wygenerowac hashtagi.'}), 400
|
||||
|
||||
try:
|
||||
hashtags, model = social_publisher.generate_hashtags(content, post_type)
|
||||
return jsonify({'success': True, 'hashtags': hashtags, 'model': model})
|
||||
except Exception as e:
|
||||
logger.error(f"Hashtag generation failed: {e}")
|
||||
return jsonify({'success': False, 'error': 'Nie udalo sie wygenerowac hashtagow. Sprobuj ponownie.'}), 500
|
||||
|
||||
|
||||
# ============================================================
|
||||
# SOCIAL PUBLISHER - SETTINGS (per company)
|
||||
# ============================================================
|
||||
|
||||
@ -410,6 +410,35 @@ class SocialPublisherService:
|
||||
|
||||
return result.strip(), 'gemini-3-flash'
|
||||
|
||||
def generate_hashtags(self, content: str, post_type: str = '') -> Tuple[str, str]:
|
||||
"""Generate hashtags for given post content using AI.
|
||||
|
||||
Returns:
|
||||
(hashtags: str, ai_model: str)
|
||||
"""
|
||||
prompt = f"""Na podstawie poniższej treści posta na Facebook Izby Gospodarczej NORDA Biznes,
|
||||
wygeneruj 5-8 trafnych hashtagów.
|
||||
|
||||
Treść posta:
|
||||
{content}
|
||||
|
||||
Zasady:
|
||||
- Zawsze uwzględnij #NordaBiznes i #IzbaGospodarcza
|
||||
- Dodaj hashtagi branżowe i lokalne (#Wejherowo, #Pomorze, #Kaszuby)
|
||||
- Hashtagi powinny zwiększać zasięg i widoczność posta
|
||||
- Każdy hashtag zaczynaj od #, oddzielaj spacjami
|
||||
- Odpowiedz WYŁĄCZNIE hashtagami, nic więcej"""
|
||||
|
||||
from gemini_service import generate_text
|
||||
result = generate_text(prompt)
|
||||
|
||||
if not result:
|
||||
raise RuntimeError("AI nie wygenerował hashtagów. Spróbuj ponownie.")
|
||||
|
||||
# Clean up - ensure only hashtags
|
||||
tags = ' '.join(w for w in result.strip().split() if w.startswith('#'))
|
||||
return tags, 'gemini-3-flash'
|
||||
|
||||
def get_company_context(self, company_id: int) -> dict:
|
||||
"""Get company data for AI prompt context."""
|
||||
db = SessionLocal()
|
||||
|
||||
@ -101,6 +101,39 @@
|
||||
cursor: wait;
|
||||
}
|
||||
|
||||
.btn-generate-sm {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: var(--font-size-xs);
|
||||
padding: var(--spacing-xs) var(--spacing-sm);
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
.btn-generate-sm:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.btn-generate-sm:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: wait;
|
||||
}
|
||||
|
||||
.ai-engine-info {
|
||||
font-size: 11px;
|
||||
color: var(--text-tertiary, #9ca3af);
|
||||
margin-top: var(--spacing-xs);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.hashtag-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.status-info {
|
||||
background: var(--background);
|
||||
padding: var(--spacing-md);
|
||||
@ -293,11 +326,23 @@
|
||||
|
||||
<!-- Hashtagi -->
|
||||
<div class="form-group">
|
||||
<label for="hashtags">Hashtagi</label>
|
||||
<div class="hashtag-header">
|
||||
<label for="hashtags">Hashtagi</label>
|
||||
<button type="button" id="btn-generate-hashtags" class="btn-generate-sm">
|
||||
Generuj hashtagi AI
|
||||
</button>
|
||||
</div>
|
||||
<input type="text" id="hashtags" name="hashtags"
|
||||
value="{{ post.hashtags if post else '' }}"
|
||||
placeholder="#NordaBiznes #Wejherowo #Pomorze">
|
||||
<p class="form-hint">Hashtagi oddzielone spacjami</p>
|
||||
<div id="hashtag-error-msg" style="display:none; padding: var(--spacing-xs) var(--spacing-sm); margin-top: var(--spacing-xs); border-radius: var(--radius); background: var(--error-bg, #fef2f2); color: var(--error, #dc2626); border: 1px solid var(--error, #dc2626); font-size: var(--font-size-xs);"></div>
|
||||
</div>
|
||||
|
||||
<!-- Info o silniku AI -->
|
||||
<div class="ai-engine-info">
|
||||
Generowanie tresc i hashtagow: <strong>Google Gemini 3 Flash</strong> (model: gemini-3-flash-preview).
|
||||
Obecnie jest to jedyny dostepny silnik AI. W przyszlosci planowane jest dodanie wyboru miedzy modelami (np. GPT, Claude).
|
||||
</div>
|
||||
|
||||
<!-- Akcje -->
|
||||
@ -429,6 +474,50 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Hashtag generation
|
||||
document.getElementById('btn-generate-hashtags')?.addEventListener('click', async function() {
|
||||
const content = document.getElementById('content').value.trim();
|
||||
const errEl = document.getElementById('hashtag-error-msg');
|
||||
|
||||
if (!content) {
|
||||
errEl.textContent = 'Wpisz najpierw tresc posta, aby wygenerowac hashtagi.';
|
||||
errEl.style.display = 'block';
|
||||
return;
|
||||
}
|
||||
|
||||
errEl.style.display = 'none';
|
||||
this.disabled = true;
|
||||
this.textContent = 'Generowanie...';
|
||||
|
||||
try {
|
||||
const resp = await fetch("{{ url_for('admin.social_publisher_generate_hashtags') }}", {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': document.querySelector('[name=csrf_token]')?.value || ''
|
||||
},
|
||||
body: JSON.stringify({
|
||||
content: content,
|
||||
post_type: document.getElementById('post_type')?.value || ''
|
||||
})
|
||||
});
|
||||
const data = await resp.json();
|
||||
if (data.success) {
|
||||
document.getElementById('hashtags').value = data.hashtags;
|
||||
errEl.style.display = 'none';
|
||||
} else {
|
||||
errEl.textContent = data.error || 'Nie udalo sie wygenerowac hashtagow.';
|
||||
errEl.style.display = 'block';
|
||||
}
|
||||
} catch (err) {
|
||||
errEl.textContent = 'Blad polaczenia z serwerem.';
|
||||
errEl.style.display = 'block';
|
||||
} finally {
|
||||
this.disabled = false;
|
||||
this.textContent = 'Generuj hashtagi AI';
|
||||
}
|
||||
});
|
||||
|
||||
// Show/hide context fields based on post type
|
||||
document.getElementById('post_type')?.addEventListener('change', function() {
|
||||
const type = this.value;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user