koishi-plugin-my-pig-group-friends 1.1.1 → 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 -1
- package/lib/index.js +154 -36
- package/lib/services/pexels.d.ts +6 -0
- package/package.json +1 -1
package/lib/config.d.ts
CHANGED
|
@@ -14,10 +14,14 @@ 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;
|
|
21
|
-
emojiFont: 'Noto Color Emoji' | 'Twemoji' | 'System';
|
|
22
26
|
}
|
|
23
27
|
export declare const Config: Schema<Config>;
|
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,7 +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()}日`;
|
|
180
|
-
const
|
|
192
|
+
const bgCssValue = bgImage ? `url("${bgImage}")` : "none";
|
|
181
193
|
const html = `
|
|
182
194
|
<!DOCTYPE html>
|
|
183
195
|
<html>
|
|
@@ -195,12 +207,18 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
195
207
|
width: 1080px;
|
|
196
208
|
height: 1920px;
|
|
197
209
|
overflow: hidden;
|
|
198
|
-
/*
|
|
199
|
-
font-family:
|
|
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";
|
|
200
212
|
background: #f0f0f2;
|
|
201
|
-
--bg-image:
|
|
213
|
+
--bg-image: ${bgCssValue};
|
|
202
214
|
}
|
|
203
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
|
+
|
|
204
222
|
.wrapper {
|
|
205
223
|
position: relative;
|
|
206
224
|
width: 100%;
|
|
@@ -215,10 +233,9 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
215
233
|
inset: 0;
|
|
216
234
|
width: 100%;
|
|
217
235
|
height: 100%;
|
|
236
|
+
display: block;
|
|
237
|
+
object-fit: cover;
|
|
218
238
|
background-color: #d1d1d6;
|
|
219
|
-
background-image: var(--bg-image);
|
|
220
|
-
background-size: cover;
|
|
221
|
-
background-position: center;
|
|
222
239
|
z-index: 0;
|
|
223
240
|
}
|
|
224
241
|
|
|
@@ -376,7 +393,7 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
376
393
|
.message-text {
|
|
377
394
|
font-size: 56px;
|
|
378
395
|
line-height: 1.25;
|
|
379
|
-
font-weight:
|
|
396
|
+
font-weight: 900;
|
|
380
397
|
color: #1d1d1f;
|
|
381
398
|
letter-spacing: -0.03em;
|
|
382
399
|
word-break: break-word;
|
|
@@ -390,8 +407,11 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
390
407
|
box-decoration-break: clone;
|
|
391
408
|
-webkit-box-decoration-break: clone;
|
|
392
409
|
display: inline-block;
|
|
410
|
+
font-weight: 900;
|
|
411
|
+
letter-spacing: -0.01em;
|
|
393
412
|
}
|
|
394
413
|
|
|
414
|
+
|
|
395
415
|
.divider {
|
|
396
416
|
height: 2px;
|
|
397
417
|
background: rgba(0,0,0,0.08);
|
|
@@ -424,14 +444,14 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
424
444
|
|
|
425
445
|
.location-pill span {
|
|
426
446
|
font-size: 26px;
|
|
427
|
-
font-weight:
|
|
447
|
+
font-weight: 800;
|
|
428
448
|
color: #ffffff;
|
|
429
449
|
letter-spacing: 0.02em;
|
|
430
450
|
}
|
|
431
451
|
|
|
432
452
|
.landmark-name {
|
|
433
453
|
font-size: 38px;
|
|
434
|
-
font-weight:
|
|
454
|
+
font-weight: 900;
|
|
435
455
|
color: #1d1d1f;
|
|
436
456
|
letter-spacing: -0.01em;
|
|
437
457
|
padding-left: 6px;
|
|
@@ -463,7 +483,7 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
463
483
|
</head>
|
|
464
484
|
<body>
|
|
465
485
|
<div class="wrapper">
|
|
466
|
-
<
|
|
486
|
+
<img class="bg-image" src="${bgImage || ""}" alt="" />
|
|
467
487
|
<div class="bg-overlay"></div>
|
|
468
488
|
|
|
469
489
|
<div class="card-container">
|
|
@@ -482,7 +502,7 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
482
502
|
|
|
483
503
|
<div class="message-body">
|
|
484
504
|
<div class="message-text">
|
|
485
|
-
今天
|
|
505
|
+
今天 <span class="twemoji">🐷</span>猪醒在<br/>
|
|
486
506
|
<span class="highlight">${data.location.landmarkZh || data.location.landmark}</span>
|
|
487
507
|
</div>
|
|
488
508
|
</div>
|
|
@@ -498,7 +518,7 @@ async function generateFootprintCard(ctx, config, data, userInfo, platform, back
|
|
|
498
518
|
</div>
|
|
499
519
|
|
|
500
520
|
<div class="brand-tag">
|
|
501
|
-
<div class="brand-icon">🐷</div>
|
|
521
|
+
<div class="brand-icon"><span class="twemoji">🐷</span></div>
|
|
502
522
|
<div class="brand-name">Pig Travel</div>
|
|
503
523
|
</div>
|
|
504
524
|
</div>
|
|
@@ -1066,6 +1086,50 @@ async function searchUnsplashPhoto(ctx, accessKey, query, debug = false) {
|
|
|
1066
1086
|
}
|
|
1067
1087
|
__name(searchUnsplashPhoto, "searchUnsplashPhoto");
|
|
1068
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
|
+
|
|
1069
1133
|
// src/services/location.ts
|
|
1070
1134
|
var LOCATION_CATEGORIES = [
|
|
1071
1135
|
"自然奇观(峡谷、瀑布、火山、冰川、沙漠绿洲等)",
|
|
@@ -1080,13 +1144,43 @@ var LOCATION_CATEGORIES = [
|
|
|
1080
1144
|
"神秘与奇特之地(地质奇观、UFO小镇、怪异地貌等)"
|
|
1081
1145
|
];
|
|
1082
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");
|
|
1083
1176
|
function getRandomPromptHints() {
|
|
1084
1177
|
const category = LOCATION_CATEGORIES[Math.floor(Math.random() * LOCATION_CATEGORIES.length)];
|
|
1085
1178
|
const continent = CONTINENTS[Math.floor(Math.random() * CONTINENTS.length)];
|
|
1086
1179
|
const hotCountries = ["法国", "日本", "意大利", "美国", "英国", "中国", "西班牙", "泰国", "澳大利亚"];
|
|
1087
1180
|
const shuffled = hotCountries.sort(() => Math.random() - 0.5);
|
|
1088
1181
|
const avoidCountries = shuffled.slice(0, 3 + Math.floor(Math.random() * 4)).join("、");
|
|
1089
|
-
|
|
1182
|
+
const sunriseHint = getSunriseTimezoneHint();
|
|
1183
|
+
return { category, continent, avoidCountries, sunriseHint };
|
|
1090
1184
|
}
|
|
1091
1185
|
__name(getRandomPromptHints, "getRandomPromptHints");
|
|
1092
1186
|
var LOCATION_GENERATION_PROMPT = `你是一位资深旅行探险家,专门发掘世界各地的独特目的地。
|
|
@@ -1121,12 +1215,23 @@ async function generateLocationWithLLM(ctx, config) {
|
|
|
1121
1215
|
return getRandomStaticLocation();
|
|
1122
1216
|
}
|
|
1123
1217
|
const hints = getRandomPromptHints();
|
|
1124
|
-
|
|
1218
|
+
let userPrompt = `请生成一个【${hints.category}】类型的旅游目的地。
|
|
1125
1219
|
|
|
1126
|
-
|
|
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 += `
|
|
1127
1232
|
|
|
1128
1233
|
直接输出JSON,不要有任何其他文字。`;
|
|
1129
|
-
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}`);
|
|
1130
1235
|
const messages = [
|
|
1131
1236
|
new import_messages.SystemMessage(LOCATION_GENERATION_PROMPT),
|
|
1132
1237
|
new import_messages.HumanMessage(userPrompt)
|
|
@@ -1137,29 +1242,37 @@ async function generateLocationWithLLM(ctx, config) {
|
|
|
1137
1242
|
const location = parseLocationResponse(content);
|
|
1138
1243
|
if (location) {
|
|
1139
1244
|
ctx.logger("pig").info(`LLM generated location: ${location.landmarkZh} (${location.landmark}), ${location.countryZh}`);
|
|
1140
|
-
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");
|
|
1141
1248
|
const searchQueries = [
|
|
1249
|
+
formatQuery(template),
|
|
1250
|
+
// Primary: User template
|
|
1142
1251
|
`${location.landmark} ${location.country}`,
|
|
1143
|
-
//
|
|
1252
|
+
// Fallback 1: specific
|
|
1144
1253
|
location.city ? `${location.city} ${location.country}` : null,
|
|
1145
|
-
//
|
|
1146
|
-
`${location.country} landscape`,
|
|
1147
|
-
// Country landscape
|
|
1254
|
+
// Fallback 2: city
|
|
1148
1255
|
location.country
|
|
1149
|
-
//
|
|
1256
|
+
// Fallback 3: country
|
|
1150
1257
|
].filter(Boolean);
|
|
1151
1258
|
let photoUrl = null;
|
|
1152
1259
|
for (const query of searchQueries) {
|
|
1153
|
-
if (config.
|
|
1154
|
-
|
|
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
|
+
}
|
|
1155
1268
|
if (photoUrl) {
|
|
1156
|
-
|
|
1269
|
+
ctx.logger("pig").info(`Found photo URL: ${photoUrl}`);
|
|
1157
1270
|
location.landscapeUrl = photoUrl;
|
|
1158
1271
|
break;
|
|
1159
1272
|
}
|
|
1160
1273
|
}
|
|
1161
1274
|
if (!photoUrl && config.debug) {
|
|
1162
|
-
ctx.logger("pig").debug("All
|
|
1275
|
+
ctx.logger("pig").debug("All image searches returned no results, using LLM-generated URL fallback");
|
|
1163
1276
|
}
|
|
1164
1277
|
}
|
|
1165
1278
|
return location;
|
|
@@ -1190,7 +1303,8 @@ function parseLocationResponse(content) {
|
|
|
1190
1303
|
landscapeUrl: data.landscapeUrl
|
|
1191
1304
|
};
|
|
1192
1305
|
if (!location.landscapeUrl.startsWith("http")) {
|
|
1193
|
-
|
|
1306
|
+
const query = `${encodeURIComponent(location.landmark)},${encodeURIComponent(location.country)}`;
|
|
1307
|
+
location.landscapeUrl = `https://images.unsplash.com/featured/?${query}`;
|
|
1194
1308
|
}
|
|
1195
1309
|
return location;
|
|
1196
1310
|
} catch (e) {
|
|
@@ -1303,17 +1417,21 @@ var import_koishi = require("koishi");
|
|
|
1303
1417
|
var Config = import_koishi.Schema.intersect([
|
|
1304
1418
|
import_koishi.Schema.object({
|
|
1305
1419
|
outputMode: import_koishi.Schema.union(["text", "image"]).default("image").description("输出模式:text 纯文本,image 生成精美卡片"),
|
|
1306
|
-
emojiFont: import_koishi.Schema.union([
|
|
1307
|
-
import_koishi.Schema.const("System").description("系统默认"),
|
|
1308
|
-
import_koishi.Schema.const("Noto Color Emoji").description("Noto Color Emoji"),
|
|
1309
|
-
import_koishi.Schema.const("Twemoji").description("Twemoji (Twitter Emoji)")
|
|
1310
|
-
]).default("System").description("Emoji 字体偏好(需确保容器内已安装相应字体)"),
|
|
1311
1420
|
travelMessageTemplate: import_koishi.Schema.string().default("去了 {landmark},{country}!📸").description("旅行消息模板(可用变量:{landmark} 地标名, {country} 国家名)")
|
|
1312
1421
|
}).description("基础设置"),
|
|
1313
1422
|
import_koishi.Schema.object({
|
|
1314
1423
|
llmLocationEnabled: import_koishi.Schema.boolean().default(false).description("启用后使用 LLM 动态生成全球旅行地点,关闭则使用预设地点库"),
|
|
1315
1424
|
llmLocationModel: import_koishi.Schema.dynamic("model").description("用于生成地点的模型(推荐使用快速模型如 gemini-flash)"),
|
|
1316
|
-
|
|
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("背景图服务端拉取超时(毫秒)")
|
|
1317
1435
|
}).description("地点与图片 🌍"),
|
|
1318
1436
|
import_koishi.Schema.object({
|
|
1319
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>;
|