Skip to content

Commit 6812559

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

File tree

27 files changed

+505
-63
lines changed

27 files changed

+505
-63
lines changed

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

Lines changed: 8 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,14 @@ def execute(self, function_lib_id, input_field_list, **kwargs) -> NodeResult:
107108
), **field}
108109
for field in
109110
function_lib.input_field_list]}
111+
init_field_list = json.loads(rsa_long_decrypt(function_lib.init_field_list))
112+
init_params = {field.get('field'): field.get('value') if field.get('value',
113+
None) is not None else field.get(
114+
'default_value') for field in init_field_list}
110115
self.context['params'] = params
111-
result = function_executor.exec_code(function_lib.code, params)
116+
# 合并初始化参数
117+
all_params = init_params | params
118+
result = function_executor.exec_code(function_lib.code, all_params)
112119
return NodeResult({'result': result}, {}, _write_context=write_context)
113120

114121
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: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# Generated by Django 4.2.15 on 2025-03-13 02:56
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, 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):
7+
import requests
8+
import json
9+
url = "https://customsearch.googleapis.com/customsearch/v1"
10+
params = {
11+
"q": query,
12+
"key": apikey,
13+
"cx": cx,
14+
"num": 10, # 每次最多返回10条
15+
}
16+
17+
response = requests.get(url, params=params)
18+
if response.status_code == 200:
19+
contexts = response.json()[\'items\']
20+
max_context = min(len(contexts), 10)
21+
format_contexts = []
22+
for i in range(max_context):
23+
formatted_context = f"[[引用:{i + 1}]]\\n网页标题:{contexts[i][\'title\']}\\n网页链接:{contexts[i][\'link\']}\\n网页内容:{contexts[i][\'snippet\']}\\n网站名称:{contexts[i][\'displayLink\']}"
24+
format_contexts.append(formatted_context)
25+
26+
context = "\\n\\n".join(format_contexts)
27+
return context
28+
else:
29+
print(f"Error: {response.status_code}")
30+
return None', '{"{\"name\": \"query\", \"type\": \"string\", \"source\": \"reference\", \"is_required\": true}"}', 'f0dd8f71-e4ee-11ee-8c84-a8a1595801ab', true, 'PUBLIC', 'INTERNAL', '/src/assets/fx/google_search/icon.png', 'd3OH0CJYyODrbL1+EgFQ0umVWmb3ZpLsZkv5eqskvXeikcuHXoF0Ta/sVBvdLBDcm4LCLKEgZkUOq9JQb+9qiVA6IHq0ZSFj+JpMIDgl3YVnFbhyTpGp3nAxOm2Y7ufmeMtVIOq20Is1ynOrdIB7UHWrvEOmSq+O8kY612X6VtMHrshkMFL9huiRdQThhnsEZdLdhHgkp9BjpCBJl8SbzTjJmVX4QeswobF5Kr3IRPZBPzrFh0S4jM6Ie0dW6OA5UwgCOBeIVyBxNytarj629kz9EWluns/UGVY8IoXQsphB9m63tXADZ9+djKfRV6TUBosi963DZLi893yY+M7o5UN+eK2u+6FQfy8pTwwiSdNIXtC16pcpvJvG+2jmNeTF1bzOS1fok+L0k/kHhOyzARk8BG1DDyvCsn73QIlnTbKrqCYN9q5zsRQvZPhBMg/g1/oOL147pRArs41htrzOObFP6MbQVM5DXX8tbvro24F7EjGMktoYpPLhqtiMNv9qn7tQbpRfDMYvMHUMiXfLXSroQH2u9a2pb7rBk0QtNJF18069t3p6nXRw3UsUsOXHvYZ1AyBQb6Jy+JbT2OIyUVKfqCvv86ZgnX6JNGqCQXHiFMuxmFI4i62b8f4uPpPBGw9PS5LFZYTm4VWHALoOKQyyOdrbIxk2+lCii5DeT2NkYNi+EaHCQ8/TKHhyG1DGymZPZ7VEK+WxmCwRlr6DEtQfEntlFyWgAimhHtxaTTM7uVViAU3ddCDUtmrOQBteK5c0BzvsMcLMSvsev5UKKo7Q1jipPORgKCun+d0El/qg4Fe38yqWHXBS4jbTuwtiNDsdabrZ0rJnDm3BRJQydouak1rg9GDXcCsHligdR5hJJqP1VqLLUDuoRC8V9urFI0udNQLWKFYPog3J4S/XYbdeQZvio8ZfDQRSWtADWj9B8voLRK8aJMT6HkKXsveRw8GlDNKu/JK44KS7uLCaE9QsIp4zYxRfpkYTx29VXI5vm+a6zvPGz9sJO9nowIOjTV5RMZ3MoS49JM7oGAjJ/5gTk5ZYWC56kmr7712NKZYxiDhDWhs+IYewujcEnj17L9hULDWQCqL+xGR25ayMGukWp4TREVTZxn3p0H7VZrlSrSiLWCISl6+dLED3reclcVsUsqR1YxHCNnPv+0VKmxS8MiMANYf3mf2QoI0F3tHst+sMSq08eJNLbYqCTCP6hOhG5rVbh3pDvSbpfMaPsRumzi3R0FY6mudBoG9g31Jl4N4HF82luL7Oj/kIkzA18aq1Zcl2UTy7Nnqjn8oTRqc8I3RjFxV1BY2zaiK3pvMPKDw7QBSWTa8T6xdq1/17cETKQRwVjjb8gWy1R8Q9khkEMN49TaZDoMLIsCN6EzvsmHXmUdxFxh5kBmG3GLmbttpYpKOPwGCFbykUf8x8jxubOLrgLsyUhNk/vMI/Y4ZHWVIAjZNlRowJYklyHMSmYFwSywczvg1mkE4qmAcKPJGOuBWzlh788VlQrc5E8yil7VexqW8nN/ho/aFd+G+RSPECaE6AvklZa6CPZTZzyhUPqHLVSG0Yq7lWxqc1XUbW3BJWPRF64ghf8VCAguSZpwSoTMBXBKGWa9er0cLSCZheTQSs5tIOkt93zhnATjeebvJPR/IhOZpM6m83o9JHtNLR6jsXS8R87+VivMJA+fp1NyWemwqBm9BNKt3A2E8=', null);
31+
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, 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):
32+
import requests
33+
import json
34+
url = "https://api.bochaai.com/v1/web-search"
35+
payload = json.dumps({
36+
"query": query,
37+
"Boolean": \'true\',
38+
"count": 8
39+
})
40+
41+
headers = {
42+
\'Authorization\': \'Bearer \' + apikey, #鉴权参数,示例:Bearer xxxxxx,API KEY请先前往博查AI开放平台(https://open.bochaai.com)> API KEY 管理中获取。
43+
\'Content-Type\': \'application/json\'
44+
}
45+
46+
response = requests.request("POST", url, headers=headers, data=payload)
47+
return response.json()', '{"{\"name\": \"query\", \"type\": \"string\", \"source\": \"reference\", \"is_required\": true}"}', 'f0dd8f71-e4ee-11ee-8c84-a8a1595801ab', true, 'PUBLIC', 'INTERNAL', '/src/assets/fx/bochaai/icon.png', 'X1ukYeWnI4usm6Emy2bVb0NigczyEZVe4MVst83D1Hgiqti9CNOiLNcANkuX05K+huX1D5p2g7LVFghgpM8ddoSMax5faAsG7tw1UZtPoexYp0ssjXDHBfFCbZcIs/X4Gjio5Lk33X7FQojOM1BIR1P/itxv0U5G1Q45FKg51kdiZoafKYuf24aqqMNDscCnLLQxwVt259BGU5JY4zIuv9hxAxX/7QCXJmgu5CrheuLiTqjRS4TzqBUrLtB/AT4QjrlILeZBwnQ5k2BKFp0mbVeAA+rAaJzBg0GmmnljsJolrKjdPuCWEwCnNw2uptlE3DePXvELsAPEuADBoeE/L5q4RFFzNvkgREsfWn2PaeSkutLUAItE+S3+Ol0QGmnIE7OabifpAgNDH6aalRjYcPNuWZ0V17XzcjFXRwpQFHd6TjkfsgpI5J2m+rZyGayZ9+4XFNbzv9u84TurOvLTGa5IHTbP9Yj4ND4xXyGT+zN0TeOZ3c7XeyoqJWVMNcsp6dc7hiQT5jc9rpRmNUtYo47KPcZfRHq3ToQjdJhx7ZpLA1Uun1RcW+lKhrDpy/ce2f8TjC2+gE7HpDIYeYMB+W0eDX/LHICAWdw/v8gaTn0wlmw9TVW8loqgVBQVlWdEUV2ErkJNfxliwcCD/AxWXlrvaF1FpLOGy6wgUPExoetnDS5BftFumvOEj6R3jfy7jThdEI3+YtNGTg6QA9cBlJ7Ey3nrixZGt/+j9TwAnPhNXcjs/SVGUzxBx+VmUN+jCXMJr93D/yOwnlUkkHljRisyoWIXXOlvOx9y41p2yJRXA1SWQ5n7O/FUA38Z/6w89OMNnPJHfMZgztV8SxgBsayR2echA6XXdmvBLbZlgyr1AugwcR+ZN2t3ayRG8muRYL9S6gNSywxOyaLKFuesOCDO+vU1NdegTFMKYoJuXts0W7bIzYjDB1vQyX9ggAzodTWLUz9sjzAh4zDMbnxPJdNXGVx4O61H0qoU40bPGLZGnPl1+b+mahgCVM7Q28UA', null);
48+
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, 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
49+
', e'def search(query, apikey):
50+
import requests
51+
import json
52+
url = "https://api.langsearch.com/v1/web-search"
53+
payload = json.dumps({
54+
"query": query,
55+
"summary": True,
56+
"freshness": "noLimit",
57+
"summary": True,
58+
"livecrawl": True,
59+
"count": 20
60+
})
61+
headers = {
62+
\'Authorization\': apikey,
63+
\'Content-Type\': \'application/json\'
64+
}
65+
# key从官网申请 https://langsearch.com/
66+
response = requests.request("POST", url, headers=headers, data=payload)
67+
if response.status_code == 200:
68+
return str(response.json())
69+
else:
70+
raise Exception(f"API请求失败: {response.status_code}, 错误信息: {response.text}")
71+
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', 'DGp5NooY3zGFJjzQ3t+uscqoTZbZHax2RdHvfyZ6NCcb/5JhcJHsB9rzCoGjQVvewugnFzjIdATJcryhjis3enkl4l1TAFdOxDT7Py63JpuOapoE52pkhsE9QYW5f1tg6Nd9gssYY6rYnyqMvSf4wUjQJBDQOxv29+CqRCTWSUnQfHD8aWUaPe4rXZObdFnLLg42ROg8cVu5UJkJXdA6EcRF8G082NqQ+LOB49OSffkfhg+fk4nibKIvYcFo3Y1MP+bTuqO23O5tzbNUnPmqsqGPnxbJqZmvJvkksZg1L/NTzYSvvZYuPNUbGfR7wC9FucFN/TFFRMGFdCxtiXGlUQhrZvz8W5vjMKlzsRfnKXTFS4Cg62MmCvQFK6yybLMx0QMOc/yftFt4MkZdLepjim08ctLav3mNApaFNtZ0Isz+A40jpimrZkj5Ahg1KpXCQXUQyOtmQXc6MUVVFOzFlXTQfa3ua4tkiAdAwZEHvaYgjQh28dq4nrtgqFhe+hojJ7kIlJsqtPvb9/+RYwIWVlwef4jVDV2a3Eu+1fMlid1ZJT/KwNkCv2179jRaYhXGkXfU8ii1OOhL9mIGtSJ5lThuJouXgQvNyRr7MajMCVDZYUEOf+kolH/SWEtCFxImT4zaMVFcuZyzLWGh48BX9KuKoAhfPToSs4RgTk0G9h1hQqCrZP4GSXXiBgpMiz2niFGmWk1oWRa6XfU3Dy3Xkft4Q1+iQbnSXcfzZggYoZ4g6qbaf7iBUKN6mW/BvLbSVuqftgy9KF1dHMD95bSMBX6o47rJyAUbaJduLRsH086uNTDTaIE2f/F0ahD5WbokCQGzhWp6W8h4YgIcj8SC3uHiyCOeW5nIm/zEM2+bY4BuClr1IuvYR32GBu0wDma1f7gxEU7Exu49oDojjSdOaFb8isvsaJ9dCNOP/V/ONldBS9VOcZ9l4RNawWwLhrzZhhml5TUI5ZCUywHDFqu/0uBnTI1AHlg+NAs4iJ4VZoVJztZrQmNa9etbRWvhU8yd', null);
72+
"""
73+
74+
75+
class Migration(migrations.Migration):
76+
77+
dependencies = [
78+
('function_lib', '0002_functionlib_is_active_functionlib_permission_type'),
79+
]
80+
81+
operations = [
82+
migrations.AddField(
83+
model_name='functionlib',
84+
name='function_type',
85+
field=models.CharField(choices=[('INTERNAL', '内置'), ('PUBLIC', '公开')], default='PUBLIC', max_length=20, verbose_name='函数类型'),
86+
),
87+
migrations.AddField(
88+
model_name='functionlib',
89+
name='icon',
90+
field=models.CharField(default='/ui/favicon.ico', max_length=256, verbose_name='函数库icon'),
91+
),
92+
migrations.AddField(
93+
model_name='functionlib',
94+
name='init_field_list',
95+
field=models.CharField(max_length=102400, null=True, verbose_name='启动字段列表'),
96+
),
97+
migrations.AddField(
98+
model_name='functionlib',
99+
name='template_id',
100+
field=models.UUIDField(default=None, null=True, verbose_name='模版id'),
101+
),
102+
migrations.RunSQL(function_template)
103+
]

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 & 1 deletion
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")
@@ -29,11 +33,14 @@ class FunctionLib(AppModelMixin):
2933
input_field_list = ArrayField(verbose_name="输入字段列表",
3034
base_field=models.JSONField(verbose_name="输入字段", default=dict)
3135
, default=list)
32-
init_field_list = models.JSONField(verbose_name="启动字段列表", default=list)
36+
init_field_list = models.CharField(max_length=102400, verbose_name="启动字段列表", null=True)
3337
icon = models.CharField(max_length=256, verbose_name="函数库icon", default="/ui/favicon.ico")
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)
3744

3845
class Meta:
3946
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)