117 lines
5.0 KiB
Python
117 lines
5.0 KiB
Python
"""
|
||
System utilities - default prompts and helper functions
|
||
"""
|
||
from typing import Optional
|
||
|
||
|
||
def get_default_prompt(prompt_type: str) -> str:
|
||
"""Get default prompt value by type"""
|
||
defaults = {
|
||
'clustering': """Analyze the following keywords and group them into topic clusters.
|
||
|
||
Each cluster should include:
|
||
- "name": A clear, descriptive topic name
|
||
- "description": A brief explanation of what the cluster covers
|
||
- "keywords": A list of related keywords that belong to this cluster
|
||
|
||
Format the output as a JSON object with a "clusters" array.
|
||
|
||
IMPORTANT: In the "keywords" array, you MUST use the EXACT keyword strings from the input list below. Do not modify, paraphrase, or create variations of the keywords. Only use the exact keywords as they appear in the input list.
|
||
|
||
Clustering rules:
|
||
- Group keywords based on strong semantic or topical relationships (intent, use-case, function, audience, etc.)
|
||
- Clusters should reflect how people actually search — problem ➝ solution, general ➝ specific, product ➝ benefit, etc.
|
||
- Avoid grouping keywords just because they share similar words — focus on meaning
|
||
- Include 3–10 keywords per cluster where appropriate
|
||
- Skip unrelated or outlier keywords that don't fit a clear theme
|
||
- CRITICAL: Only return keywords that exactly match the input keywords (case-insensitive matching is acceptable)
|
||
|
||
Keywords to process:
|
||
[IGNY8_KEYWORDS]""",
|
||
|
||
'ideas': """Generate SEO-optimized, high-quality content ideas and detailed outlines for each of the following keyword clusters.
|
||
|
||
Clusters to analyze:
|
||
[IGNY8_CLUSTERS]
|
||
|
||
Keywords in each cluster:
|
||
[IGNY8_CLUSTER_KEYWORDS]
|
||
|
||
Return your response as JSON with an "ideas" array.
|
||
For each cluster, generate 1-3 content ideas.
|
||
|
||
Each idea must include:
|
||
- "title": compelling blog/article title that naturally includes a primary keyword
|
||
- "description": detailed content outline with H2/H3 structure (as plain text or structured JSON)
|
||
- "content_type": the type of content (blog_post, article, guide, tutorial)
|
||
- "content_structure": the editorial structure (cluster_hub, landing_page, pillar_page, supporting_page)
|
||
- "estimated_word_count": estimated total word count (1500-2200 words)
|
||
- "target_keywords": comma-separated list of keywords that will be covered (or "covered_keywords")
|
||
- "cluster_name": name of the cluster this idea belongs to (REQUIRED)
|
||
- "cluster_id": ID of the cluster this idea belongs to (REQUIRED - use the exact cluster ID from the input)
|
||
|
||
IMPORTANT: You MUST include the exact "cluster_id" from the cluster data provided. Match the cluster name to find the correct cluster_id.
|
||
|
||
Return only valid JSON with an "ideas" array.""",
|
||
|
||
'content_generation': """You are an editorial content strategist. Generate a complete blog post/article based on the provided content idea.
|
||
|
||
CONTENT IDEA DETAILS:
|
||
[IGNY8_IDEA]
|
||
|
||
KEYWORD CLUSTER:
|
||
[IGNY8_CLUSTER]
|
||
|
||
ASSOCIATED KEYWORDS:
|
||
[IGNY8_KEYWORDS]
|
||
|
||
Generate well-structured, SEO-optimized content with:
|
||
- Engaging introduction
|
||
- 5-8 H2 sections with H3 subsections
|
||
- Natural keyword integration
|
||
- 1500-2000 words total
|
||
- Proper HTML formatting (h2, h3, p, ul, ol, table tags)
|
||
|
||
Return the content as plain text with HTML tags.""",
|
||
|
||
'image_prompt_extraction': """Extract image prompts from the following article content.
|
||
|
||
ARTICLE TITLE: {title}
|
||
|
||
ARTICLE CONTENT:
|
||
{content}
|
||
|
||
Extract image prompts for:
|
||
1. Featured Image: One main image that represents the article topic
|
||
2. In-Article Images: Up to {max_images} images that would be useful within the article content
|
||
|
||
Return a JSON object with this structure:
|
||
{{
|
||
"featured_prompt": "Detailed description of the featured image",
|
||
"in_article_prompts": [
|
||
"Description of first in-article image",
|
||
"Description of second in-article image",
|
||
...
|
||
]
|
||
}}
|
||
|
||
Make sure each prompt is detailed enough for image generation, describing the visual elements, style, mood, and composition.""",
|
||
|
||
'image_prompt_template': 'Create a high-quality {image_type} image to use as a featured photo for a blog post titled "{post_title}". The image should visually represent the theme, mood, and subject implied by the image prompt: {image_prompt}. Focus on a realistic, well-composed scene that naturally communicates the topic without text or logos. Use balanced lighting, pleasing composition, and photographic detail suitable for lifestyle or editorial web content. Avoid adding any visible or readable text, brand names, or illustrative effects. **And make sure image is not blurry.**',
|
||
|
||
'negative_prompt': 'text, watermark, logo, overlay, title, caption, writing on walls, writing on objects, UI, infographic elements, post title',
|
||
}
|
||
|
||
return defaults.get(prompt_type, '')
|
||
|
||
|
||
def get_prompt_value(account, prompt_type: str) -> str:
|
||
"""Get prompt value for an account, or default if not set"""
|
||
try:
|
||
from .models import AIPrompt
|
||
prompt = AIPrompt.objects.get(account=account, prompt_type=prompt_type, is_active=True)
|
||
return prompt.prompt_value
|
||
except AIPrompt.DoesNotExist:
|
||
return get_default_prompt(prompt_type)
|
||
|