mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-08-15 05:04:27 +08:00
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:
@@ -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
|
||||
)
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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, "")
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
.chunkText() {
|
||||
em {
|
||||
color: var(--accent-primary);
|
||||
color: rgb(var(--accent-primary));
|
||||
font-style: normal;
|
||||
}
|
||||
table {
|
||||
|
||||
@@ -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>
|
||||
))}
|
||||
|
||||
@@ -201,7 +201,7 @@ export default function SearchingView({
|
||||
></ImageWithPopover>
|
||||
)}
|
||||
<HighLightMarkdown>
|
||||
{chunk.content_with_weight}
|
||||
{chunk.highlight || chunk.content_with_weight}
|
||||
</HighLightMarkdown>
|
||||
</div>
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user