Merge pull request #494 from SuanmoSuanyangTechnology/release/v0.2.6
Release/v0.2.6
This commit is contained in:
@@ -371,6 +371,11 @@ def update_model(
|
|||||||
|
|
||||||
if model_data.type is not None or model_data.provider is not None:
|
if model_data.type is not None or model_data.provider is not None:
|
||||||
raise BusinessException("不允许更改模型类型和供应商", BizCode.INVALID_PARAMETER)
|
raise BusinessException("不允许更改模型类型和供应商", BizCode.INVALID_PARAMETER)
|
||||||
|
|
||||||
|
if model_data.is_active:
|
||||||
|
active_keys = ModelApiKeyService.get_api_keys_by_model(db=db, model_config_id=model_id, is_active=model_data.is_active)
|
||||||
|
if not active_keys:
|
||||||
|
raise BusinessException("请先为该模型配置可用的 API Key", BizCode.INVALID_PARAMETER)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
api_logger.debug(f"开始更新模型配置: model_id={model_id}")
|
api_logger.debug(f"开始更新模型配置: model_id={model_id}")
|
||||||
|
|||||||
@@ -192,8 +192,10 @@ class Settings:
|
|||||||
# Celery configuration (internal)
|
# Celery configuration (internal)
|
||||||
# NOTE: 变量名不以 CELERY_ 开头,避免被 Celery CLI 的前缀匹配机制劫持
|
# NOTE: 变量名不以 CELERY_ 开头,避免被 Celery CLI 的前缀匹配机制劫持
|
||||||
# 详见 docs/celery-env-bug-report.md
|
# 详见 docs/celery-env-bug-report.md
|
||||||
REDIS_DB_CELERY_BROKER: int = int(os.getenv("REDIS_DB_CELERY_BROKER", "1"))
|
# 默认使用 Redis DB 3 (broker) 和 DB 4 (backend),与业务缓存 (DB 1/2) 隔离
|
||||||
REDIS_DB_CELERY_BACKEND: int = int(os.getenv("REDIS_DB_CELERY_BACKEND", "2"))
|
# 多人共用同一 Redis 时,每位开发者应在 .env 中配置不同的 DB 编号避免任务互相干扰
|
||||||
|
REDIS_DB_CELERY_BROKER: int = int(os.getenv("REDIS_DB_CELERY_BROKER", "3"))
|
||||||
|
REDIS_DB_CELERY_BACKEND: int = int(os.getenv("REDIS_DB_CELERY_BACKEND", "4"))
|
||||||
|
|
||||||
# SMTP Email Configuration
|
# SMTP Email Configuration
|
||||||
SMTP_SERVER: str = os.getenv("SMTP_SERVER", "smtp.gmail.com")
|
SMTP_SERVER: str = os.getenv("SMTP_SERVER", "smtp.gmail.com")
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class ModelConfigBase(BaseModel):
|
|||||||
load_balance_strategy: Optional[str] = Field(LoadBalanceStrategy.NONE.value, description="负载均衡策略")
|
load_balance_strategy: Optional[str] = Field(LoadBalanceStrategy.NONE.value, description="负载均衡策略")
|
||||||
capability: List[str] = Field(default_factory=list, description="模型能力列表")
|
capability: List[str] = Field(default_factory=list, description="模型能力列表")
|
||||||
is_omni: bool = Field(False, description="是否为Omni模型")
|
is_omni: bool = Field(False, description="是否为Omni模型")
|
||||||
|
model_id: Optional[uuid.UUID] = Field(None, description="基础模型ID")
|
||||||
|
|
||||||
|
|
||||||
class ApiKeyCreateNested(BaseModel):
|
class ApiKeyCreateNested(BaseModel):
|
||||||
|
|||||||
@@ -703,7 +703,7 @@ class AppService:
|
|||||||
self.db.flush()
|
self.db.flush()
|
||||||
|
|
||||||
# 如果是 agent 类型,复制 AgentConfig
|
# 如果是 agent 类型,复制 AgentConfig
|
||||||
if source_app.type == "agent":
|
if source_app.type == AppType.AGENT:
|
||||||
source_config = self.db.query(AgentConfig).filter(
|
source_config = self.db.query(AgentConfig).filter(
|
||||||
AgentConfig.app_id == source_app.id
|
AgentConfig.app_id == source_app.id
|
||||||
).first()
|
).first()
|
||||||
@@ -725,6 +725,50 @@ class AppService:
|
|||||||
)
|
)
|
||||||
self.db.add(new_config)
|
self.db.add(new_config)
|
||||||
|
|
||||||
|
elif source_app.type == AppType.WORKFLOW:
|
||||||
|
source_config = self.db.query(WorkflowConfig).filter(
|
||||||
|
WorkflowConfig.app_id == source_app.id
|
||||||
|
).first()
|
||||||
|
|
||||||
|
if source_config:
|
||||||
|
new_config = WorkflowConfig(
|
||||||
|
id=uuid.uuid4(),
|
||||||
|
app_id=new_app.id,
|
||||||
|
nodes=source_config.nodes.copy() if source_config.nodes else [],
|
||||||
|
edges=source_config.edges.copy() if source_config.edges else [],
|
||||||
|
variables=source_config.variables.copy() if source_config.variables else [],
|
||||||
|
execution_config=source_config.execution_config.copy() if source_config.execution_config else {},
|
||||||
|
triggers=source_config.triggers.copy() if source_config.triggers else [],
|
||||||
|
is_active=True,
|
||||||
|
created_at=now,
|
||||||
|
updated_at=now,
|
||||||
|
)
|
||||||
|
self.db.add(new_config)
|
||||||
|
|
||||||
|
elif source_app.type == AppType.MULTI_AGENT:
|
||||||
|
source_config = self.db.query(MultiAgentConfig).filter(
|
||||||
|
MultiAgentConfig.app_id == source_app.id
|
||||||
|
).first()
|
||||||
|
|
||||||
|
if source_config:
|
||||||
|
new_config = MultiAgentConfig(
|
||||||
|
id=uuid.uuid4(),
|
||||||
|
app_id=new_app.id,
|
||||||
|
master_agent_id=source_config.master_agent_id,
|
||||||
|
master_agent_name=source_config.master_agent_name,
|
||||||
|
default_model_config_id=source_config.default_model_config_id,
|
||||||
|
model_parameters=source_config.model_parameters,
|
||||||
|
orchestration_mode=source_config.orchestration_mode,
|
||||||
|
sub_agents=source_config.sub_agents.copy() if source_config.sub_agents else [],
|
||||||
|
routing_rules=source_config.routing_rules.copy() if source_config.routing_rules else None,
|
||||||
|
execution_config=source_config.execution_config.copy() if source_config.execution_config else {},
|
||||||
|
aggregation_strategy=source_config.aggregation_strategy,
|
||||||
|
is_active=True,
|
||||||
|
created_at=now,
|
||||||
|
updated_at=now,
|
||||||
|
)
|
||||||
|
self.db.add(new_config)
|
||||||
|
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
self.db.refresh(new_app)
|
self.db.refresh(new_app)
|
||||||
|
|
||||||
|
|||||||
@@ -780,6 +780,7 @@ class ModelBaseService:
|
|||||||
"description": model_base.description,
|
"description": model_base.description,
|
||||||
"capability": model_base.capability,
|
"capability": model_base.capability,
|
||||||
"is_omni": model_base.is_omni,
|
"is_omni": model_base.is_omni,
|
||||||
|
"is_active": False,
|
||||||
"is_composite": False
|
"is_composite": False
|
||||||
}
|
}
|
||||||
model_config = ModelConfigRepository.create(db, model_config_data)
|
model_config = ModelConfigRepository.create(db, model_config_data)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @Author: ZhaoYing
|
* @Author: ZhaoYing
|
||||||
* @Date: 2025-12-10 16:46:14
|
* @Date: 2025-12-10 16:46:14
|
||||||
* @Last Modified by: ZhaoYing
|
* @Last Modified by: ZhaoYing
|
||||||
* @Last Modified time: 2026-03-04 18:42:49
|
* @Last Modified time: 2026-03-06 13:36:20
|
||||||
*/
|
*/
|
||||||
import { type FC, useEffect, useMemo } from 'react'
|
import { type FC, useEffect, useMemo } from 'react'
|
||||||
import { Flex, Input, Form } from 'antd'
|
import { Flex, Input, Form } from 'antd'
|
||||||
@@ -50,13 +50,13 @@ const ChatInput: FC<ChatInputProps> = ({
|
|||||||
|
|
||||||
|
|
||||||
const handleDelete = (file: any) => {
|
const handleDelete = (file: any) => {
|
||||||
fileChange?.(fileList?.filter(item => item.uid !== file.uid) || [])
|
fileChange?.(fileList?.filter(item => file.url ? item.url !== file.url : item.uid !== file.uid) || [])
|
||||||
}
|
}
|
||||||
// Convert file object to preview URL
|
// Convert file object to preview URL
|
||||||
const previewFileList = useMemo(() => {
|
const previewFileList = useMemo(() => {
|
||||||
return fileList?.map(file => ({
|
return fileList?.map(file => ({
|
||||||
...file,
|
...file,
|
||||||
url: file.url || (file.originFileObj ? URL.createObjectURL(file.originFileObj) : file.thumbUrl)
|
url: file.thumbUrl || file.url || (file.originFileObj ? URL.createObjectURL(file.originFileObj) : undefined)
|
||||||
})) || []
|
})) || []
|
||||||
}, [fileList])
|
}, [fileList])
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ const ChatInput: FC<ChatInputProps> = ({
|
|||||||
{previewFileList.map((file) => {
|
{previewFileList.map((file) => {
|
||||||
if (file.type.includes('image')) {
|
if (file.type.includes('image')) {
|
||||||
return (
|
return (
|
||||||
<div key={file.uid} className="rb:inline-block rb:group rb:relative rb:rounded-lg">
|
<div key={file.url || file.uid} className="rb:inline-block rb:group rb:relative rb:rounded-lg">
|
||||||
<img src={file.url} alt={file.name} className="rb:size-12! rb:rounded-lg rb:object-cover rb:cursor-pointer" />
|
<img src={file.url} alt={file.name} className="rb:size-12! rb:rounded-lg rb:object-cover rb:cursor-pointer" />
|
||||||
<div
|
<div
|
||||||
className="rb:hidden rb:group-hover:block rb:absolute rb:-right-1 rb:-top-1 rb:size-3.5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/delete.svg')] rb:hover:bg-[url('@/assets/images/conversation/delete_hover.svg')]"
|
className="rb:hidden rb:group-hover:block rb:absolute rb:-right-1 rb:-top-1 rb:size-3.5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/delete.svg')] rb:hover:bg-[url('@/assets/images/conversation/delete_hover.svg')]"
|
||||||
@@ -83,7 +83,7 @@ const ChatInput: FC<ChatInputProps> = ({
|
|||||||
}
|
}
|
||||||
if (file.type.includes('video')) {
|
if (file.type.includes('video')) {
|
||||||
return (
|
return (
|
||||||
<div key={file.uid} className="rb:w-45 rb:h-16 rb:inline-block rb:group rb:relative rb:rounded-lg">
|
<div key={file.url || file.uid} className="rb:w-45 rb:h-16 rb:inline-block rb:group rb:relative rb:rounded-lg">
|
||||||
<video src={file.url} controls className="rb:w-45 rb:h-16 rb:rounded-lg rb:object-cover rb:cursor-pointer" />
|
<video src={file.url} controls className="rb:w-45 rb:h-16 rb:rounded-lg rb:object-cover rb:cursor-pointer" />
|
||||||
<div
|
<div
|
||||||
className="rb:hidden rb:group-hover:block rb:absolute rb:-right-1 rb:-top-1 rb:size-3.5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/delete.svg')] rb:hover:bg-[url('@/assets/images/conversation/delete_hover.svg')]"
|
className="rb:hidden rb:group-hover:block rb:absolute rb:-right-1 rb:-top-1 rb:size-3.5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/delete.svg')] rb:hover:bg-[url('@/assets/images/conversation/delete_hover.svg')]"
|
||||||
@@ -94,7 +94,7 @@ const ChatInput: FC<ChatInputProps> = ({
|
|||||||
}
|
}
|
||||||
if (file.type.includes('audio')) {
|
if (file.type.includes('audio')) {
|
||||||
return (
|
return (
|
||||||
<div key={file.uid} className="rb:w-45 rb:h-16 rb:inline-flex rb:items-center rb:group rb:relative rb:rounded-lg rb:bg-[#F0F3F8] rb:py-2 rb:px-2.5 rb:gap-2">
|
<div key={file.url || file.uid} className="rb:w-45 rb:h-16 rb:inline-flex rb:items-center rb:group rb:relative rb:rounded-lg rb:bg-[#F0F3F8] rb:py-2 rb:px-2.5 rb:gap-2">
|
||||||
<audio src={file.url} controls className="rb:w-45 rb:h-16" />
|
<audio src={file.url} controls className="rb:w-45 rb:h-16" />
|
||||||
<div
|
<div
|
||||||
className="rb:hidden rb:group-hover:block rb:absolute rb:-right-1 rb:-top-1 rb:size-3.5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/delete.svg')] rb:hover:bg-[url('@/assets/images/conversation/delete_hover.svg')]"
|
className="rb:hidden rb:group-hover:block rb:absolute rb:-right-1 rb:-top-1 rb:size-3.5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/delete.svg')] rb:hover:bg-[url('@/assets/images/conversation/delete_hover.svg')]"
|
||||||
@@ -104,7 +104,7 @@ const ChatInput: FC<ChatInputProps> = ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div key={file.uid} className="rb:w-45 rb:text-[12px] rb:gap-2.5 rb:flex rb:items-center rb:group rb:relative rb:rounded-lg rb:bg-[#F0F3F8] rb:py-2 rb:px-2.5">
|
<div key={file.url || file.uid} className="rb:w-45 rb:text-[12px] rb:gap-2.5 rb:flex rb:items-center rb:group rb:relative rb:rounded-lg rb:bg-[#F0F3F8] rb:py-2 rb:px-2.5">
|
||||||
{(file.type.includes('doc') || file.type.includes('docx') || file.type.includes('word') || file.type.includes('wordprocessingml.document')) && <div
|
{(file.type.includes('doc') || file.type.includes('docx') || file.type.includes('word') || file.type.includes('wordprocessingml.document')) && <div
|
||||||
className="rb:size-5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/word_disabled.svg')] rb:hover:bg-[url('@/assets/images/conversation/word.svg')]"
|
className="rb:size-5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/conversation/word_disabled.svg')] rb:hover:bg-[url('@/assets/images/conversation/word.svg')]"
|
||||||
></div>}
|
></div>}
|
||||||
|
|||||||
@@ -1572,7 +1572,7 @@ export const en = {
|
|||||||
intelligentSemanticPruningFunction: 'Intelligent Semantic Pruning Function',
|
intelligentSemanticPruningFunction: 'Intelligent Semantic Pruning Function',
|
||||||
intelligentSemanticPruningFunctionDesc: 'Whether to activate intelligent semantic pruning (true/false).',
|
intelligentSemanticPruningFunctionDesc: 'Whether to activate intelligent semantic pruning (true/false).',
|
||||||
intelligentSemanticPruningScene: 'Intelligent Semantic Pruning Scene',
|
intelligentSemanticPruningScene: 'Intelligent Semantic Pruning Scene',
|
||||||
intelligentSemanticPruningSceneDesc: 'Select intelligent semantic pruning scene (education, online_service, outbound).',
|
intelligentSemanticPruningSceneDesc: 'Semantic pruning scenarios are consistent with ontology engineering scenarios',
|
||||||
intelligentSemanticPruningThreshold: 'Intelligent Semantic Pruning Threshold',
|
intelligentSemanticPruningThreshold: 'Intelligent Semantic Pruning Threshold',
|
||||||
intelligentSemanticPruningThresholdDesc: 'Set intelligent semantic pruning threshold (0-0.9).',
|
intelligentSemanticPruningThresholdDesc: 'Set intelligent semantic pruning threshold (0-0.9).',
|
||||||
reflectionEngine: 'Self-Reflexion Engine',
|
reflectionEngine: 'Self-Reflexion Engine',
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ export const zh = {
|
|||||||
createMemorySummary: '创建记忆摘要',
|
createMemorySummary: '创建记忆摘要',
|
||||||
memoryManagement: '记忆管理',
|
memoryManagement: '记忆管理',
|
||||||
spaceManagement: '空间管理',
|
spaceManagement: '空间管理',
|
||||||
memoryExtractionEngine: '记忆提取引擎',
|
memoryExtractionEngine: '记忆萃取引擎',
|
||||||
forgettingEngine: '遗忘引擎',
|
forgettingEngine: '遗忘引擎',
|
||||||
apiKeyManagement: 'API KEY管理',
|
apiKeyManagement: 'API KEY管理',
|
||||||
knowledgePrivate: '详情',
|
knowledgePrivate: '详情',
|
||||||
@@ -1283,7 +1283,7 @@ export const zh = {
|
|||||||
createConfiguration: '创建配置',
|
createConfiguration: '创建配置',
|
||||||
editConfiguration: '编辑配置',
|
editConfiguration: '编辑配置',
|
||||||
desc: '描述',
|
desc: '描述',
|
||||||
memoryExtractionEngine: '记忆提取引擎',
|
memoryExtractionEngine: '记忆萃取引擎',
|
||||||
forgottenEngine: '遗忘引擎',
|
forgottenEngine: '遗忘引擎',
|
||||||
active: '活跃',
|
active: '活跃',
|
||||||
inactive: '不活跃',
|
inactive: '不活跃',
|
||||||
@@ -1571,7 +1571,7 @@ export const zh = {
|
|||||||
intelligentSemanticPruningFunction: '智能语义修剪功能',
|
intelligentSemanticPruningFunction: '智能语义修剪功能',
|
||||||
intelligentSemanticPruningFunctionDesc: '是否激活智能语义修剪(true/false)。',
|
intelligentSemanticPruningFunctionDesc: '是否激活智能语义修剪(true/false)。',
|
||||||
intelligentSemanticPruningScene: '智能语义修剪场景',
|
intelligentSemanticPruningScene: '智能语义修剪场景',
|
||||||
intelligentSemanticPruningSceneDesc: '选择智能语义修剪场景(education、online_service、outbound)。',
|
intelligentSemanticPruningSceneDesc: '语义剪枝场景与本体工程场景一致',
|
||||||
intelligentSemanticPruningThreshold: '智能语义修剪阈值',
|
intelligentSemanticPruningThreshold: '智能语义修剪阈值',
|
||||||
intelligentSemanticPruningThresholdDesc: '设置智能语义修剪阈值(0-0.9)。',
|
intelligentSemanticPruningThresholdDesc: '设置智能语义修剪阈值(0-0.9)。',
|
||||||
reflectionEngine: '自我反思引擎',
|
reflectionEngine: '自我反思引擎',
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @Author: ZhaoYing
|
* @Author: ZhaoYing
|
||||||
* @Date: 2026-02-28 14:08:14
|
* @Date: 2026-02-28 14:08:14
|
||||||
* @Last Modified by: ZhaoYing
|
* @Last Modified by: ZhaoYing
|
||||||
* @Last Modified time: 2026-03-02 17:39:49
|
* @Last Modified time: 2026-03-06 12:05:46
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* UploadWorkflowModal Component
|
* UploadWorkflowModal Component
|
||||||
@@ -101,6 +101,7 @@ const UploadWorkflowModal = forwardRef<UploadWorkflowModalRef, UploadWorkflowMod
|
|||||||
formData.append('platform', values.platform);
|
formData.append('platform', values.platform);
|
||||||
formData.append('file', values.file[0]);
|
formData.append('file', values.file[0]);
|
||||||
|
|
||||||
|
setLoading(true)
|
||||||
// Call import workflow API
|
// Call import workflow API
|
||||||
importWorkflow(formData)
|
importWorkflow(formData)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
@@ -114,21 +115,24 @@ const UploadWorkflowModal = forwardRef<UploadWorkflowModalRef, UploadWorkflowMod
|
|||||||
} else {
|
} else {
|
||||||
setCurrent(2);
|
setCurrent(2);
|
||||||
// Pre-fill form with file information
|
// Pre-fill form with file information
|
||||||
|
const fileNameSplit = values.file[0].name.split('.')
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
name: values.file[0].name.split('.')[0],
|
name: fileNameSplit.slice(0, fileNameSplit.length - 1).join('.'),
|
||||||
platform: values.platform,
|
platform: values.platform,
|
||||||
fileName: values.file[0].name,
|
fileName: values.file[0].name,
|
||||||
fileSize: values.file[0].size,
|
fileSize: values.file[0].size,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
.finally(() => setLoading(false));
|
||||||
break;
|
break;
|
||||||
case 1: // Step 2: Error/warning display
|
case 1: // Step 2: Error/warning display
|
||||||
if (firstFormData) {
|
if (firstFormData) {
|
||||||
const { file, platform } = firstFormData;
|
const { file, platform } = firstFormData;
|
||||||
|
const fileNameSplit = firstFormData.file[0].name.split('.')
|
||||||
// Pre-fill form with file information
|
// Pre-fill form with file information
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
name: file[0].name.split('.')[0],
|
name: fileNameSplit.slice(0, fileNameSplit.length - 1).join('.'),
|
||||||
platform: platform,
|
platform: platform,
|
||||||
fileName: file[0].name,
|
fileName: file[0].name,
|
||||||
fileSize: file[0].size,
|
fileSize: file[0].size,
|
||||||
@@ -175,7 +179,9 @@ const UploadWorkflowModal = forwardRef<UploadWorkflowModalRef, UploadWorkflowMod
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reset form if not going back to error/warning step
|
// Reset form if not going back to error/warning step
|
||||||
if (newStep !== 1) {
|
if (newStep === 0) {
|
||||||
|
form.setFieldsValue(firstFormData || {})
|
||||||
|
} else if (newStep !== 1) {
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
}
|
}
|
||||||
setCurrent(newStep);
|
setCurrent(newStep);
|
||||||
@@ -186,14 +192,16 @@ const UploadWorkflowModal = forwardRef<UploadWorkflowModalRef, UploadWorkflowMod
|
|||||||
* @param {string} type - Navigation type ('detail' or 'list')
|
* @param {string} type - Navigation type ('detail' or 'list')
|
||||||
*/
|
*/
|
||||||
const handleJump = (type: string) => {
|
const handleJump = (type: string) => {
|
||||||
switch(type) {
|
|
||||||
case 'detail':
|
|
||||||
// Open application detail page in new tab
|
|
||||||
window.open(`/#/application/config/${appId}`, '_blank');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
refresh();
|
|
||||||
handleClose();
|
handleClose();
|
||||||
|
refresh();
|
||||||
|
setTimeout(() => {
|
||||||
|
switch (type) {
|
||||||
|
case 'detail':
|
||||||
|
// Open application detail page in new tab
|
||||||
|
window.open(`/#/application/config/${appId}`, '_blank');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -350,7 +358,7 @@ const UploadWorkflowModal = forwardRef<UploadWorkflowModalRef, UploadWorkflowMod
|
|||||||
title={t('application.importSuccess')}
|
title={t('application.importSuccess')}
|
||||||
subTitle={t('application.importSuccessDesc')}
|
subTitle={t('application.importSuccessDesc')}
|
||||||
extra={[
|
extra={[
|
||||||
<Button key="back" onClick={() => handleJump('list')}>
|
<Button key="back" onClick={() => handleJump('list')}>
|
||||||
{t('application.gotoList')}
|
{t('application.gotoList')}
|
||||||
</Button>,
|
</Button>,
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @Author: ZhaoYing
|
* @Author: ZhaoYing
|
||||||
* @Date: 2026-02-06 21:09:42
|
* @Date: 2026-02-06 21:09:42
|
||||||
* @Last Modified by: ZhaoYing
|
* @Last Modified by: ZhaoYing
|
||||||
* @Last Modified time: 2026-03-05 15:09:22
|
* @Last Modified time: 2026-03-06 12:20:43
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* File Upload Component
|
* File Upload Component
|
||||||
@@ -208,6 +208,7 @@ const UploadFiles = forwardRef<UploadFilesRef, UploadFilesProps>(({
|
|||||||
newFileList.map(file => {
|
newFileList.map(file => {
|
||||||
const type = (file.type && transform_file_type[file.type as keyof typeof transform_file_type]) || file.type || 'document'
|
const type = (file.type && transform_file_type[file.type as keyof typeof transform_file_type]) || file.type || 'document'
|
||||||
file.type = type
|
file.type = type
|
||||||
|
file.thumbUrl = file.thumbUrl || URL.createObjectURL(file.originFileObj as Blob)
|
||||||
})
|
})
|
||||||
setFileList(newFileList);
|
setFileList(newFileList);
|
||||||
if (onChange) {
|
if (onChange) {
|
||||||
|
|||||||
@@ -672,9 +672,17 @@ const CreateModal = forwardRef<CreateModalRef, CreateModalRefProps>(({
|
|||||||
{currentType !== 'Folder' && dynamicTypeList.map((tp) => {
|
{currentType !== 'Folder' && dynamicTypeList.map((tp) => {
|
||||||
const fieldKey = typeToFieldKey(tp);
|
const fieldKey = typeToFieldKey(tp);
|
||||||
// When tp is 'llm', merge llm and chat options
|
// When tp is 'llm', merge llm and chat options
|
||||||
const options = tp.toLowerCase() === 'llm' || tp.toLowerCase() === 'image2text'
|
let options = tp.toLowerCase() === 'llm' || tp.toLowerCase() === 'image2text'
|
||||||
? [...(modelOptionsByType['llm'] || []), ...(modelOptionsByType['chat'] || [])]
|
? [...(modelOptionsByType['llm'] || []), ...(modelOptionsByType['chat'] || [])]
|
||||||
: modelOptionsByType[tp] || [];
|
: modelOptionsByType[tp] || [];
|
||||||
|
|
||||||
|
// When tp is 'image2text', filter to only include models with 'vision' capability
|
||||||
|
if (tp.toLowerCase() === 'image2text') {
|
||||||
|
options = options.filter((opt: any) => {
|
||||||
|
const model = models?.items?.find((m: any) => m.id === opt.value);
|
||||||
|
return model?.capability?.includes('vision');
|
||||||
|
});
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Form.Item
|
<Form.Item
|
||||||
key={tp}
|
key={tp}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @Author: ZhaoYing
|
* @Author: ZhaoYing
|
||||||
* @Date: 2026-02-03 17:30:06
|
* @Date: 2026-02-03 17:30:06
|
||||||
* @Last Modified by: ZhaoYing
|
* @Last Modified by: ZhaoYing
|
||||||
* @Last Modified time: 2026-02-04 10:09:45
|
* @Last Modified time: 2026-03-06 13:49:00
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Memory Extraction Engine Configuration Constants
|
* Memory Extraction Engine Configuration Constants
|
||||||
@@ -140,13 +140,8 @@ export const configList: ConfigVo[] = [
|
|||||||
{
|
{
|
||||||
label: 'intelligentSemanticPruningScene',
|
label: 'intelligentSemanticPruningScene',
|
||||||
variableName: 'pruning_scene',
|
variableName: 'pruning_scene',
|
||||||
control: 'select',
|
control: 'text',
|
||||||
type: 'enum',
|
type: 'enum',
|
||||||
options: [
|
|
||||||
{ label: 'education', value: 'education' },
|
|
||||||
{ label: 'online_service', value: 'online_service' },
|
|
||||||
{ label: 'outbound', value: 'outbound' },
|
|
||||||
],
|
|
||||||
meaning: 'intelligentSemanticPruningSceneDesc',
|
meaning: 'intelligentSemanticPruningSceneDesc',
|
||||||
},
|
},
|
||||||
// Intelligent semantic pruning阈值
|
// Intelligent semantic pruning阈值
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* @Author: ZhaoYing
|
* @Author: ZhaoYing
|
||||||
* @Date: 2026-02-03 17:30:02
|
* @Date: 2026-02-03 17:30:02
|
||||||
* @Last Modified by: ZhaoYing
|
* @Last Modified by: ZhaoYing
|
||||||
* @Last Modified time: 2026-02-03 17:30:02
|
* @Last Modified time: 2026-03-06 13:50:05
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Memory Extraction Engine Configuration Page
|
* Memory Extraction Engine Configuration Page
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
import { type FC, useState, useEffect } from 'react'
|
import { type FC, useState, useEffect } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useParams } from 'react-router-dom'
|
import { useParams } from 'react-router-dom'
|
||||||
import { Row, Col, Space, Select, InputNumber, Slider, App, Form } from 'antd'
|
import { Row, Col, Space, Select, InputNumber, Slider, App, Form, Input } from 'antd'
|
||||||
import clsx from 'clsx'
|
import clsx from 'clsx'
|
||||||
|
|
||||||
import Card from './components/Card'
|
import Card from './components/Card'
|
||||||
@@ -35,15 +35,15 @@ const keys = [
|
|||||||
/**
|
/**
|
||||||
* Configuration description component
|
* Configuration description component
|
||||||
*/
|
*/
|
||||||
const ConfigDesc: FC<{ config: Variable, className?: string }> = ({config, className}) => {
|
const ConfigDesc: FC<{ config: Variable, className?: string; onlyMeaning?: boolean; }> = ({ config, className, onlyMeaning = false}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
<Space size={8} className={clsx("rb:mt-1 rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-4 ")}>
|
{!onlyMeaning && <Space size={8} className={clsx("rb:mt-1 rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-4 ")}>
|
||||||
{config.variableName && <span className="rb:font-regular">{t('memoryExtractionEngine.variableName')}: {config.variableName}</span>}
|
{config.variableName && <span className="rb:font-regular">{t('memoryExtractionEngine.variableName')}: {config.variableName}</span>}
|
||||||
{config.control && <span className="rb:font-regular">{t('memoryExtractionEngine.control')}: {t(`memoryExtractionEngine.${config.control}`)}</span>}
|
{config.control && <span className="rb:font-regular">{t('memoryExtractionEngine.control')}: {t(`memoryExtractionEngine.${config.control}`)}</span>}
|
||||||
{config.type && <span className="rb:font-regular">{t('memoryExtractionEngine.type')}: {config.type}</span>}
|
{config.type && <span className="rb:font-regular">{t('memoryExtractionEngine.type')}: {config.type}</span>}
|
||||||
</Space>
|
</Space>}
|
||||||
{config.meaning && <div className={clsx("rb:mt-1 rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-4 ")}>{t('memoryExtractionEngine.Meaning')}: {t(`memoryExtractionEngine.${config.meaning}`)}</div>}
|
{config.meaning && <div className={clsx("rb:mt-1 rb:text-[12px] rb:text-[#5B6167] rb:font-regular rb:leading-4 ")}>{t('memoryExtractionEngine.Meaning')}: {t(`memoryExtractionEngine.${config.meaning}`)}</div>}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@@ -253,6 +253,21 @@ const MemoryExtractionEngine: FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
{config.control === 'text' &&
|
||||||
|
<>
|
||||||
|
<div className="rb:text-[14px] rb:font-medium rb:leading-5 rb:mt-6 rb:mb-2">
|
||||||
|
-{t(`memoryExtractionEngine.${config.label}`)}
|
||||||
|
</div>
|
||||||
|
<div className="rb:pl-2">
|
||||||
|
<Form.Item
|
||||||
|
name={config.variableName}
|
||||||
|
>
|
||||||
|
<Input placeholder={t('common.pleaseEnter')} disabled />
|
||||||
|
</Form.Item>
|
||||||
|
<ConfigDesc config={config} onlyMeaning={true} className="rb:-mt-4!" />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @Author: ZhaoYing
|
* @Author: ZhaoYing
|
||||||
* @Date: 2026-02-03 17:33:15
|
* @Date: 2026-02-03 17:33:15
|
||||||
* @Last Modified by: ZhaoYing
|
* @Last Modified by: ZhaoYing
|
||||||
* @Last Modified time: 2026-03-05 16:28:58
|
* @Last Modified time: 2026-03-06 13:53:53
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Memory Management Page
|
* Memory Management Page
|
||||||
@@ -154,10 +154,10 @@ const MemoryManagement: React.FC = () => {
|
|||||||
className="rb:w-5 rb:h-5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/edit.svg')] rb:hover:bg-[url('@/assets/images/edit_hover.svg')]"
|
className="rb:w-5 rb:h-5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/edit.svg')] rb:hover:bg-[url('@/assets/images/edit_hover.svg')]"
|
||||||
onClick={() => handleEdit(item)}
|
onClick={() => handleEdit(item)}
|
||||||
></div>
|
></div>
|
||||||
<div
|
{!item.is_system_default && <div
|
||||||
className="rb:w-5 rb:h-5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/delete.svg')] rb:hover:bg-[url('@/assets/images/delete_hover.svg')]"
|
className="rb:w-5 rb:h-5 rb:cursor-pointer rb:bg-cover rb:bg-[url('@/assets/images/delete.svg')] rb:hover:bg-[url('@/assets/images/delete_hover.svg')]"
|
||||||
onClick={() => handleDelete(item)}
|
onClick={() => handleDelete(item)}
|
||||||
></div>
|
></div>}
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
</RbCard>
|
</RbCard>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @Author: ZhaoYing
|
* @Author: ZhaoYing
|
||||||
* @Date: 2026-02-03 16:49:45
|
* @Date: 2026-02-03 16:49:45
|
||||||
* @Last Modified by: ZhaoYing
|
* @Last Modified by: ZhaoYing
|
||||||
* @Last Modified time: 2026-03-04 11:50:47
|
* @Last Modified time: 2026-03-06 12:26:12
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Model List Detail Drawer
|
* Model List Detail Drawer
|
||||||
@@ -153,7 +153,7 @@ const ModelListDetail = forwardRef<ModelListDetailRef, ModelListDetailProps>(({
|
|||||||
<div className="rb:absolute rb:bottom-4 rb:left-6 rb:right-6">
|
<div className="rb:absolute rb:bottom-4 rb:left-6 rb:right-6">
|
||||||
<Row gutter={12}>
|
<Row gutter={12}>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Button block onClick={() => handleEdit(item)}>{t('modelNew.modelConfiguration')}</Button>
|
{!item.model_id && <Button block onClick={() => handleEdit(item)}>{t('modelNew.modelConfiguration')}</Button>}
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Button type="primary" ghost block onClick={() => handleKeyConfig(item)}>{t('modelNew.keyConfig')}</Button>
|
<Button type="primary" ghost block onClick={() => handleKeyConfig(item)}>{t('modelNew.keyConfig')}</Button>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* @Author: ZhaoYing
|
* @Author: ZhaoYing
|
||||||
* @Date: 2026-02-03 16:50:18
|
* @Date: 2026-02-03 16:50:18
|
||||||
* @Last Modified by: ZhaoYing
|
* @Last Modified by: ZhaoYing
|
||||||
* @Last Modified time: 2026-03-04 11:39:20
|
* @Last Modified time: 2026-03-06 12:26:11
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Type definitions for Model Management
|
* Type definitions for Model Management
|
||||||
@@ -121,6 +121,7 @@ export interface ModelApiKey {
|
|||||||
* Model list item data structure
|
* Model list item data structure
|
||||||
*/
|
*/
|
||||||
export interface ModelListItem {
|
export interface ModelListItem {
|
||||||
|
model_id?: string;
|
||||||
/** Model name */
|
/** Model name */
|
||||||
model_name?: string;
|
model_name?: string;
|
||||||
/** Associated model config IDs */
|
/** Associated model config IDs */
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ const Detail: FC = () => {
|
|||||||
<Tag color="warning">{t('common.default')}</Tag>
|
<Tag color="warning">{t('common.default')}</Tag>
|
||||||
</Space>}
|
</Space>}
|
||||||
subTitle={<Tooltip title={data.scene_description}><div className="rb:h-4 rb:text-ellipsis rb:overflow-hidden rb:whitespace-nowrap">{data.scene_description}</div></Tooltip>}
|
subTitle={<Tooltip title={data.scene_description}><div className="rb:h-4 rb:text-ellipsis rb:overflow-hidden rb:whitespace-nowrap">{data.scene_description}</div></Tooltip>}
|
||||||
extra={data.is_system_default ? undefined : (<Space>
|
extra={!data.is_system_default ? undefined : (<Space>
|
||||||
<Button type="primary" ghost className="rb:h-6! rb:px-2! rb:leading-5.5!" onClick={handleAdd}>+ {t('ontology.addClass')}</Button>
|
<Button type="primary" ghost className="rb:h-6! rb:px-2! rb:leading-5.5!" onClick={handleAdd}>+ {t('ontology.addClass')}</Button>
|
||||||
<Button className="rb:h-6! rb:px-2! rb:leading-5.5!" type="primary" onClick={handleExtract}>+ {t('ontology.extract')}</Button>
|
<Button className="rb:h-6! rb:px-2! rb:leading-5.5!" type="primary" onClick={handleExtract}>+ {t('ontology.extract')}</Button>
|
||||||
</Space>)}
|
</Space>)}
|
||||||
|
|||||||
Reference in New Issue
Block a user