前台8项体验修复: 知识库上传自动刷新; 资产PDF归类; Token驾驶舱媒体统计; AI模糊意图澄清选择; ChatPage增加MCP/附件上传/语音; 技能市场安装态修复+清理演示数据; MCP协议应用改名MCP应用; Agent单应用接入(名称/介绍/API Key)

This commit is contained in:
QihuAI Design committed 2026-07-15 10:33:43 +08:00
1 parent 463824480b
commit bc2899ed09
11 files changed
+945 -154

No files matched your search

+87 -96
View File
@@ -173,7 +173,7 @@ function renderAppIconLarge(app: MarketApp): React.ReactNode {
const typeLabels: Record<AppType, string> = {
skill: 'Skills工具',
agent: '智能Agent',
mcp: 'MCP协议应用',
mcp: 'MCP应用',
};
const typeIcons: Record<AppType, React.ReactNode> = {
@@ -1158,122 +1158,109 @@ const mcpClient = new MCPClient({
);
};
// ===== Agent Platform Connect Modal (修改4) =====
// ===== Agent 单接入 Modal(修改8:以单个Agent方式接入,含名称/介绍) =====
interface AgentConnectModalProps {
onClose: () => void;
onConnect: (platformId: string, config: Record<string, string>, price?: number) => void;
onConnect: (platformId: string, config: Record<string, string>, price?: number, name?: string, description?: string) => void;
}
const AgentConnectModal: React.FC<AgentConnectModalProps> = ({ onClose, onConnect }) => {
const [selectedPlatform, setSelectedPlatform] = useState<string | null>(null);
const [platform, setPlatform] = useState<string>('dify');
const [name, setName] = useState('');
const [intro, setIntro] = useState('');
const [apiKey, setApiKey] = useState('');
const [endpoint, setEndpoint] = useState('');
const [price, setPrice] = useState<number>(0);
const [connecting, setConnecting] = useState(false);
const [connected, setConnected] = useState<string | null>(null);
const handleConnect = () => {
if (!selectedPlatform || !apiKey.trim()) return;
if (!name.trim() || !endpoint.trim() || !apiKey.trim()) return;
setConnecting(true);
setTimeout(() => {
setConnecting(false);
setConnected(selectedPlatform);
onConnect(selectedPlatform, { apiKey: apiKey.trim(), endpoint: endpoint.trim() }, price);
}, 1500);
onConnect(platform, { apiKey: apiKey.trim(), endpoint: endpoint.trim() }, price, name.trim(), intro.trim());
}, 800);
};
return (
<div className="market-modal-overlay" onClick={onClose}>
<div className="market-modal agent-connect-modal" onClick={e => e.stopPropagation()}>
<div className="market-modal-header">
<h2>对接外部Agent平台</h2>
<h2>接入单个 Agent</h2>
<button className="market-modal-close" onClick={onClose}><CloseIcon /></button>
</div>
<div className="market-modal-body">
<p className="hub-import-desc">
将外部平台的Agent接入AIFlow应用市场,实现跨平台的Agent管理与调度。
以单个 Agent 方式接入(例如 Dify 中每个 Agent 都有独立的访问地址与密钥)。请填写该 Agent 的名称、介绍及连接信息。
</p>
{!selectedPlatform ? (
<div className="agent-platforms">
<div className="form-section">
<label className="form-label">所属平台</label>
<select className="form-input" value={platform} onChange={e => setPlatform(e.target.value)}>
{agentPlatforms.map(p => (
<div
key={p.id}
className={`agent-platform-card ${connected === p.id ? 'connected' : ''}`}
onClick={() => { setSelectedPlatform(p.id); setEndpoint(p.id === 'dify' ? 'https://api.dify.ai/v1' : p.id === 'n8n' ? 'https://n8n.example.com/api/v1' : 'https://api.coze.cn/v1'); }}
>
<div className="agent-platform-icon">
<ApiIcon />
</div>
<div className="agent-platform-info">
<strong>{p.name}</strong>
<span>{p.description}</span>
</div>
{connected === p.id ? (
<span className="connected-badge"><CheckCircleIcon /> 已连接</span>
) : (
<span className="connect-indicator">配置</span>
)}
</div>
<option key={p.id} value={p.id}>{p.name}</option>
))}
</div>
) : (
<div className="agent-config-form">
<button className="back-btn" onClick={() => setSelectedPlatform(null)}>
&larr; 返回选择
</button>
<div className="form-section">
<label className="form-label">平台</label>
<input type="text" className="form-input" value={agentPlatforms.find(p => p.id === selectedPlatform)?.name || ''} disabled />
</div>
<div className="form-section">
<label className="form-label">API Key <span className="required">*</span></label>
<input
type="password"
className="form-input"
placeholder="请输入API Key"
value={apiKey}
onChange={e => setApiKey(e.target.value)}
/>
</div>
<div className="form-section">
<label className="form-label">API Endpoint</label>
<input
type="text"
className="form-input"
placeholder="https://..."
value={endpoint}
onChange={e => setEndpoint(e.target.value)}
/>
</div>
<div className="form-section">
<label className="form-label">定价(元)</label>
<input
type="number"
min="0"
step="0.01"
className="form-input"
placeholder="0 为免费"
value={price}
onChange={e => setPrice(parseFloat(e.target.value) || 0)}
/>
<span className="hub-price-hint">用户对接的Agent:是否收费由您决定;管理员导入默认免费且审核通过。</span>
</div>
<button
className="form-submit-btn"
onClick={handleConnect}
disabled={!apiKey.trim() || connecting}
>
{connecting ? '连接验证中...' : '连接并同步Agent'}
</button>
{connecting && (
<div className="hub-importing-status">
<div className="audit-spinner small" />
<span>正在验证连接并同步Agent列表...</span>
</div>
)}
</div>
)}
</select>
</div>
<div className="form-section">
<label className="form-label">Agent 名称 <span className="required">*</span></label>
<input
type="text"
className="form-input"
placeholder="例如:我的客服 Agent"
value={name}
onChange={e => setName(e.target.value)}
/>
</div>
<div className="form-section">
<label className="form-label">Agent 介绍</label>
<textarea
className="form-input"
rows={3}
placeholder="简要描述该 Agent 的能力与用途"
value={intro}
onChange={e => setIntro(e.target.value)}
/>
</div>
<div className="form-section">
<label className="form-label">API Endpoint(该 Agent 专属地址)<span className="required">*</span></label>
<input
type="text"
className="form-input"
placeholder="https://..."
value={endpoint}
onChange={e => setEndpoint(e.target.value)}
/>
</div>
<div className="form-section">
<label className="form-label">API Key <span className="required">*</span></label>
<input
type="password"
className="form-input"
placeholder="请输入该 Agent 的 API Key"
value={apiKey}
onChange={e => setApiKey(e.target.value)}
/>
</div>
<div className="form-section">
<label className="form-label">定价(元)</label>
<input
type="number"
min="0"
step="0.01"
className="form-input"
placeholder="0 为免费"
value={price}
onChange={e => setPrice(parseFloat(e.target.value) || 0)}
/>
<span className="hub-price-hint">用户对接的 Agent 是否收费由您决定;管理员导入默认免费且审核通过。</span>
</div>
<button
className="form-submit-btn"
onClick={handleConnect}
disabled={!name.trim() || !endpoint.trim() || !apiKey.trim() || connecting}
>
{connecting ? '接入中...' : '接入 Agent'}
</button>
</div>
</div>
</div>
@@ -1344,7 +1331,7 @@ const MarketPage: React.FC = () => {
{ key: 'all', label: '全部' },
{ key: 'skill', label: 'Skills工具' },
{ key: 'agent', label: '智能Agent' },
{ key: 'mcp', label: 'MCP协议应用' },
{ key: 'mcp', label: 'MCP应用' },
];
// Handle create tool - 调用后端 API 创建应用
@@ -1388,20 +1375,24 @@ const MarketPage: React.FC = () => {
setShowHubImport(null);
};
// Handle agent connect - 调用后端 API 创建应用
const handleAgentConnect = async (platformId: string, config: Record<string, string>, price?: number) => {
// Handle agent connect - 调用后端 API 创建应用(单个Agent方式接入)
const handleAgentConnect = async (platformId: string, config: Record<string, string>, price?: number, name?: string, description?: string) => {
const platform = agentPlatforms.find(p => p.id === platformId);
if (!platform) return;
const finalName = (name && name.trim()) ? name.trim() : `${platform?.name || '外部'} Agent`;
const finalDesc = (description && description.trim())
? description.trim()
: `从 ${platform?.name || '外部平台'} 对接导入的智能Agent`;
try {
await marketAPI.createApp({
name: `${platform.name} Agent`,
name: finalName,
type: 'agent',
description: `从 ${platform.name} 对接导入的智能Agent`,
description: finalDesc,
price: price || 0,
is_member_free: (price || 0) === 0,
join_promotion: false,
source: 'user',
agent_endpoint: config.endpoint || '',
api_key: config.apiKey || '',
});
// 重新加载列表
loadApps();