Skip to content

Commit f63ed18

Browse files
committed
feat: Support internal functionlib
--story=1017939 --user=刘瑞斌 【函数库】- 支持 系统内置函数 https://www.tapd.cn/57709429/s/1665943
1 parent 1414cdc commit f63ed18

File tree

28 files changed

+557
-88
lines changed

28 files changed

+557
-88
lines changed

apps/application/flow/step_node/function_lib_node/impl/base_function_lib_node.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from application.flow.step_node.function_lib_node.i_function_lib_node import IFunctionLibNode
1717
from common.exception.app_exception import AppApiException
1818
from common.util.function_code import FunctionExecutor
19+
from common.util.rsa_util import rsa_long_decrypt
1920
from function_lib.models.function import FunctionLib
2021
from smartdoc.const import CONFIG
2122

@@ -107,8 +108,11 @@ def execute(self, function_lib_id, input_field_list, **kwargs) -> NodeResult:
107108
), **field}
108109
for field in
109110
function_lib.input_field_list]}
111+
110112
self.context['params'] = params
111-
result = function_executor.exec_code(function_lib.code, params)
113+
# 合并初始化参数
114+
all_params = json.loads(rsa_long_decrypt(function_lib.init_params)) | params
115+
result = function_executor.exec_code(function_lib.code, all_params)
112116
return NodeResult({'result': result}, {}, _write_context=write_context)
113117

114118
def get_details(self, index: int, **kwargs):

apps/application/serializers/application_serializers.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
from dataset.models import DataSet, Document, Image
4646
from dataset.serializers.common_serializers import list_paragraph, get_embedding_model_by_dataset_id_list
4747
from embedding.models import SearchMode
48-
from function_lib.models.function import FunctionLib, PermissionType
48+
from function_lib.models.function import FunctionLib, PermissionType, FunctionType
4949
from function_lib.serializers.function_lib_serializer import FunctionLibSerializer, FunctionLibModelSerializer
5050
from setting.models import AuthOperate, TeamMemberPermission
5151
from setting.models.model_management import Model
@@ -810,8 +810,10 @@ def list_function_lib(self, with_valid=True):
810810
if with_valid:
811811
self.is_valid(raise_exception=True)
812812
application = QuerySet(Application).filter(id=self.data.get("application_id")).first()
813-
return FunctionLibSerializer.Query(data={'user_id': application.user_id, 'is_active': True}).list(
814-
with_valid=True)
813+
return FunctionLibSerializer.Query(
814+
data={'user_id': application.user_id, 'is_active': True,
815+
'function_type': FunctionType.PUBLIC}
816+
).list(with_valid=True)
815817

816818
def get_function_lib(self, function_lib_id, with_valid=True):
817819
if with_valid:
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Generated by Django 4.2.15 on 2025-03-13 07:21
2+
3+
from django.db import migrations, models
4+
5+
function_template = '''
6+
INSERT INTO function_lib (create_time, update_time, id, name, "desc", code, input_field_list, user_id, is_active, permission_type, function_type, icon, init_field_list, init_params, template_id) VALUES ('2025-03-10 06:20:35.945414 +00:00', '2025-03-10 09:19:23.608026 +00:00', 'c75cb48e-fd77-11ef-84d2-5618c4394482', '博查AI', '从博查搜索任何信息和网页URL', e'def bocha_search(query, apikey):
7+
import requests
8+
import json
9+
url = "https://api.bochaai.com/v1/web-search"
10+
payload = json.dumps({
11+
"query": query,
12+
"Boolean": "true",
13+
"count": 8
14+
})
15+
16+
headers = {
17+
"Authorization": "Bearer " + apikey, #鉴权参数,示例:Bearer xxxxxx,API KEY请先前往博查AI开放平台(https://open.bochaai.com)> API KEY 管理中获取。
18+
"Content-Type": "application/json"
19+
}
20+
21+
response = requests.request("POST", url, headers=headers, data=payload)
22+
if response.status_code == 200:
23+
return response.json()
24+
else:
25+
raise Exception(f"API请求失败: {response.status_code}, 错误信息: {response.text}")
26+
return (response.text)', '{"{\\"name\\": \\"query\\", \\"type\\": \\"string\\", \\"source\\": \\"reference\\", \\"is_required\\": true}"}', 'f0dd8f71-e4ee-11ee-8c84-a8a1595801ab', TRUE, 'PUBLIC', 'INTERNAL', '/src/assets/fx/bochaai/icon.png', '[{"attrs": {"type": "password", "maxlength": 200, "minlength": 1, "show-password": true, "show-word-limit": true}, "field": "apikey", "label": "apikey", "required": true, "input_type": "PasswordInput", "props_info": {"rules": [{"message": "apikey 为必填属性", "required": true}, {"max": 200, "min": 1, "message": "apikey长度在 1 到 200 个字符", "trigger": "blur"}]}, "default_value": "x", "show_default_value": false}]', '', NULL);
27+
INSERT INTO function_lib (create_time, update_time, id, name, "desc", code, input_field_list, user_id, is_active, permission_type, function_type, icon, init_field_list, init_params, template_id) VALUES ('2025-02-26 03:36:48.187286 +00:00', '2025-03-11 07:23:46.123972 +00:00', 'e89ad2ae-f3f2-11ef-ad09-0242ac110002', 'Google Search', 'Google Web Search', e'def google_search(query, apikey, cx):
28+
import requests
29+
import json
30+
url = "https://customsearch.googleapis.com/customsearch/v1"
31+
params = {
32+
"q": query,
33+
"key": apikey,
34+
"cx": cx,
35+
"num": 10, # 每次最多返回10条
36+
}
37+
38+
response = requests.get(url, params=params)
39+
if response.status_code == 200:
40+
return response.json()
41+
else:
42+
raise Exception(f"API请求失败: {response.status_code}, 错误信息: {response.text}")
43+
return (response.text)', '{"{\\"name\\": \\"query\\", \\"type\\": \\"string\\", \\"source\\": \\"reference\\", \\"is_required\\": true}"}', 'f0dd8f71-e4ee-11ee-8c84-a8a1595801ab', TRUE, 'PUBLIC', 'INTERNAL', '/src/assets/fx/google_search/icon.png', '[{"attrs": {"type": "password", "maxlength": 200, "minlength": 1, "show-password": true, "show-word-limit": true}, "field": "apikey", "label": "apikey", "required": true, "input_type": "PasswordInput", "props_info": {"rules": [{"message": "apikey 为必填属性", "required": true}, {"max": 200, "min": 1, "message": "apikey长度在 1 到 200 个字符", "trigger": "blur"}]}, "default_value": "x", "show_default_value": false}, {"attrs": {"maxlength": 200, "minlength": 1, "show-word-limit": true}, "field": "cx", "label": "cx", "required": true, "input_type": "TextInput", "props_info": {"rules": [{"message": "cx 为必填属性", "required": true}, {"max": 200, "min": 1, "message": "cx长度在 1 到 200 个字符", "trigger": "blur"}]}, "default_value": "x", "show_default_value": false}]', '', NULL);
44+
INSERT INTO function_lib (create_time, update_time, id, name, "desc", code, input_field_list, user_id, is_active, permission_type, function_type, icon, init_field_list, init_params, template_id) VALUES ('2025-02-25 07:44:40.141515 +00:00', '2025-03-11 06:33:53.248495 +00:00', '5e912f00-f34c-11ef-8a9c-5618c4394482', 'LangSearch API', e'A Web Search API supporting natural language search
45+
', e'
46+
def langsearch(query, apikey):
47+
import json
48+
import requests
49+
50+
url = "https://api.langsearch.com/v1/web-search"
51+
payload = json.dumps({
52+
"query": query,
53+
"summary": True,
54+
"freshness": "noLimit",
55+
"livecrawl": True,
56+
"count": 20
57+
})
58+
headers = {
59+
"Authorization": apikey,
60+
"Content-Type": "application/json"
61+
}
62+
# key从官网申请 https://langsearch.com/
63+
response = requests.request("POST", url, headers=headers, data=payload)
64+
if response.status_code == 200:
65+
return response.json()
66+
else:
67+
raise Exception(f"API请求失败: {response.status_code}, 错误信息: {response.text}")
68+
return (response.text)', '{"{\\"name\\": \\"query\\", \\"type\\": \\"string\\", \\"source\\": \\"reference\\", \\"is_required\\": true}"}', 'f0dd8f71-e4ee-11ee-8c84-a8a1595801ab', TRUE, 'PUBLIC', 'INTERNAL', '/src/assets/fx/langsearch/icon.png', '[{"attrs": {"type": "password", "maxlength": 200, "minlength": 1, "show-password": true, "show-word-limit": true}, "field": "apikey", "label": "apikey", "required": true, "input_type": "PasswordInput", "props_info": {"rules": [{"message": "apikey 为必填属性", "required": true}, {"max": 200, "min": 1, "message": "apikey长度在 1 到 200 个字符", "trigger": "blur"}]}, "default_value": "x", "show_default_value": false}]', '', NULL);
69+
70+
'''
71+
72+
73+
class Migration(migrations.Migration):
74+
dependencies = [
75+
('function_lib', '0002_functionlib_is_active_functionlib_permission_type'),
76+
]
77+
78+
operations = [
79+
migrations.AddField(
80+
model_name='functionlib',
81+
name='function_type',
82+
field=models.CharField(choices=[('INTERNAL', '内置'), ('PUBLIC', '公开')],
83+
default='PUBLIC', max_length=20, verbose_name='函数类型'),
84+
),
85+
migrations.AddField(
86+
model_name='functionlib',
87+
name='icon',
88+
field=models.CharField(default='/ui/favicon.ico', max_length=256,
89+
verbose_name='函数库icon'),
90+
),
91+
migrations.AddField(
92+
model_name='functionlib',
93+
name='init_field_list',
94+
field=models.JSONField(default=list, verbose_name='启动字段列表'),
95+
),
96+
migrations.AddField(
97+
model_name='functionlib',
98+
name='init_params',
99+
field=models.CharField(max_length=102400, null=True, verbose_name='初始化参数'),
100+
),
101+
migrations.AddField(
102+
model_name='functionlib',
103+
name='template_id',
104+
field=models.UUIDField(default=None, null=True, verbose_name='模版id'),
105+
),
106+
migrations.RunSQL(function_template)
107+
]

apps/function_lib/migrations/0003_functionlib_icon_functionlib_init_field_list.py

Lines changed: 0 additions & 23 deletions
This file was deleted.

apps/function_lib/models/function.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ class PermissionType(models.TextChoices):
1919
PUBLIC = "PUBLIC", '公开'
2020
PRIVATE = "PRIVATE", "私有"
2121

22+
class FunctionType(models.TextChoices):
23+
INTERNAL = "INTERNAL", '内置'
24+
PUBLIC = "PUBLIC", "公开"
25+
2226

2327
class FunctionLib(AppModelMixin):
2428
id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid1, editable=False, verbose_name="主键id")
@@ -34,6 +38,10 @@ class FunctionLib(AppModelMixin):
3438
is_active = models.BooleanField(default=True)
3539
permission_type = models.CharField(max_length=20, verbose_name='权限类型', choices=PermissionType.choices,
3640
default=PermissionType.PRIVATE)
41+
function_type = models.CharField(max_length=20, verbose_name='函数类型', choices=FunctionType.choices,
42+
default=FunctionType.PUBLIC)
43+
template_id = models.UUIDField(max_length=128, verbose_name="模版id", null=True, default=None)
44+
init_params = models.CharField(max_length=102400, verbose_name="初始化参数", null=True)
3745

3846
class Meta:
3947
db_table = "function_lib"
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# coding=utf-8
2+
"""
3+
@project: MaxKB
4+
@Author:虎
5+
@file: __init__.py.py
6+
@date:2024/8/2 14:55
7+
@desc:
8+
"""

0 commit comments

Comments
 (0)