Skip to content

Commit a5fb2e1

Browse files
committed
feat: add initial SQL migration for tool data and integrate file content retrieval
1 parent f5fc51c commit a5fb2e1

File tree

2 files changed

+154
-0
lines changed

2 files changed

+154
-0
lines changed

apps/tools/migrations/0001_initial.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
# Generated by Django 5.2 on 2025-04-18 04:07
2+
import os
23

34
import django.db.models.deletion
45
import mptt.fields
56
import uuid_utils.compat
67
from django.db import migrations, models
78

9+
from common.utils.common import get_file_content
10+
from maxkb.conf import PROJECT_DIR
811
from tools.models import ToolFolder
912

1013

@@ -80,4 +83,5 @@ class Migration(migrations.Migration):
8083
'db_table': 'tool',
8184
},
8285
),
86+
migrations.RunSQL(get_file_content(os.path.join(PROJECT_DIR, "apps", "tools", 'migrations', 'internal_tool.sql')))
8387
]
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
INSERT INTO public.tool (create_time, update_time, id, name, "desc", code, input_field_list, init_field_list, icon, is_active, scope, tool_type, template_id, workspace_id, init_params, user_id, folder_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', '博查搜索', '从博查搜索任何信息和网页URL', e'def bocha_search(query, apikey):
2+
import requests
3+
import json
4+
url = "https://api.bochaai.com/v1/web-search"
5+
payload = json.dumps({
6+
"query": query,
7+
"summary": True,
8+
"count": 8
9+
})
10+
11+
headers = {
12+
"Authorization": "Bearer " + apikey, #鉴权参数,示例:Bearer xxxxxx,API KEY请先前往博查AI开放平台(https://open.bochaai.com)> API KEY 管理中获取。
13+
"Content-Type": "application/json"
14+
}
15+
16+
response = requests.request("POST", url, headers=headers, data=payload)
17+
if response.status_code == 200:
18+
return response.json()
19+
else:
20+
raise Exception(f"API请求失败: {response.status_code}, 错误信息: {response.text}")
21+
return (response.text)', '[{"name": "query", "type": "string", "source": "reference", "is_required": true}]', '[{"attrs": {"type": "password", "maxlength": 200, "minlength": 1, "show-password": true, "show-word-limit": true}, "field": "apikey", "label": "API Key", "required": true, "input_type": "PasswordInput", "props_info": {"rules": [{"message": "API Key 为必填属性", "required": true}, {"max": 200, "min": 1, "message": "API Key 长度在 1 到 200 个字符", "trigger": "blur"}]}, "default_value": "x", "show_default_value": false}]', '/ui/fx/bochaai/icon.png', true, 'SHARED', 'INTERNAL', null, 'None', '', 'f0dd8f71-e4ee-11ee-8c84-a8a1595801ab', 'root');
22+
INSERT INTO public.tool (create_time, update_time, id, name, "desc", code, input_field_list, init_field_list, icon, is_active, scope, tool_type, template_id, workspace_id, init_params, user_id, folder_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):
23+
import requests
24+
import json
25+
url = "https://customsearch.googleapis.com/customsearch/v1"
26+
params = {
27+
"q": query,
28+
"key": apikey,
29+
"cx": cx,
30+
"num": 10, # 每次最多返回10条
31+
}
32+
33+
response = requests.get(url, params=params)
34+
if response.status_code == 200:
35+
return response.json()
36+
else:
37+
raise Exception(f"API请求失败: {response.status_code}, 错误信息: {response.text}")
38+
return (response.text)', '[{"name": "query", "type": "string", "source": "reference", "is_required": true}]', '[{"attrs": {"type": "password", "maxlength": 200, "minlength": 1, "show-password": true, "show-word-limit": true}, "field": "apikey", "label": "API Key", "required": true, "input_type": "PasswordInput", "props_info": {"rules": [{"message": "API Key 为必填属性", "required": true}, {"max": 200, "min": 1, "message": "API Key 长度在 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}]', '/ui/fx/google_search/icon.png', true, 'SHARED', 'INTERNAL', null, 'None', '', 'f0dd8f71-e4ee-11ee-8c84-a8a1595801ab', 'root');
39+
INSERT INTO public.tool (create_time, update_time, id, name, "desc", code, input_field_list, init_field_list, icon, is_active, scope, tool_type, template_id, workspace_id, init_params, user_id, folder_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', e'A Web Search tool supporting natural language search
40+
', e'
41+
def langsearch(query, apikey):
42+
import json
43+
import requests
44+
45+
url = "https://api.langsearch.com/v1/web-search"
46+
payload = json.dumps({
47+
"query": query,
48+
"summary": True,
49+
"freshness": "noLimit",
50+
"livecrawl": True,
51+
"count": 20
52+
})
53+
headers = {
54+
"Authorization": apikey,
55+
"Content-Type": "application/json"
56+
}
57+
# key从官网申请 https://langsearch.com/
58+
response = requests.request("POST", url, headers=headers, data=payload)
59+
if response.status_code == 200:
60+
return response.json()
61+
else:
62+
raise Exception(f"API请求失败: {response.status_code}, 错误信息: {response.text}")
63+
return (response.text)', '[{"name": "query", "type": "string", "source": "reference", "is_required": true}]', '[{"attrs": {"type": "password", "maxlength": 200, "minlength": 1, "show-password": true, "show-word-limit": true}, "field": "apikey", "label": "API Key", "required": true, "input_type": "PasswordInput", "props_info": {"rules": [{"message": "API Key 为必填属性", "required": true}, {"max": 200, "min": 1, "message": "API Key 长度在 1 到 200 个字符", "trigger": "blur"}]}, "default_value": "x", "show_default_value": false}]', '/ui/fx/langsearch/icon.png', true, 'SHARED', 'INTERNAL', null, 'None', '', 'f0dd8f71-e4ee-11ee-8c84-a8a1595801ab', 'root');
64+
INSERT INTO public.tool (create_time, update_time, id, name, "desc", code, input_field_list, init_field_list, icon, is_active, scope, tool_type, template_id, workspace_id, init_params, user_id, folder_id) VALUES ('2025-03-17 08:16:32.626245 +00:00', '2025-03-17 08:16:32.626308 +00:00', '22c21b76-0308-11f0-9694-5618c4394482', 'MySQL 查询', '一个连接MySQL数据库执行SQL查询的工具', e'
65+
def query_mysql(host,port, user, password, database, sql):
66+
import pymysql
67+
import json
68+
from pymysql.cursors import DictCursor
69+
70+
try:
71+
# 创建连接
72+
db = pymysql.connect(
73+
host=host,
74+
port=int(port),
75+
user=user,
76+
password=password,
77+
database=database,
78+
cursorclass=DictCursor # 使用字典游标
79+
)
80+
81+
# 使用 cursor() 方法创建一个游标对象 cursor
82+
cursor = db.cursor()
83+
84+
# 使用 execute() 方法执行 SQL 查询
85+
cursor.execute(sql)
86+
87+
# 使用 fetchall() 方法获取所有数据
88+
data = cursor.fetchall()
89+
90+
# 处理 bytes 类型的数据
91+
for row in data:
92+
for key, value in row.items():
93+
if isinstance(value, bytes):
94+
row[key] = value.decode("utf-8") # 转换为字符串
95+
96+
# 将数据序列化为 JSON
97+
json_data = json.dumps(data, ensure_ascii=False)
98+
return json_data
99+
100+
# 关闭数据库连接
101+
db.close()
102+
103+
except Exception as e:
104+
print(f"Error while connecting to MySQL: {e}")
105+
raise e', '[{"name": "sql", "type": "string", "source": "reference", "is_required": true}]', '[{"attrs": {"maxlength": 200, "minlength": 1, "show-word-limit": true}, "field": "host", "label": "host", "required": true, "input_type": "TextInput", "props_info": {"rules": [{"message": "host 为必填属性", "required": true}, {"max": 200, "min": 1, "message": "host长度在 1 到 200 个字符", "trigger": "blur"}]}, "default_value": "x", "show_default_value": false}, {"attrs": {"maxlength": 20, "minlength": 1, "show-word-limit": true}, "field": "port", "label": "port", "required": true, "input_type": "TextInput", "props_info": {"rules": [{"message": "port 为必填属性", "required": true}, {"max": 20, "min": 1, "message": "port长度在 1 到 20 个字符", "trigger": "blur"}]}, "default_value": "3306", "show_default_value": false}, {"attrs": {"maxlength": 200, "minlength": 1, "show-word-limit": true}, "field": "user", "label": "user", "required": true, "input_type": "TextInput", "props_info": {"rules": [{"message": "user 为必填属性", "required": true}, {"max": 200, "min": 1, "message": "user长度在 1 到 200 个字符", "trigger": "blur"}]}, "default_value": "root", "show_default_value": false}, {"attrs": {"type": "password", "maxlength": 200, "minlength": 1, "show-password": true, "show-word-limit": true}, "field": "password", "label": "password", "required": true, "input_type": "PasswordInput", "props_info": {"rules": [{"message": "password 为必填属性", "required": true}, {"max": 200, "min": 1, "message": "password长度在 1 到 200 个字符", "trigger": "blur"}]}, "default_value": "x", "show_default_value": false}, {"attrs": {"maxlength": 200, "minlength": 1, "show-word-limit": true}, "field": "database", "label": "database", "required": true, "input_type": "TextInput", "props_info": {"rules": [{"message": "database 为必填属性", "required": true}, {"max": 200, "min": 1, "message": "database长度在 1 到 200 个字符", "trigger": "blur"}]}, "default_value": "x", "show_default_value": false}]', '/ui/fx/mysql/icon.png', true, 'SHARED', 'INTERNAL', null, 'None', null, 'f0dd8f71-e4ee-11ee-8c84-a8a1595801ab', 'root');
106+
INSERT INTO public.tool (create_time, update_time, id, name, "desc", code, input_field_list, init_field_list, icon, is_active, scope, tool_type, template_id, workspace_id, init_params, user_id, folder_id) VALUES ('2025-03-17 07:37:54.620836 +00:00', '2025-03-17 07:37:54.620887 +00:00', 'bd1e8b88-0302-11f0-87bb-5618c4394482', 'PostgreSQL 查询', '一个连接PostgreSQL数据库执行SQL查询的工具', e'
107+
def queryPgSQL(database, user, password, host, port, query):
108+
import psycopg2
109+
import json
110+
from datetime import datetime
111+
112+
# 自定义 JSON 序列化函数
113+
def default_serializer(obj):
114+
if isinstance(obj, datetime):
115+
return obj.isoformat() # 将 datetime 转换为 ISO 格式字符串
116+
raise TypeError(f"Type {type(obj)} not serializable")
117+
118+
# 数据库连接信息
119+
conn_params = {
120+
"dbname": database,
121+
"user": user,
122+
"password": password,
123+
"host": host,
124+
"port": port
125+
}
126+
try:
127+
# 建立连接
128+
conn = psycopg2.connect(**conn_params)
129+
print("连接成功!")
130+
# 创建游标对象
131+
cursor = conn.cursor()
132+
# 执行查询语句
133+
cursor.execute(query)
134+
# 获取查询结果
135+
rows = cursor.fetchall()
136+
# 处理 bytes 类型的数据
137+
columns = [desc[0] for desc in cursor.description]
138+
result = [dict(zip(columns, row)) for row in rows]
139+
# 转换为 JSON 格式
140+
json_result = json.dumps(result, default=default_serializer, ensure_ascii=False)
141+
return json_result
142+
except Exception as e:
143+
print(f"发生错误:{e}")
144+
raise e
145+
finally:
146+
# 关闭游标和连接
147+
if cursor:
148+
cursor.close()
149+
if conn:
150+
conn.close()', '[{"name": "query", "type": "string", "source": "reference", "is_required": true}]', '[{"attrs": {"maxlength": 200, "minlength": 1, "show-word-limit": true}, "field": "host", "label": "host", "required": true, "input_type": "TextInput", "props_info": {"rules": [{"message": "host 为必填属性", "required": true}, {"max": 200, "min": 1, "message": "host长度在 1 到 200 个字符", "trigger": "blur"}]}, "default_value": "x", "show_default_value": false}, {"attrs": {"maxlength": 20, "minlength": 1, "show-word-limit": true}, "field": "port", "label": "port", "required": true, "input_type": "TextInput", "props_info": {"rules": [{"message": "port 为必填属性", "required": true}, {"max": 20, "min": 1, "message": "port长度在 1 到 20 个字符", "trigger": "blur"}]}, "default_value": "5432", "show_default_value": false}, {"attrs": {"maxlength": 200, "minlength": 1, "show-word-limit": true}, "field": "user", "label": "user", "required": true, "input_type": "TextInput", "props_info": {"rules": [{"message": "user 为必填属性", "required": true}, {"max": 200, "min": 1, "message": "user长度在 1 到 200 个字符", "trigger": "blur"}]}, "default_value": "root", "show_default_value": false}, {"attrs": {"type": "password", "maxlength": 200, "minlength": 1, "show-password": true, "show-word-limit": true}, "field": "password", "label": "password", "required": true, "input_type": "PasswordInput", "props_info": {"rules": [{"message": "password 为必填属性", "required": true}, {"max": 200, "min": 1, "message": "password长度在 1 到 200 个字符", "trigger": "blur"}]}, "default_value": "x", "show_default_value": false}, {"attrs": {"maxlength": 200, "minlength": 1, "show-word-limit": true}, "field": "database", "label": "database", "required": true, "input_type": "TextInput", "props_info": {"rules": [{"message": "database 为必填属性", "required": true}, {"max": 200, "min": 1, "message": "database长度在 1 到 200 个字符", "trigger": "blur"}]}, "default_value": "x", "show_default_value": false}]', '/ui/fx/postgresql/icon.png', true, 'SHARED', 'INTERNAL', null, 'None', null, 'f0dd8f71-e4ee-11ee-8c84-a8a1595801ab', 'root');

0 commit comments

Comments
 (0)