智能体详情页工具栏增加发布到市场按钮
This commit is contained in:
parent
b22df1b48b
commit
fb2363be65
@ -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;
|
||||||
|
|||||||
@ -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)}")
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user