Feat: support query mode prefix in retrieval input

This commit is contained in:
yangdx
2025-04-23 01:26:34 +08:00
parent 6f064925eb
commit e97e54b7a5
6 changed files with 64 additions and 13 deletions

View File

@@ -10,6 +10,7 @@ import QuerySettings from '@/components/retrieval/QuerySettings'
import { ChatMessage, MessageWithError } from '@/components/retrieval/ChatMessage' import { ChatMessage, MessageWithError } from '@/components/retrieval/ChatMessage'
import { EraserIcon, SendIcon } from 'lucide-react' import { EraserIcon, SendIcon } from 'lucide-react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import type { QueryMode } from '@/api/lightrag'
export default function RetrievalTesting() { export default function RetrievalTesting() {
const { t } = useTranslation() const { t } = useTranslation()
@@ -18,6 +19,7 @@ export default function RetrievalTesting() {
) )
const [inputValue, setInputValue] = useState('') const [inputValue, setInputValue] = useState('')
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const [inputError, setInputError] = useState('') // Error message for input
// Reference to track if we should follow scroll during streaming (using ref for synchronous updates) // Reference to track if we should follow scroll during streaming (using ref for synchronous updates)
const shouldFollowScrollRef = useRef(true) const shouldFollowScrollRef = useRef(true)
// Reference to track if user interaction is from the form area // Reference to track if user interaction is from the form area
@@ -47,7 +49,38 @@ export default function RetrievalTesting() {
e.preventDefault() e.preventDefault()
if (!inputValue.trim() || isLoading) return if (!inputValue.trim() || isLoading) return
// Parse query mode prefix
const allowedModes: QueryMode[] = ['naive', 'local', 'global', 'hybrid', 'mix', 'bypass']
const prefixMatch = inputValue.match(/^\/(\w+)\s+(.+)/)
let modeOverride: QueryMode | undefined = undefined
let actualQuery = inputValue
// If input starts with a slash, but does not match the valid prefix pattern, treat as error
if (/^\/\S+/.test(inputValue) && !prefixMatch) {
setInputError(t('retrievePanel.retrieval.queryModePrefixInvalid'))
return
}
if (prefixMatch) {
const mode = prefixMatch[1] as QueryMode
const query = prefixMatch[2]
if (!allowedModes.includes(mode)) {
setInputError(
t('retrievePanel.retrieval.queryModeError', {
modes: 'naive, local, global, hybrid, mix, bypass',
})
)
return
}
modeOverride = mode
actualQuery = query
}
// Clear error message
setInputError('')
// Create messages // Create messages
// Save the original input (with prefix if any) in userMessage.content for display
const userMessage: Message = { const userMessage: Message = {
content: inputValue, content: inputValue,
role: 'user' role: 'user'
@@ -103,11 +136,12 @@ export default function RetrievalTesting() {
const state = useSettingsStore.getState() const state = useSettingsStore.getState()
const queryParams = { const queryParams = {
...state.querySettings, ...state.querySettings,
query: userMessage.content, query: actualQuery,
conversation_history: prevMessages conversation_history: prevMessages
.filter((m) => m.isError !== true) .filter((m) => m.isError !== true)
.slice(-(state.querySettings.history_turns || 0) * 2) .slice(-(state.querySettings.history_turns || 0) * 2)
.map((m) => ({ role: m.role, content: m.content })) .map((m) => ({ role: m.role, content: m.content })),
...(modeOverride ? { mode: modeOverride } : {})
} }
try { try {
@@ -270,10 +304,17 @@ export default function RetrievalTesting() {
id="query-input" id="query-input"
className="w-full" className="w-full"
value={inputValue} value={inputValue}
onChange={(e) => setInputValue(e.target.value)} onChange={(e) => {
setInputValue(e.target.value)
if (inputError) setInputError('')
}}
placeholder={t('retrievePanel.retrieval.placeholder')} placeholder={t('retrievePanel.retrieval.placeholder')}
disabled={isLoading} disabled={isLoading}
/> />
{/* Error message below input */}
{inputError && (
<div className="absolute left-0 top-full mt-1 text-xs text-red-500">{inputError}</div>
)}
</div> </div>
<Button type="submit" variant="default" disabled={isLoading} size="sm"> <Button type="submit" variant="default" disabled={isLoading} size="sm">
<SendIcon /> <SendIcon />

View File

@@ -303,8 +303,10 @@
"startPrompt": "ابدأ الاسترجاع بكتابة استفسارك أدناه", "startPrompt": "ابدأ الاسترجاع بكتابة استفسارك أدناه",
"clear": "مسح", "clear": "مسح",
"send": "إرسال", "send": "إرسال",
"placeholder": "اكتب استفسارك...", "placeholder": "اكتب استفسارك... (بادئة وضع الاستعلام: /<Query Mode>)",
"error": "خطأ: فشل الحصول على الرد" "error": "خطأ: فشل الحصول على الرد",
"queryModeError": "يُسمح فقط بأنماط الاستعلام التالية: {{modes}}",
"queryModePrefixInvalid": "بادئة وضع الاستعلام غير صالحة. استخدم: /<الوضع> [مسافة] استفسارك"
}, },
"querySettings": { "querySettings": {
"parametersTitle": "المعلمات", "parametersTitle": "المعلمات",

View File

@@ -303,8 +303,10 @@
"startPrompt": "Start a retrieval by typing your query below", "startPrompt": "Start a retrieval by typing your query below",
"clear": "Clear", "clear": "Clear",
"send": "Send", "send": "Send",
"placeholder": "Type your query...", "placeholder": "Type your query... (Query mode prefix: /<Query Mode>)",
"error": "Error: Failed to get response" "error": "Error: Failed to get response",
"queryModeError": "Only supports the following query modes: {{modes}}",
"queryModePrefixInvalid": "Invalid query mode prefix. Use: /<mode> [space] your query"
}, },
"querySettings": { "querySettings": {
"parametersTitle": "Parameters", "parametersTitle": "Parameters",

View File

@@ -303,8 +303,10 @@
"startPrompt": "Démarrez une récupération en tapant votre requête ci-dessous", "startPrompt": "Démarrez une récupération en tapant votre requête ci-dessous",
"clear": "Effacer", "clear": "Effacer",
"send": "Envoyer", "send": "Envoyer",
"placeholder": "Tapez votre requête...", "placeholder": "Tapez votre requête... (Préfixe du mode de requête : /<Query Mode>)",
"error": "Erreur : Échec de l'obtention de la réponse" "error": "Erreur : Échec de l'obtention de la réponse",
"queryModeError": "Seuls les modes de requête suivants sont pris en charge : {{modes}}",
"queryModePrefixInvalid": "Préfixe de mode de requête invalide. Utilisez : /<mode> [espace] votre requête"
}, },
"querySettings": { "querySettings": {
"parametersTitle": "Paramètres", "parametersTitle": "Paramètres",

View File

@@ -304,8 +304,10 @@
"startPrompt": "输入查询开始检索", "startPrompt": "输入查询开始检索",
"clear": "清空", "clear": "清空",
"send": "发送", "send": "发送",
"placeholder": "输入查询...", "placeholder": "输入查询...(查询模式前缀:/<Query Mode>)",
"error": "错误:获取响应失败" "error": "错误:获取响应失败",
"queryModeError": "仅支持以下查询模式:{{modes}}",
"queryModePrefixInvalid": "无效的查询模式前缀。请使用:/<模式> [空格] 查询内容"
}, },
"querySettings": { "querySettings": {
"parametersTitle": "参数", "parametersTitle": "参数",

View File

@@ -303,8 +303,10 @@
"startPrompt": "輸入查詢開始檢索", "startPrompt": "輸入查詢開始檢索",
"clear": "清空", "clear": "清空",
"send": "送出", "send": "送出",
"placeholder": "輸入查詢...", "placeholder": "輸入查詢...(查詢模式前綴:/<Query Mode>)",
"error": "錯誤:取得回應失敗" "error": "錯誤:取得回應失敗",
"queryModeError": "僅支援以下查詢模式:{{modes}}",
"queryModePrefixInvalid": "無效的查詢模式前綴。請使用:/<模式> [空格] 查詢內容"
}, },
"querySettings": { "querySettings": {
"parametersTitle": "參數", "parametersTitle": "參數",