koishi-plugin-my-pig-group-friends 1.1.0 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/config.d.ts +5 -0
- package/lib/index.js +154 -30
- package/lib/services/pexels.d.ts +6 -0
- package/package.json +1 -1
package/lib/config.d.ts
CHANGED
|
@@ -14,7 +14,12 @@ export interface Config {
|
|
|
14
14
|
logPath: string;
|
|
15
15
|
llmLocationEnabled: boolean;
|
|
16
16
|
llmLocationModel: string;
|
|
17
|
+
llmLocationCustomContext: string;
|
|
18
|
+
imageSearchPrompt: string;
|
|
17
19
|
unsplashAccessKey: string;
|
|
20
|
+
pexelsApiKey: string;
|
|
21
|
+
backgroundFetchMode: 'auto' | 'always' | 'never';
|
|
22
|
+
backgroundFetchTimeoutMs: number;
|
|
18
23
|
logRetentionDays: number;
|
|
19
24
|
experimentalAutoDetect: boolean;
|
|
20
25
|
debug: boolean;
|
package/lib/index.js
CHANGED
|
@@ -101,6 +101,13 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
101
101
|
return "image/jpeg";
|
|
102
102
|
}, "sniffMime");
|
|
103
103
|
const inlineMaxBytes = 900 * 1024;
|
|
104
|
+
const fetchTimeoutMs = config.backgroundFetchTimeoutMs ?? 8e3;
|
|
105
|
+
const shouldServerFetch = /* @__PURE__ */ __name((url) => {
|
|
106
|
+
const mode = config.backgroundFetchMode || "auto";
|
|
107
|
+
if (mode === "never") return false;
|
|
108
|
+
if (mode === "always") return true;
|
|
109
|
+
return !/^https?:\/\/(images|source)\.unsplash\.com\//i.test(url);
|
|
110
|
+
}, "shouldServerFetch");
|
|
104
111
|
const fetchToDataUrl = /* @__PURE__ */ __name(async (url) => {
|
|
105
112
|
const normalized = normalizeImageUrl(url);
|
|
106
113
|
if (config.debug) ctx.logger("pig").debug(`Normalized background URL: ${normalized}`);
|
|
@@ -122,12 +129,17 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
122
129
|
}
|
|
123
130
|
}
|
|
124
131
|
if (/^https?:\/\//i.test(normalized)) {
|
|
132
|
+
if (!shouldServerFetch(normalized)) {
|
|
133
|
+
if (config.debug) {
|
|
134
|
+
ctx.logger("pig").debug(`Skip server-side fetch for background: ${normalized}`);
|
|
135
|
+
}
|
|
136
|
+
return normalized;
|
|
137
|
+
}
|
|
125
138
|
try {
|
|
126
139
|
if (config.debug) ctx.logger("pig").debug(`Server-side fetching background: ${normalized}`);
|
|
127
140
|
const response = await ctx.http(normalized, {
|
|
128
141
|
responseType: "arraybuffer",
|
|
129
|
-
timeout:
|
|
130
|
-
// Reduced from 15s to 8s for better responsiveness
|
|
142
|
+
timeout: fetchTimeoutMs,
|
|
131
143
|
headers: {
|
|
132
144
|
"User-Agent": "Mozilla/5.0",
|
|
133
145
|
"Accept": "image/avif,image/webp,image/apng,image/*,*/*;q=0.8"
|
|
@@ -177,6 +189,7 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
177
189
|
}
|
|
178
190
|
const now = /* @__PURE__ */ new Date();
|
|
179
191
|
const dateStr = `${now.getFullYear()}年${now.getMonth() + 1}月${now.getDate()}日`;
|
|
192
|
+
const bgCssValue = bgImage ? `url("${bgImage}")` : "none";
|
|
180
193
|
const html = `
|
|
181
194
|
<!DOCTYPE html>
|
|
182
195
|
<html>
|
|
@@ -194,12 +207,18 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
194
207
|
width: 1080px;
|
|
195
208
|
height: 1920px;
|
|
196
209
|
overflow: hidden;
|
|
197
|
-
/*
|
|
198
|
-
font-family: "Noto Sans CJK SC", "Noto Sans SC", "Source Han Sans SC", "Microsoft YaHei", "WenQuanYi Micro Hei", "Droid Sans Fallback", "PingFang SC", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica Neue", Arial, sans-serif, "
|
|
210
|
+
/* Default emoji font set to Noto Color Emoji to maintain layout consistency */
|
|
211
|
+
font-family: "Noto Sans CJK SC", "Noto Sans SC", "Source Han Sans SC", "Microsoft YaHei", "WenQuanYi Micro Hei", "Droid Sans Fallback", "PingFang SC", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica Neue", Arial, sans-serif, "Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji";
|
|
199
212
|
background: #f0f0f2;
|
|
200
|
-
--bg-image:
|
|
213
|
+
--bg-image: ${bgCssValue};
|
|
201
214
|
}
|
|
202
215
|
|
|
216
|
+
/* Specific class for the pig emoji to use Twemoji */
|
|
217
|
+
.twemoji {
|
|
218
|
+
font-family: "Twemoji", "Noto Color Emoji", sans-serif;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
|
|
203
222
|
.wrapper {
|
|
204
223
|
position: relative;
|
|
205
224
|
width: 100%;
|
|
@@ -214,10 +233,9 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
214
233
|
inset: 0;
|
|
215
234
|
width: 100%;
|
|
216
235
|
height: 100%;
|
|
236
|
+
display: block;
|
|
237
|
+
object-fit: cover;
|
|
217
238
|
background-color: #d1d1d6;
|
|
218
|
-
background-image: var(--bg-image);
|
|
219
|
-
background-size: cover;
|
|
220
|
-
background-position: center;
|
|
221
239
|
z-index: 0;
|
|
222
240
|
}
|
|
223
241
|
|
|
@@ -375,7 +393,7 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
375
393
|
.message-text {
|
|
376
394
|
font-size: 56px;
|
|
377
395
|
line-height: 1.25;
|
|
378
|
-
font-weight:
|
|
396
|
+
font-weight: 900;
|
|
379
397
|
color: #1d1d1f;
|
|
380
398
|
letter-spacing: -0.03em;
|
|
381
399
|
word-break: break-word;
|
|
@@ -389,8 +407,11 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
389
407
|
box-decoration-break: clone;
|
|
390
408
|
-webkit-box-decoration-break: clone;
|
|
391
409
|
display: inline-block;
|
|
410
|
+
font-weight: 900;
|
|
411
|
+
letter-spacing: -0.01em;
|
|
392
412
|
}
|
|
393
413
|
|
|
414
|
+
|
|
394
415
|
.divider {
|
|
395
416
|
height: 2px;
|
|
396
417
|
background: rgba(0,0,0,0.08);
|
|
@@ -423,14 +444,14 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
423
444
|
|
|
424
445
|
.location-pill span {
|
|
425
446
|
font-size: 26px;
|
|
426
|
-
font-weight:
|
|
447
|
+
font-weight: 800;
|
|
427
448
|
color: #ffffff;
|
|
428
449
|
letter-spacing: 0.02em;
|
|
429
450
|
}
|
|
430
451
|
|
|
431
452
|
.landmark-name {
|
|
432
453
|
font-size: 38px;
|
|
433
|
-
font-weight:
|
|
454
|
+
font-weight: 900;
|
|
434
455
|
color: #1d1d1f;
|
|
435
456
|
letter-spacing: -0.01em;
|
|
436
457
|
padding-left: 6px;
|
|
@@ -462,7 +483,7 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
462
483
|
</head>
|
|
463
484
|
<body>
|
|
464
485
|
<div class="wrapper">
|
|
465
|
-
<
|
|
486
|
+
<img class="bg-image" src="${bgImage || ""}" alt="" />
|
|
466
487
|
<div class="bg-overlay"></div>
|
|
467
488
|
|
|
468
489
|
<div class="card-container">
|
|
@@ -481,7 +502,7 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
481
502
|
|
|
482
503
|
<div class="message-body">
|
|
483
504
|
<div class="message-text">
|
|
484
|
-
今天
|
|
505
|
+
今天 <span class="twemoji">🐷</span>猪醒在<br/>
|
|
485
506
|
<span class="highlight">${data.location.landmarkZh || data.location.landmark}</span>
|
|
486
507
|
</div>
|
|
487
508
|
</div>
|
|
@@ -497,7 +518,7 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
497
518
|
</div>
|
|
498
519
|
|
|
499
520
|
<div class="brand-tag">
|
|
500
|
-
<div class="brand-icon">🐷</div>
|
|
521
|
+
<div class="brand-icon"><span class="twemoji">🐷</span></div>
|
|
501
522
|
<div class="brand-name">Pig Travel</div>
|
|
502
523
|
</div>
|
|
503
524
|
</div>
|
|
@@ -1065,6 +1086,50 @@ async function searchUnsplashPhoto(ctx, accessKey, query, debug = false) {
|
|
|
1065
1086
|
}
|
|
1066
1087
|
__name(searchUnsplashPhoto, "searchUnsplashPhoto");
|
|
1067
1088
|
|
|
1089
|
+
// src/services/pexels.ts
|
|
1090
|
+
var PEXELS_API_BASE = "https://api.pexels.com/v1";
|
|
1091
|
+
async function searchPexelsPhoto(ctx, apiKey, query, debug = false) {
|
|
1092
|
+
if (!apiKey) {
|
|
1093
|
+
if (debug) ctx.logger("pig").debug("Pexels: No API key provided");
|
|
1094
|
+
return null;
|
|
1095
|
+
}
|
|
1096
|
+
try {
|
|
1097
|
+
if (debug) ctx.logger("pig").debug(`Pexels: Searching for "${query}"`);
|
|
1098
|
+
const response = await ctx.http.get(
|
|
1099
|
+
`${PEXELS_API_BASE}/search`,
|
|
1100
|
+
{
|
|
1101
|
+
params: {
|
|
1102
|
+
query,
|
|
1103
|
+
per_page: 1,
|
|
1104
|
+
orientation: "landscape"
|
|
1105
|
+
},
|
|
1106
|
+
headers: {
|
|
1107
|
+
Authorization: apiKey
|
|
1108
|
+
},
|
|
1109
|
+
timeout: 1e4
|
|
1110
|
+
}
|
|
1111
|
+
);
|
|
1112
|
+
if (response.photos && response.photos.length > 0) {
|
|
1113
|
+
let photoUrl = response.photos[0].src.large2x || response.photos[0].src.large;
|
|
1114
|
+
if (photoUrl.includes("w=")) {
|
|
1115
|
+
photoUrl = photoUrl.replace(/w=\d+/, "w=1080");
|
|
1116
|
+
} else if (photoUrl.includes("?")) {
|
|
1117
|
+
photoUrl += "&w=1080";
|
|
1118
|
+
} else {
|
|
1119
|
+
photoUrl += "?w=1080";
|
|
1120
|
+
}
|
|
1121
|
+
if (debug) ctx.logger("pig").debug(`Pexels: Found photo URL: ${photoUrl}`);
|
|
1122
|
+
return photoUrl;
|
|
1123
|
+
}
|
|
1124
|
+
if (debug) ctx.logger("pig").debug("Pexels: No photos found for query");
|
|
1125
|
+
return null;
|
|
1126
|
+
} catch (e) {
|
|
1127
|
+
ctx.logger("pig").warn(`Pexels API error: ${e}`);
|
|
1128
|
+
return null;
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
__name(searchPexelsPhoto, "searchPexelsPhoto");
|
|
1132
|
+
|
|
1068
1133
|
// src/services/location.ts
|
|
1069
1134
|
var LOCATION_CATEGORIES = [
|
|
1070
1135
|
"自然奇观(峡谷、瀑布、火山、冰川、沙漠绿洲等)",
|
|
@@ -1079,13 +1144,43 @@ var LOCATION_CATEGORIES = [
|
|
|
1079
1144
|
"神秘与奇特之地(地质奇观、UFO小镇、怪异地貌等)"
|
|
1080
1145
|
];
|
|
1081
1146
|
var CONTINENTS = ["亚洲", "欧洲", "非洲", "北美洲", "南美洲", "大洋洲", "南极洲"];
|
|
1147
|
+
function getSunriseTimezoneHint() {
|
|
1148
|
+
const now = /* @__PURE__ */ new Date();
|
|
1149
|
+
const utcHour = now.getUTCHours();
|
|
1150
|
+
const targetLocalHour = 6;
|
|
1151
|
+
const idealOffset = targetLocalHour - utcHour;
|
|
1152
|
+
const normalizeOffset = /* @__PURE__ */ __name((offset) => {
|
|
1153
|
+
if (offset < -12) return offset + 24;
|
|
1154
|
+
if (offset > 14) return offset - 24;
|
|
1155
|
+
return offset;
|
|
1156
|
+
}, "normalizeOffset");
|
|
1157
|
+
const minOffset = normalizeOffset(idealOffset - 1);
|
|
1158
|
+
const maxOffset = normalizeOffset(idealOffset + 1);
|
|
1159
|
+
const getRegionByOffset = /* @__PURE__ */ __name((offset) => {
|
|
1160
|
+
if (offset >= 9 && offset <= 12) return "东亚、澳大利亚东部、太平洋岛屿";
|
|
1161
|
+
if (offset >= 5 && offset <= 8) return "南亚、东南亚、中亚";
|
|
1162
|
+
if (offset >= 2 && offset <= 4) return "中东、东欧、东非";
|
|
1163
|
+
if (offset >= -1 && offset <= 1) return "西欧、西非";
|
|
1164
|
+
if (offset >= -5 && offset <= -2) return "南美洲东部、大西洋";
|
|
1165
|
+
if (offset >= -8 && offset <= -6) return "北美洲西部、太平洋东部";
|
|
1166
|
+
if (offset >= -12 && offset <= -9) return "太平洋中部、夏威夷、阿拉斯加";
|
|
1167
|
+
return "全球各地";
|
|
1168
|
+
}, "getRegionByOffset");
|
|
1169
|
+
const formatOffset = /* @__PURE__ */ __name((offset) => offset >= 0 ? `UTC+${offset}` : `UTC${offset}`, "formatOffset");
|
|
1170
|
+
return {
|
|
1171
|
+
utcOffsetRange: `${formatOffset(minOffset)} 到 ${formatOffset(maxOffset)}`,
|
|
1172
|
+
regionHint: getRegionByOffset(idealOffset)
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
__name(getSunriseTimezoneHint, "getSunriseTimezoneHint");
|
|
1082
1176
|
function getRandomPromptHints() {
|
|
1083
1177
|
const category = LOCATION_CATEGORIES[Math.floor(Math.random() * LOCATION_CATEGORIES.length)];
|
|
1084
1178
|
const continent = CONTINENTS[Math.floor(Math.random() * CONTINENTS.length)];
|
|
1085
1179
|
const hotCountries = ["法国", "日本", "意大利", "美国", "英国", "中国", "西班牙", "泰国", "澳大利亚"];
|
|
1086
1180
|
const shuffled = hotCountries.sort(() => Math.random() - 0.5);
|
|
1087
1181
|
const avoidCountries = shuffled.slice(0, 3 + Math.floor(Math.random() * 4)).join("、");
|
|
1088
|
-
|
|
1182
|
+
const sunriseHint = getSunriseTimezoneHint();
|
|
1183
|
+
return { category, continent, avoidCountries, sunriseHint };
|
|
1089
1184
|
}
|
|
1090
1185
|
__name(getRandomPromptHints, "getRandomPromptHints");
|
|
1091
1186
|
var LOCATION_GENERATION_PROMPT = `你是一位资深旅行探险家,专门发掘世界各地的独特目的地。
|
|
@@ -1120,12 +1215,23 @@ async function generateLocationWithLLM(ctx, config) {
|
|
|
1120
1215
|
return getRandomStaticLocation();
|
|
1121
1216
|
}
|
|
1122
1217
|
const hints = getRandomPromptHints();
|
|
1123
|
-
|
|
1218
|
+
let userPrompt = `请生成一个【${hints.category}】类型的旅游目的地。
|
|
1124
1219
|
|
|
1125
|
-
|
|
1220
|
+
🌅 时区要求(重要):当前 UTC 时间是 ${(/* @__PURE__ */ new Date()).getUTCHours()}:${String((/* @__PURE__ */ new Date()).getUTCMinutes()).padStart(2, "0")},请选择一个正处于日出时段(当地时间约 5:00-7:00)的地点。
|
|
1221
|
+
符合条件的时区范围大约是 ${hints.sunriseHint.utcOffsetRange},对应地区包括:${hints.sunriseHint.regionHint}。
|
|
1222
|
+
|
|
1223
|
+
如果上述地区没有合适的【${hints.category}】类型目的地,可以适当放宽到邻近时区,但优先选择正在迎接日出的地方。
|
|
1224
|
+
|
|
1225
|
+
特别要求:请避开 ${hints.avoidCountries} 这些热门国家,选择一个更独特、更少人知道的地方。要求这个地方在地理位置或文化上具有独特性。`;
|
|
1226
|
+
if (config.llmLocationCustomContext) {
|
|
1227
|
+
userPrompt += `
|
|
1228
|
+
|
|
1229
|
+
此外,请参考以下用户提供的偏好或上下文:${config.llmLocationCustomContext}`;
|
|
1230
|
+
}
|
|
1231
|
+
userPrompt += `
|
|
1126
1232
|
|
|
1127
1233
|
直接输出JSON,不要有任何其他文字。`;
|
|
1128
|
-
if (config.debug) ctx.logger("pig").debug(`Location prompt hints:
|
|
1234
|
+
if (config.debug) ctx.logger("pig").debug(`Location prompt hints: sunrise=${hints.sunriseHint.regionHint}, category=${hints.category}`);
|
|
1129
1235
|
const messages = [
|
|
1130
1236
|
new import_messages.SystemMessage(LOCATION_GENERATION_PROMPT),
|
|
1131
1237
|
new import_messages.HumanMessage(userPrompt)
|
|
@@ -1136,29 +1242,37 @@ async function generateLocationWithLLM(ctx, config) {
|
|
|
1136
1242
|
const location = parseLocationResponse(content);
|
|
1137
1243
|
if (location) {
|
|
1138
1244
|
ctx.logger("pig").info(`LLM generated location: ${location.landmarkZh} (${location.landmark}), ${location.countryZh}`);
|
|
1139
|
-
if (config.unsplashAccessKey) {
|
|
1245
|
+
if (config.unsplashAccessKey || config.pexelsApiKey) {
|
|
1246
|
+
const template = config.imageSearchPrompt || "{landmark} {country} landscape";
|
|
1247
|
+
const formatQuery = /* @__PURE__ */ __name((tmpl) => tmpl.replace("{landmark}", location.landmark).replace("{country}", location.country).replace("{city}", location.city || "").trim(), "formatQuery");
|
|
1140
1248
|
const searchQueries = [
|
|
1249
|
+
formatQuery(template),
|
|
1250
|
+
// Primary: User template
|
|
1141
1251
|
`${location.landmark} ${location.country}`,
|
|
1142
|
-
//
|
|
1252
|
+
// Fallback 1: specific
|
|
1143
1253
|
location.city ? `${location.city} ${location.country}` : null,
|
|
1144
|
-
//
|
|
1145
|
-
`${location.country} landscape`,
|
|
1146
|
-
// Country landscape
|
|
1254
|
+
// Fallback 2: city
|
|
1147
1255
|
location.country
|
|
1148
|
-
//
|
|
1256
|
+
// Fallback 3: country
|
|
1149
1257
|
].filter(Boolean);
|
|
1150
1258
|
let photoUrl = null;
|
|
1151
1259
|
for (const query of searchQueries) {
|
|
1152
|
-
if (config.
|
|
1153
|
-
|
|
1260
|
+
if (config.unsplashAccessKey) {
|
|
1261
|
+
if (config.debug) ctx.logger("pig").debug(`Searching Unsplash for: ${query}`);
|
|
1262
|
+
photoUrl = await searchUnsplashPhoto(ctx, config.unsplashAccessKey, query, config.debug);
|
|
1263
|
+
}
|
|
1264
|
+
if (!photoUrl && config.pexelsApiKey) {
|
|
1265
|
+
if (config.debug) ctx.logger("pig").debug(`Searching Pexels for: ${query}`);
|
|
1266
|
+
photoUrl = await searchPexelsPhoto(ctx, config.pexelsApiKey, query, config.debug);
|
|
1267
|
+
}
|
|
1154
1268
|
if (photoUrl) {
|
|
1155
|
-
|
|
1269
|
+
ctx.logger("pig").info(`Found photo URL: ${photoUrl}`);
|
|
1156
1270
|
location.landscapeUrl = photoUrl;
|
|
1157
1271
|
break;
|
|
1158
1272
|
}
|
|
1159
1273
|
}
|
|
1160
1274
|
if (!photoUrl && config.debug) {
|
|
1161
|
-
ctx.logger("pig").debug("All
|
|
1275
|
+
ctx.logger("pig").debug("All image searches returned no results, using LLM-generated URL fallback");
|
|
1162
1276
|
}
|
|
1163
1277
|
}
|
|
1164
1278
|
return location;
|
|
@@ -1189,7 +1303,8 @@ function parseLocationResponse(content) {
|
|
|
1189
1303
|
landscapeUrl: data.landscapeUrl
|
|
1190
1304
|
};
|
|
1191
1305
|
if (!location.landscapeUrl.startsWith("http")) {
|
|
1192
|
-
|
|
1306
|
+
const query = `${encodeURIComponent(location.landmark)},${encodeURIComponent(location.country)}`;
|
|
1307
|
+
location.landscapeUrl = `https://images.unsplash.com/featured/?${query}`;
|
|
1193
1308
|
}
|
|
1194
1309
|
return location;
|
|
1195
1310
|
} catch (e) {
|
|
@@ -1307,7 +1422,16 @@ var Config = import_koishi.Schema.intersect([
|
|
|
1307
1422
|
import_koishi.Schema.object({
|
|
1308
1423
|
llmLocationEnabled: import_koishi.Schema.boolean().default(false).description("启用后使用 LLM 动态生成全球旅行地点,关闭则使用预设地点库"),
|
|
1309
1424
|
llmLocationModel: import_koishi.Schema.dynamic("model").description("用于生成地点的模型(推荐使用快速模型如 gemini-flash)"),
|
|
1310
|
-
|
|
1425
|
+
llmLocationCustomContext: import_koishi.Schema.string().role("textarea").default("").description("自定义生成上下文(如:关注北欧神话、赛博朋克风格建筑等,留空则完全随机)"),
|
|
1426
|
+
imageSearchPrompt: import_koishi.Schema.string().default("{landmark} {country} landscape").description("搜图关键词模板(可用变量:{landmark} 地标英文名, {country} 国家英文名, {city} 城市英文名)"),
|
|
1427
|
+
unsplashAccessKey: import_koishi.Schema.string().role("secret").default("").description("Unsplash API Access Key (可选)"),
|
|
1428
|
+
pexelsApiKey: import_koishi.Schema.string().role("secret").default("").description("Pexels API Key (可选,作为 Unsplash 的补充)"),
|
|
1429
|
+
backgroundFetchMode: import_koishi.Schema.union([
|
|
1430
|
+
import_koishi.Schema.const("auto").description("自动:尽量内联远程图片,遇到易超时域名则直接使用 URL"),
|
|
1431
|
+
import_koishi.Schema.const("always").description("强制服务端拉取并内联(更稳但可能慢)"),
|
|
1432
|
+
import_koishi.Schema.const("never").description("不进行服务端拉取,直接使用 URL")
|
|
1433
|
+
]).default("auto").description("背景图服务端拉取策略"),
|
|
1434
|
+
backgroundFetchTimeoutMs: import_koishi.Schema.number().default(8e3).description("背景图服务端拉取超时(毫秒)")
|
|
1311
1435
|
}).description("地点与图片 🌍"),
|
|
1312
1436
|
import_koishi.Schema.object({
|
|
1313
1437
|
aigcEnabled: import_koishi.Schema.boolean().default(false).description("启用后使用 AI 生成小猪旅行插画(需要 media-luna 插件)"),
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Context } from 'koishi';
|
|
2
|
+
/**
|
|
3
|
+
* Search for a photo on Pexels and return the large-sized URL
|
|
4
|
+
* @returns The photo URL or null if not found/error
|
|
5
|
+
*/
|
|
6
|
+
export declare function searchPexelsPhoto(ctx: Context, apiKey: string, query: string, debug?: boolean): Promise<string | null>;
|