Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
ai-bot-edge-function
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
duanjinfei
ai-bot-edge-function
Commits
c0e075cb
Commit
c0e075cb
authored
Jan 25, 2025
by
duanjinfei
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
bot conversation
parent
01fad00a
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
2386 additions
and
4 deletions
+2386
-4
context_ex.yaml
context_ex.yaml
+55
-0
.env
supabase/.env
+25
-1
cli-latest
supabase/.temp/cli-latest
+1
-1
index.ts
supabase/functions/check_bot_chat/index.ts
+109
-0
index.ts
supabase/functions/check_event/index.ts
+203
-0
index.ts
supabase/functions/fastgpt_webhook/index.ts
+44
-0
index.ts
supabase/functions/tg_bot_D/index.ts
+98
-2
index.ts
supabase/functions/tg_bot_E/index.ts
+141
-0
index.ts
supabase/functions/tg_bot_F/index.ts
+44
-0
bot.ts
supabase/functions/tg_bot_test/bot.ts
+129
-0
conversations.ts
supabase/functions/tg_bot_test/conversations.ts
+763
-0
conversations_util.ts
supabase/functions/tg_bot_test/conversations_util.ts
+189
-0
db.ts
supabase/functions/tg_bot_test/db.ts
+296
-0
fastgpt.ts
supabase/functions/tg_bot_test/fastgpt.ts
+228
-0
index.ts
supabase/functions/tg_bot_test/index.ts
+61
-0
No files found.
context_ex.yaml
0 → 100644
View file @
c0e075cb
Context {
update
:
{
update_id
:
379077430
,
message
:
{
message_id
:
558
,
from
:
{
id
:
5740112902
,
is_bot
:
false
,
first_name
:
"
D"
,
last_name
:
"
JJFF"
,
username
:
"
DDDDJJJJ8888"
,
language_code
:
"
zh-hans"
},
chat
:
{
id
:
5740112902
,
first_name
:
"
D"
,
last_name
:
"
JJFF"
,
username
:
"
DDDDJJJJ8888"
,
type
:
"
private"
},
date
:
1736848472
,
text
:
"
/start"
,
entities
:
[
{
offset
:
0
,
length
:
6
,
type
:
"
bot_command"
}
]
}
}
,
api
:
Api {
token
:
"
7840941877:AAE7NJQvddWH-O00NLoaoQhIFQ1-tn2ihFY"
,
options
:
undefined,
raw
:
{}
,
config
:
{
use
:
[
Function
:
use
],
installedTransformers
:
[
Function
:
installedTransformers
]
}
},
me
:
{
id
:
7840941877
,
is_bot
:
true
,
first_name
:
"
chatflowBot"
,
username
:
"
tg_chatflow_bot"
,
can_join_groups
:
true
,
can_read_all_group_messages
:
false
,
supports_inline_queries
:
false
,
can_connect_to_business
:
false
,
has_main_web_app
:
false
}
,
match
:
"
"
,
session
:
[
Getter/Setter
]
,
conversation
:
ConversationControls {
enter
:
[
AsyncFunction (anonymous)
]
,
[
Symbol(conversations)
]:
{
ids
:
Set(1)
{
"
createagent"
},
session
:
[
AsyncFunction (anonymous)
]
}
}
}
supabase/.env
View file @
c0e075cb
...
@@ -2,11 +2,35 @@ TELEGRAM_BOT_TOKEN_A=6351960109:AAHi3c7_3-dxLSExSBxwZH6C-_v9pEQeIYE
...
@@ -2,11 +2,35 @@ TELEGRAM_BOT_TOKEN_A=6351960109:AAHi3c7_3-dxLSExSBxwZH6C-_v9pEQeIYE
TELEGRAM_BOT_TOKEN_B=7438818892:AAFOklft4GEyadDgq18Ise0eS53wtc2O9r8
TELEGRAM_BOT_TOKEN_B=7438818892:AAFOklft4GEyadDgq18Ise0eS53wtc2O9r8
TELEGRAM_BOT_TOKEN_C=7952562405:AAEB55ItdDQRPxg578JuOL-3EWm8KbqeXbc
TELEGRAM_BOT_TOKEN_C=7952562405:AAEB55ItdDQRPxg578JuOL-3EWm8KbqeXbc
TELEGRAM_BOT_TOKEN_D=7619523873:AAEzQ022F-n_qu_tGssJSpeDB0CZeMZXBrA
TELEGRAM_BOT_TOKEN_D=7619523873:AAEzQ022F-n_qu_tGssJSpeDB0CZeMZXBrA
TELEGRAM_BOT_TOKEN_E=7403262814:AAEz5XTxYHbYNcRagazc6JdesSeDrB_Iq8Q
TELEGRAM_BOT_TOKEN_F=7844691549:AAExMlqa8G83u50ILZXs0Ns0lzexRhL9oY4
TELEGRAM_BOT_TOKEN_TEST=7840941877:AAE7NJQvddWH-O00NLoaoQhIFQ1-tn2ihFY
FUNCTION_SECRET_A=AAHi3c7_3-dxLSExSBxwZH6C-_v9pEQeIYE
FUNCTION_SECRET_A=AAHi3c7_3-dxLSExSBxwZH6C-_v9pEQeIYE
FUNCTION_SECRET_B=AAFOklft4GEyadDgq18Ise0eS53wtc2O9r8
FUNCTION_SECRET_B=AAFOklft4GEyadDgq18Ise0eS53wtc2O9r8
FUNCTION_SECRET_C=AAEB55ItdDQRPxg578JuOL-3EWm8KbqeXbc
FUNCTION_SECRET_C=AAEB55ItdDQRPxg578JuOL-3EWm8KbqeXbc
FUNCTION_SECRET_D=AAEzQ022F-n_qu_tGssJSpeDB0CZeMZXBrA
FUNCTION_SECRET_D=AAEzQ022F-n_qu_tGssJSpeDB0CZeMZXBrA
FUNCTION_SECRET_E=AAEz5XTxYHbYNcRagazc6JdesSeDrB_Iq8Q
FUNCTION_SECRET_F=AAExMlqa8G83u50ILZXs0Ns0lzexRhL9oY4
FUNCTION_SECRET_TEST=AAE7NJQvddWH-O00NLoaoQhIFQ1-tn2ihFY
DIFY_API_KEY_A=app-hVXNz9r7ss5WlWCTphDBROxR
DIFY_API_KEY_A=app-hVXNz9r7ss5WlWCTphDBROxR
DIFY_API_KEY_B=app-K5m3nhVjNPYC5bjrz9jBedod
DIFY_API_KEY_B=app-K5m3nhVjNPYC5bjrz9jBedod
DIFY_API_KEY_C=app-3a1LeRzAG17TVPQo4qVYZWcH
DIFY_API_KEY_C=app-3a1LeRzAG17TVPQo4qVYZWcH
DIFY_API_KEY_D=app-t3gQ1DIhBU8lK5bcTwdGLeGn
DIFY_API_KEY_D=app-t3gQ1DIhBU8lK5bcTwdGLeGn
\ No newline at end of file
DIFY_API_KEY_E=app-fzfERJzj2umyd0FYo48FBspa
DIFY_API_KEY_F=app-POOgCW7u2W9icnlFQnXB8UhJ
FASTGPT_API_KEY_D=fastgpt-wqtzzN6HY2FwDnTAChLlBa9vCZ0oOMXQe9ZqqBPaBhpoVyyDU1m7jAV
FASTGPT_API_URL=https://api.fastgpt.in/api/v1/chat/completions
FASTGPT_KNOWLEDGE_URL=https://api.fastgpt.in/api/core/dataset
FASTGPT_KNOWLEDGE_COLLECTION_URL=https://api.fastgpt.in/api/core/dataset/collection
FASTGPT_API_KEY_EVENT=fastgpt-awmDKXGxELXMaB9h9VRKjo3dQR7aUQ9etD4O8xeKzqFdafLyft3B2XsLq1Bm6LM
FASTGPT_API_KEY_AGENT=fastgpt-uHHPpoq0VtiZp5WB7XrkhxWNcIHhW0Fs4C0Ytm5zZAojNVHsOA0KaW9OAb7
FASTGPT_API_KEY_AGENT_CREATE=fastgpt-oYK4ghLDVUTHWfhzZrLL1avqW0lVyQR01W4Snp7fuMhn0UFEoL9Nvv
FASTGPT_API_KEY_ACTION=fastgpt-yHL5yVPhsB7OgTicXwje456cg6qsQeQKmFGQsGAeUqUZteYtaZFa
FASTGPT_API_KEY_ROLE=fastgpt-ssWwuvC1QFtX7rlckwycQP4x1uUMPRvzBZ9gpxCTSYPO1XqMqlk6Gq3P6Fw
FASTGPT_API_KEY_KNOWLEDGE=fastgpt-wwqDG9uVpDZemTYIlBQpqB9JHcFXSI9UDeYht0eVzRRKm5RGDZUjyE19QcM2
FASTGPT_API_KEY_ANSWER=fastgpt-yunKjnKn9YP1CKdm5yITZId1g49YUyMD77gaH2ExJEUZVshjjwQVf
AGENT_ADMIN=f06d467a-cd76-427e-a64b-e7a59a865848
SUPPORT_BOT=["tg_chat_flow","BotsHHHBot"]
SUPPORT_BOT_TOKEN=tg_chat_flow~7840941877:AAE7NJQvddWH-O00NLoaoQhIFQ1-tn2ihFY;BotsHHHBot~7844691549:AAExMlqa8G83u50ILZXs0Ns0lzexRhL9oY4
supabase/.temp/cli-latest
View file @
c0e075cb
v2.2.1
v2.6.8
\ No newline at end of file
\ No newline at end of file
supabase/functions/check_bot_chat/index.ts
0 → 100644
View file @
c0e075cb
import
{
createClient
}
from
"
jsr:@supabase/supabase-js@2
"
;
import
{
Bot
}
from
'
https://deno.land/x/grammy@v1.34.0/mod.ts
'
// 初始化 Supabase 客户端
const
supabaseUrl
=
Deno
.
env
.
get
(
"
SUPABASE_URL
"
);
const
supabaseKey
=
Deno
.
env
.
get
(
"
SUPABASE_SERVICE_ROLE_KEY
"
);
const
supabase
=
createClient
(
supabaseUrl
,
supabaseKey
);
const
sendTimeToleranceMs
=
5
*
60
*
1000
;
// 5分钟的时间窗口
async
function
processBotChat
()
{
try
{
const
currentTime
=
new
Date
();
const
startTime
=
new
Date
(
currentTime
.
getTime
()
-
sendTimeToleranceMs
).
toISOString
();
const
endTime
=
new
Date
(
currentTime
.
getTime
()
+
sendTimeToleranceMs
).
toISOString
();
console
.
log
(
`Processing bot_chat records between
${
startTime
}
and
${
endTime
}
`
);
// 查询符合条件的 bot_chat 记录
const
{
data
:
botChats
,
error
:
fetchError
}
=
await
supabase
.
from
(
"
bot_chat
"
)
.
select
(
"
id, content, bot_id, agent_id, send_time
"
)
.
gte
(
"
send_time
"
,
startTime
)
.
lte
(
"
send_time
"
,
endTime
)
.
eq
(
"
status
"
,
"
0
"
);
if
(
fetchError
)
{
console
.
error
(
"
Error fetching bot_chat records:
"
,
fetchError
);
return
;
}
if
(
!
botChats
||
botChats
.
length
===
0
)
{
console
.
log
(
"
No bot_chat records found in the time window.
"
);
return
;
}
console
.
log
(
`Fetched
${
botChats
.
length
}
bot_chat records.`
);
// 处理每条 bot_chat 记录
for
(
const
chat
of
botChats
)
{
const
{
id
,
content
,
bot_id
,
agent_id
}
=
chat
;
try
{
// 查询 agent_tg 表获取 tg_chat_id
const
{
data
:
agentData
,
error
:
agentError
}
=
await
supabase
.
from
(
"
agent_tg
"
)
.
select
(
"
tg_chat_id
"
)
.
eq
(
"
agent_id
"
,
agent_id
)
if
(
agentError
||
!
agentData
||
agentData
.
length
===
0
)
{
console
.
error
(
`Failed to fetch tg_chat_id for agent_id
${
agent_id
}
:`
,
agentError
);
continue
;
}
// 查询 agent_tg 表获取 tg_chat_id
const
{
data
:
botData
,
error
:
botError
}
=
await
supabase
.
from
(
"
bot
"
)
.
select
(
"
id,tg_token
"
)
.
eq
(
"
id
"
,
bot_id
)
.
single
();
if
(
botError
||
!
botData
)
{
console
.
error
(
`Failed to fetch bot token for bot_id
${
bot_id
}
:`
,
botError
);
continue
;
}
const
{
tg_chat_id
}
=
agentData
[
0
];
// 使用 bot_id 初始化 Telegram Bot
const
bot
=
new
Bot
(
botData
.
tg_token
);
await
bot
.
api
.
sendMessage
(
tg_chat_id
,
content
);
console
.
log
(
`Message sent to chat_id
${
tg_chat_id
}
for bot_chat ID
${
id
}
`
);
// 更新 bot_chat 状态为已发送
const
{
error
:
updateError
}
=
await
supabase
.
from
(
"
bot_chat
"
)
.
update
({
status
:
"
1
"
,
finished_at
:
new
Date
().
toISOString
()
})
.
eq
(
"
id
"
,
id
);
if
(
updateError
)
{
console
.
error
(
`Failed to update bot_chat status for ID
${
id
}
:`
,
updateError
);
}
}
catch
(
err
)
{
console
.
error
(
`Error processing bot_chat ID
${
id
}
:`
,
err
);
}
}
}
catch
(
err
)
{
console
.
error
(
"
Unexpected error in processBotChat:
"
,
err
);
}
}
// 主流程:每次请求调用事件处理函数
Deno
.
serve
(
async
()
=>
{
try
{
EdgeRuntime
.
waitUntil
(
processBotChat
())
return
new
Response
(
JSON
.
stringify
({
message
:
"
Bot chat processed successfully
"
}),
{
status
:
200
,
headers
:
{
"
Content-Type
"
:
"
application/json
"
},
});
}
catch
(
err
)
{
console
.
error
(
"
Unexpected error:
"
,
err
);
return
new
Response
(
JSON
.
stringify
({
error
:
"
Internal server error
"
}),
{
headers
:
{
"
Content-Type
"
:
"
application/json
"
},
status
:
500
,
});
}
});
\ No newline at end of file
supabase/functions/check_event/index.ts
0 → 100644
View file @
c0e075cb
import
{
createClient
}
from
"
jsr:@supabase/supabase-js@2
"
;
import
{
Cron
}
from
"
https://deno.land/x/croner@5.1.1/src/croner.js
"
;
const
AUTH_TOKEN
=
Deno
.
env
.
get
(
'
FASTGPT_API_KEY_EVENT
'
);
const
FASTGPT_API_URL
=
Deno
.
env
.
get
(
'
FASTGPT_API_URL
'
);
interface
ChatRequest
{
stream
:
boolean
;
detail
:
boolean
;
variables
:
{
uid
:
string
;
name
:
string
;
};
messages
:
Array
<
{
role
:
string
;
content
:
string
;
}
>
;
}
// 初始化 Supabase 客户端
const
supabaseUrl
=
Deno
.
env
.
get
(
"
SUPABASE_URL
"
)
??
""
;
const
supabaseKey
=
Deno
.
env
.
get
(
"
SUPABASE_SERVICE_ROLE_KEY
"
)
??
""
;
const
supabase
=
createClient
(
supabaseUrl
,
supabaseKey
);
const
batchSize
=
100
;
const
requestInterval
=
300
;
// 每秒最多发送一个请求,控制 API 请求频率
// 查询并处理事件
async
function
processEventsInBatches
()
{
let
offset
=
0
;
let
hasMore
=
true
;
// 获取当前时间
const
currentTime
=
new
Date
().
toISOString
();
console
.
log
(
`Processing events at
${
currentTime
}
`
);
while
(
hasMore
)
{
// 查询符合条件的事件
const
{
data
,
error
}
=
await
supabase
.
from
(
"
agent_event
"
)
.
select
(
"
id, trigger_cron, trigger_condition, event_type, is_triggered, triggered_count,last_triggered_time,send_cron
"
)
.
eq
(
"
is_triggered
"
,
false
)
// 只查询未触发的事件
.
range
(
offset
,
offset
+
batchSize
-
1
);
// 分页查询
if
(
error
||
!
data
)
{
console
.
error
(
"
Error fetching events:
"
,
error
);
break
;
}
console
.
log
(
`Fetched
${
data
.
length
}
events`
);
// 处理当前批次的事件
await
Promise
.
all
(
data
.
map
(
event
=>
processEvent
(
event
,
currentTime
)));
// 如果查询到的记录数少于批次大小,说明没有更多数据了
if
(
data
.
length
<
batchSize
)
{
hasMore
=
false
;
}
// 更新 offset,继续查询下一批
offset
+=
batchSize
;
}
}
// 处理单个事件
async
function
processEvent
(
event
:
any
,
currentTime
:
string
)
{
console
.
log
(
"
Processing event:
"
,
event
);
const
{
id
,
trigger_cron
,
send_cron
,
trigger_condition
,
event_type
,
last_triggered_time
,
triggered_count
}
=
event
;
const
currentDateTime
=
new
Date
(
currentTime
);
const
cron
=
new
Cron
(
trigger_cron
);
const
sendCron
=
new
Cron
(
send_cron
);
const
nextSendTime
=
sendCron
.
next
(
new
Date
());
trigger_condition
.
send_time
=
nextSendTime
?.
toISOString
();
console
.
log
(
"
send_time:
"
,
trigger_condition
.
send_time
);
// 使用 Cron 解析器获取下一次触发时间
const
nextTriggerTime
=
cron
.
next
(
new
Date
(
last_triggered_time
));
// 容忍范围:1秒
const
toleranceMs
=
1000
;
console
.
log
(
`Current time:
${
currentDateTime
}
, Next trigger:
${
nextTriggerTime
}
`
);
if
(
nextTriggerTime
&&
currentDateTime
.
getTime
()
>=
nextTriggerTime
.
getTime
()
-
toleranceMs
)
{
if
(
event_type
===
1
)
{
console
.
log
(
`Processing recurrent event
${
id
}
`
);
await
handleRecurrentEvent
(
trigger_condition
,
id
,
triggered_count
);
}
else
if
(
event_type
===
2
)
{
console
.
log
(
`Processing single event
${
id
}
`
);
await
handleSingleEvent
(
trigger_condition
,
id
,
triggered_count
);
}
// 更新 last_triggered_time
await
updateLastTriggeredTime
(
id
);
}
else
{
console
.
log
(
`Event
${
id
}
not triggered. Current time:
${
currentDateTime
}
, Next trigger:
${
nextTriggerTime
}
`
);
}
}
async
function
updateLastTriggeredTime
(
id
:
number
)
{
const
{
error
}
=
await
supabase
.
from
(
"
agent_event
"
)
.
update
({
last_triggered_time
:
new
Date
()
})
.
eq
(
"
id
"
,
id
);
if
(
error
)
{
console
.
error
(
`Failed to update last_triggered_time for event ID
${
id
}
:`
,
error
);
}
}
// 处理循环任务
async
function
handleRecurrentEvent
(
triggerCondition
:
any
,
eventId
:
number
,
triggered_count
:
number
)
{
// 控制请求发送的频率
await
triggerThirdPartyAPIWithRateLimit
(
triggerCondition
);
// 更新事件的触发次数
const
{
error
}
=
await
supabase
.
from
(
"
agent_event
"
)
.
update
({
triggered_count
:
triggered_count
+
1
})
.
eq
(
"
id
"
,
eventId
);
if
(
error
)
{
console
.
error
(
"
Failed to update triggered_count:
"
,
error
);
}
}
// 处理单次任务
async
function
handleSingleEvent
(
triggerCondition
:
any
,
eventId
:
number
,
triggered_count
:
number
)
{
// 触发第三方 API
await
triggerThirdPartyAPIWithRateLimit
(
triggerCondition
);
// 标记事件为已触发
const
{
error
}
=
await
supabase
.
from
(
"
agent_event
"
)
.
update
({
is_triggered
:
true
,
triggered_count
:
triggered_count
+
1
})
.
eq
(
"
id
"
,
eventId
);
if
(
error
)
{
console
.
error
(
"
Failed to mark event as triggered:
"
,
error
);
}
}
// 向第三方 API 发送请求,并进行流控
let
lastRequestTime
=
Date
.
now
();
async
function
triggerThirdPartyAPIWithRateLimit
(
triggerCondition
:
any
)
{
const
now
=
Date
.
now
();
const
timeSinceLastRequest
=
now
-
lastRequestTime
;
// 等待直到达到时间间隔后再发送请求
if
(
timeSinceLastRequest
<
requestInterval
)
{
console
.
log
(
"
Waiting for next request...
"
);
await
new
Promise
(
resolve
=>
setTimeout
(
resolve
,
requestInterval
-
timeSinceLastRequest
));
}
const
requestData
:
ChatRequest
=
{
stream
:
false
,
detail
:
false
,
variables
:
triggerCondition
,
messages
:
[
{
role
:
'
user
'
,
content
:
''
}
]
};
console
.
log
(
"
Sending request to third-party API:
"
,
requestData
);
// 非阻塞地发送请求
fetch
(
FASTGPT_API_URL
,
{
method
:
"
POST
"
,
headers
:
{
"
Content-Type
"
:
"
application/json
"
,
"
Authorization
"
:
`Bearer
${
AUTH_TOKEN
}
`
},
body
:
JSON
.
stringify
(
requestData
),
}).
catch
((
error
)
=>
{
console
.
error
(
"
API call failed:
"
,
error
);
});
console
.
log
(
"
Request sent successfully
"
);
// 更新最后请求时间
lastRequestTime
=
Date
.
now
();
}
// 主流程:定时调用事件处理函数
Deno
.
serve
(
async
(
req
)
=>
{
try
{
EdgeRuntime
.
waitUntil
(
processEventsInBatches
())
return
new
Response
(
JSON
.
stringify
({
message
:
"
Events processed successfully
"
}),
{
status
:
200
,
headers
:
{
"
Content-Type
"
:
"
application/json
"
},
});
}
catch
(
err
)
{
console
.
error
(
'
Unexpected error:
'
,
err
);
return
new
Response
(
JSON
.
stringify
({
error
:
'
Internal server error
'
}),
{
headers
:
{
'
Content-Type
'
:
'
application/json
'
},
status
:
500
,
});
}
});
\ No newline at end of file
supabase/functions/fastgpt_webhook/index.ts
0 → 100644
View file @
c0e075cb
import
{
createClient
}
from
"
jsr:@supabase/supabase-js@2
"
;
import
{
Bot
}
from
'
https://deno.land/x/grammy@v1.34.0/mod.ts
'
// 初始化 Supabase 客户端
const
supabaseUrl
=
Deno
.
env
.
get
(
"
SUPABASE_URL
"
)
??
""
;
const
supabaseKey
=
Deno
.
env
.
get
(
"
SUPABASE_SERVICE_ROLE_KEY
"
)
??
""
;
const
supabase
=
createClient
(
supabaseUrl
,
supabaseKey
);
async
function
processWebhook
(
req
:
any
)
{
const
body
=
await
req
.
json
();
console
.
log
(
'
webhook body:
'
,
body
);
const
{
tg_chat_id
,
bot_id
,
content
}
=
body
;
if
(
!
tg_chat_id
||
!
bot_id
||
!
content
)
{
console
.
error
(
'
Invalid request body:
'
,
body
);
return
;
}
// 通过bot_id查询bot 获得tg_id
const
{
data
:
botsData
,
error
}
=
await
supabase
.
from
(
"
bot
"
).
select
(
"
tg_token
"
).
eq
(
"
id
"
,
bot_id
).
single
();
if
(
error
||
!
botsData
)
{
console
.
error
(
"
获取Bot数据失败:
"
,
error
?.
message
||
"
未知错误
"
);
return
;
}
const
bot
=
new
Bot
(
botsData
.
tg_token
);
console
.
log
(
'
bot:
'
,
bot
);
await
bot
.
api
.
sendMessage
(
tg_chat_id
,
content
);
console
.
log
(
'
Message sent successfully
'
);
}
// 主流程:定时调用事件处理函数
Deno
.
serve
(
async
(
req
)
=>
{
try
{
EdgeRuntime
.
waitUntil
(
processWebhook
(
req
))
return
new
Response
(
JSON
.
stringify
({
message
:
"
Events processed successfully
"
}),
{
status
:
200
,
headers
:
{
"
Content-Type
"
:
"
application/json
"
},
});
}
catch
(
err
)
{
console
.
error
(
'
Unexpected error:
'
,
err
);
return
new
Response
(
JSON
.
stringify
({
error
:
'
Internal server error
'
}),
{
headers
:
{
'
Content-Type
'
:
'
application/json
'
},
status
:
500
,
});
}
});
\ No newline at end of file
supabase/functions/tg_bot_D/index.ts
View file @
c0e075cb
...
@@ -6,13 +6,109 @@ console.log(`Function "telegram-bot" up and running!`)
...
@@ -6,13 +6,109 @@ console.log(`Function "telegram-bot" up and running!`)
import
{
Bot
,
webhookCallback
}
from
'
https://deno.land/x/grammy@v1.34.0/mod.ts
'
import
{
Bot
,
webhookCallback
}
from
'
https://deno.land/x/grammy@v1.34.0/mod.ts
'
const
API_URL
=
'
https://api.fastgpt.in/api/v1/chat/completions
'
;
interface
ChatRequest
{
chatId
:
string
;
stream
:
boolean
;
detail
:
boolean
;
responseChatItemId
:
string
;
variables
:
{
uid
:
string
;
name
:
string
;
};
messages
:
Array
<
{
role
:
string
;
content
:
string
;
}
>
;
}
interface
ChatResponse
{
id
:
string
;
model
:
string
;
usage
:
{
prompt_tokens
:
number
;
completion_tokens
:
number
;
total_tokens
:
number
;
};
choices
:
Array
<
{
message
:
{
role
:
string
;
content
:
string
;
};
finish_reason
:
string
;
index
:
number
;
}
>
;
}
async
function
sendChatRequest
(
requestData
:
ChatRequest
):
Promise
<
ChatResponse
|
null
>
{
try
{
const
AUTH_TOKEN
=
Deno
.
env
.
get
(
'
FASTGPT_API_KEY_D
'
);
console
.
log
(
"
AUTH_TOKEN:
"
,
AUTH_TOKEN
);
const
response
=
await
fetch
(
API_URL
,
{
method
:
'
POST
'
,
headers
:
{
Authorization
:
`Bearer
${
AUTH_TOKEN
}
`
,
'
Content-Type
'
:
'
application/json
'
,
},
body
:
JSON
.
stringify
(
requestData
),
});
if
(
!
response
.
ok
)
{
console
.
error
(
'
Failed to fetch:
'
,
response
.
statusText
);
return
null
;
}
const
data
:
ChatResponse
=
await
response
.
json
();
return
data
;
}
catch
(
error
)
{
console
.
error
(
'
Error during request:
'
,
error
);
return
null
;
}
}
const
bot
=
new
Bot
(
Deno
.
env
.
get
(
'
TELEGRAM_BOT_TOKEN_D
'
)
||
''
)
const
bot
=
new
Bot
(
Deno
.
env
.
get
(
'
TELEGRAM_BOT_TOKEN_D
'
)
||
''
)
bot
.
command
(
'
start
'
,
(
ctx
)
=>
ctx
.
reply
(
'
Welcome! Up and running.
'
))
bot
.
command
(
'
start
'
,
(
ctx
)
=>
{
console
.
log
(
"
ctx:
"
,
ctx
.
message
.
text
);
ctx
.
reply
(
'
Welcome! Up and running.
'
)
})
bot
.
command
(
'
ping
'
,
(
ctx
)
=>
ctx
.
reply
(
`Pong!
${
new
Date
()}
${
Date
.
now
()}
`
))
bot
.
command
(
'
ping
'
,
(
ctx
)
=>
ctx
.
reply
(
`Pong!
${
new
Date
()}
${
Date
.
now
()}
`
))
// bot.on('message', (ctx) => ctx.reply('你好,我是tg_D'))
bot
.
on
(
'
message:text
'
,
(
ctx
)
=>
respMsg
(
ctx
))
async
function
respMsg
(
ctx
)
{
const
message
=
ctx
.
message
as
Message
.
TextMessage
;
let
question
=
message
.
text
;
const
requestData
:
ChatRequest
=
{
chatId
:
'
my_chat_id_20
'
,
stream
:
false
,
detail
:
false
,
// responseChatItemId: 'my_responseChatItemId_1',
variables
:
{
selectdata
:
[
// { datasetId: "677df2c0fd2ccc1d37088969" },
// { datasetId: "677e13e29c52479ad3fce8b8" },
// { datasetId: "677f79639c52479ad308090f" },
{
datasetId
:
"
677e27e9fd2ccc1d370b6737
"
}
]
},
messages
:
[
{
role
:
'
user
'
,
content
:
question
,
},
],
};
let
respMsg
=
await
sendChatRequest
(
requestData
);
if
(
respMsg
)
{
console
.
log
(
"
respMsg:
"
,
respMsg
);
await
bot
.
api
.
sendMessage
(
ctx
.
chat
.
id
,
respMsg
.
choices
[
0
].
message
.
content
);
}
}
const
handleUpdate
=
webhookCallback
(
bot
,
'
std/http
'
)
const
handleUpdate
=
webhookCallback
(
bot
,
'
std/http
'
)
...
...
supabase/functions/tg_bot_E/index.ts
0 → 100644
View file @
c0e075cb
// Follow this setup guide to integrate the Deno language server with your editor:
// https://deno.land/manual/getting_started/setup_your_environment
// This enables autocomplete, go to definition, etc.
console
.
log
(
`Function "telegram-bot" up and running!`
)
import
{
Bot
,
webhookCallback
,
Context
}
from
'
https://deno.land/x/grammy@v1.34.0/mod.ts
'
interface
DifyResponse
{
answer
?:
string
;
[
key
:
string
]:
any
;
}
interface
DifyPayload
{
inputs
:
Record
<
string
,
any
>
;
query
:
string
;
response_mode
:
string
;
conversation_id
:
string
;
user
:
string
;
files
:
any
[];
}
let
question
=
""
;
let
answer
=
""
;
const
bot
=
new
Bot
(
Deno
.
env
.
get
(
'
TELEGRAM_BOT_TOKEN_E
'
)
||
''
)
const
bot_b
=
new
Bot
(
Deno
.
env
.
get
(
'
TELEGRAM_BOT_TOKEN_F
'
)
||
''
)
bot
.
command
(
'
start
'
,
(
ctx
)
=>
ctx
.
reply
(
'
Welcome! Up and running.
'
))
bot
.
command
(
'
ping
'
,
(
ctx
)
=>
ctx
.
reply
(
`Pong!
${
new
Date
()}
${
Date
.
now
()}
`
))
bot
.
on
(
'
message
'
,
(
ctx
)
=>
{
// console.log("ctx:", ctx);
// ctx.reply('你好,我是tg_E');
handleMessage
(
ctx
,
true
);
})
const
handleUpdate
=
webhookCallback
(
bot
,
'
std/http
'
)
async
function
callDifyApi
(
query
:
string
,
apiKey
:
string
,
conversationId
:
string
=
""
):
Promise
<
DifyResponse
>
{
const
url
=
"
https://api.dify.ai/v1/chat-messages
"
;
const
headers
=
{
'
Authorization
'
:
`Bearer
${
apiKey
}
`
,
'
Content-Type
'
:
'
application/json
'
};
const
payload
:
DifyPayload
=
{
inputs
:
{},
query
:
query
,
response_mode
:
"
blocking
"
,
conversation_id
:
conversationId
,
user
:
"
telegram-user
"
,
files
:
[]
};
const
response
=
await
fetch
(
url
,
{
method
:
'
POST
'
,
headers
:
headers
,
body
:
JSON
.
stringify
(
payload
),
});
try
{
const
jsonData
=
await
response
.
json
();
return
jsonData
;
// 返回解析后的 JSON 数据
}
catch
(
err
)
{
const
text
=
await
response
.
text
();
// 捕获非 JSON 响应
console
.
error
(
"
Response is not JSON:
"
,
text
);
let
res
=
{
answer
:
text
};
return
res
;
}
}
async
function
callDify
(
query
:
string
,
difyApiKey
:
string
):
Promise
<
string
>
{
const
response
=
await
callDifyApi
(
query
,
difyApiKey
);
console
.
log
(
difyApiKey
,
response
);
return
response
.
answer
||
"
Sorry, I don't understand.
"
;
}
async
function
handleMessage_userToE
(
chatId
:
number
,
userMessage
:
string
)
{
console
.
log
(
"
handleMessage_userToE
"
,
userMessage
);
const
difyResponse
=
await
callDify
(
userMessage
,
Deno
.
env
.
get
(
'
DIFY_API_KEY_E
'
)
||
""
);
await
bot
.
api
.
sendMessage
(
chatId
,
difyResponse
);
return
difyResponse
;
}
async
function
handleMessage_E_send_F
(
chatId
:
number
,
userMessage
:
string
)
{
console
.
log
(
"
handleMessage_E_send_F
"
,
userMessage
);
const
difyResponse
=
await
callDify
(
userMessage
,
Deno
.
env
.
get
(
'
DIFY_API_KEY_F
'
)
||
""
);
await
bot_b
.
api
.
sendMessage
(
chatId
,
difyResponse
);
return
difyResponse
;
}
async
function
handleMessage
(
ctx
:
Context
,
isFirst
:
boolean
)
{
let
i
=
0
;
while
(
i
<
5
)
{
i
++
;
if
(
isFirst
)
{
const
message
=
ctx
.
message
as
Message
.
TextMessage
;
question
=
message
.
text
;
isFirst
=
false
;
}
answer
=
await
handleMessage_userToE
(
ctx
.
chat
.
id
,
question
);
await
new
Promise
(
resolve
=>
setTimeout
(
resolve
,
2000
));
// 延时2秒钟
question
=
await
handleMessage_E_send_F
(
ctx
.
chat
.
id
,
answer
)
||
""
;
console
.
log
(
"
question
"
,
question
);
}
}
Deno
.
serve
(
async
(
req
:
Request
)
=>
{
try
{
const
url
=
new
URL
(
req
.
url
)
if
(
url
.
searchParams
.
get
(
'
secret
'
)
!==
Deno
.
env
.
get
(
'
FUNCTION_SECRET_E
'
))
{
return
new
Response
(
'
not allowed
'
,
{
status
:
405
})
}
// 检查请求体
if
(
req
.
body
===
null
)
{
return
new
Response
(
'
Empty request body
'
,
{
status
:
400
})
}
const
response
=
await
handleUpdate
(
req
)
if
(
!
response
)
{
return
new
Response
(
'
Invalid update
'
,
{
status
:
400
})
}
return
response
}
catch
(
err
)
{
console
.
error
(
`Error processing request
${
req
.
method
}
${
req
.
url
}
:`
,
err
)
return
new
Response
(
JSON
.
stringify
({
error
:
err
.
message
}),
{
status
:
500
,
headers
:
{
'
Content-Type
'
:
'
application/json
'
}
});
}
})
\ No newline at end of file
supabase/functions/tg_bot_F/index.ts
0 → 100644
View file @
c0e075cb
// Follow this setup guide to integrate the Deno language server with your editor:
// https://deno.land/manual/getting_started/setup_your_environment
// This enables autocomplete, go to definition, etc.
console
.
log
(
`Function "telegram-bot" up and running!`
)
import
{
Bot
,
webhookCallback
}
from
'
https://deno.land/x/grammy@v1.34.0/mod.ts
'
const
bot
=
new
Bot
(
Deno
.
env
.
get
(
'
TELEGRAM_BOT_TOKEN_F
'
)
||
''
)
bot
.
command
(
'
start
'
,
(
ctx
)
=>
ctx
.
reply
(
'
Welcome! Up and running.
'
))
bot
.
command
(
'
ping
'
,
(
ctx
)
=>
ctx
.
reply
(
`Pong!
${
new
Date
()}
${
Date
.
now
()}
`
))
// bot.on('message', (ctx) => ctx.reply('你好,我是tg_F'))
const
handleUpdate
=
webhookCallback
(
bot
,
'
std/http
'
)
Deno
.
serve
(
async
(
req
)
=>
{
try
{
const
url
=
new
URL
(
req
.
url
)
if
(
url
.
searchParams
.
get
(
'
secret
'
)
!==
Deno
.
env
.
get
(
'
FUNCTION_SECRET_F
'
))
{
return
new
Response
(
'
not allowed
'
,
{
status
:
405
})
}
// 检查请求体
if
(
req
.
body
===
null
)
{
return
new
Response
(
'
Empty request body
'
,
{
status
:
400
})
}
const
response
=
await
handleUpdate
(
req
)
if
(
!
response
)
{
return
new
Response
(
'
Invalid update
'
,
{
status
:
400
})
}
return
response
}
catch
(
err
)
{
console
.
error
(
err
)
return
new
Response
(
JSON
.
stringify
({
error
:
err
.
message
}),
{
status
:
500
,
headers
:
{
'
Content-Type
'
:
'
application/json
'
}
});
}
})
\ No newline at end of file
supabase/functions/tg_bot_test/bot.ts
0 → 100644
View file @
c0e075cb
import
{
Bot
,
Context
,
SessionFlavor
}
from
'
https://deno.land/x/grammy@v1.34.0/mod.ts
'
import
{
type
ConversationFlavor
,
conversations
,
createConversation
}
from
"
https://raw.githubusercontent.com/grammyjs/conversations/c90b7fed54d610b7a37c2e0b90e728bc4d739d9b/src/mod.ts
"
;
import
{
guard
,
isAdmin
,
reply
}
from
"
https://deno.land/x/grammy_guard/mod.ts
"
;
import
{
freeStorage
}
from
"
https://deno.land/x/grammy_storages@v2.4.2/free/src/mod.ts
"
;
import
{
createagent
,
updateagent
,
deleteagent
,
createrole
,
updaterole
,
listroles
,
deleterole
,
listagents
,
bindchatagent
,
answerQuestion
,
createknowleage
,
listknowledges
,
addknowlegecollection
,
listknowlegecollection
,
deleteknowlegecollection
,
createaction
}
from
"
./conversations.ts
"
;
// Define a guard
const
isAdminGuard
=
guard
(
isAdmin
,
reply
(
"
You are not an admin
"
));
// Define a context flavor
interface
SessionData
{
agent
:
{
agentName
:
string
;
agentDescription
:
string
;
}
}
type
MyContext
=
Context
&
SessionFlavor
<
SessionData
>
&
ConversationFlavor
<
Context
>
;
async
function
constructorBot
(
botToken
:
string
)
{
const
bot
=
new
Bot
<
MyContext
>
(
botToken
)
let
storageAdapter
=
freeStorage
<
SessionData
>
(
botToken
);
const
storage
=
{
storage
:
{
type
:
"
key
"
,
adapter
:
storageAdapter
,
getStorageKey
:
(
ctx
)
=>
ctx
.
from
?.
id
.
toString
(),
prefix
:
"
agent-
"
,
},
}
bot
.
use
(
conversations
(
storage
));
bot
.
use
(
createConversation
(
bindchatagent
));
bot
.
use
(
createConversation
(
createaction
));
bot
.
use
(
createConversation
(
createagent
));
bot
.
use
(
createConversation
(
updateagent
));
bot
.
use
(
createConversation
(
deleteagent
));
bot
.
use
(
createConversation
(
listagents
));
bot
.
use
(
createConversation
(
createrole
));
bot
.
use
(
createConversation
(
updaterole
));
bot
.
use
(
createConversation
(
listroles
));
bot
.
use
(
createConversation
(
deleterole
));
bot
.
use
(
createConversation
(
createknowleage
));
bot
.
use
(
createConversation
(
listknowledges
));
bot
.
use
(
createConversation
(
addknowlegecollection
));
bot
.
use
(
createConversation
(
listknowlegecollection
));
bot
.
use
(
createConversation
(
deleteknowlegecollection
));
// Define commands
bot
.
command
(
'
start
'
,
async
(
ctx
)
=>
{
await
ctx
.
reply
(
`Welcome! Up and running.`
)
})
bot
.
command
(
"
cancel
"
,
isAdminGuard
,
async
(
ctx
)
=>
{
if
(
ctx
.
conversation
.
active
())
{
await
ctx
.
conversation
.
exitAll
();
}
await
ctx
.
reply
(
"
Leaving.
"
);
});
bot
.
command
(
"
bindchatagent
"
,
isAdminGuard
,
async
(
ctx
)
=>
{
await
ctx
.
conversation
.
enter
(
"
bindchatagent
"
);
});
bot
.
command
(
"
createaction
"
,
isAdminGuard
,
async
(
ctx
)
=>
{
await
ctx
.
conversation
.
enter
(
"
createaction
"
);
});
// Agent
bot
.
command
(
"
createagent
"
,
isAdminGuard
,
async
(
ctx
)
=>
{
await
ctx
.
conversation
.
enter
(
"
createagent
"
);
});
bot
.
command
(
"
updateagent
"
,
isAdminGuard
,
async
(
ctx
)
=>
{
await
ctx
.
conversation
.
enter
(
"
updateagent
"
);
});
bot
.
command
(
"
deleteagent
"
,
isAdminGuard
,
async
(
ctx
)
=>
{
await
ctx
.
conversation
.
enter
(
"
deleteagent
"
);
});
bot
.
command
(
"
listagents
"
,
isAdminGuard
,
async
(
ctx
)
=>
{
await
ctx
.
conversation
.
enter
(
"
listagents
"
);
});
// Knowledge
bot
.
command
(
"
createknowleage
"
,
isAdminGuard
,
async
(
ctx
)
=>
{
await
ctx
.
conversation
.
enter
(
"
createknowleage
"
);
});
bot
.
command
(
"
listknowledges
"
,
isAdminGuard
,
async
(
ctx
)
=>
{
await
ctx
.
conversation
.
enter
(
"
listknowledges
"
);
});
// Knowledge Collection
bot
.
command
(
"
addknowlegecollection
"
,
isAdminGuard
,
async
(
ctx
)
=>
{
await
ctx
.
conversation
.
enter
(
"
addknowlegecollection
"
);
});
bot
.
command
(
"
listknowlegecollection
"
,
isAdminGuard
,
async
(
ctx
)
=>
{
await
ctx
.
conversation
.
enter
(
"
listknowlegecollection
"
);
});
bot
.
command
(
"
deleteknowlegecollection
"
,
isAdminGuard
,
async
(
ctx
)
=>
{
await
ctx
.
conversation
.
enter
(
"
deleteknowlegecollection
"
);
});
// Role
bot
.
command
(
"
createrole
"
,
isAdminGuard
,
async
(
ctx
)
=>
{
await
ctx
.
conversation
.
enter
(
"
createrole
"
);
});
bot
.
command
(
"
updaterole
"
,
isAdminGuard
,
async
(
ctx
)
=>
{
await
ctx
.
conversation
.
enter
(
"
updaterole
"
);
});
bot
.
command
(
"
listroles
"
,
isAdminGuard
,
async
(
ctx
)
=>
{
await
ctx
.
conversation
.
enter
(
"
listroles
"
);
});
bot
.
command
(
"
deleterole
"
,
isAdminGuard
,
async
(
ctx
)
=>
{
await
ctx
.
conversation
.
enter
(
"
deleterole
"
);
});
bot
.
on
(
"
message:text
"
,
async
(
ctx
)
=>
{
console
.
log
(
"
ctx.message.text:
"
,
ctx
.
message
.
text
);
console
.
log
(
"
ctx.me.username:
"
,
ctx
.
me
.
username
);
const
mentions
=
ctx
.
message
.
text
.
match
(
/@
\w
+/g
);
if
(
mentions
?.
includes
(
`@
${
ctx
.
me
.
username
}
`
))
{
const
cleanText
=
ctx
.
message
.
text
.
replace
(
/@
\w
+/g
,
""
).
trim
();
ctx
.
message
.
text
=
cleanText
EdgeRuntime
.
waitUntil
(
answerQuestion
(
ctx
));
}
});
return
bot
;
}
export
{
constructorBot
}
\ No newline at end of file
supabase/functions/tg_bot_test/conversations.ts
0 → 100644
View file @
c0e075cb
import
{
waitForMoreOptionSelection
,
waitForOptionSelection
,
waitForTextInputTips
}
from
"
./conversations_util.ts
"
;
import
{
fetchRoles
,
fetchKnowledge
,
fetchAgentByBotId
,
getBotInfo
,
getBotAcionInfo
,
insertData
,
getUserInfo
,
bindChatAgent
,
fetchKnowledgeCollection
,
getAgentBindKnowledge
,
deleteKnowledgeCollection
,
fetchAgentByUserId
,
bindagentAction
}
from
"
./db.ts
"
;
import
{
type
Conversation
,
type
ConversationFlavor
,
}
from
"
https://raw.githubusercontent.com/grammyjs/conversations/c90b7fed54d610b7a37c2e0b90e728bc4d739d9b/src/mod.ts
"
;
import
{
respMsgAgent
,
respMsgQuestion
,
respKnowledgeApi
,
respKnowledgeCollectionApi
,
respKnowledgeCollectionDelApi
}
from
"
./fastgpt.ts
"
;
const
adminUUID
=
Deno
.
env
.
get
(
'
AGENT_ADMIN
'
)
??
""
;
type
MyContext
=
Context
&
SessionFlavor
<
SessionData
>
&
ConversationFlavor
;
type
MyConversation
=
Conversation
<
MyContext
>
;
async
function
asyncResponse
(
ctx
,
variables
,
agentTips
,
auth_token
)
{
const
{
data
:
res
,
error
}
=
await
respMsgAgent
(
variables
,
agentTips
,
auth_token
);
if
(
error
)
{
console
.
error
(
`Failed to insert data:
${
error
.
message
}
`
);
}
else
{
if
(
res
&&
res
.
choices
&&
res
.
choices
[
0
]
&&
res
.
choices
[
0
].
message
)
{
await
ctx
.
reply
(
res
.
choices
[
0
].
message
.
content
);
}
else
{
await
ctx
.
reply
(
"
Failed to retrieve response message content.
"
);
}
}
}
async
function
createagent
(
conversation
:
MyConversation
,
ctx
:
MyContext
)
{
const
auth_token
=
Deno
.
env
.
get
(
'
FASTGPT_API_KEY_AGENT_CREATE
'
)
??
""
;
console
.
log
(
"
auth_token:
"
,
auth_token
);
const
userInfo
=
await
getUserInfo
(
ctx
.
from
.
id
);
if
(
!
userInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve user information, operation terminated
"
);
return
;
}
const
{
id
:
userUUID
}
=
userInfo
;
console
.
log
(
"
ctx.me.id:
"
,
ctx
.
me
.
id
);
const
botInfo
=
await
getBotInfo
(
ctx
.
me
.
id
);
if
(
!
botInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve bot information, operation terminated
"
);
return
;
}
const
{
id
:
botUUID
}
=
botInfo
;
const
is_admin
=
userUUID
===
adminUUID
;
// fetchRoles
const
roles
=
await
fetchRoles
(
is_admin
?
""
:
botUUID
,
userUUID
);
if
(
!
roles
)
{
await
ctx
.
reply
(
"
Failed to retrieve roles, operation terminated
"
);
return
;
}
const
availableRoles
=
roles
.
map
((
role
)
=>
`[
${
role
.
name
}
],`
).
join
(
"
\n
"
);
const
prompt
=
`
关于agent角色,可选择的角色有:
${
availableRoles
}
您好,现在开始创建agent,请按照以下 格式 输入 agent相关信息:
名称:xxx
描述:xxx
角色:xxx
我会讲的语言:
1,xxx
2,xxx
`
const
agentTips
=
await
waitForTextInputTips
(
conversation
,
ctx
,
prompt
);
if
(
!
agentTips
)
return
;
const
role_type
=
is_admin
?
1
:
2
;
const
variables
=
{
bot_id
:
botUUID
,
user_id
:
userUUID
,
role_type
:
role_type
,
};
await
asyncResponse
(
ctx
,
variables
,
agentTips
,
auth_token
);
// EdgeRuntime.waitUntil()
}
async
function
updateagent
(
conversation
:
MyConversation
,
ctx
:
MyContext
)
{
const
auth_token
=
Deno
.
env
.
get
(
'
FASTGPT_API_KEY_AGENT
'
)
??
""
;
console
.
log
(
"
auth_token:
"
,
auth_token
);
const
botInfo
=
await
getBotInfo
(
ctx
.
me
.
id
);
if
(
!
botInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve bot information, operation terminated
"
);
return
;
}
const
{
id
:
botUUID
}
=
botInfo
;
const
userInfo
=
await
getUserInfo
(
ctx
.
from
.
id
);
if
(
!
userInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve user information, operation terminated
"
);
return
;
}
const
{
id
:
userUUID
}
=
userInfo
;
const
is_admin
=
userUUID
===
adminUUID
;
// fetchRoles
const
roles
=
await
fetchRoles
(
is_admin
?
""
:
botUUID
,
userUUID
);
if
(
!
roles
)
{
await
ctx
.
reply
(
"
Failed to retrieve roles, operation terminated
"
);
return
;
}
const
availableRoles
=
roles
.
map
((
role
)
=>
`[
${
role
.
name
}
],`
).
join
(
"
\n
"
);
const
prompt
=
`
关于agent角色,可选择的角色有:
:
${
availableRoles
}
您好,请问 您希望我帮你做什么呢?您可以这样回答我,比如:
1,把 知识库 xxx 绑定 到 agent上,agent名称为 xxx (绑定知识库)
2,我 需要 把 知识库 xxx 从 名称为 xxx 的agent 上 解除 (解绑知识库)
3,我要把名称为 xxx 的agent 名称 修改 为 xxx (修改名称)
4,修改 名称为 xxx 的 agent 的描述为 xxx (修改描述)
5,把 名称为 xxx 的 agent 的 角色 换为 xxx (更换 角色)
`
const
agentTips
=
await
waitForTextInputTips
(
conversation
,
ctx
,
prompt
);
if
(
!
agentTips
)
return
;
const
role_type
=
is_admin
?
1
:
2
;
const
variables
=
{
bot_id
:
botUUID
,
user_id
:
userUUID
,
role_type
:
role_type
,
};
await
asyncResponse
(
ctx
,
variables
,
agentTips
,
auth_token
);
// EdgeRuntime.waitUntil(asyncResponse(ctx, variables, agentTips, auth_token))
}
async
function
deleteagent
(
conversation
:
MyConversation
,
ctx
:
MyContext
)
{
const
auth_token
=
Deno
.
env
.
get
(
'
FASTGPT_API_KEY_AGENT
'
)
??
""
;
console
.
log
(
"
auth_token:
"
,
auth_token
);
const
userInfo
=
await
getUserInfo
(
ctx
.
from
.
id
);
if
(
!
userInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve user information, operation terminated
"
);
return
;
}
const
{
id
:
userUUID
}
=
userInfo
;
const
botInfo
=
await
getBotInfo
(
ctx
.
me
.
id
);
if
(
!
botInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve bot information, operation terminated
"
);
return
;
}
const
{
id
:
botUUID
}
=
botInfo
;
const
agents
=
await
fetchAgentByBotId
(
botUUID
,
userUUID
);
if
(
!
agents
)
{
await
ctx
.
reply
(
"
Failed to retrieve agent information, operation terminated
"
);
return
;
}
const
agentName
=
agents
.
map
((
agent
)
=>
`agent name:
${
agent
.
name
}
`
).
join
(
"
\n
"
);
const
prompt
=
`
目前支持您删除的agent有:
${
agentName
}
您好,请问 您希望我帮你做什么呢?您可以这样回答我,比如:
我 要删除 xxx agent`
const
agentTips
=
await
waitForTextInputTips
(
conversation
,
ctx
,
prompt
);
if
(
!
agentTips
)
return
;
const
role_type
=
userUUID
===
adminUUID
?
1
:
2
;
const
variables
=
{
bot_id
:
botUUID
,
user_id
:
userUUID
,
role_type
:
role_type
,
};
await
asyncResponse
(
ctx
,
variables
,
agentTips
,
auth_token
);
// EdgeRuntime.waitUntil(asyncResponse(ctx, variables, agentTips, auth_token))
}
async
function
listagents
(
conversation
:
MyConversation
,
ctx
:
MyContext
)
{
const
userInfo
=
await
getUserInfo
(
ctx
.
from
.
id
);
if
(
!
userInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve user information, operation terminated
"
);
return
;
}
const
{
id
:
userUUID
}
=
userInfo
;
const
botInfo
=
await
getBotInfo
(
ctx
.
me
.
id
);
if
(
!
botInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve bot information, operation terminated
"
);
return
;
}
const
{
id
:
botUUID
}
=
botInfo
;
const
agents
=
await
fetchAgentByBotId
(
botUUID
,
userUUID
);
if
(
!
agents
)
{
await
ctx
.
reply
(
"
Failed to retrieve agent information, operation terminated
"
);
return
;
}
if
(
agents
.
length
===
0
)
{
await
ctx
.
reply
(
"
No agents found
"
);
return
;
}
const
agentName
=
agents
.
map
((
agent
)
=>
`agent name:
${
agent
.
name
}
`
).
join
(
"
\n
"
);
await
ctx
.
reply
(
`The agents you can operate are
${
agentName
}
`
);
}
async
function
createrole
(
conversation
:
MyConversation
,
ctx
:
MyContext
)
{
const
auth_token
=
Deno
.
env
.
get
(
'
FASTGPT_API_KEY_ROLE
'
)
??
""
;
console
.
log
(
"
auth_token:
"
,
auth_token
);
const
prompt
=
`您好,很高兴见到您,您可以这样回答我:
创建一个角色
名称:xxx
描述:xxx
性别:男/女/保密
性格:
1,xxx
2,xxx
3,xxx
技能:
1,xxx
2,xxx
3,xxx
目标任务:
1,xxx
2,xxx
我不能做什么:
1,xxx
2,xxx
我会讲的语言:
1,汉语
2,英文
3,西班牙语等`
const
agentTips
=
await
waitForTextInputTips
(
conversation
,
ctx
,
prompt
);
if
(
!
agentTips
)
return
;
const
botInfo
=
await
getBotInfo
(
ctx
.
me
.
id
);
if
(
!
botInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve bot information, operation terminated
"
);
return
;
}
const
{
id
:
botUUID
}
=
botInfo
;
const
userInfo
=
await
getUserInfo
(
ctx
.
from
.
id
);
if
(
!
userInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve user information, operation terminated
"
);
return
;
}
const
{
id
:
userUUID
}
=
userInfo
;
const
isAdmin
=
userUUID
===
adminUUID
;
const
role_type
=
isAdmin
?
1
:
2
;
const
variables
=
{
bot_id
:
botUUID
,
user_id
:
userUUID
,
role_type
:
role_type
,
};
await
asyncResponse
(
ctx
,
variables
,
agentTips
,
auth_token
);
// EdgeRuntime.waitUntil(asyncResponse(ctx, variables, agentTips, auth_token))
}
async
function
updaterole
(
conversation
:
MyConversation
,
ctx
:
MyContext
)
{
const
auth_token
=
Deno
.
env
.
get
(
'
FASTGPT_API_KEY_ROLE
'
)
??
""
;
console
.
log
(
"
auth_token:
"
,
auth_token
);
const
botInfo
=
await
getBotInfo
(
ctx
.
me
.
id
);
if
(
!
botInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve bot information, operation terminated
"
);
return
;
}
const
{
id
:
botUUID
}
=
botInfo
;
const
userInfo
=
await
getUserInfo
(
ctx
.
from
.
id
);
if
(
!
userInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve user information, operation terminated
"
);
return
;
}
const
{
id
:
userUUID
}
=
userInfo
;
const
is_admin
=
userUUID
===
adminUUID
;
// fetchRoles
const
roles
=
await
fetchRoles
(
is_admin
?
""
:
botUUID
,
userUUID
);
if
(
!
roles
)
{
await
ctx
.
reply
(
"
Failed to retrieve roles, operation terminated
"
);
return
;
}
const
roleNames
=
roles
.
map
((
role
)
=>
`[
${
role
.
name
}
],`
).
join
(
"
\n
"
);
const
prompt
=
`
目前支持您修改的角色有:
{
${
roleNames
}
}
您好,很高兴见到您,您可以这样回答我:
修改 名称 为 xxx 的角色 的信息为:
新名称:xxx
描述:xxx
性别:男/女/保密
性格:
1,xxx
2,xxx
3,xxx
技能:
1,xxx
2,xxx
3,xxx
目标任务:
1,xxx
2,xxx
我不能做什么:
1,xxx
2,xxx
我会讲的语言:
1,汉语
2,英文
3,西班牙语等`
const
agentTips
=
await
waitForTextInputTips
(
conversation
,
ctx
,
prompt
);
if
(
!
agentTips
)
return
;
const
role_type
=
is_admin
?
1
:
2
;
const
variables
=
{
bot_id
:
botUUID
,
user_id
:
userUUID
,
role_type
:
role_type
,
};
await
asyncResponse
(
ctx
,
variables
,
agentTips
,
auth_token
);
// EdgeRuntime.waitUntil(asyncResponse(ctx, variables, agentTips, auth_token))
}
async
function
deleterole
(
conversation
:
MyConversation
,
ctx
:
MyContext
)
{
const
auth_token
=
Deno
.
env
.
get
(
'
FASTGPT_API_KEY_ROLE
'
)
??
""
;
console
.
log
(
"
auth_token:
"
,
auth_token
);
const
botInfo
=
await
getBotInfo
(
ctx
.
me
.
id
);
if
(
!
botInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve bot information, operation terminated
"
);
return
;
}
const
{
id
:
botUUID
}
=
botInfo
;
const
userInfo
=
await
getUserInfo
(
ctx
.
from
.
id
);
if
(
!
userInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve user information, operation terminated
"
);
return
;
}
const
{
id
:
userUUID
}
=
userInfo
;
const
is_admin
=
userUUID
===
adminUUID
;
// fetchRoles
const
roles
=
await
fetchRoles
(
is_admin
?
""
:
botUUID
,
userUUID
);
if
(
!
roles
)
{
await
ctx
.
reply
(
"
Failed to retrieve roles, operation terminated
"
);
return
;
}
const
roleNames
=
roles
.
map
((
role
)
=>
`[
${
role
.
name
}
],`
).
join
(
"
\n
"
);
const
prompt
=
`
目前支持您删除的角色有:
{
${
roleNames
}
您好,很高兴见到您,您可以这样回答我:
删除 名称为xxx 的角色`
const
agentTips
=
await
waitForTextInputTips
(
conversation
,
ctx
,
prompt
);
if
(
!
agentTips
)
return
;
const
role_type
=
is_admin
?
1
:
2
;
const
variables
=
{
bot_id
:
botUUID
,
user_id
:
userUUID
,
role_type
:
role_type
,
};
await
asyncResponse
(
ctx
,
variables
,
agentTips
,
auth_token
);
// EdgeRuntime.waitUntil(asyncResponse(ctx, variables, agentTips, auth_token))
}
async
function
listroles
(
conversation
:
MyConversation
,
ctx
:
MyContext
)
{
const
botInfo
=
await
getBotInfo
(
ctx
.
me
.
id
);
if
(
!
botInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve bot information, operation terminated
"
);
return
;
}
const
{
id
:
botUUID
}
=
botInfo
;
const
userInfo
=
await
getUserInfo
(
ctx
.
from
.
id
);
if
(
!
userInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve user information, operation terminated
"
);
return
;
}
const
{
id
:
userUUID
}
=
userInfo
;
const
is_admin
=
userUUID
===
adminUUID
;
// fetchRoles
const
roles
=
await
fetchRoles
(
is_admin
?
""
:
botUUID
,
userUUID
);
if
(
!
roles
)
{
await
ctx
.
reply
(
"
Failed to retrieve roles, operation terminated
"
);
return
;
}
if
(
roles
.
length
===
0
)
{
await
ctx
.
reply
(
"
No roles found
"
);
return
;
}
await
ctx
.
reply
(
`The roles you can operate are:
${
roles
.
map
((
role
)
=>
`[
${
role
.
name
}
],`
).
join
(
"
\n
"
)}
`
);
}
async
function
createknowleage
(
conversation
:
MyConversation
,
ctx
:
MyContext
)
{
const
res
=
await
waitForTextInputTips
(
conversation
,
ctx
,
"
Please input the knowledge name
"
);
if
(
!
res
)
return
;
const
auth_token
=
Deno
.
env
.
get
(
'
FASTGPT_API_KEY_AGENT
'
)
??
""
;
console
.
log
(
"
auth_token:
"
,
auth_token
);
const
botInfo
=
await
getBotInfo
(
ctx
.
me
.
id
);
if
(
!
botInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve bot information, operation terminated
"
);
return
;
}
const
{
id
:
botUUID
}
=
botInfo
;
const
userInfo
=
await
getUserInfo
(
ctx
.
from
.
id
);
if
(
!
userInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve user information, operation terminated
"
);
return
;
}
const
{
id
:
userUUID
}
=
userInfo
;
const
isAdmin
=
userUUID
===
adminUUID
;
const
{
data
:
apiRes
,
error
}
=
await
respKnowledgeApi
(
res
,
auth_token
);
console
.
log
(
"
apiRes:
"
,
apiRes
);
if
(
error
)
{
console
.
error
(
`Failed to insert data:
${
error
.
message
}
`
);
}
else
{
const
insertKnowledgeRes
=
await
insertData
(
"
kb_dataset
"
,
{
name
:
res
,
owner_id
:
userUUID
,
bot_id
:
botUUID
,
ai_dataset_id
:
apiRes
.
data
,
knowledge_type
:
isAdmin
?
1
:
2
});
if
(
!
insertKnowledgeRes
)
{
await
ctx
.
reply
(
"
Failed to insert knowledge data, operation terminated
"
);
}
await
ctx
.
reply
(
"
Knowledge created successfully
"
);
}
}
async
function
listknowledges
(
conversation
:
MyConversation
,
ctx
:
MyContext
)
{
const
botInfo
=
await
getBotInfo
(
ctx
.
me
.
id
);
if
(
!
botInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve bot information, operation terminated
"
);
return
;
}
const
{
id
:
botUUID
}
=
botInfo
;
const
userInfo
=
await
getUserInfo
(
ctx
.
from
.
id
);
if
(
!
userInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve user information, operation terminated
"
);
return
;
}
const
{
id
:
userUUID
}
=
userInfo
;
const
isAdmin
=
userUUID
===
adminUUID
;
const
res
=
await
fetchKnowledge
(
isAdmin
?
""
:
botUUID
,
userUUID
);
if
(
!
res
)
{
await
ctx
.
reply
(
"
Failed to retrieve knowledge information, operation terminated
"
);
return
;
}
if
(
res
.
length
===
0
)
{
await
ctx
.
reply
(
"
No knowledge found
"
);
return
;
}
await
ctx
.
reply
(
`The knowledge you can operate are:
${
res
.
map
((
item
)
=>
`Source:
${
item
.
name
}
`
).
join
(
"
\n
"
)}
`
);
}
async
function
addknowlegecollection
(
conversation
:
MyConversation
,
ctx
:
MyContext
)
{
const
auth_token
=
Deno
.
env
.
get
(
'
FASTGPT_API_KEY_KNOWLEDGE
'
)
??
""
;
console
.
log
(
"
auth_token:
"
,
auth_token
);
const
botInfo
=
await
getBotInfo
(
ctx
.
me
.
id
);
if
(
!
botInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve bot information, operation terminated
"
);
return
;
}
const
{
id
:
botUUID
}
=
botInfo
;
const
userInfo
=
await
getUserInfo
(
ctx
.
from
.
id
);
if
(
!
userInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve user information, operation terminated
"
);
return
;
}
const
{
id
:
userUUID
}
=
userInfo
;
const
isAdmin
=
userUUID
===
adminUUID
;
const
knowledgeResponse
=
await
fetchKnowledge
(
isAdmin
?
""
:
botUUID
,
userUUID
);
if
(
!
knowledgeResponse
)
{
await
ctx
.
reply
(
"
Failed to retrieve knowledge information, operation terminated
"
);
return
;
}
const
knowledgeMap
=
new
Map
(
knowledgeResponse
.
map
((
item
)
=>
[
item
.
id
,
item
.
name
]));
const
knowledgeDatsetMap
=
new
Map
(
knowledgeResponse
.
map
((
item
)
=>
[
item
.
id
,
item
.
ai_dataset_id
]));
const
selectionRes
=
await
waitForOptionSelection
(
conversation
,
ctx
,
"
Please select a knowledge collection to add to
"
,
knowledgeMap
,
false
);
if
(
!
selectionRes
)
return
;
const
knowledgeId
=
selectionRes
.
id
;
const
linkInput
=
await
waitForTextInputTips
(
conversation
,
ctx
,
"
Please input knowledge collection web link
"
);
if
(
!
linkInput
)
return
;
// check if the link is valid
if
(
!
isValidUrl
(
linkInput
))
{
await
ctx
.
reply
(
"
Invalid link, operation terminated
"
);
return
;
}
const
name
=
await
waitForTextInputTips
(
conversation
,
ctx
,
"
Please input knowledge collection name
"
);
if
(
!
name
)
return
;
// check name length than 30
if
(
name
.
length
>
30
)
{
await
ctx
.
reply
(
"
The name length should be less than 30, operation terminated
"
);
return
;
}
const
requestData
=
{
name
:
name
,
link
:
linkInput
,
datasetId
:
knowledgeDatsetMap
.
get
(
knowledgeId
)
??
""
,
trainingType
:
"
chunk
"
}
const
{
data
:
apiRes
,
error
}
=
await
respKnowledgeCollectionApi
(
requestData
,
auth_token
);
console
.
log
(
"
apiRes knowledge collection:
"
,
apiRes
);
if
(
error
)
{
console
.
error
(
`Failed to insert data:
${
error
.
message
}
`
);
}
else
{
const
insertKnowledgeRes
=
await
insertData
(
"
kb_collection
"
,
{
name
:
name
,
source_name
:
linkInput
,
data_source
:
linkInput
,
owner_id
:
userUUID
,
dataset_id
:
knowledgeId
,
collection_id
:
apiRes
.
data
.
collectionId
});
if
(
!
insertKnowledgeRes
)
{
await
ctx
.
reply
(
"
Failed to insert knowledge data, operation terminated
"
);
}
await
ctx
.
reply
(
"
Knowledge collection added successfully
"
);
}
}
async
function
listknowlegecollection
(
conversation
:
MyConversation
,
ctx
:
MyContext
)
{
const
userInfo
=
await
getUserInfo
(
ctx
.
from
.
id
);
if
(
!
userInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve user information, operation terminated
"
);
return
;
}
const
{
id
:
userUUID
}
=
userInfo
;
const
knowledgeCollectionResponse
=
await
fetchKnowledgeCollection
(
userUUID
);
if
(
!
knowledgeCollectionResponse
)
{
await
ctx
.
reply
(
"
Failed to retrieve knowledge collection information, operation terminated
"
);
return
;
}
if
(
knowledgeCollectionResponse
.
length
===
0
)
{
await
ctx
.
reply
(
"
No knowledge collection found
"
);
return
;
}
await
ctx
.
reply
(
`The knowledge collection you can operate are:
${
knowledgeCollectionResponse
.
map
((
item
)
=>
`Source:
${
item
.
data_source
}
`
).
join
(
"
\n
"
)}
`
);
}
async
function
deleteknowlegecollection
(
conversation
:
MyConversation
,
ctx
:
MyContext
)
{
const
auth_token
=
Deno
.
env
.
get
(
'
FASTGPT_API_KEY_KNOWLEDGE
'
)
??
""
;
console
.
log
(
"
auth_token:
"
,
auth_token
);
const
userInfo
=
await
getUserInfo
(
ctx
.
from
.
id
);
if
(
!
userInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve user information, operation terminated
"
);
return
;
}
const
{
id
:
userUUID
}
=
userInfo
;
const
knowledgeCollectionResponse
=
await
fetchKnowledgeCollection
(
userUUID
);
if
(
!
knowledgeCollectionResponse
)
{
await
ctx
.
reply
(
"
Failed to retrieve knowledge collection information, operation terminated
"
);
return
;
}
if
(
knowledgeCollectionResponse
.
length
===
0
)
{
await
ctx
.
reply
(
"
No knowledge collection found
"
);
return
;
}
const
knowledgeCollectionMap
=
new
Map
(
knowledgeCollectionResponse
.
map
((
item
)
=>
[
item
.
id
,
item
.
data_source
]));
const
knowledgeCollectionIdMap
=
new
Map
(
knowledgeCollectionResponse
.
map
((
item
)
=>
[
item
.
id
,
item
.
collection_id
]));
const
selectionRes
=
await
waitForOptionSelection
(
conversation
,
ctx
,
"
Please select a knowledge collection to delete
"
,
knowledgeCollectionMap
,
false
);
if
(
!
selectionRes
)
return
;
const
knowledgeCollectionId
=
selectionRes
.
id
;
console
.
log
(
"
knowledgeCollectionId:
"
,
knowledgeCollectionId
);
const
collectionId
=
knowledgeCollectionIdMap
.
get
(
knowledgeCollectionId
);
const
{
success
,
error
:
databaseError
}
=
await
deleteKnowledgeCollection
(
knowledgeCollectionId
);
if
(
databaseError
)
{
console
.
error
(
`Failed to delete knowledge collection:
${
databaseError
.
message
}
`
);
return
;
}
const
{
data
:
res
,
error
}
=
await
respKnowledgeCollectionDelApi
({
id
:
collectionId
},
auth_token
);
if
(
error
)
{
console
.
error
(
`Failed to delete knowledge collection:
${
error
.
message
}
`
);
return
;
}
console
.
log
(
"
res:
"
,
res
);
if
(
res
.
code
!==
200
)
{
await
ctx
.
reply
(
"
Failed to delete knowledge collection
"
);
return
;
}
await
ctx
.
reply
(
"
Knowledge collection deleted successfully
"
);
}
async
function
bindchatagent
(
conversation
:
MyConversation
,
ctx
:
MyContext
)
{
await
ctx
.
reply
(
"
Proceeding with Agent list, please follow the steps.
"
);
const
{
id
:
botUUID
}
=
await
getBotInfo
(
ctx
.
me
.
id
);
const
{
id
:
userUUID
}
=
await
getUserInfo
(
ctx
.
from
.
id
);
// Step 0: 从ctx中获取bot_id,通过BotId获取 Agent 数据
const
agent
=
await
fetchAgentByBotId
(
botUUID
,
userUUID
);
if
(
!
agent
)
{
await
ctx
.
reply
(
"
No corresponding Agent found, operation terminated
"
);
return
;
}
const
agentMap
=
new
Map
(
agent
.
map
((
item
)
=>
[
item
.
id
,
item
.
name
]));
const
selectedAgent
=
await
waitForOptionSelection
(
conversation
,
ctx
,
"
Please select an Agent to query:
"
,
agentMap
,
false
);
if
(
!
selectedAgent
)
return
;
const
agentId
=
selectedAgent
.
id
;
const
{
success
:
_success
,
error
}
=
await
bindChatAgent
(
agentId
,
ctx
.
message
.
chat
.
id
);
if
(
error
)
{
console
.
error
(
`Bind chat agent is failed:
${
error
.
message
}
`
);
}
else
{
await
ctx
.
reply
(
"
Agent bind chat is successful
"
);
}
}
async
function
createaction
(
conversation
:
MyConversation
,
ctx
:
MyContext
)
{
const
auth_token
=
Deno
.
env
.
get
(
'
FASTGPT_API_KEY_ACTION
'
)
??
""
;
console
.
log
(
"
auth_token:
"
,
auth_token
);
const
prompt
=
`您好,很高兴见到您,您可以这样回答我:
创建一个角色
名称:xxx
描述:xxx
性别:男/女/保密
性格:
1,xxx
2,xxx
3,xxx
技能:
1,xxx
2,xxx
3,xxx
目标任务:
1,xxx
2,xxx
我不能做什么:
1,xxx
2,xxx
我会讲的语言:
1,汉语
2,英文
3,西班牙语等`
const
actionTips
=
await
waitForTextInputTips
(
conversation
,
ctx
,
prompt
);
if
(
!
actionTips
)
return
;
const
botInfo
=
await
getBotInfo
(
ctx
.
me
.
id
);
if
(
!
botInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve bot information, operation terminated
"
);
return
;
}
const
{
id
:
botUUID
}
=
botInfo
;
const
userInfo
=
await
getUserInfo
(
ctx
.
from
.
id
);
if
(
!
userInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve user information, operation terminated
"
);
return
;
}
const
{
id
:
userUUID
}
=
userInfo
;
const
isAdmin
=
userUUID
===
adminUUID
;
const
role_type
=
isAdmin
?
1
:
2
;
const
variables
=
{
bot_id
:
botUUID
,
user_id
:
userUUID
,
role_type
:
role_type
};
const
{
data
:
res
,
error
}
=
await
respMsgAgent
(
variables
,
actionTips
,
auth_token
);
if
(
error
)
{
console
.
error
(
`Failed to insert data:
${
error
.
message
}
`
);
}
else
{
if
(
res
&&
res
.
choices
&&
res
.
choices
[
0
]
&&
res
.
choices
[
0
].
message
)
{
await
ctx
.
reply
(
res
.
choices
[
0
].
message
.
content
);
}
else
{
await
ctx
.
reply
(
"
Failed to retrieve response message content.
"
);
}
}
}
async
function
answerQuestion
(
ctx
:
MyContext
)
{
const
auth_token
=
Deno
.
env
.
get
(
'
FASTGPT_API_KEY_ACTION
'
)
??
""
;
console
.
log
(
"
auth_token:
"
,
auth_token
);
// getBotInfo
const
botInfo
=
await
getBotInfo
(
ctx
.
me
.
id
);
if
(
!
botInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve bot information, operation terminated
"
);
return
;
}
// query data in the agent_action throough bot_id match trigger_object
const
{
id
:
botUUID
}
=
botInfo
;
const
botActionInfo
=
await
getBotAcionInfo
(
botUUID
);
if
(
!
botActionInfo
)
{
await
ctx
.
reply
(
"
Failed to retrieve bot action information, operation terminated
"
);
return
;
}
const
question
=
ctx
.
message
.
text
;
// chat id
// const tg_chat_id = ctx.message.chat.id;
// const datasetJson = await getAgentBindKnowledge(tg_chat_id);
// console.log("datasetJson:", datasetJson);
// if (!datasetJson) {
// await ctx.reply("Failed to retrieve dataset information, operation terminated");
// return;
// }
const
datasetJson
=
{
action_id
:
botActionInfo
.
id
};
console
.
log
(
"
datasetJson:
"
,
datasetJson
);
const
{
data
:
ResData
,
error
}
=
await
respMsgQuestion
(
datasetJson
,
question
,
auth_token
)
if
(
error
)
{
console
.
error
(
`Failed to fetch response:
${
error
.
message
}
`
);
return
;
}
const
answer
=
ResData
.
choices
[
0
].
message
.
content
;
console
.
log
(
"
answer:
"
,
answer
);
// await ctx.reply(answer);
}
// isValidUrl
function
isValidUrl
(
url
:
string
)
{
try
{
new
URL
(
url
);
return
true
;
}
catch
(
error
)
{
console
.
log
(
"
Invalid URL:
"
,
error
);
return
false
;
}
}
export
{
createagent
,
updateagent
,
deleteagent
,
createrole
,
updaterole
,
listroles
,
deleterole
,
listagents
,
bindchatagent
,
answerQuestion
,
createknowleage
,
listknowledges
,
addknowlegecollection
,
listknowlegecollection
,
deleteknowlegecollection
,
createaction
};
\ No newline at end of file
supabase/functions/tg_bot_test/conversations_util.ts
0 → 100644
View file @
c0e075cb
import
{
InlineKeyboard
}
from
'
https://deno.land/x/grammy@v1.34.0/mod.ts
'
// 工具函数:等待用户输入文本
async
function
waitForTextInput
(
conversation
:
MyConversation
,
ctx
:
MyContext
,
promptMessage
:
string
):
Promise
<
string
|
null
>
{
await
ctx
.
reply
(
promptMessage
);
const
inputCtx
=
await
conversation
.
waitFor
(
"
:text
"
);
console
.
log
(
"
inputCtx.message.text:
"
,
inputCtx
.
message
.
text
);
if
(
inputCtx
.
message
.
text
.
startsWith
(
"
/skip
"
))
{
return
"
/skip
"
;
}
if
(
inputCtx
.
message
.
text
.
startsWith
(
"
/cancel
"
))
{
await
ctx
.
reply
(
"
操作已取消
"
);
return
null
;
}
return
inputCtx
.
message
.
text
;
}
async
function
waitForTextInputTips
(
conversation
:
MyConversation
,
ctx
:
MyContext
,
promptMessage
:
string
):
Promise
<
string
|
null
>
{
// reply 格式化提示信息,让信息更加友好
promptMessage
=
promptMessage
.
replace
(
/<b>/g
,
"
[b]
"
).
replace
(
/<
\/
b>/g
,
"
[/b]
"
).
replace
(
/<i>/g
,
"
[i]
"
).
replace
(
/<
\/
i>/g
,
"
[/i]
"
);
await
ctx
.
reply
(
promptMessage
);
const
inputCtx
=
await
conversation
.
waitFor
(
"
:text
"
);
console
.
log
(
"
inputCtx.message.text:
"
,
inputCtx
.
message
.
text
);
if
(
inputCtx
.
message
.
text
.
startsWith
(
"
/skip
"
))
{
return
null
;
}
if
(
inputCtx
.
message
.
text
.
startsWith
(
"
/cancel
"
))
{
await
ctx
.
reply
(
"
操作已取消
"
);
return
null
;
}
return
inputCtx
.
message
.
text
;
}
async
function
waitForFileInput
(
conversation
:
MyConversation
,
ctx
:
MyContext
,
promptMessage
:
string
):
Promise
<
string
|
null
>
{
await
ctx
.
reply
(
promptMessage
);
const
inputCtx
=
await
conversation
.
waitFor
(
"
:file
"
);
console
.
log
(
"
inputCtx
"
,
inputCtx
);
const
res
=
await
inputCtx
.
getFile
();
console
.
log
(
"
res
"
,
res
);
return
inputCtx
.
message
.
text
;
}
// 工具函数:等待用户从键盘选择选项
async
function
waitForOptionSelection
(
conversation
:
MyConversation
,
ctx
:
MyContext
,
promptMessage
:
string
,
options
:
Map
<
string
,
string
>
,
isAddSkip
:
boolean
):
Promise
<
{
id
:
string
;
name
:
string
}
|
null
>
{
if
(
options
.
size
===
0
)
{
await
ctx
.
reply
(
"
没有可用的选项
"
);
return
null
;
}
const
keyboard
=
new
InlineKeyboard
();
for
(
const
[
id
,
name
]
of
options
.
entries
())
{
keyboard
.
text
(
name
,
id
);
keyboard
.
row
();
}
if
(
isAddSkip
)
{
options
.
set
(
"
skip
"
,
"
skip
"
);
keyboard
.
row
().
text
(
"
skip
"
,
"
skip
"
);
}
const
sentMessage
=
await
ctx
.
reply
(
promptMessage
,
{
reply_markup
:
keyboard
});
const
response
=
await
conversation
.
waitForCallbackQuery
([...
options
.
keys
()],
{
timeout
:
60
_000
});
const
selectedId
=
response
.
match
;
if
(
selectedId
==
"
skip
"
)
{
await
response
.
answerCallbackQuery
();
// 反馈用户操作
await
response
.
api
.
editMessageReplyMarkup
(
sentMessage
.
chat
.
id
,
sentMessage
.
message_id
,
{
reply_markup
:
undefined
,
// 清除按钮
});
return
{
id
:
"
skip
"
,
name
:
"
skip
"
};
}
const
selectedName
=
options
.
get
(
selectedId
);
console
.
log
(
"
selectedName:
"
,
selectedName
);
if
(
selectedName
)
{
// 编辑消息,移除 Inline Keyboard 或标记为已选择
await
response
.
api
.
editMessageReplyMarkup
(
sentMessage
.
chat
.
id
,
sentMessage
.
message_id
,
{
reply_markup
:
undefined
,
// 清除按钮
});
// 可选:更新消息文本,标明用户选择
await
response
.
api
.
editMessageText
(
sentMessage
.
chat
.
id
,
sentMessage
.
message_id
,
`You choosed:
${
selectedName
}
`
);
}
await
response
.
answerCallbackQuery
();
// 反馈用户操作
return
selectedName
?
{
id
:
selectedId
,
name
:
selectedName
}
:
null
;
}
async
function
waitForMoreOptionSelection
(
conversation
:
MyConversation
,
ctx
:
MyContext
,
promptMessage
:
string
,
options
:
Map
<
string
,
string
>
,
isAddSkip
:
Boolean
):
Promise
<
Array
<
{
id
:
string
;
name
:
string
}
>>
{
if
(
options
.
size
===
0
)
{
await
ctx
.
reply
(
"
没有可用的选项
"
);
return
[];
}
let
selectedOptions
=
new
Set
<
string
>
();
// 构建键盘
const
getKeyboard
=
()
=>
{
const
keyboard
=
new
InlineKeyboard
();
for
(
const
[
id
,
name
]
of
options
.
entries
())
{
const
label
=
selectedOptions
.
has
(
id
)
?
`✅
${
name
}
`
:
name
;
keyboard
.
text
(
label
,
id
);
}
options
.
set
(
"
done
"
,
"
done
"
);
if
(
isAddSkip
)
{
options
.
set
(
"
skip
"
,
"
skip
"
);
keyboard
.
row
().
text
(
"
skip
"
,
"
skip
"
).
text
(
"
done
"
,
"
done
"
);
}
else
{
keyboard
.
row
().
text
(
"
done
"
,
"
done
"
)
}
return
keyboard
;
};
// 发送消息
let
sentMessage
=
await
ctx
.
reply
(
promptMessage
,
{
reply_markup
:
getKeyboard
()
});
while
(
true
)
{
const
response
=
await
conversation
.
waitForCallbackQuery
([...
options
.
keys
()],
{
timeout
:
60000
});
const
selectedId
=
response
.
match
;
if
(
selectedId
==
"
skip
"
)
{
await
response
.
answerCallbackQuery
({
text
:
"
seleted done!
"
});
// 将所有的选项都隐藏,
await
response
.
api
.
editMessageReplyMarkup
(
sentMessage
.
chat
.
id
,
sentMessage
.
message_id
,
{
reply_markup
:
undefined
,
});
break
;
}
// if user click "done"
if
(
selectedId
===
"
done
"
)
{
await
response
.
answerCallbackQuery
({
text
:
"
seleted done!
"
});
// 将所有的选项都隐藏,
await
response
.
api
.
editMessageReplyMarkup
(
sentMessage
.
chat
.
id
,
sentMessage
.
message_id
,
{
reply_markup
:
undefined
,
});
const
selectedLanguages
=
Array
.
from
(
selectedOptions
).
map
((
id
)
=>
({
id
,
name
:
options
.
get
(
id
)
!
,
}));
await
response
.
api
.
editMessageText
(
sentMessage
.
chat
.
id
,
sentMessage
.
message_id
,
`You selected:
${
selectedLanguages
.
map
((
lang
)
=>
lang
.
name
).
join
(
"
,
"
)}
`
);
break
;
}
// 切换选中状态
if
(
selectedOptions
.
has
(
selectedId
))
{
selectedOptions
.
delete
(
selectedId
);
}
else
{
selectedOptions
.
add
(
selectedId
);
}
// 更新键盘显示状态
await
response
.
answerCallbackQuery
();
// 反馈用户操作
await
response
.
api
.
editMessageReplyMarkup
(
sentMessage
.
chat
.
id
,
sentMessage
.
message_id
,
{
reply_markup
:
getKeyboard
(),
});
}
// 返回结果
const
result
=
Array
.
from
(
selectedOptions
).
map
((
id
)
=>
({
id
,
name
:
options
.
get
(
id
)
!
,
}));
return
result
;
}
export
{
waitForTextInput
,
waitForOptionSelection
,
waitForMoreOptionSelection
,
waitForTextInputTips
,
waitForFileInput
};
\ No newline at end of file
supabase/functions/tg_bot_test/db.ts
0 → 100644
View file @
c0e075cb
import
{
time
}
from
"
node:console
"
;
import
{
createClient
}
from
"
jsr:@supabase/supabase-js@2
"
;
const
supabase
=
createClient
(
Deno
.
env
.
get
(
'
SUPABASE_URL
'
)
??
''
,
Deno
.
env
.
get
(
'
SUPABASE_ANON_KEY
'
)
??
''
)
// 工具函数:获取角色数据
async
function
fetchRoles
(
bot_id
:
string
,
owner_id
:
string
):
Promise
<
{
id
:
string
;
name
:
string
}[]
|
null
>
{
if
(
bot_id
!==
""
)
{
// deleted_at is timestampz type
const
{
data
:
rolesData
,
error
}
=
await
supabase
.
from
(
"
agent_role
"
).
select
(
"
id, name
"
).
eq
(
"
bot_id
"
,
bot_id
).
eq
(
"
owner_id
"
,
owner_id
).
is
(
"
deleted_at
"
,
null
);
if
(
error
||
!
rolesData
)
{
console
.
error
(
"
获取角色数据失败:
"
,
error
?.
message
||
"
未知错误
"
);
return
null
;
}
return
rolesData
}
else
{
const
{
data
:
rolesData
,
error
}
=
await
supabase
.
from
(
"
agent_role
"
).
select
(
"
id, name
"
).
eq
(
"
owner_id
"
,
owner_id
).
is
(
"
deleted_at
"
,
null
);
if
(
error
||
!
rolesData
)
{
console
.
error
(
"
获取角色数据失败:
"
,
error
?.
message
||
"
未知错误
"
);
return
null
;
}
return
rolesData
}
}
async
function
fetchKnowledge
(
bot_id
:
string
,
owner_id
:
string
):
Promise
<
{
id
:
string
;
name
:
string
,
ai_dataset_id
:
string
}[]
|
null
>
{
if
(
bot_id
!==
""
)
{
const
{
data
:
knowledgeData
,
error
}
=
await
supabase
.
from
(
"
kb_dataset
"
).
select
(
"
id, name,ai_dataset_id
"
).
eq
(
"
bot_id
"
,
bot_id
).
eq
(
"
owner_id
"
,
owner_id
).
is
(
"
deleted_at
"
,
null
);
if
(
error
||
!
knowledgeData
)
{
console
.
error
(
"
获取knowledge数据失败:
"
,
error
?.
message
||
"
未知错误
"
);
return
null
;
}
return
knowledgeData
;
}
else
{
const
{
data
:
knowledgeData
,
error
}
=
await
supabase
.
from
(
"
kb_dataset
"
).
select
(
"
id, name,ai_dataset_id
"
).
eq
(
"
owner_id
"
,
owner_id
).
is
(
"
deleted_at
"
,
null
);
if
(
error
||
!
knowledgeData
)
{
console
.
error
(
"
获取knowledge数据失败:
"
,
error
?.
message
||
"
未知错误
"
);
return
null
;
}
return
knowledgeData
;
}
}
async
function
fetchKnowledgeCollection
(
owner_id
:
string
):
Promise
<
{
id
:
string
;
data_source
:
string
,
collection_id
:
string
}[]
|
null
>
{
const
{
data
:
knowledgeData
,
error
}
=
await
supabase
.
from
(
"
kb_collection
"
).
select
(
"
id, data_source,collection_id
"
).
eq
(
"
owner_id
"
,
owner_id
).
is
(
"
deleted_at
"
,
null
);
if
(
error
||
!
knowledgeData
)
{
console
.
error
(
"
获取knowledge collection数据失败:
"
,
error
?.
message
||
"
未知错误
"
);
return
null
;
}
return
knowledgeData
;
}
// 工具函数:获取Agent数据
async
function
fetchAgents
(
owner_id
:
string
):
Promise
<
Map
<
string
,
string
>>
{
const
{
data
:
agentsData
,
error
}
=
await
supabase
.
from
(
"
agent
"
).
select
(
"
id,name
"
).
eq
(
"
is_delete
"
,
false
).
eq
(
"
owner_id
"
,
owner_id
);
if
(
error
||
!
agentsData
)
{
console
.
error
(
"
获取Agent数据失败:
"
,
error
?.
message
||
"
未知错误
"
);
return
new
Map
();
}
return
new
Map
(
agentsData
.
map
((
agent
)
=>
[
agent
.
id
,
agent
.
name
]));
}
async
function
bindChatAgent
(
agentId
:
string
,
chatId
:
number
)
{
// step1 : 先查询绑定关系是否存在
const
{
count
,
error
}
=
await
supabase
.
from
(
"
agent_tg
"
)
.
select
(
"
*
"
,
{
count
:
"
exact
"
,
head
:
true
})
// 使用 `count: "exact"` 获取满足条件的记录数
.
eq
(
"
tg_chat_id
"
,
chatId
)
.
eq
(
"
agent_id
"
,
agentId
);
// step2 : 如果不存在,则插入新数据
if
(
error
||
count
===
null
)
{
console
.
error
(
"
获取记录数量失败:
"
,
error
?.
message
||
"
未知错误
"
);
return
{
success
:
false
,
error
:
error
};
}
console
.
log
(
"
count:
"
,
count
);
if
(
count
===
0
)
{
const
{
error
}
=
await
supabase
.
from
(
"
agent_tg
"
).
insert
({
agent_id
:
agentId
,
tg_chat_id
:
chatId
,
is_active
:
true
});
if
(
error
)
{
console
.
error
(
`插入Agent数据失败:
${
error
.
message
}
`
);
return
{
success
:
false
,
error
:
error
};
}
return
{
success
:
true
,
error
:
undefined
};
}
else
{
// step3 : 如果存在,则更新数据
const
{
error
}
=
await
supabase
.
from
(
"
agent_tg
"
).
update
({
"
agent_id
"
:
agentId
,
is_active
:
true
}).
eq
(
"
tg_chat_id
"
,
chatId
);
if
(
error
)
{
console
.
error
(
`更新Agent数据失败:
${
error
.
message
}
`
);
return
{
success
:
false
,
error
:
error
};
}
return
{
success
:
true
,
error
:
undefined
};
}
}
async
function
bindagentAction
(
agentIds
:
string
[])
{
// step1 : 先查询绑定关系是否存在
const
{
data
,
error
}
=
await
supabase
.
from
(
"
agent_action
"
)
.
select
(
"
id
"
)
.
eq
(
"
agents
"
,
agentIds
);
if
(
error
||
!
data
)
{
console
.
error
(
"
获取记录数量失败:
"
,
error
?.
message
||
"
未知错误
"
);
return
{
success
:
false
,
error
:
error
};
}
console
.
log
(
"
data:
"
,
data
);
if
(
data
.
length
===
0
)
{
const
{
error
}
=
await
supabase
.
from
(
"
agent_action
"
).
insert
({
action_type
:
"
chat_topic
"
,
agents
:
agentIds
});
if
(
error
)
{
console
.
error
(
`插入Agent数据失败:
${
error
.
message
}
`
);
return
{
success
:
false
,
error
:
error
};
}
return
{
success
:
true
,
error
:
undefined
};
}
else
{
return
{
success
:
true
,
error
:
undefined
};
}
}
// 工具函数:updateAgent
async
function
updateAgent
(
id
:
string
,
data
)
{
const
{
error
}
=
await
supabase
.
from
(
"
agent
"
).
update
(
data
).
eq
(
"
id
"
,
id
);
if
(
error
)
{
console
.
error
(
`更新Agent数据失败:
${
error
.
message
}
`
);
return
{
success
:
false
,
error
};
}
return
{
success
:
true
};
}
// 工具函数:getAgentInfo
async
function
getAgentInfo
(
id
:
string
)
{
let
result
=
{};
const
{
data
,
error
}
=
await
supabase
.
from
(
"
agent
"
).
select
(
"
*
"
).
eq
(
"
id
"
,
id
).
single
();
if
(
error
||
!
data
)
{
console
.
error
(
"
获取Agent数据失败:
"
,
error
?.
message
||
"
未知错误
"
);
return
{
data
:
null
,
error
:
error
};
}
// 通过agent.role_id查询agent_role表获取role_name
const
{
data
:
roleData
,
error
:
roleError
}
=
await
supabase
.
from
(
"
agent_role
"
).
select
(
"
name
"
).
eq
(
"
id
"
,
data
.
role_id
).
single
();
if
(
roleError
||
!
roleData
)
{
console
.
error
(
"
获取Agent Role数据失败:
"
,
roleError
?.
message
||
"
未知错误
"
);
return
{
data
:
null
,
error
:
roleError
};
}
// 通过agent.knowledges查询kb_dataset表获取knowledge_name
const
{
data
:
knowledgeData
,
error
:
knowledgeError
}
=
await
supabase
.
from
(
"
kb_dataset
"
).
select
(
"
name
"
).
in
(
"
id
"
,
data
.
knowledges
);
if
(
knowledgeError
||
!
knowledgeData
)
{
console
.
error
(
"
获取Agent Knowledge数据失败:
"
,
knowledgeError
?.
message
||
"
未知错误
"
);
return
{
data
:
null
,
error
:
knowledgeError
};
}
const
{
data
:
botData
,
error
:
botError
}
=
await
supabase
.
from
(
"
bot
"
).
select
(
"
tg_name
"
).
eq
(
"
id
"
,
data
.
bot_id
).
single
();
if
(
botError
||
!
botData
)
{
console
.
error
(
"
获取Agent Bot数据失败:
"
,
botError
?.
message
||
"
未知错误
"
);
return
{
data
:
null
,
error
:
botError
};
}
result
=
{
agentName
:
data
.
name
,
agentDescription
:
data
.
description
,
role_name
:
roleData
.
name
,
knowledge_names
:
knowledgeData
.
map
((
item
)
=>
item
.
name
),
bot_name
:
botData
.
name
,
};
return
{
data
:
result
,
error
:
null
};
}
async
function
getAgentBindKnowledge
(
tg_chat_id
:
number
)
{
const
{
data
:
res
,
error
}
=
await
supabase
.
from
(
"
agent_tg
"
).
select
(
"
agent_id
"
).
eq
(
"
tg_chat_id
"
,
tg_chat_id
).
single
();
if
(
error
||
!
res
)
{
console
.
error
(
"
获取AgentTG数据失败:
"
,
error
?.
message
||
"
未知错误
"
);
return
null
;
}
const
{
data
:
agentData
,
error
:
agentError
}
=
await
supabase
.
from
(
"
agent
"
).
select
(
"
knowledges
"
).
eq
(
"
id
"
,
res
.
agent_id
).
is
(
"
deleted_at
"
,
null
).
single
();
if
(
agentError
||
!
agentData
)
{
console
.
error
(
"
获取Agent数据失败:
"
,
agentError
?.
message
||
"
未知错误
"
);
return
null
;
}
if
(
agentData
.
knowledges
===
null
||
agentData
.
knowledges
.
length
===
0
)
{
return
null
;
}
const
{
data
:
knowledgeData
,
error
:
knowledgeError
}
=
await
supabase
.
from
(
"
kb_dataset
"
).
select
(
"
ai_dataset_id
"
).
in
(
"
id
"
,
agentData
.
knowledges
);
if
(
knowledgeError
||
!
knowledgeData
)
{
console
.
error
(
"
获取Knowledge数据失败:
"
,
knowledgeError
?.
message
||
"
未知错误
"
);
return
null
;
}
if
(
knowledgeData
.
length
===
0
)
{
return
null
;
}
let
knowledgeRequest
=
{
agent_id
:
res
.
agent_id
,
datasets
:
[]
};
knowledgeData
.
forEach
((
item
)
=>
{
knowledgeRequest
.
datasets
.
push
({
datasetId
:
item
.
ai_dataset_id
});
});
return
knowledgeRequest
;
}
// database functions deleteAgent - update is_delete to true
async
function
deleteAgent
(
id
:
string
)
{
const
{
error
}
=
await
supabase
.
from
(
"
agent
"
).
update
({
is_delete
:
true
}).
eq
(
"
id
"
,
id
);
if
(
error
)
{
console
.
error
(
`删除Agent数据失败:
${
error
.
message
}
`
);
return
{
success
:
false
,
error
};
}
return
{
success
:
true
};
}
async
function
deleteKnowledgeCollection
(
id
:
string
)
{
const
{
error
}
=
await
supabase
.
from
(
"
kb_collection
"
).
update
({
deleted_at
:
new
Date
().
toISOString
()
}).
eq
(
"
id
"
,
id
);
if
(
error
)
{
console
.
error
(
`删除collection数据失败:
${
error
.
message
}
`
);
return
{
success
:
false
,
error
:
error
};
}
return
{
success
:
true
,
error
:
null
};
}
// 工具函数:获取指定BotId的Agent数据
async
function
fetchAgentByBotId
(
botId
:
string
,
owner_id
:
string
):
Promise
<
{
id
:
string
;
name
:
string
}[]
|
null
>
{
const
{
data
:
agentData
,
error
}
=
await
supabase
.
from
(
"
agent
"
)
.
select
(
"
id,name
"
)
.
eq
(
"
bot_id
"
,
botId
)
.
eq
(
"
owner_id
"
,
owner_id
)
.
eq
(
"
is_delete
"
,
false
)
.
is
(
"
deleted_at
"
,
null
);
if
(
error
||
!
agentData
)
{
console
.
error
(
"
获取Agent数据失败:
"
,
error
?.
message
||
"
未知错误
"
);
return
null
;
}
return
agentData
;
}
async
function
fetchAgentByUserId
(
owner_id
:
string
):
Promise
<
{
id
:
string
;
name
:
string
,
bot_id
:
string
}[]
|
null
>
{
const
{
data
:
agentData
,
error
}
=
await
supabase
.
from
(
"
agent
"
)
.
select
(
"
id,name,bot_id
"
)
.
eq
(
"
owner_id
"
,
owner_id
)
.
eq
(
"
is_delete
"
,
false
)
.
is
(
"
deleted_at
"
,
null
);
if
(
error
||
!
agentData
)
{
console
.
error
(
"
获取Agent数据失败:
"
,
error
?.
message
||
"
未知错误
"
);
return
null
;
}
return
agentData
;
}
// 通过传入的表名以及data进行插入操作
async
function
insertData
<
T
extends
Record
<
string
,
any
>>
(
tableName
:
string
,
data
:
T
):
Promise
<
{
success
:
boolean
;
error
?:
Error
}
>
{
const
{
error
}
=
await
supabase
.
from
(
tableName
).
insert
(
data
);
if
(
error
)
{
console
.
error
(
`插入数据失败:
${
error
.
message
}
`
);
return
{
success
:
false
,
error
:
error
};
}
return
{
success
:
true
,
error
:
null
};
}
async
function
getBotInfo
(
botId
:
string
):
Promise
<
{
id
:
string
}
|
null
>
{
const
{
data
,
error
}
=
await
supabase
.
from
(
"
bot
"
).
select
(
"
id
"
).
eq
(
"
tg_id
"
,
botId
).
single
();
if
(
error
||
!
data
)
{
console
.
error
(
"
获取Bot数据失败:
"
,
error
?.
message
||
"
未知错误
"
);
return
null
;
}
console
.
log
(
"
Bot数据:
"
,
data
);
return
data
;
}
async
function
getBotAcionInfo
(
triggerObject
:
string
):
Promise
<
{
id
:
string
}
|
null
>
{
const
{
data
,
error
}
=
await
supabase
.
from
(
"
agent_action
"
).
select
(
"
id
"
).
eq
(
"
trigger_object
"
,
triggerObject
).
single
();
if
(
error
||
!
data
)
{
console
.
error
(
"
获取BotAction数据失败
"
,
error
?.
message
||
"
未知错误
"
);
return
null
;
}
console
.
log
(
"
BotAction数据:
"
,
data
);
return
data
;
}
async
function
getUserInfo
(
userId
:
number
):
Promise
<
{
id
:
string
}
|
null
>
{
const
{
data
,
error
}
=
await
supabase
.
from
(
"
user
"
).
select
(
"
id
"
).
eq
(
"
tg_id
"
,
userId
).
single
();
if
(
error
||
!
data
)
{
console
.
error
(
"
获取User数据失败:
"
,
error
?.
message
||
"
未知错误
"
);
return
null
;
}
console
.
log
(
"
User数据:
"
,
data
);
return
data
;
}
export
{
fetchRoles
,
fetchAgents
,
fetchAgentByBotId
,
insertData
,
getBotInfo
,
getUserInfo
,
updateAgent
,
fetchKnowledge
,
deleteAgent
,
getAgentInfo
,
bindChatAgent
,
fetchKnowledgeCollection
,
getAgentBindKnowledge
,
deleteKnowledgeCollection
,
fetchAgentByUserId
,
bindagentAction
,
getBotAcionInfo
};
\ No newline at end of file
supabase/functions/tg_bot_test/fastgpt.ts
0 → 100644
View file @
c0e075cb
interface
ChatRequest
{
chatId
:
string
;
stream
:
boolean
;
detail
:
boolean
;
responseChatItemId
:
string
;
variables
:
{};
messages
:
Array
<
{
role
:
string
;
content
:
string
;
}
>
;
}
interface
ChatResponse
{
id
:
string
;
model
:
string
;
usage
:
{
prompt_tokens
:
number
;
completion_tokens
:
number
;
total_tokens
:
number
;
};
choices
:
Array
<
{
message
:
{
role
:
string
;
content
:
string
;
};
finish_reason
:
string
;
index
:
number
;
}
>
;
}
interface
CreateKnowledgeRequest
{
name
:
string
;
}
interface
CreateKnowledgeCollectionRequest
{
link
:
string
;
datasetId
:
string
;
name
:
string
;
trainingType
:
string
;
}
interface
DeleteKnowledgeCollectionRequest
{
id
:
string
;
}
interface
CreateKnowledgeCollectionResponse
{
code
:
number
;
statusText
:
string
;
message
:
string
;
data
:
{
collectionId
:
string
;
};
}
interface
CreateKnowledgeResponse
{
code
:
number
;
statusText
:
string
;
message
:
string
;
data
:
string
;
}
async
function
sendChatRequest
(
requestData
:
ChatRequest
,
auth_token
:
string
):
Promise
<
ChatResponse
|
null
>
{
try
{
const
API_URL
=
Deno
.
env
.
get
(
'
FASTGPT_API_URL
'
)
??
""
;
const
response
=
await
fetch
(
API_URL
,
{
method
:
'
POST
'
,
headers
:
{
Authorization
:
`Bearer
${
auth_token
}
`
,
'
Content-Type
'
:
'
application/json
'
,
},
body
:
JSON
.
stringify
(
requestData
),
});
if
(
!
response
.
ok
)
{
console
.
error
(
'
Failed to fetch:
'
,
response
.
statusText
);
return
null
;
}
const
data
:
ChatResponse
=
await
response
.
json
();
return
data
;
}
catch
(
error
)
{
console
.
error
(
'
Error during request:
'
,
error
);
return
null
;
}
}
async
function
postKnowledgeRequest
(
requestData
:
CreateKnowledgeRequest
,
auth_token
:
string
,
op
:
string
):
Promise
<
CreateKnowledgeResponse
|
null
>
{
try
{
const
API_URL
=
Deno
.
env
.
get
(
'
FASTGPT_KNOWLEDGE_URL
'
)
??
""
;
const
response
=
await
fetch
(
`
${
API_URL
}
/
${
op
}
`
,
{
method
:
'
POST
'
,
headers
:
{
Authorization
:
`Bearer
${
auth_token
}
`
,
'
Content-Type
'
:
'
application/json
'
,
},
body
:
JSON
.
stringify
(
requestData
),
});
if
(
!
response
.
ok
)
{
console
.
error
(
'
Failed to fetch:
'
,
response
.
statusText
);
return
null
;
}
const
data
:
CreateKnowledgeResponse
=
await
response
.
json
();
if
(
data
.
code
!=
200
)
{
console
.
error
(
'
Failed to fetch:
'
,
data
.
message
);
return
null
;
}
return
data
;
}
catch
(
error
)
{
console
.
error
(
'
Error during request:
'
,
error
);
return
null
;
}
}
async
function
postKnowledgeCollectionRequest
(
requestData
,
auth_token
:
string
,
is_create
:
boolean
,
op
:
string
):
Promise
<
CreateKnowledgeCollectionResponse
|
null
>
{
try
{
const
API_URL
=
Deno
.
env
.
get
(
'
FASTGPT_KNOWLEDGE_COLLECTION_URL
'
)
??
""
;
let
url
=
`
${
API_URL
}${
is_create
?
"
/create
"
:
"
/delete
"
}${
op
==
""
?
""
:
op
}
`
const
method
=
`
${
is_create
?
"
POST
"
:
"
DELETE
"
}
`
const
request
=
{
method
:
method
,
headers
:
{
Authorization
:
`Bearer
${
auth_token
}
`
,
'
Content-Type
'
:
'
application/json
'
,
}
}
if
(
is_create
)
{
request
.
body
=
JSON
.
stringify
(
requestData
);
}
else
{
url
=
`
${
url
}
?id=
${
requestData
.
id
}
`
}
console
.
log
(
"
method:
"
,
method
);
console
.
log
(
"
url:
"
,
url
);
console
.
log
(
"
request:
"
,
request
);
const
response
=
await
fetch
(
url
,
request
);
if
(
!
response
.
ok
)
{
console
.
error
(
'
Failed to fetch:
'
,
response
.
statusText
);
return
null
;
}
const
data
:
CreateKnowledgeCollectionResponse
=
await
response
.
json
();
if
(
data
.
code
!=
200
)
{
console
.
error
(
'
Failed to fetch:
'
,
data
.
message
);
return
null
;
}
return
data
;
}
catch
(
error
)
{
console
.
error
(
'
Error during request:
'
,
error
);
return
null
;
}
}
async
function
respMsgAgent
(
variables
,
question
:
any
,
auth_token
:
string
)
{
const
requestData
:
ChatRequest
=
{
stream
:
false
,
detail
:
false
,
variables
:
variables
,
messages
:
[
{
role
:
'
user
'
,
content
:
question
,
},
],
};
console
.
log
(
"
Sending request to third-party API:
"
,
requestData
);
const
res
=
await
sendChatRequest
(
requestData
,
auth_token
);
console
.
log
(
"
Send request to third-party API success
"
);
if
(
res
==
null
)
{
return
{
data
:
null
,
error
:
new
Error
(
"
Failed to fetch response
"
)
};
}
return
{
data
:
res
,
error
:
null
};
}
async
function
respKnowledgeApi
(
name
:
string
,
auth_token
:
string
)
{
const
requestData
=
{
name
:
name
};
const
res
=
await
postKnowledgeRequest
(
requestData
,
auth_token
,
"
create
"
);
if
(
res
==
null
)
{
return
{
data
:
null
,
error
:
new
Error
(
"
Failed to fetch response
"
)
};
}
return
{
data
:
res
,
error
:
null
};
}
async
function
respKnowledgeCollectionApi
(
requestData
:
CreateKnowledgeCollectionRequest
,
auth_token
:
string
)
{
const
res
=
await
postKnowledgeCollectionRequest
(
requestData
,
auth_token
,
true
,
"
/link
"
);
if
(
res
==
null
)
{
return
{
data
:
null
,
error
:
new
Error
(
"
Failed to fetch response
"
)
};
}
return
{
data
:
res
,
error
:
null
};
}
async
function
respKnowledgeCollectionDelApi
(
requestData
:
DeleteKnowledgeCollectionRequest
,
auth_token
:
string
)
{
const
res
=
await
postKnowledgeCollectionRequest
(
requestData
,
auth_token
,
false
,
""
);
if
(
res
==
null
)
{
return
{
data
:
null
,
error
:
new
Error
(
"
Failed to fetch response
"
)
};
}
return
{
data
:
res
,
error
:
null
};
}
async
function
respMsgQuestion
(
variables
,
question
:
any
,
auth_token
:
string
)
{
const
requestData
:
ChatRequest
=
{
stream
:
false
,
detail
:
false
,
variables
:
variables
,
messages
:
[
{
role
:
'
user
'
,
content
:
question
,
},
],
};
console
.
log
(
"
Sending request to third-party API:
"
,
requestData
);
const
res
=
await
sendChatRequest
(
requestData
,
auth_token
);
console
.
log
(
"
Send request to third-party API success
"
);
if
(
res
==
null
)
{
return
{
data
:
null
,
error
:
new
Error
(
"
Failed to fetch response
"
)
};
}
return
{
data
:
res
,
error
:
null
};
}
export
{
respMsgAgent
,
respMsgQuestion
,
respKnowledgeApi
,
respKnowledgeCollectionApi
,
respKnowledgeCollectionDelApi
}
\ No newline at end of file
supabase/functions/tg_bot_test/index.ts
0 → 100644
View file @
c0e075cb
// Follow this setup guide to integrate the Deno language server with your editor:
// https://deno.land/manual/getting_started/setup_your_environment
// This enables autocomplete, go to definition, etc.
console
.
log
(
`Function "telegram-bot" up and running!`
)
import
"
jsr:@supabase/functions-js/edge-runtime.d.ts
"
;
import
{
webhookCallback
}
from
'
https://deno.land/x/grammy@v1.34.0/mod.ts
'
import
{
constructorBot
}
from
"
./bot.ts
"
;
Deno
.
serve
(
async
(
req
)
=>
{
try
{
const
url
=
new
URL
(
req
.
url
)
if
(
url
.
searchParams
.
get
(
'
secret
'
)
!==
Deno
.
env
.
get
(
'
FUNCTION_SECRET_TEST
'
))
{
return
new
Response
(
'
not allowed
'
,
{
status
:
405
})
}
const
user
=
url
.
searchParams
.
get
(
'
user
'
);
const
supportBot
=
JSON
.
parse
(
Deno
.
env
.
get
(
'
SUPPORT_BOT
'
)
||
'
[]
'
);
if
(
!
supportBot
.
includes
(
user
))
{
return
new
Response
(
'
not allowed
'
,
{
status
:
405
})
}
// 检查请求体
if
(
req
.
body
===
null
)
{
return
new
Response
(
'
Empty request body
'
,
{
status
:
400
})
}
const
SUPPORT_BOT_TOKEN_ENV
=
Deno
.
env
.
get
(
'
SUPPORT_BOT_TOKEN
'
)
||
''
;
const
supportBotToken
=
SUPPORT_BOT_TOKEN_ENV
.
split
(
"
;
"
).
reduce
((
acc
,
pair
)
=>
{
const
[
key
,
value
]
=
pair
.
split
(
"
~
"
);
acc
[
key
]
=
value
;
return
acc
;
},
{});
console
.
log
(
"
supportBotToken:
"
,
supportBotToken
);
const
botToken
=
supportBotToken
[
user
];
console
.
log
(
"
botToken:
"
,
botToken
);
const
bot
=
await
constructorBot
(
botToken
);
const
handleUpdate
=
webhookCallback
(
bot
,
'
std/http
'
);
const
response
=
await
handleUpdate
(
req
)
if
(
!
response
)
{
return
new
Response
(
'
Invalid update
'
,
{
status
:
400
})
}
return
response
}
catch
(
err
)
{
console
.
error
(
err
)
return
new
Response
(
JSON
.
stringify
({
error
:
err
.
message
}),
{
status
:
500
,
headers
:
{
'
Content-Type
'
:
'
application/json
'
}
});
}
})
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment