Add semantic post tag suggestions

This commit is contained in:
2026-07-20 22:52:03 +02:00
parent d1829f0e9b
commit b641f6492b
12 changed files with 500 additions and 27 deletions

View File

@@ -7,6 +7,11 @@ impl BdsApp {
SyncEmbeddedPreview,
Analyze(String),
AnalyzeTaxonomy(String),
EnsureTag {
post_id: String,
tag: String,
},
LoadSemanticTags(String),
AddGalleryImages(String),
DetectLanguage(String),
OpenTranslate(String),
@@ -127,6 +132,9 @@ impl BdsApp {
}
PostEditorMsg::ToggleMetadata => {
state.metadata_expanded = !state.metadata_expanded;
if state.metadata_expanded {
deferred = DeferredPostAction::LoadSemanticTags(state.post_id.clone());
}
}
PostEditorMsg::ToggleExcerpt => {
state.excerpt_expanded = !state.excerpt_expanded;
@@ -139,12 +147,24 @@ impl BdsApp {
}
PostEditorMsg::TagsInputChanged(s) => {
state.tags_input = s;
if state.tags_input.trim().is_empty() {
deferred = DeferredPostAction::LoadSemanticTags(state.post_id.clone());
}
}
PostEditorMsg::TagsInputSubmit => {
let tag = state.tags_input.trim().to_string();
if !tag.is_empty() && !state.tags.contains(&tag) {
state.tags.push(tag);
if !tag.is_empty()
&& !state
.tags
.iter()
.any(|current| current.eq_ignore_ascii_case(&tag))
{
state.tags.push(tag.clone());
state.mark_dirty();
deferred = DeferredPostAction::EnsureTag {
post_id: state.post_id.clone(),
tag,
};
}
state.tags_input.clear();
}
@@ -156,10 +176,12 @@ impl BdsApp {
{
state.tags.push(tag.clone());
state.mark_dirty();
deferred = DeferredPostAction::EnsureTag {
post_id: state.post_id.clone(),
tag: tag.clone(),
};
}
state
.semantic_tag_suggestions
.retain(|candidate| !candidate.eq_ignore_ascii_case(&tag));
state.tags_input.clear();
}
PostEditorMsg::RemoveTag(tag) => {
state.tags.retain(|t| t != &tag);
@@ -286,6 +308,12 @@ impl BdsApp {
DeferredPostAction::SyncEmbeddedPreview => self.sync_embedded_preview_for_active_post(),
DeferredPostAction::Analyze(tab_id) => self.run_post_ai_analysis(&tab_id),
DeferredPostAction::AnalyzeTaxonomy(tab_id) => self.run_post_taxonomy_analysis(&tab_id),
DeferredPostAction::EnsureTag { post_id, tag } => {
self.ensure_post_editor_tag(&post_id, &tag)
}
DeferredPostAction::LoadSemanticTags(post_id) => {
Task::done(Message::LoadSemanticTagSuggestions(post_id))
}
DeferredPostAction::AddGalleryImages(post_id) => self.add_gallery_images(&post_id),
DeferredPostAction::DetectLanguage(tab_id) => self.detect_post_language(&tab_id),
DeferredPostAction::OpenTranslate(tab_id) => self.open_post_translation_modal(&tab_id),

View File

@@ -219,6 +219,12 @@ impl BdsApp {
} => {
let search_rebuild_finished = self.search_index_rebuild_task_id == Some(task_id);
let cancelled = self.task_manager.status(task_id) == Some(TaskStatus::Cancelled);
let refresh_semantic_tags = !cancelled
&& result.is_ok()
&& matches!(
operation,
"embeddings.indexing" | "menu.item.rebuildEmbeddingIndex"
);
match &result {
_ if cancelled => {}
Ok(detail) => {
@@ -265,8 +271,22 @@ impl BdsApp {
self.sync_menu_state();
}
let sidebar_task = self.refresh_counts();
let semantic_task = if refresh_semantic_tags {
self.active_tab
.as_ref()
.filter(|id| {
self.tabs
.iter()
.any(|tab| tab.id == id.as_str() && tab.tab_type == TabType::Post)
})
.map_or_else(Task::none, |id| {
Task::done(Message::LoadSemanticTagSuggestions(id.clone()))
})
} else {
Task::none()
};
self.refresh_task_snapshots();
sidebar_task
Task::batch([sidebar_task, semantic_task])
}
Message::SiteGenerationSectionDone {
group_id,