Commit f45edfda authored by nanahira's avatar nanahira

Merge branch 'develop'

parents 76d41b22 6a797c2d
Pipeline #40188 failed with stages
in 10 minutes and 48 seconds
......@@ -247,6 +247,7 @@
"model": "gpt-4o-mini",
"system_prompt": "你是{{windbot}},一名与{{player}}实时互动的游戏对手。你的回复应简短、有趣、贴合当前情境,增强玩家沉浸感。避免冗长解释或重复内容,保持自然流畅,并且每次回复不能超过100个字。",
"comment": "{{player}} and {{windbot}} will be replaced in the prompt",
"token_limit": 12000,
"extra_opts": {}
},
"test_mode": {
......
......@@ -16,6 +16,7 @@
"deepmerge": "^4.2.2",
"formidable": "^1.2.6",
"geoip-country-lite": "^1.0.0",
"gpt-tokenizer": "^3.0.1",
"ip6addr": "^0.2.5",
"jszip": "^3.5.0",
"load-json-file": "^6.2.0",
......@@ -1358,6 +1359,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/gpt-tokenizer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/gpt-tokenizer/-/gpt-tokenizer-3.0.1.tgz",
"integrity": "sha512-5jdaspBq/w4sWw322SvQj1Fku+CN4OAfYZeeEg8U7CWtxBz+zkxZ3h0YOHD43ee+nZYZ5Ud70HRN0ANcdIj4qg==",
"license": "MIT"
},
"node_modules/graceful-fs": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.1.14.tgz",
......@@ -4688,6 +4695,11 @@
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="
},
"gpt-tokenizer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/gpt-tokenizer/-/gpt-tokenizer-3.0.1.tgz",
"integrity": "sha512-5jdaspBq/w4sWw322SvQj1Fku+CN4OAfYZeeEg8U7CWtxBz+zkxZ3h0YOHD43ee+nZYZ5Ud70HRN0ANcdIj4qg=="
},
"graceful-fs": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.1.14.tgz",
......
......@@ -26,6 +26,7 @@ zlib = require 'zlib'
axios = require 'axios'
osu = require 'node-os-utils'
mustache = require 'mustache'
gpt_tokenizer = require 'gpt-tokenizer/model/gpt-4o'
bunyan = require 'bunyan'
log = global.log = bunyan.createLogger name: "mycard"
......@@ -3677,17 +3678,30 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)->
cancel = true
if not cancel and settings.modules.chatgpt.enabled and room.windbot and not client.is_post_watcher and client.pos < 2 and not client.is_local
# session_key = "#{settings.modules.chatgpt.session}:#{settings.port}:#{CLIENT_get_authorize_key(client)}"
if room.is_requesting_chatgpt
return false
room.is_requesting_chatgpt = true
if not room.chatgpt_conversation
room.chatgpt_conversation = []
openai_req_body = {
messages: [
{ role: "user", content: msg }
],
messages: Array.from(room.chatgpt_conversation),
model: settings.modules.chatgpt.model
}
openai_req_body.messages.push { role: "user", content: msg }
shrink_index = 0
if settings.modules.chatgpt.system_prompt
openai_req_body.messages.unshift { role: "system", content: mustache.render(settings.modules.chatgpt.system_prompt, {
player: client.name,
windbot: room.windbot.name,
}, undefined, { escape: (v) -> v }) }
shrink_index = 1
# trim conversation if too long
shrink_count = 0
while !gpt_tokenizer.isWithinTokenLimit(openai_req_body.messages, settings.modules.chatgpt.max_tokens)
if openai_req_body.messages.length <= (1 + shrink_index)
break
openai_req_body.messages.splice(shrink_index, 2) # remove the oldest user+assistant pair
shrink_count += 2
Object.assign(openai_req_body, settings.modules.chatgpt.extra_opts)
axios.post("#{settings.modules.chatgpt.endpoint}/v1/chat/completions", openai_req_body, {
timeout: 300000,
......@@ -3704,8 +3718,15 @@ ygopro.ctos_follow 'CHAT', true, (buffer, info, client, server, datas)->
ygopro.stoc_send_chat_to_room(room, chunk.join(''), 1 - client.pos)
else
ygopro.stoc_send_chat_to_room(room, ' ', 1 - client.pos)
# save text
if shrink_count > 0
room.chatgpt_conversation.splice(0, shrink_count)
room.chatgpt_conversation.push { role: "user", content: msg }
room.chatgpt_conversation.push { role: "assistant", content: text }
).catch((err) ->
log.error "CHATGPT ERROR", err
).finally(() ->
room.is_requesting_chatgpt = false
)
return false
if !(room and (room.random_type or room.arena)) and not settings.modules.mycard.enabled
......
// Generated by CoffeeScript 2.7.0
(function() {
// 标准库
var Aragami, CLIENT_check_vip, CLIENT_get_absolute_pos, CLIENT_get_authorize_key, CLIENT_get_kick_reconnect_target, CLIENT_get_partner, CLIENT_get_save_data, CLIENT_heartbeat_register, CLIENT_heartbeat_unregister, CLIENT_import_data, CLIENT_is_able_to_kick_reconnect, CLIENT_is_able_to_reconnect, CLIENT_is_banned_by_mc, CLIENT_is_player, CLIENT_kick, CLIENT_kick_reconnect, CLIENT_pre_reconnect, CLIENT_reconnect, CLIENT_reconnect_register, CLIENT_reconnect_unregister, CLIENT_send_pre_reconnect_info, CLIENT_send_reconnect_info, CLIENT_send_replays, CLIENT_send_replays_and_kick, CLIENT_send_vip_status, CLIENT_set_ip, CLIENT_use_cdkey, PQueue, Q, ROOM_all, ROOM_bad_ip, ROOM_ban_player, ROOM_clear_disconnect, ROOM_connected_ip, ROOM_find_by_name, ROOM_find_by_pid, ROOM_find_by_port, ROOM_find_by_title, ROOM_find_or_create_ai, ROOM_find_or_create_by_name, ROOM_find_or_create_random, ROOM_kick, ROOM_player_flee, ROOM_player_get_score, ROOM_player_lose, ROOM_player_win, ROOM_players_oppentlist, ROOM_unwelcome, ROOM_validate, ReplayParser, ResolveData, Room, SERVER_clear_disconnect, SERVER_kick, SOCKET_flush_data, VIP_generate_cdkeys, YGOProDeck, _, _async, addCallback, aragami, aragami_classes, athleticChecker, auth, axios, badwordR, badwords, ban_user, bunyan, challonge, checkFileExists, concat_name, createDirectoryIfNotExists, crypto, dataManager, deck_name_match, dialogues, disconnect_list, exec, execFile, extra_mode_list, fs, geoip, getDuelLogQueryFromQs, getRealIp, get_memory_usage, http, httpRequestListener, importOldConfig, import_datas, init, ip6addr, isTrustedProxy, lflists, loadJSON, loadJSONAsync, loadLFList, loadRemoteData, load_dialogues, load_dialogues_custom, load_tips, load_tips_zh, load_words, log, long_resolve_cards, memory_usage, merge, moment, moment_long_ago_string, moment_now, moment_now_string, msg_polyfill, mustache, neosRequestListener, net, netRequestHandler, os, osu, path, qs, real_windbot_server_ip, release_disconnect, report_to_big_brother, request, roomlist, rooms_count, setting_change, setting_get, setting_save, settings, spawn, spawnSync, spawn_windbot, tips, toIpv4, toIpv6, url, users_cache, util, utility, wait_room_start, wait_room_start_arena, windbot_looplimit, windbot_process, windbots, words, ygopro, zlib;
var Aragami, CLIENT_check_vip, CLIENT_get_absolute_pos, CLIENT_get_authorize_key, CLIENT_get_kick_reconnect_target, CLIENT_get_partner, CLIENT_get_save_data, CLIENT_heartbeat_register, CLIENT_heartbeat_unregister, CLIENT_import_data, CLIENT_is_able_to_kick_reconnect, CLIENT_is_able_to_reconnect, CLIENT_is_banned_by_mc, CLIENT_is_player, CLIENT_kick, CLIENT_kick_reconnect, CLIENT_pre_reconnect, CLIENT_reconnect, CLIENT_reconnect_register, CLIENT_reconnect_unregister, CLIENT_send_pre_reconnect_info, CLIENT_send_reconnect_info, CLIENT_send_replays, CLIENT_send_replays_and_kick, CLIENT_send_vip_status, CLIENT_set_ip, CLIENT_use_cdkey, PQueue, Q, ROOM_all, ROOM_bad_ip, ROOM_ban_player, ROOM_clear_disconnect, ROOM_connected_ip, ROOM_find_by_name, ROOM_find_by_pid, ROOM_find_by_port, ROOM_find_by_title, ROOM_find_or_create_ai, ROOM_find_or_create_by_name, ROOM_find_or_create_random, ROOM_kick, ROOM_player_flee, ROOM_player_get_score, ROOM_player_lose, ROOM_player_win, ROOM_players_oppentlist, ROOM_unwelcome, ROOM_validate, ReplayParser, ResolveData, Room, SERVER_clear_disconnect, SERVER_kick, SOCKET_flush_data, VIP_generate_cdkeys, YGOProDeck, _, _async, addCallback, aragami, aragami_classes, athleticChecker, auth, axios, badwordR, badwords, ban_user, bunyan, challonge, checkFileExists, concat_name, createDirectoryIfNotExists, crypto, dataManager, deck_name_match, dialogues, disconnect_list, exec, execFile, extra_mode_list, fs, geoip, getDuelLogQueryFromQs, getRealIp, get_memory_usage, gpt_tokenizer, http, httpRequestListener, importOldConfig, import_datas, init, ip6addr, isTrustedProxy, lflists, loadJSON, loadJSONAsync, loadLFList, loadRemoteData, load_dialogues, load_dialogues_custom, load_tips, load_tips_zh, load_words, log, long_resolve_cards, memory_usage, merge, moment, moment_long_ago_string, moment_now, moment_now_string, msg_polyfill, mustache, neosRequestListener, net, netRequestHandler, os, osu, path, qs, real_windbot_server_ip, release_disconnect, report_to_big_brother, request, roomlist, rooms_count, setting_change, setting_get, setting_save, settings, spawn, spawnSync, spawn_windbot, tips, toIpv4, toIpv6, url, users_cache, util, utility, wait_room_start, wait_room_start_arena, windbot_looplimit, windbot_process, windbots, words, ygopro, zlib;
net = require('net');
......@@ -49,6 +49,8 @@
mustache = require('mustache');
gpt_tokenizer = require('gpt-tokenizer/model/gpt-4o');
bunyan = require('bunyan');
log = global.log = bunyan.createLogger({
......@@ -4655,7 +4657,7 @@
//else
//log.info 'BIG BROTHER OK', response.statusCode, roomname, body
ygopro.ctos_follow('CHAT', true, async function(buffer, info, client, server, datas) {
var buy_result, cancel, ccolor, cip, cmd, cmsg, cname, code, color, cvalue, isVip, j, key, len, msg, name, oldmsg, openai_req_body, player, ref, ref1, room, struct, sur_player, uname, windbot, word;
var buy_result, cancel, ccolor, cip, cmd, cmsg, cname, code, color, cvalue, isVip, j, key, len, msg, name, oldmsg, openai_req_body, player, ref, ref1, room, shrink_count, shrink_index, struct, sur_player, uname, windbot, word;
room = ROOM_all[client.rid];
if (!room) {
return;
......@@ -4911,15 +4913,22 @@
}
if (!cancel && settings.modules.chatgpt.enabled && room.windbot && !client.is_post_watcher && client.pos < 2 && !client.is_local) {
// session_key = "#{settings.modules.chatgpt.session}:#{settings.port}:#{CLIENT_get_authorize_key(client)}"
if (room.is_requesting_chatgpt) {
return false;
}
room.is_requesting_chatgpt = true;
if (!room.chatgpt_conversation) {
room.chatgpt_conversation = [];
}
openai_req_body = {
messages: [
{
role: "user",
content: msg
}
],
messages: Array.from(room.chatgpt_conversation),
model: settings.modules.chatgpt.model
};
openai_req_body.messages.push({
role: "user",
content: msg
});
shrink_index = 0;
if (settings.modules.chatgpt.system_prompt) {
openai_req_body.messages.unshift({
role: "system",
......@@ -4932,6 +4941,16 @@
}
})
});
shrink_index = 1;
}
// trim conversation if too long
shrink_count = 0;
while (!gpt_tokenizer.isWithinTokenLimit(openai_req_body.messages, settings.modules.chatgpt.max_tokens)) {
if (openai_req_body.messages.length <= (1 + shrink_index)) {
break;
}
openai_req_body.messages.splice(shrink_index, 2); // remove the oldest user+assistant pair
shrink_count += 2;
}
Object.assign(openai_req_body, settings.modules.chatgpt.extra_opts);
axios.post(`${settings.modules.chatgpt.endpoint}/v1/chat/completions`, openai_req_body, {
......@@ -4940,30 +4959,37 @@
Authorization: `Bearer ${settings.modules.chatgpt.token}`
}
}).then(function(res) {
var chunk, chunks, l, len1, line, lines, results, text;
var chunk, chunks, l, len1, len2, line, lines, m, text;
text = res.data.choices[0].message.content;
lines = text.split("\n");
results = [];
for (l = 0, len1 = lines.length; l < len1; l++) {
line = lines[l];
if (line) {
chunks = _.chunk(line, 100);
results.push((function() {
var len2, m, results1;
results1 = [];
for (m = 0, len2 = chunks.length; m < len2; m++) {
chunk = chunks[m];
results1.push(ygopro.stoc_send_chat_to_room(room, chunk.join(''), 1 - client.pos));
}
return results1;
})());
for (m = 0, len2 = chunks.length; m < len2; m++) {
chunk = chunks[m];
ygopro.stoc_send_chat_to_room(room, chunk.join(''), 1 - client.pos);
}
} else {
results.push(ygopro.stoc_send_chat_to_room(room, ' ', 1 - client.pos));
ygopro.stoc_send_chat_to_room(room, ' ', 1 - client.pos);
}
}
return results;
// save text
if (shrink_count > 0) {
room.chatgpt_conversation.splice(0, shrink_count);
}
room.chatgpt_conversation.push({
role: "user",
content: msg
});
return room.chatgpt_conversation.push({
role: "assistant",
content: text
});
}).catch(function(err) {
return log.error("CHATGPT ERROR", err);
}).finally(function() {
return room.is_requesting_chatgpt = false;
});
return false;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment