feat: Add Global Module Settings and Caption to Images
- Introduced GlobalModuleSettings model for platform-wide module enable/disable settings. - Added 'caption' field to Images model to store image captions. - Updated GenerateImagePromptsFunction to handle new caption structure in prompts. - Enhanced AIPromptViewSet to return global prompt types and validate active prompts. - Modified serializers and views to accommodate new caption field and global settings. - Updated frontend components to display captions and filter prompts based on active types. - Created migrations for GlobalModuleSettings and added caption field to Images.
This commit is contained in:
@@ -73,6 +73,7 @@ export default function Prompts() {
|
||||
const [prompts, setPrompts] = useState<Record<string, PromptData>>({});
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [saving, setSaving] = useState<Record<string, boolean>>({});
|
||||
const [activePromptTypes, setActivePromptTypes] = useState<string[]>([]);
|
||||
|
||||
// Load all prompts
|
||||
useEffect(() => {
|
||||
@@ -82,7 +83,15 @@ export default function Prompts() {
|
||||
const loadPrompts = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const promises = PROMPT_TYPES.map(async (type) => {
|
||||
// First, get the list of globally active prompt types
|
||||
const activeTypesResponse = await fetchAPI('/v1/system/prompts/active_types/');
|
||||
const activeTypes = activeTypesResponse.active_types || [];
|
||||
setActivePromptTypes(activeTypes);
|
||||
|
||||
// Only load prompts that are globally active
|
||||
const activePromptConfigs = PROMPT_TYPES.filter(type => activeTypes.includes(type.key));
|
||||
|
||||
const promises = activePromptConfigs.map(async (type) => {
|
||||
try {
|
||||
// fetchAPI extracts data from unified format {success: true, data: {...}}
|
||||
// So response IS the data object
|
||||
@@ -100,15 +109,6 @@ export default function Prompts() {
|
||||
results.forEach(({ key, data }) => {
|
||||
if (data) {
|
||||
promptsMap[key] = data;
|
||||
} else {
|
||||
// Use default if not found
|
||||
promptsMap[key] = {
|
||||
prompt_type: key,
|
||||
prompt_type_display: PROMPT_TYPES.find(t => t.key === key)?.label || key,
|
||||
prompt_value: '',
|
||||
default_prompt: '',
|
||||
is_active: true,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@@ -218,6 +218,7 @@ export default function Prompts() {
|
||||
<div className="p-6">
|
||||
|
||||
{/* Planner Prompts Section */}
|
||||
{PROMPT_TYPES.filter(t => ['clustering', 'ideas'].includes(t.key) && activePromptTypes.includes(t.key)).length > 0 && (
|
||||
<div className="mb-8">
|
||||
<div className="mb-4">
|
||||
<h2 className="text-xl font-semibold text-gray-800 dark:text-white mb-1">
|
||||
@@ -231,7 +232,7 @@ export default function Prompts() {
|
||||
{/* 2-Column Grid for Planner Prompts */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
{/* Clustering Prompt */}
|
||||
{PROMPT_TYPES.filter(t => ['clustering', 'ideas'].includes(t.key)).map((type) => {
|
||||
{PROMPT_TYPES.filter(t => ['clustering', 'ideas'].includes(t.key) && activePromptTypes.includes(t.key)).map((type) => {
|
||||
const prompt = prompts[type.key] || {
|
||||
prompt_type: type.key,
|
||||
prompt_type_display: type.label,
|
||||
@@ -287,8 +288,10 @@ export default function Prompts() {
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Writer Prompts Section */}
|
||||
{PROMPT_TYPES.filter(t => t.key === 'content_generation' && activePromptTypes.includes(t.key)).length > 0 && (
|
||||
<div className="mb-8">
|
||||
<div className="mb-4">
|
||||
<h2 className="text-xl font-semibold text-gray-800 dark:text-white mb-1">
|
||||
@@ -301,7 +304,7 @@ export default function Prompts() {
|
||||
|
||||
{/* Content Generation Prompt */}
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-gray-900">
|
||||
{PROMPT_TYPES.filter(t => t.key === 'content_generation').map((type) => {
|
||||
{PROMPT_TYPES.filter(t => t.key === 'content_generation' && activePromptTypes.includes(t.key)).map((type) => {
|
||||
const prompt = prompts[type.key] || {
|
||||
prompt_type: type.key,
|
||||
prompt_type_display: type.label,
|
||||
@@ -357,8 +360,10 @@ export default function Prompts() {
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Image Generation Section */}
|
||||
{PROMPT_TYPES.filter(t => ['image_prompt_extraction', 'image_prompt_template', 'negative_prompt'].includes(t.key) && activePromptTypes.includes(t.key)).length > 0 && (
|
||||
<div className="mb-8">
|
||||
<div className="mb-4">
|
||||
<h2 className="text-xl font-semibold text-gray-800 dark:text-white mb-1">
|
||||
@@ -371,7 +376,7 @@ export default function Prompts() {
|
||||
|
||||
{/* 2-Column Grid for Image Prompts */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
{PROMPT_TYPES.filter(t => ['image_prompt_extraction', 'image_prompt_template', 'negative_prompt'].includes(t.key)).map((type) => {
|
||||
{PROMPT_TYPES.filter(t => ['image_prompt_extraction', 'image_prompt_template', 'negative_prompt'].includes(t.key) && activePromptTypes.includes(t.key)).map((type) => {
|
||||
const prompt = prompts[type.key] || {
|
||||
prompt_type: type.key,
|
||||
prompt_type_display: type.label,
|
||||
@@ -429,8 +434,10 @@ export default function Prompts() {
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Site Builder Prompts Section */}
|
||||
{PROMPT_TYPES.filter(t => t.key === 'site_structure_generation' && activePromptTypes.includes(t.key)).length > 0 && (
|
||||
<div className="mb-8">
|
||||
<div className="mb-4">
|
||||
<h2 className="text-xl font-semibold text-gray-800 dark:text-white mb-1">
|
||||
@@ -443,7 +450,7 @@ export default function Prompts() {
|
||||
|
||||
{/* Site Structure Generation Prompt */}
|
||||
<div className="rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-gray-900">
|
||||
{PROMPT_TYPES.filter(t => t.key === 'site_structure_generation').map((type) => {
|
||||
{PROMPT_TYPES.filter(t => t.key === 'site_structure_generation' && activePromptTypes.includes(t.key)).map((type) => {
|
||||
const prompt = prompts[type.key] || {
|
||||
prompt_type: type.key,
|
||||
prompt_type_display: type.label,
|
||||
@@ -508,6 +515,7 @@ export default function Prompts() {
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user