Merge pull request #19 from ComfyAssets/add-tags

Add tags
This commit is contained in:
Vito
2025-05-29 06:48:49 -07:00
committed by GitHub
2 changed files with 122 additions and 8 deletions
+72
View File
@@ -186,6 +186,10 @@ class PromptManagerAPI:
async def remove_tag_route(request):
return await self.remove_prompt_tag(request)
@routes.post("/prompt_manager/prompts/tags")
async def add_tags_to_prompt_route(request):
return await self.add_tags_to_prompt(request)
# Bulk operations
@routes.post("/prompt_manager/bulk/delete")
async def bulk_delete_route(request):
@@ -786,6 +790,74 @@ class PromptManagerAPI:
{"success": False, "error": f"Failed to add tag: {str(e)}"}, status=500
)
async def add_tags_to_prompt(self, request):
"""Add multiple tags to a single prompt."""
try:
data = await request.json()
prompt_id = data.get("prompt_id")
new_tags = data.get("tags", [])
if not prompt_id:
return web.json_response(
{"success": False, "error": "Prompt ID is required"}, status=400
)
if not new_tags or not isinstance(new_tags, list):
return web.json_response(
{"success": False, "error": "Tags must be a non-empty list"}, status=400
)
# Get current prompt
prompt = self.db.get_prompt_by_id(prompt_id)
if not prompt:
return web.json_response(
{"success": False, "error": "Prompt not found"}, status=404
)
# Get current tags
current_tags = prompt.get("tags", [])
if not isinstance(current_tags, list):
current_tags = []
# Add new tags if not already present
tags_added = 0
for new_tag in new_tags:
new_tag = new_tag.strip()
if new_tag and new_tag not in current_tags:
current_tags.append(new_tag)
tags_added += 1
# Update database if any tags were added
if tags_added > 0:
with self.db.model.get_connection() as conn:
cursor = conn.execute(
"UPDATE prompts SET tags = ?, updated_at = ? WHERE id = ?",
(
json.dumps(current_tags),
datetime.datetime.now(datetime.timezone.utc).isoformat(),
prompt_id,
),
)
conn.commit()
message = f"{tags_added} tag(s) added successfully"
if tags_added == 0:
message = "No new tags to add (all tags already exist)"
return web.json_response(
{"success": True, "message": message, "tags_added": tags_added}
)
except ValueError:
return web.json_response(
{"success": False, "error": "Invalid prompt ID"}, status=400
)
except Exception as e:
self.logger.error(f"Add tags error: {e}")
return web.json_response(
{"success": False, "error": f"Failed to add tags: {str(e)}"}, status=500
)
async def remove_prompt_tag(self, request):
"""Remove tag from prompt."""
try:
+50 -8
View File
@@ -328,6 +328,30 @@
</div>
</div>
<!-- Individual Tag Modal -->
<div id="individualTagModal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center z-50">
<div class="bg-gray-800 rounded-xl p-6 max-w-md w-full mx-4 border border-gray-700">
<h3 class="text-xl font-semibold text-gray-100 mb-6">🏷️ Add Tags to Prompt</h3>
<div>
<label class="block text-sm font-medium text-gray-400 mb-2">Tags (comma-separated)</label>
<input type="text" id="individualTagInput" placeholder="tag1, tag2, tag3..."
class="w-full px-4 py-3 bg-gray-700 border border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-gray-100">
</div>
<div class="flex justify-end space-x-3 mt-6">
<button id="cancelIndividualTag"
class="px-6 py-2 bg-gray-600 hover:bg-gray-700 text-white font-medium rounded-lg transition-colors">
Cancel
</button>
<button id="confirmIndividualTag"
class="px-6 py-2 bg-indigo-600 hover:bg-indigo-700 text-white font-medium rounded-lg transition-colors">
Add Tags
</button>
</div>
</div>
</div>
<!-- Bulk Category Modal -->
<div id="bulkCategoryModal" class="fixed inset-0 bg-black bg-opacity-50 hidden items-center justify-center z-50">
<div class="bg-gray-800 rounded-xl p-6 max-w-md w-full mx-4 border border-gray-700">
@@ -849,6 +873,10 @@
document.getElementById("confirmBulkTag").addEventListener("click", () => this.confirmBulkTag());
document.getElementById("cancelBulkTag").addEventListener("click", () => this.hideModal("bulkTagModal"));
// Individual tag modal
document.getElementById("confirmIndividualTag").addEventListener("click", () => this.confirmIndividualTag());
document.getElementById("cancelIndividualTag").addEventListener("click", () => this.hideModal("individualTagModal"));
// Bulk category modal
document.getElementById("confirmBulkCategory").addEventListener("click", () => this.confirmBulkCategory());
document.getElementById("cancelBulkCategory").addEventListener("click", () => this.hideModal("bulkCategoryModal"));
@@ -1144,7 +1172,7 @@
`).join("")}
<button class="inline-flex items-center space-x-1 bg-gray-600 hover:bg-gray-500 text-gray-300 px-3 py-1 rounded-full text-sm transition-colors" onclick="window.admin.addTag(${prompt.id})">
<span>+</span>
<span>Add Tag</span>
<span>Add Tags</span>
</button>
</div>
</div>
@@ -1322,25 +1350,39 @@
}
}
async addTag(promptId) {
const tag = prompt("Enter new tag:");
if (!tag) return;
addTag(promptId) {
// Store the prompt ID for later use
this.currentTagPromptId = promptId;
// Clear the input and show the modal
document.getElementById("individualTagInput").value = "";
this.showModal("individualTagModal");
}
async confirmIndividualTag() {
const tags = document.getElementById("individualTagInput").value.split(",")
.map((tag) => tag.trim()).filter((tag) => tag);
if (tags.length === 0) return;
try {
const response = await fetch(`/prompt_manager/prompts/${promptId}/tags`, {
const response = await fetch("/prompt_manager/prompts/tags", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ tag: tag.trim() }),
body: JSON.stringify({
prompt_id: this.currentTagPromptId,
tags: tags,
}),
});
if (response.ok) {
this.showNotification("Tag added", "success");
this.showNotification(`Tags added to prompt`, "success");
this.hideModal("individualTagModal");
// Refresh both stats and results
await this.loadStatistics();
this.search();
}
} catch (error) {
this.showNotification("Failed to add tag", "error");
this.showNotification("Failed to add tags", "error");
}
}