Integrate LLM support into the application, enhancing the rule management system with a new matcher mode. Update the frontend to handle LLM configurations, including API key management and prompt definitions. Modify the backend to support LLM event matching alongside existing keyword matching, ensuring seamless integration and improved event detection capabilities.
This commit is contained in:
@@ -16,9 +16,16 @@ import {
|
||||
restoreRuleVersion,
|
||||
saveAndActivateRules,
|
||||
} from './api';
|
||||
import { Rule, RuleSet, RuleVersionSummary } from './types';
|
||||
import { LlmConfig, Rule, RuleSet, RuleVersionSummary } from './types';
|
||||
|
||||
const TRANSFER_SET_ID = 'transfer';
|
||||
const DEFAULT_LLM_CONFIG: LlmConfig = {
|
||||
baseUrl: 'https://api.openai.com/v1',
|
||||
model: 'gpt-4.1-mini',
|
||||
timeoutMs: 3000,
|
||||
maxOutputTokens: 64,
|
||||
prompt: '',
|
||||
};
|
||||
|
||||
function emptyTransferSet(): RuleSet {
|
||||
return {
|
||||
@@ -43,12 +50,32 @@ function replaceTransferRules(ruleSets: RuleSet[], rules: Rule[]): RuleSet[] {
|
||||
);
|
||||
}
|
||||
|
||||
function transferMatcher(ruleSets: RuleSet[]): 'ac-keyword' | 'llm' {
|
||||
return ruleSets.find(ruleSet => ruleSet.id === TRANSFER_SET_ID)?.matcher === 'llm'
|
||||
? 'llm'
|
||||
: 'ac-keyword';
|
||||
}
|
||||
|
||||
function replaceTransferMatcher(
|
||||
ruleSets: RuleSet[],
|
||||
matcher: 'ac-keyword' | 'llm',
|
||||
): RuleSet[] {
|
||||
if (!ruleSets.some(ruleSet => ruleSet.id === TRANSFER_SET_ID)) {
|
||||
return [{ ...emptyTransferSet(), matcher }, ...ruleSets];
|
||||
}
|
||||
return ruleSets.map(ruleSet =>
|
||||
ruleSet.id === TRANSFER_SET_ID ? { ...ruleSet, matcher } : ruleSet
|
||||
);
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
// Global Active Tab: 'rules' | 'sandbox'
|
||||
const [activeTab, setActiveTab] = useState<'rules' | 'sandbox'>('rules');
|
||||
|
||||
const [ruleSets, setRuleSets] = useState<RuleSet[]>([]);
|
||||
const [publishedRuleSets, setPublishedRuleSets] = useState<RuleSet[]>([]);
|
||||
const [llmConfig, setLlmConfig] = useState<LlmConfig>(DEFAULT_LLM_CONFIG);
|
||||
const [publishedLlmConfig, setPublishedLlmConfig] = useState<LlmConfig>(DEFAULT_LLM_CONFIG);
|
||||
const [publishedVersion, setPublishedVersion] = useState(0);
|
||||
const [loadingRules, setLoadingRules] = useState(true);
|
||||
const [savingRules, setSavingRules] = useState(false);
|
||||
@@ -82,6 +109,8 @@ export default function App() {
|
||||
if (!active) return;
|
||||
setRuleSets(data.ruleSets);
|
||||
setPublishedRuleSets(data.ruleSets);
|
||||
setLlmConfig(data.llmConfig);
|
||||
setPublishedLlmConfig(data.llmConfig);
|
||||
setPublishedVersion(data.version);
|
||||
})
|
||||
.catch(error => {
|
||||
@@ -101,17 +130,24 @@ export default function App() {
|
||||
setRuleSets(current => replaceTransferRules(current, updatedRules));
|
||||
};
|
||||
|
||||
const handleUpdateMatcher = (matcher: 'ac-keyword' | 'llm') => {
|
||||
setRuleSets(current => replaceTransferMatcher(current, matcher));
|
||||
};
|
||||
|
||||
const isDirty = useMemo(() => {
|
||||
return JSON.stringify(ruleSets) !== JSON.stringify(publishedRuleSets);
|
||||
}, [ruleSets, publishedRuleSets]);
|
||||
return JSON.stringify(ruleSets) !== JSON.stringify(publishedRuleSets)
|
||||
|| JSON.stringify(llmConfig) !== JSON.stringify(publishedLlmConfig);
|
||||
}, [llmConfig, publishedLlmConfig, publishedRuleSets, ruleSets]);
|
||||
|
||||
const handlePublish = async () => {
|
||||
if (!isDirty || savingRules || restoringVersion !== null) return;
|
||||
setSavingRules(true);
|
||||
try {
|
||||
const result = await saveAndActivateRules(publishedVersion, ruleSets);
|
||||
const result = await saveAndActivateRules(publishedVersion, llmConfig, ruleSets);
|
||||
setRuleSets(result.ruleSets);
|
||||
setPublishedRuleSets(result.ruleSets);
|
||||
setLlmConfig(result.llmConfig);
|
||||
setPublishedLlmConfig(result.llmConfig);
|
||||
setPublishedVersion(result.version);
|
||||
addToast(`保存成功,监控规则 V${result.version} 已发布生效`, 'success');
|
||||
result.warnings.forEach(warning => addToast(warning, 'warning'));
|
||||
@@ -155,6 +191,8 @@ export default function App() {
|
||||
const result = await restoreRuleVersion(sourceVersion, publishedVersion);
|
||||
setRuleSets(result.ruleSets);
|
||||
setPublishedRuleSets(result.ruleSets);
|
||||
setLlmConfig(result.llmConfig);
|
||||
setPublishedLlmConfig(result.llmConfig);
|
||||
setPublishedVersion(result.version);
|
||||
addToast(`已基于 V${sourceVersion} 创建并生效 V${result.version}`, 'success');
|
||||
result.warnings.forEach(warning => addToast(warning, 'warning'));
|
||||
@@ -205,6 +243,10 @@ export default function App() {
|
||||
<RuleManagement
|
||||
rules={rules}
|
||||
setRules={handleUpdateRules}
|
||||
matcher={transferMatcher(ruleSets)}
|
||||
setMatcher={handleUpdateMatcher}
|
||||
llmConfig={llmConfig}
|
||||
setLlmConfig={setLlmConfig}
|
||||
onSavePublish={handlePublish}
|
||||
isDirty={isDirty}
|
||||
loading={loadingRules}
|
||||
@@ -223,6 +265,7 @@ export default function App() {
|
||||
>
|
||||
<SandboxSimulation
|
||||
rules={activeRules}
|
||||
matcher={transferMatcher(publishedRuleSets)}
|
||||
addToast={addToast}
|
||||
/>
|
||||
</motion.div>
|
||||
|
||||
Reference in New Issue
Block a user