chore: save local changes
This commit is contained in:
@@ -1,17 +1,24 @@
|
||||
import { useState, useRef, useCallback, useEffect } from 'react';
|
||||
import { ConfigProvider, Layout, theme, Typography, Space, Tabs, Slider, Radio } from 'antd';
|
||||
import { ApartmentOutlined, ThunderboltOutlined, FilterOutlined } from '@ant-design/icons';
|
||||
import { useState, useRef, useCallback, useEffect, useMemo } from 'react';
|
||||
import { ConfigProvider, Layout, theme, Typography, Space, Tabs, Slider, Radio, Switch, Segmented } from 'antd';
|
||||
import { ApartmentOutlined, ThunderboltOutlined, FilterOutlined, SwapOutlined, FileSearchOutlined, GlobalOutlined } from '@ant-design/icons';
|
||||
import { ThemeToggle } from './components/ThemeToggle';
|
||||
import { InputPanel } from './components/InputPanel';
|
||||
import { TransformationInputPanel } from './components/TransformationInputPanel';
|
||||
import { MindmapPanel } from './components/MindmapPanel';
|
||||
import { TransformationPanel } from './components/TransformationPanel';
|
||||
import { DeduplicationPanel } from './components/DeduplicationPanel';
|
||||
import { PatentSearchPanel } from './components/PatentSearchPanel';
|
||||
import { DualPathInputPanel } from './components/DualPathInputPanel';
|
||||
import { DualPathMindmapPanel } from './components/DualPathMindmapPanel';
|
||||
import { CrossoverPanel } from './components/CrossoverPanel';
|
||||
import { useAttribute } from './hooks/useAttribute';
|
||||
import { useDualPathAttribute } from './hooks/useDualPathAttribute';
|
||||
import { getModels } from './services/api';
|
||||
import { crossoverPairsToDAGs, type CrossoverDAGResult } from './utils/crossoverToDAG';
|
||||
import { DualTransformationPanel } from './components/DualTransformationPanel';
|
||||
import type { MindmapDAGRef } from './components/MindmapDAG';
|
||||
import type { TransformationDAGRef } from './components/TransformationDAG';
|
||||
import type { CategoryMode, ExpertSource, ExpertTransformationDAGResult, DeduplicationMethod } from './types';
|
||||
import type { CategoryMode, ExpertSource, ExpertTransformationDAGResult, DeduplicationMethod, ExpertMode, CrossoverPair, PromptLanguage } from './types';
|
||||
|
||||
const { Header, Sider, Content } = Layout;
|
||||
const { Title } = Typography;
|
||||
@@ -24,7 +31,15 @@ interface VisualSettings {
|
||||
function App() {
|
||||
const [isDark, setIsDark] = useState(true);
|
||||
const [activeTab, setActiveTab] = useState<string>('attribute');
|
||||
const [dualPathMode, setDualPathMode] = useState(false);
|
||||
const [promptLanguage, setPromptLanguage] = useState<PromptLanguage>('zh');
|
||||
|
||||
// Single path hook
|
||||
const { loading, progress, error, currentResult, history, analyze, loadFromHistory } = useAttribute();
|
||||
|
||||
// Dual path hook
|
||||
const dualPath = useDualPathAttribute();
|
||||
|
||||
const [visualSettings, setVisualSettings] = useState<VisualSettings>({
|
||||
nodeSpacing: 32,
|
||||
fontSize: 14,
|
||||
@@ -32,6 +47,21 @@ function App() {
|
||||
const mindmapRef = useRef<MindmapDAGRef>(null);
|
||||
const transformationRef = useRef<TransformationDAGRef>(null);
|
||||
|
||||
// Dual path expert mode
|
||||
const [expertMode, setExpertMode] = useState<ExpertMode>('shared');
|
||||
const [selectedCrossoverPairs, setSelectedCrossoverPairs] = useState<CrossoverPair[]>([]);
|
||||
|
||||
// Convert selected crossover pairs to two separate DAGs for dual transformation
|
||||
const crossoverDAGs = useMemo((): CrossoverDAGResult | null => {
|
||||
if (selectedCrossoverPairs.length === 0) return null;
|
||||
if (!dualPath.pathA.result || !dualPath.pathB.result) return null;
|
||||
return crossoverPairsToDAGs(
|
||||
selectedCrossoverPairs,
|
||||
dualPath.pathA.result,
|
||||
dualPath.pathB.result
|
||||
);
|
||||
}, [selectedCrossoverPairs, dualPath.pathA.result, dualPath.pathB.result]);
|
||||
|
||||
// Transformation Agent settings
|
||||
const [transformModel, setTransformModel] = useState<string>('');
|
||||
const [transformTemperature, setTransformTemperature] = useState<number>(0.95);
|
||||
@@ -83,9 +113,10 @@ function App() {
|
||||
chainCount?: number,
|
||||
categoryMode?: CategoryMode,
|
||||
customCategories?: string[],
|
||||
suggestedCategoryCount?: number
|
||||
suggestedCategoryCount?: number,
|
||||
lang?: PromptLanguage
|
||||
) => {
|
||||
await analyze(query, model, temperature, chainCount, categoryMode, customCategories, suggestedCategoryCount);
|
||||
await analyze(query, model, temperature, chainCount, categoryMode, customCategories, suggestedCategoryCount, lang || promptLanguage);
|
||||
};
|
||||
|
||||
const handleResetView = useCallback(() => {
|
||||
@@ -96,6 +127,30 @@ function App() {
|
||||
setShouldStartTransform(true);
|
||||
}, []);
|
||||
|
||||
// Dual path analysis handler
|
||||
const handleDualPathAnalyze = useCallback(async (
|
||||
queryA: string,
|
||||
queryB: string,
|
||||
options?: {
|
||||
model?: string;
|
||||
temperature?: number;
|
||||
chainCount?: number;
|
||||
categoryMode?: CategoryMode;
|
||||
customCategories?: string[];
|
||||
suggestedCategoryCount?: number;
|
||||
lang?: PromptLanguage;
|
||||
}
|
||||
) => {
|
||||
await dualPath.analyzeParallel(queryA, queryB, { ...options, lang: options?.lang || promptLanguage });
|
||||
}, [dualPath, promptLanguage]);
|
||||
|
||||
// Handle mode switch
|
||||
const handleModeSwitch = useCallback((checked: boolean) => {
|
||||
setDualPathMode(checked);
|
||||
// Reset to attribute tab when switching modes
|
||||
setActiveTab('attribute');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
@@ -140,7 +195,31 @@ function App() {
|
||||
Novelty Seeking
|
||||
</Title>
|
||||
</Space>
|
||||
<ThemeToggle isDark={isDark} onToggle={setIsDark} />
|
||||
<Space align="center" size="middle">
|
||||
<Space size="small">
|
||||
<Typography.Text type="secondary">Single</Typography.Text>
|
||||
<Switch
|
||||
checked={dualPathMode}
|
||||
onChange={handleModeSwitch}
|
||||
checkedChildren={<SwapOutlined />}
|
||||
unCheckedChildren={<ApartmentOutlined />}
|
||||
/>
|
||||
<Typography.Text type="secondary">Dual</Typography.Text>
|
||||
</Space>
|
||||
<Space size="small">
|
||||
<GlobalOutlined style={{ color: isDark ? '#177ddc' : '#1890ff' }} />
|
||||
<Segmented
|
||||
size="small"
|
||||
value={promptLanguage}
|
||||
onChange={(value) => setPromptLanguage(value as PromptLanguage)}
|
||||
options={[
|
||||
{ label: '中文', value: 'zh' },
|
||||
{ label: 'EN', value: 'en' },
|
||||
]}
|
||||
/>
|
||||
</Space>
|
||||
<ThemeToggle isDark={isDark} onToggle={setIsDark} />
|
||||
</Space>
|
||||
</Header>
|
||||
<Layout>
|
||||
<Content
|
||||
@@ -155,7 +234,98 @@ function App() {
|
||||
onChange={setActiveTab}
|
||||
style={{ height: '100%' }}
|
||||
tabBarStyle={{ marginBottom: 8 }}
|
||||
items={[
|
||||
items={dualPathMode ? [
|
||||
// ===== Dual Path Mode Tabs =====
|
||||
{
|
||||
key: 'attribute',
|
||||
label: (
|
||||
<span>
|
||||
<SwapOutlined style={{ marginRight: 8 }} />
|
||||
Dual Path Attribute
|
||||
</span>
|
||||
),
|
||||
children: (
|
||||
<div style={{ height: 'calc(100vh - 140px)' }}>
|
||||
<DualPathMindmapPanel
|
||||
pathA={dualPath.pathA}
|
||||
pathB={dualPath.pathB}
|
||||
isDark={isDark}
|
||||
visualSettings={visualSettings}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'crossover',
|
||||
label: (
|
||||
<span>
|
||||
<SwapOutlined style={{ marginRight: 8 }} />
|
||||
Crossover
|
||||
</span>
|
||||
),
|
||||
children: (
|
||||
<div style={{ height: 'calc(100vh - 140px)', padding: 16 }}>
|
||||
<CrossoverPanel
|
||||
pathAResult={dualPath.pathA.result}
|
||||
pathBResult={dualPath.pathB.result}
|
||||
isDark={isDark}
|
||||
expertMode={expertMode}
|
||||
onExpertModeChange={setExpertMode}
|
||||
onCrossoverReady={setSelectedCrossoverPairs}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'transformation',
|
||||
label: (
|
||||
<span>
|
||||
<ThunderboltOutlined style={{ marginRight: 8 }} />
|
||||
Transformation Agent
|
||||
{crossoverDAGs && (
|
||||
<span style={{ marginLeft: 4, fontSize: 10, opacity: 0.7 }}>
|
||||
(A:{crossoverDAGs.pathA.nodes.length} / B:{crossoverDAGs.pathB.nodes.length})
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
),
|
||||
children: (
|
||||
<div style={{ height: 'calc(100vh - 140px)' }}>
|
||||
<DualTransformationPanel
|
||||
crossoverDAGA={crossoverDAGs?.pathA ?? null}
|
||||
crossoverDAGB={crossoverDAGs?.pathB ?? null}
|
||||
isDark={isDark}
|
||||
model={transformModel}
|
||||
temperature={transformTemperature}
|
||||
expertConfig={expertConfig}
|
||||
expertSource={expertSource}
|
||||
expertLanguage={expertLanguage}
|
||||
lang={promptLanguage}
|
||||
shouldStartTransform={shouldStartTransform}
|
||||
onTransformComplete={() => setShouldStartTransform(false)}
|
||||
onLoadingChange={setTransformLoading}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'patent',
|
||||
label: (
|
||||
<span>
|
||||
<FileSearchOutlined style={{ marginRight: 8 }} />
|
||||
Patent Search
|
||||
</span>
|
||||
),
|
||||
children: (
|
||||
<div style={{ height: 'calc(100vh - 140px)' }}>
|
||||
<PatentSearchPanel
|
||||
isDark={isDark}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
] : [
|
||||
// ===== Single Path Mode Tabs =====
|
||||
{
|
||||
key: 'attribute',
|
||||
label: (
|
||||
@@ -196,6 +366,7 @@ function App() {
|
||||
expertConfig={expertConfig}
|
||||
expertSource={expertSource}
|
||||
expertLanguage={expertLanguage}
|
||||
lang={promptLanguage}
|
||||
shouldStartTransform={shouldStartTransform}
|
||||
onTransformComplete={() => setShouldStartTransform(false)}
|
||||
onLoadingChange={setTransformLoading}
|
||||
@@ -221,6 +392,24 @@ function App() {
|
||||
onThresholdChange={setDeduplicationThreshold}
|
||||
method={deduplicationMethod}
|
||||
onMethodChange={setDeduplicationMethod}
|
||||
lang={promptLanguage}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: 'patent',
|
||||
label: (
|
||||
<span>
|
||||
<FileSearchOutlined style={{ marginRight: 8 }} />
|
||||
Patent Search
|
||||
</span>
|
||||
),
|
||||
children: (
|
||||
<div style={{ height: 'calc(100vh - 140px)' }}>
|
||||
<PatentSearchPanel
|
||||
descriptions={transformationResult?.results.flatMap(r => r.descriptions)}
|
||||
isDark={isDark}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
@@ -236,24 +425,54 @@ function App() {
|
||||
overflow: 'auto',
|
||||
}}
|
||||
>
|
||||
{activeTab === 'attribute' && (
|
||||
{activeTab === 'attribute' && !dualPathMode && (
|
||||
<InputPanel
|
||||
loading={loading}
|
||||
progress={progress}
|
||||
history={history}
|
||||
currentResult={currentResult}
|
||||
onAnalyze={handleAnalyze}
|
||||
onLoadHistory={loadFromHistory}
|
||||
onLoadHistory={(item, lang) => loadFromHistory(item, lang || promptLanguage)}
|
||||
onResetView={handleResetView}
|
||||
visualSettings={visualSettings}
|
||||
onVisualSettingsChange={setVisualSettings}
|
||||
lang={promptLanguage}
|
||||
/>
|
||||
)}
|
||||
{activeTab === 'attribute' && dualPathMode && (
|
||||
<DualPathInputPanel
|
||||
onAnalyze={handleDualPathAnalyze}
|
||||
loadingA={dualPath.pathA.loading}
|
||||
loadingB={dualPath.pathB.loading}
|
||||
progressA={dualPath.pathA.progress}
|
||||
progressB={dualPath.pathB.progress}
|
||||
availableModels={availableModels}
|
||||
lang={promptLanguage}
|
||||
/>
|
||||
)}
|
||||
{activeTab === 'crossover' && dualPathMode && (
|
||||
<div style={{ padding: 16 }}>
|
||||
<Typography.Title level={5} style={{ marginBottom: 16 }}>
|
||||
<SwapOutlined style={{ marginRight: 8 }} />
|
||||
Crossover Settings
|
||||
</Typography.Title>
|
||||
<Typography.Text type="secondary">
|
||||
Select attribute pairs in the main panel to create crossover combinations.
|
||||
{selectedCrossoverPairs.length > 0 && (
|
||||
<div style={{ marginTop: 8 }}>
|
||||
<Typography.Text strong>
|
||||
{selectedCrossoverPairs.length} pairs selected
|
||||
</Typography.Text>
|
||||
</div>
|
||||
)}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
)}
|
||||
{activeTab === 'transformation' && (
|
||||
<TransformationInputPanel
|
||||
onTransform={handleTransform}
|
||||
loading={transformLoading}
|
||||
hasData={!!currentResult}
|
||||
hasData={dualPathMode ? !!crossoverDAGs : !!currentResult}
|
||||
isDark={isDark}
|
||||
model={transformModel}
|
||||
temperature={transformTemperature}
|
||||
|
||||
Reference in New Issue
Block a user