Fix: forwarding highlight param (#14112)

Closes #9078

### What problem does this PR solve?

The `retrieval_test` endpoint in `chunk_app.py` never forwarded the
`highlight` request parameter to `retriever.retrieval()`, so the search
engine never produced highlight snippets. Additionally, the frontend
always rendered `content_with_weight` instead of preferring the
`highlight` field, and the CSS rule color `var(--accent-primary)` didn't
work because the variable stores an RGB triplet `(45,212,191)` requiring
the `rgb()` wrapper.

### Before

- Search page: displayed raw content_with_weight as a wall of plain
white text with no term highlighting, including markdown headings
rendered as literal text
- Retrieval testing page: showed `content_with_weight` in a plain `<p>`
tag, no `<em>` tags rendered, no highlight coloring
- Children chunks: when child chunks were consolidated into a parent via
`retrieval_by_children`, any highlight data from children was discarded
- TOC chunks: chunks fetched via `retrieval_by_toc` had no `highlight`
field, appearing as plain text while other chunks had highlights

**Retrieval testing**:
<img width="1449" height="1178"
alt="before-retrieval-no-highlight-cropped"
src="https://github.com/user-attachments/assets/5c6f5a5e-6c11-461a-bdb4-049d7dfb7a33"
/>

**Search**:
<img width="1378" height="711" alt="before-search-no-highlight-cropped"
src="https://github.com/user-attachments/assets/be7b5152-72ef-40da-a8fd-921e997ae7d3"
/>

### After

- Search page: displays the highlight field with search terms rendered
in teal/cyan color (`rgb(var(--accent-primary))`)
- Retrieval testing page: sends highlight: true in the request, uses
`HighLightMarkdown` component to render `<em>` tags with proper coloring
- Children chunks: highlights from child chunks are joined and preserved
on the parent
- TOC chunks: when other chunks have highlights, TOC-fetched chunks use
`content_with_weight` as a highlight fallback

**Retrieval testing**:
<img width="1410" height="1015" alt="05-retrieval-testing-results"
src="https://github.com/user-attachments/assets/f0cff8cf-0962-4320-b559-cd5037f622d2"
/>

**Search**:
<img width="1294" height="455" alt="03-search-highlight-results"
src="https://github.com/user-attachments/assets/a90e0e3e-3837-46be-8ddd-2412ff7cbc19"
/>

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
Daniil Sivak
2026-04-17 15:59:20 +03:00
committed by GitHub
parent fac46ef67f
commit 22c6648348
7 changed files with 28 additions and 5 deletions

View File

@@ -498,6 +498,15 @@ async def retrieval_test():
_question += await keyword_extraction(chat_mdl, _question)
labels = label_question(_question, [kb])
highlight_val = req.get("highlight", None)
if highlight_val is None:
highlight = False
elif isinstance(highlight_val, bool):
highlight = highlight_val
elif isinstance(highlight_val, str):
highlight = highlight_val.lower() in ("true", "1", "yes", "on")
else:
highlight = bool(highlight_val)
ranks = await settings.retriever.retrieval(
_question,
embd_mdl,
@@ -510,6 +519,7 @@ async def retrieval_test():
doc_ids=local_doc_ids,
top=top,
rerank_mdl=rerank_mdl,
highlight=highlight,
rank_feature=labels
)

View File

@@ -654,6 +654,7 @@ class Dealer:
chunk = self.dataStore.get(cid, idx_nms[0], kb_ids)
if not chunk:
continue
has_highlights = any(ck.get("highlight") for ck in chunks)
d = {
"chunk_id": cid,
"content_ltks": chunk["content_ltks"],
@@ -670,6 +671,8 @@ class Dealer:
"positions": chunk.get("position_int", []),
"doc_type_kwd": chunk.get("doc_type_kwd", "")
}
if has_highlights:
d["highlight"] = chunk["content_with_weight"]
for k in chunk.keys():
if k[-4:] == "_vec":
d["vector"] = chunk[k]
@@ -702,6 +705,7 @@ class Dealer:
vector_size = 1024
for id, cks in mom_chunks.items():
chunk = self.dataStore.get(id, idx_nms[0], [ck["kb_id"] for ck in cks])
child_highlights = [ck["highlight"] for ck in cks if ck.get("highlight")]
d = {
"chunk_id": id,
"content_ltks": " ".join([ck["content_ltks"] for ck in cks]),
@@ -718,6 +722,8 @@ class Dealer:
"positions": chunk.get("position_int", []),
"doc_type_kwd": chunk.get("doc_type_kwd", "")
}
if child_highlights:
d["highlight"] = " ".join(child_highlights)
for k in cks[0].keys():
if k[-4:] == "_vec":
d["vector"] = cks[0][k]

View File

@@ -265,8 +265,8 @@ class TestChunksRetrieval:
@pytest.mark.parametrize(
"payload, expected_code, expected_highlight, expected_message",
[
pytest.param({"highlight": True}, 0, True, "", marks=pytest.mark.skip(reason="highlight not functionnal")),
pytest.param({"highlight": "True"}, 0, True, "", marks=pytest.mark.skip(reason="highlight not functionnal")),
({"highlight": True}, 0, True, ""),
({"highlight": "True"}, 0, True, ""),
({"highlight": False}, 0, False, ""),
({"highlight": "False"}, 0, False, ""),
({"highlight": None}, 0, False, "")

View File

@@ -625,6 +625,7 @@ export const useTestChunkRetrieval = (): ResponsePostType<ITestingResult> & {
const { data } = await kbService.retrievalTest({
...values,
kb_id: values.kb_id ?? knowledgeBaseId,
highlight: true,
page,
size: pageSize,
});
@@ -669,6 +670,7 @@ export const useTestChunkAllRetrieval = (): ResponsePostType<ITestingResult> & {
const { data } = await kbService.retrievalTest({
...values,
kb_id: values.kb_id ?? knowledgeBaseId,
highlight: true,
doc_ids: [],
page,
size: pageSize,

View File

@@ -5,7 +5,7 @@
.chunkText() {
em {
color: var(--accent-primary);
color: rgb(var(--accent-primary));
font-style: normal;
}
table {

View File

@@ -1,5 +1,6 @@
import { EmptyType } from '@/components/empty/constant';
import Empty from '@/components/empty/empty';
import HighLightMarkdown from '@/components/highlight-markdown';
import { FilterButton } from '@/components/list-filter-bar';
import { FilterPopover } from '@/components/list-filter-bar/filter-popover';
import { FilterCollection } from '@/components/list-filter-bar/interface';
@@ -91,7 +92,11 @@ export function TestingResult({
<article key={x.chunk_id}>
<Card className="px-5 py-2.5 bg-transparent shadow-none">
<ChunkTitle item={x}></ChunkTitle>
<p className="!mt-2.5"> {x.content_with_weight}</p>
<div className="!mt-2.5">
<HighLightMarkdown>
{x.highlight || x.content_with_weight}
</HighLightMarkdown>
</div>
</Card>
</article>
))}

View File

@@ -201,7 +201,7 @@ export default function SearchingView({
></ImageWithPopover>
)}
<HighLightMarkdown>
{chunk.content_with_weight}
{chunk.highlight || chunk.content_with_weight}
</HighLightMarkdown>
</div>
<div