feat: Add expert source selector UI
- Add expert source dropdown in TransformationInputPanel - Options: LLM 生成, Wikidata, ConceptNet - Shows description for each source - Pass expertSource through App -> TransformationPanel -> hook -> API - Default source remains 'llm' 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,7 @@ import { useAttribute } from './hooks/useAttribute';
|
|||||||
import { getModels } from './services/api';
|
import { getModels } from './services/api';
|
||||||
import type { MindmapDAGRef } from './components/MindmapDAG';
|
import type { MindmapDAGRef } from './components/MindmapDAG';
|
||||||
import type { TransformationDAGRef } from './components/TransformationDAG';
|
import type { TransformationDAGRef } from './components/TransformationDAG';
|
||||||
import type { CategoryMode } from './types';
|
import type { CategoryMode, ExpertSource } from './types';
|
||||||
|
|
||||||
const { Header, Sider, Content } = Layout;
|
const { Header, Sider, Content } = Layout;
|
||||||
const { Title } = Typography;
|
const { Title } = Typography;
|
||||||
@@ -44,6 +44,7 @@ function App() {
|
|||||||
custom_experts: undefined,
|
custom_experts: undefined,
|
||||||
});
|
});
|
||||||
const [customExpertsInput, setCustomExpertsInput] = useState('');
|
const [customExpertsInput, setCustomExpertsInput] = useState('');
|
||||||
|
const [expertSource, setExpertSource] = useState<ExpertSource>('llm');
|
||||||
const [shouldStartTransform, setShouldStartTransform] = useState(false);
|
const [shouldStartTransform, setShouldStartTransform] = useState(false);
|
||||||
const [transformLoading, setTransformLoading] = useState(false);
|
const [transformLoading, setTransformLoading] = useState(false);
|
||||||
|
|
||||||
@@ -186,6 +187,7 @@ function App() {
|
|||||||
model={transformModel}
|
model={transformModel}
|
||||||
temperature={transformTemperature}
|
temperature={transformTemperature}
|
||||||
expertConfig={expertConfig}
|
expertConfig={expertConfig}
|
||||||
|
expertSource={expertSource}
|
||||||
shouldStartTransform={shouldStartTransform}
|
shouldStartTransform={shouldStartTransform}
|
||||||
onTransformComplete={() => setShouldStartTransform(false)}
|
onTransformComplete={() => setShouldStartTransform(false)}
|
||||||
onLoadingChange={setTransformLoading}
|
onLoadingChange={setTransformLoading}
|
||||||
@@ -226,10 +228,12 @@ function App() {
|
|||||||
temperature={transformTemperature}
|
temperature={transformTemperature}
|
||||||
expertConfig={expertConfig}
|
expertConfig={expertConfig}
|
||||||
customExpertsInput={customExpertsInput}
|
customExpertsInput={customExpertsInput}
|
||||||
|
expertSource={expertSource}
|
||||||
onModelChange={setTransformModel}
|
onModelChange={setTransformModel}
|
||||||
onTemperatureChange={setTransformTemperature}
|
onTemperatureChange={setTransformTemperature}
|
||||||
onExpertConfigChange={setExpertConfig}
|
onExpertConfigChange={setExpertConfig}
|
||||||
onCustomExpertsInputChange={setCustomExpertsInput}
|
onCustomExpertsInputChange={setCustomExpertsInput}
|
||||||
|
onExpertSourceChange={setExpertSource}
|
||||||
availableModels={availableModels}
|
availableModels={availableModels}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,9 +1,16 @@
|
|||||||
import { Card, Select, Slider, Typography, Space, Button, Divider } from 'antd';
|
import { Card, Select, Slider, Typography, Space, Button, Divider } from 'antd';
|
||||||
import { ThunderboltOutlined } from '@ant-design/icons';
|
import { ThunderboltOutlined } from '@ant-design/icons';
|
||||||
import { ExpertConfigPanel } from './transformation';
|
import { ExpertConfigPanel } from './transformation';
|
||||||
|
import type { ExpertSource } from '../types';
|
||||||
|
|
||||||
const { Title, Text } = Typography;
|
const { Title, Text } = Typography;
|
||||||
|
|
||||||
|
const EXPERT_SOURCE_OPTIONS = [
|
||||||
|
{ label: 'LLM 生成', value: 'llm' as ExpertSource, description: '使用 AI 模型生成專家' },
|
||||||
|
{ label: 'Wikidata', value: 'wikidata' as ExpertSource, description: '從維基數據查詢職業' },
|
||||||
|
{ label: 'ConceptNet', value: 'conceptnet' as ExpertSource, description: '從知識圖譜查詢概念' },
|
||||||
|
];
|
||||||
|
|
||||||
interface TransformationInputPanelProps {
|
interface TransformationInputPanelProps {
|
||||||
onTransform: () => void;
|
onTransform: () => void;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
@@ -17,6 +24,7 @@ interface TransformationInputPanelProps {
|
|||||||
custom_experts?: string[];
|
custom_experts?: string[];
|
||||||
};
|
};
|
||||||
customExpertsInput: string;
|
customExpertsInput: string;
|
||||||
|
expertSource: ExpertSource;
|
||||||
onModelChange: (model: string) => void;
|
onModelChange: (model: string) => void;
|
||||||
onTemperatureChange: (temperature: number) => void;
|
onTemperatureChange: (temperature: number) => void;
|
||||||
onExpertConfigChange: (config: {
|
onExpertConfigChange: (config: {
|
||||||
@@ -25,6 +33,7 @@ interface TransformationInputPanelProps {
|
|||||||
custom_experts?: string[];
|
custom_experts?: string[];
|
||||||
}) => void;
|
}) => void;
|
||||||
onCustomExpertsInputChange: (value: string) => void;
|
onCustomExpertsInputChange: (value: string) => void;
|
||||||
|
onExpertSourceChange: (source: ExpertSource) => void;
|
||||||
availableModels: string[];
|
availableModels: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,10 +46,12 @@ export const TransformationInputPanel: React.FC<TransformationInputPanelProps> =
|
|||||||
temperature,
|
temperature,
|
||||||
expertConfig,
|
expertConfig,
|
||||||
customExpertsInput,
|
customExpertsInput,
|
||||||
|
expertSource,
|
||||||
onModelChange,
|
onModelChange,
|
||||||
onTemperatureChange,
|
onTemperatureChange,
|
||||||
onExpertConfigChange,
|
onExpertConfigChange,
|
||||||
onCustomExpertsInputChange,
|
onCustomExpertsInputChange,
|
||||||
|
onExpertSourceChange,
|
||||||
availableModels,
|
availableModels,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
@@ -108,6 +119,31 @@ export const TransformationInputPanel: React.FC<TransformationInputPanelProps> =
|
|||||||
</Space>
|
</Space>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
{/* Expert Source Selection */}
|
||||||
|
<Card
|
||||||
|
size="small"
|
||||||
|
title="專家來源"
|
||||||
|
style={{
|
||||||
|
background: isDark ? '#1f1f1f' : '#fafafa',
|
||||||
|
border: `1px solid ${isDark ? '#434343' : '#d9d9d9'}`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Space direction="vertical" size="small" style={{ width: '100%' }}>
|
||||||
|
<Select
|
||||||
|
value={expertSource}
|
||||||
|
onChange={onExpertSourceChange}
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
options={EXPERT_SOURCE_OPTIONS.map((opt) => ({
|
||||||
|
label: opt.label,
|
||||||
|
value: opt.value,
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
|
<Text type="secondary" style={{ fontSize: 11 }}>
|
||||||
|
{EXPERT_SOURCE_OPTIONS.find((opt) => opt.value === expertSource)?.description}
|
||||||
|
</Text>
|
||||||
|
</Space>
|
||||||
|
</Card>
|
||||||
|
|
||||||
{/* Expert Configuration */}
|
{/* Expert Configuration */}
|
||||||
<ExpertConfigPanel
|
<ExpertConfigPanel
|
||||||
expertCount={expertConfig.expert_count}
|
expertCount={expertConfig.expert_count}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { forwardRef, useMemo, useCallback, useEffect } from 'react';
|
import { forwardRef, useMemo, useCallback, useEffect } from 'react';
|
||||||
import { Empty, Spin, Button, Progress, Card, Space, Typography, Tag } from 'antd';
|
import { Empty, Spin, Button, Progress, Card, Space, Typography, Tag } from 'antd';
|
||||||
import { ReloadOutlined } from '@ant-design/icons';
|
import { ReloadOutlined } from '@ant-design/icons';
|
||||||
import type { AttributeDAG, ExpertTransformationInput } from '../types';
|
import type { AttributeDAG, ExpertTransformationInput, ExpertSource } from '../types';
|
||||||
import { TransformationDAG } from './TransformationDAG';
|
import { TransformationDAG } from './TransformationDAG';
|
||||||
import type { TransformationDAGRef } from './TransformationDAG';
|
import type { TransformationDAGRef } from './TransformationDAG';
|
||||||
import { useExpertTransformation } from '../hooks/useExpertTransformation';
|
import { useExpertTransformation } from '../hooks/useExpertTransformation';
|
||||||
@@ -18,20 +18,21 @@ interface TransformationPanelProps {
|
|||||||
keywords_per_expert: number;
|
keywords_per_expert: number;
|
||||||
custom_experts?: string[];
|
custom_experts?: string[];
|
||||||
};
|
};
|
||||||
|
expertSource: ExpertSource;
|
||||||
shouldStartTransform: boolean;
|
shouldStartTransform: boolean;
|
||||||
onTransformComplete: () => void;
|
onTransformComplete: () => void;
|
||||||
onLoadingChange: (loading: boolean) => void;
|
onLoadingChange: (loading: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TransformationPanel = forwardRef<TransformationDAGRef, TransformationPanelProps>(
|
export const TransformationPanel = forwardRef<TransformationDAGRef, TransformationPanelProps>(
|
||||||
({ attributeData, isDark, model, temperature, expertConfig, shouldStartTransform, onTransformComplete, onLoadingChange }, ref) => {
|
({ attributeData, isDark, model, temperature, expertConfig, expertSource, shouldStartTransform, onTransformComplete, onLoadingChange }, ref) => {
|
||||||
const {
|
const {
|
||||||
loading,
|
loading,
|
||||||
progress,
|
progress,
|
||||||
results,
|
results,
|
||||||
transformAll,
|
transformAll,
|
||||||
clearResults,
|
clearResults,
|
||||||
} = useExpertTransformation({ model, temperature });
|
} = useExpertTransformation({ model, temperature, expertSource });
|
||||||
|
|
||||||
// Notify parent of loading state changes
|
// Notify parent of loading state changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -7,11 +7,13 @@ import type {
|
|||||||
ExpertTransformationDAGResult,
|
ExpertTransformationDAGResult,
|
||||||
ExpertProfile,
|
ExpertProfile,
|
||||||
CategoryDefinition,
|
CategoryDefinition,
|
||||||
|
ExpertSource,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
|
|
||||||
interface UseExpertTransformationOptions {
|
interface UseExpertTransformationOptions {
|
||||||
model?: string;
|
model?: string;
|
||||||
temperature?: number;
|
temperature?: number;
|
||||||
|
expertSource?: ExpertSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useExpertTransformation(options: UseExpertTransformationOptions = {}) {
|
export function useExpertTransformation(options: UseExpertTransformationOptions = {}) {
|
||||||
@@ -60,6 +62,7 @@ export function useExpertTransformation(options: UseExpertTransformationOptions
|
|||||||
expert_count: expertConfig.expert_count,
|
expert_count: expertConfig.expert_count,
|
||||||
keywords_per_expert: expertConfig.keywords_per_expert,
|
keywords_per_expert: expertConfig.keywords_per_expert,
|
||||||
custom_experts: expertConfig.custom_experts,
|
custom_experts: expertConfig.custom_experts,
|
||||||
|
expert_source: options.expertSource,
|
||||||
model: options.model,
|
model: options.model,
|
||||||
temperature: options.temperature,
|
temperature: options.temperature,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user