智能体详情页工具栏增加发布到市场按钮

This commit is contained in:
jingrow 2025-11-03 04:18:47 +08:00
parent b22df1b48b
commit fb2363be65
2 changed files with 178 additions and 1 deletions

View File

@ -76,6 +76,21 @@
{{ t('Flow Builder') }} {{ t('Flow Builder') }}
</n-button> </n-button>
<!-- 发布到市场按钮 -->
<n-button
type="default"
size="medium"
@click="handlePublish"
:disabled="loading || isNew || publishing"
class="toolbar-btn publish-btn"
v-if="!isNew"
>
<template #icon>
<n-icon><Icon icon="tabler:cloud-upload" /></n-icon>
</template>
{{ publishing ? t('Publishing...') : t('Publish to Marketplace') }}
</n-button>
<!-- 返回按钮 --> <!-- 返回按钮 -->
<n-button type="default" size="medium" @click="$emit('go-back')" :disabled="loading"> <n-button type="default" size="medium" @click="$emit('go-back')" :disabled="loading">
<template #icon> <template #icon>
@ -105,10 +120,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue' import { ref, computed, watch, onMounted } from 'vue'
import { NButton, NSpace, NIcon, useMessage } from 'naive-ui' import { NButton, NSpace, NIcon, useMessage, useDialog } from 'naive-ui'
import { Icon } from '@iconify/vue' import { Icon } from '@iconify/vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { t } from '@/shared/i18n' import { t } from '@/shared/i18n'
import axios from 'axios'
import { get_session_api_headers } from '@/shared/api/auth'
interface Props { interface Props {
entity: string entity: string
@ -135,8 +152,10 @@ const props = withDefaults(defineProps<Props>(), {
defineEmits<Emits>() defineEmits<Emits>()
const message = useMessage() const message = useMessage()
const dialog = useDialog()
const router = useRouter() const router = useRouter()
const executing = ref(false) const executing = ref(false)
const publishing = ref(false)
// //
const isNew = computed(() => { const isNew = computed(() => {
@ -211,6 +230,84 @@ async function handleFlowBuilder() {
router.push({ name: 'FlowBuilder', query: { agentId } }) router.push({ name: 'FlowBuilder', query: { agentId } })
} catch (_) {} } catch (_) {}
} }
//
function handlePublish() {
if (isNew.value || !props.record?.agent_name) {
message.warning(t('Please save the agent first'))
return
}
const agentName = props.record.agent_name
const agentFlow = props.record.agent_flow
if (!agentFlow) {
message.warning(t('Agent flow data is required for publishing'))
return
}
dialog.info({
title: t('Publish to Agent Marketplace'),
content: t('Are you sure you want to publish agent "{0}" to the marketplace?').replace('{0}', agentName),
positiveText: t('Confirm'),
negativeText: t('Cancel'),
onPositiveClick: () => {
performPublish()
}
})
}
async function performPublish() {
try {
publishing.value = true
const agentName = props.record?.agent_name || ''
const agentFlow = props.record?.agent_flow
if (!agentFlow) {
throw new Error(t('Agent flow data is required'))
}
// agent_flow
let flowData = agentFlow
if (typeof agentFlow === 'string') {
try {
flowData = JSON.parse(agentFlow)
} catch (e) {
//
}
}
//
const publishData = {
agent_name: agentName,
title: props.record?.title || agentName,
subtitle: props.record?.subtitle || '',
description: props.record?.description || '',
agent_flow: flowData
}
const response = await axios.post('/jingrow/agent/publish', publishData, {
headers: {
...get_session_api_headers(),
'Content-Type': 'application/json'
},
withCredentials: true
})
if (response.data.success) {
message.success(response.data.message || t('Agent published successfully'))
} else {
throw new Error(response.data.message || t('Publish failed'))
}
} catch (error: any) {
console.error('发布智能体失败:', error)
const errorMsg = error?.response?.data?.detail || error?.response?.data?.message || error?.message || t('Publish failed, please check permission and server logs')
message.error(errorMsg)
} finally {
publishing.value = false
}
}
</script> </script>
<style scoped> <style scoped>
@ -361,6 +458,20 @@ async function handleFlowBuilder() {
box-shadow: 0 2px 8px rgba(14, 165, 233, 0.15); box-shadow: 0 2px 8px rgba(14, 165, 233, 0.15);
} }
/* 发布按钮 - 紫色系 */
.publish-btn {
background: #f3e8ff !important;
color: #7c3aed !important;
border-color: rgba(139, 92, 246, 0.2) !important;
}
.publish-btn:hover:not(:disabled) {
background: #e9d5ff !important;
color: #6d28d9 !important;
border-color: rgba(139, 92, 246, 0.3) !important;
box-shadow: 0 2px 8px rgba(139, 92, 246, 0.15);
}
.toolbar-btn:disabled { .toolbar-btn:disabled {
opacity: 0.5; opacity: 0.5;
cursor: not-allowed; cursor: not-allowed;

View File

@ -908,3 +908,69 @@ async def get_installed_agent_names():
except Exception as e: except Exception as e:
logger.error(f"获取已安装智能体列表失败: {str(e)}") logger.error(f"获取已安装智能体列表失败: {str(e)}")
return {"success": False, "agents": []} return {"success": False, "agents": []}
@router.post("/jingrow/agent/publish")
async def publish_agent_to_marketplace(payload: Dict[str, Any]):
"""
发布智能体到Jingrow Cloud智能体市场
使用 create_local_agent API
"""
try:
agent_name = payload.get("agent_name")
agent_flow = payload.get("agent_flow")
title = payload.get("title")
description = payload.get("description", "")
subtitle = payload.get("subtitle")
if not agent_name:
raise HTTPException(status_code=400, detail="智能体名称不能为空")
if not agent_flow:
raise HTTPException(status_code=400, detail="流程数据不能为空")
if not title:
title = agent_name
url = f"{get_jingrow_cloud_url()}/api/action/jcloud.api.jlocal.create_local_agent"
headers = get_jingrow_cloud_api_headers()
headers['Content-Type'] = 'application/json'
# 准备 agent_data
agent_data = {
"agent_name": agent_name,
"title": title,
"agent_flow": agent_flow if isinstance(agent_flow, str) else json.dumps(agent_flow, ensure_ascii=False),
"description": description,
"subtitle": subtitle or ""
}
response = requests.post(url, json={
"agent_data": agent_data
}, headers=headers, timeout=20)
if response.status_code != 200:
error_detail = response.json().get('detail', f"HTTP {response.status_code}") if response.headers.get('content-type', '').startswith('application/json') else f"HTTP {response.status_code}"
raise HTTPException(status_code=response.status_code, detail=error_detail)
result = response.json()
# 检查错误
if isinstance(result, dict) and result.get('error'):
raise HTTPException(status_code=400, detail=result['error'])
message = result.get('message', {})
if isinstance(message, dict) and message.get('error'):
raise HTTPException(status_code=400, detail=message['error'])
# 成功响应
agent_name_result = message.get('name', 'unknown') if isinstance(message, dict) else result.get('message', 'unknown')
return {"success": True, "message": f"智能体发布成功,智能体名称: {agent_name_result}"}
except HTTPException:
raise
except Exception as e:
logger.error(f"发布智能体失败: {str(e)}")
logger.error(f"Traceback: {traceback.format_exc()}")
raise HTTPException(status_code=500, detail=f"发布智能体失败: {str(e)}")