feat(platform): forum search mesh merge API for Phase 128 (v0.8.93)
Add searchForumPostsWithMesh and _forumPostsFromMeshMessages to merge local forum haystack hits with guild MESSAGE_SEARCH mesh responses via pearcord-search.mergeForumSearchHits. _resolveSearchResults uses mesh for forum scope and records _lastSearchMeshMeta with scope forum for the desktop search UI. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
@@ -156,6 +156,8 @@ const {
|
|||||||
ingestGuildSearchIndexSlice,
|
ingestGuildSearchIndexSlice,
|
||||||
buildIndexRow,
|
buildIndexRow,
|
||||||
mergeSearchHits,
|
mergeSearchHits,
|
||||||
|
mergeForumSearchHits,
|
||||||
|
rankAndEnrichForumSearchHits,
|
||||||
compactMeshSearchHit,
|
compactMeshSearchHit,
|
||||||
meshHitToMessage
|
meshHitToMessage
|
||||||
} = require('pearcord-search')
|
} = require('pearcord-search')
|
||||||
@@ -1044,7 +1046,17 @@ class PearcordPlatform extends EventEmitter {
|
|||||||
id: this.activeChannelId
|
id: this.activeChannelId
|
||||||
})
|
})
|
||||||
if (!ch || !isForumChannel(ch)) return []
|
if (!ch || !isForumChannel(ch)) return []
|
||||||
return this.searchForumPosts(guildId, ch.id, q)
|
const out = await this.searchForumPostsWithMesh(guildId, ch.id, q, {
|
||||||
|
limit: 50,
|
||||||
|
mesh: this._searchIncludeMesh
|
||||||
|
})
|
||||||
|
this._lastSearchMeshMeta = {
|
||||||
|
mesh: out.mesh,
|
||||||
|
meshHitCount: out.meshHitCount || 0,
|
||||||
|
localHitCount: out.localHitCount || 0,
|
||||||
|
scope: 'forum'
|
||||||
|
}
|
||||||
|
return out.hits
|
||||||
}
|
}
|
||||||
if (this._searchScope === 'guild') {
|
if (this._searchScope === 'guild') {
|
||||||
const out = await this.searchGuildMessagesWithMesh(this.guild.guild.id, q, {
|
const out = await this.searchGuildMessagesWithMesh(this.guild.guild.id, q, {
|
||||||
@@ -1143,10 +1155,91 @@ class PearcordPlatform extends EventEmitter {
|
|||||||
snippet: String(content || '').slice(0, 160)
|
snippet: String(content || '').slice(0, 160)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const { rankAndEnrichForumSearchHits } = require('pearcord-search')
|
|
||||||
return rankAndEnrichForumSearchHits(hits, q, { limit })
|
return rankAndEnrichForumSearchHits(hits, q, { limit })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async _forumPostsFromMeshMessages (guildId, forumChannelId, messages, query) {
|
||||||
|
const q = String(query || '').trim()
|
||||||
|
if (!q || !guildId || !forumChannelId) return []
|
||||||
|
const channels =
|
||||||
|
(await this.guild?.listChannels?.()) ||
|
||||||
|
(await this.db.find(COLLECTIONS.CHANNELS, { guildId }))
|
||||||
|
const forumCh = channels.find((c) => c.id === forumChannelId)
|
||||||
|
const posts = listForumPostsForParent(channels, forumChannelId, {
|
||||||
|
includeArchived: true
|
||||||
|
})
|
||||||
|
const byThread = new Map(posts.map((p) => [p.id, p]))
|
||||||
|
const hits = []
|
||||||
|
for (const m of messages || []) {
|
||||||
|
const post = byThread.get(m.channelId)
|
||||||
|
if (!post) continue
|
||||||
|
let content = String(m.content || '')
|
||||||
|
if (!content && post.rootMessageId) {
|
||||||
|
const root = await this.db.get(COLLECTIONS.MESSAGES, {
|
||||||
|
channelId: post.id,
|
||||||
|
id: post.rootMessageId
|
||||||
|
})
|
||||||
|
if (root) content = this._messagePlaintext(enrichMessageRow(root))
|
||||||
|
}
|
||||||
|
const tags = this.forum
|
||||||
|
? await this.forum.getPostTags(guildId, post.id).catch(() => [])
|
||||||
|
: []
|
||||||
|
hits.push({
|
||||||
|
...post,
|
||||||
|
tags,
|
||||||
|
forumChannelId,
|
||||||
|
forumChannelName: forumCh?.name || 'forum',
|
||||||
|
searchHaystack: forumPostHaystack({
|
||||||
|
title: post.name,
|
||||||
|
content,
|
||||||
|
tags,
|
||||||
|
archived: post.archived
|
||||||
|
}),
|
||||||
|
snippet: String(content || '').slice(0, 160),
|
||||||
|
fromMesh: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return rankAndEnrichForumSearchHits(hits, q, { limit: 50 })
|
||||||
|
}
|
||||||
|
|
||||||
|
async searchForumPostsWithMesh (guildId, forumChannelId, query, opts = {}) {
|
||||||
|
const local = await this.searchForumPosts(guildId, forumChannelId, query, opts)
|
||||||
|
if (opts.mesh === false || !this.guild?.guild) {
|
||||||
|
return {
|
||||||
|
hits: local,
|
||||||
|
mesh: false,
|
||||||
|
meshHitCount: 0,
|
||||||
|
localHitCount: local.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const meshMsgs = await this._fetchGuildSearchFromMeshOnce(guildId, query, opts)
|
||||||
|
const meshPosts = await this._forumPostsFromMeshMessages(
|
||||||
|
guildId,
|
||||||
|
forumChannelId,
|
||||||
|
meshMsgs.map((m) => enrichMessageRow(m)),
|
||||||
|
query
|
||||||
|
)
|
||||||
|
const merged = mergeForumSearchHits(local, meshPosts, {
|
||||||
|
limit: opts.limit || 50,
|
||||||
|
query: String(query || '').trim()
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
hits: merged,
|
||||||
|
mesh: true,
|
||||||
|
meshHitCount: meshPosts.length,
|
||||||
|
localHitCount: local.length
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return {
|
||||||
|
hits: local,
|
||||||
|
mesh: false,
|
||||||
|
meshHitCount: 0,
|
||||||
|
localHitCount: local.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_getSearchIndexStore () {
|
_getSearchIndexStore () {
|
||||||
if (!this._searchIndexStore) {
|
if (!this._searchIndexStore) {
|
||||||
this._searchIndexStore = new GuildSearchIndexStore(this.storagePath)
|
this._searchIndexStore = new GuildSearchIndexStore(this.storagePath)
|
||||||
|
|||||||
Reference in New Issue
Block a user