seacloud-sdk 0.10.1 → 0.10.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/dist/cli.js CHANGED
@@ -13,51 +13,7 @@ var SeacloudError = class extends Error {
13
13
  };
14
14
 
15
15
  // src/core/config.ts
16
- function isInIframe() {
17
- try {
18
- return typeof globalThis.window !== "undefined" && globalThis.window.self !== globalThis.window.top;
19
- } catch (e) {
20
- return true;
21
- }
22
- }
23
- async function getTokenFromParent(timeout = 5e3) {
24
- if (!isInIframe()) {
25
- return null;
26
- }
27
- return new Promise((resolve) => {
28
- const messageHandler = (event) => {
29
- if (event.data && event.data.type === "seaverse:token") {
30
- cleanup();
31
- const token = event.data.payload?.accessToken;
32
- resolve(token || null);
33
- } else if (event.data && event.data.type === "seaverse:error") {
34
- cleanup();
35
- console.warn("[SeaCloud SDK] Error getting token from parent:", event.data.error);
36
- resolve(null);
37
- }
38
- };
39
- const timeoutId = setTimeout(() => {
40
- cleanup();
41
- resolve(null);
42
- }, timeout);
43
- const cleanup = () => {
44
- clearTimeout(timeoutId);
45
- globalThis.window.removeEventListener("message", messageHandler);
46
- };
47
- globalThis.window.addEventListener("message", messageHandler);
48
- try {
49
- globalThis.window.parent.postMessage(
50
- { type: "seaverse:get_token" },
51
- "*"
52
- // 允许任何源,支持跨域场景
53
- );
54
- } catch (e) {
55
- cleanup();
56
- resolve(null);
57
- }
58
- });
59
- }
60
- async function getApiToken(providedApiKey) {
16
+ function getApiToken(providedApiKey) {
61
17
  if (providedApiKey) {
62
18
  return providedApiKey;
63
19
  }
@@ -73,27 +29,23 @@ async function getApiToken(providedApiKey) {
73
29
  if (typeof process !== "undefined" && process.env?.API_SERVICE_TOKEN) {
74
30
  return process.env.API_SERVICE_TOKEN;
75
31
  }
76
- if (typeof globalThis.window !== "undefined") {
77
- const parentToken = await getTokenFromParent();
78
- if (parentToken) {
79
- return parentToken;
80
- }
81
- }
82
- return "";
32
+ throw new Error(
33
+ 'SeaCloud SDK: No API token found. Please ensure token is available in localStorage.getItem("auth_token") (browser) or process.env.API_SERVICE_TOKEN (Node.js), or initialize with initSeacloud({ apiKey: "your-token" }).'
34
+ );
83
35
  }
84
36
  function createConfig(options = {}) {
85
- const apiKey = options.apiKey;
37
+ const apiKey = getApiToken(options.apiKey);
86
38
  const baseUrl = options.baseUrl || (typeof process !== "undefined" ? process.env?.SEACLOUD_BASE_URL : void 0) || "https://proxy-rs.seaverse.ai";
87
39
  const fetchImpl = options.fetch || (globalThis.fetch ? globalThis.fetch.bind(globalThis) : void 0);
88
40
  if (!fetchImpl) {
89
41
  throw new Error("fetch is not available. Please provide a fetch implementation in config or upgrade to Node.js 18+");
90
42
  }
91
43
  return {
92
- apiKey: apiKey || "",
93
- // 提供默认空字符串,实际请求时会动态获取
44
+ apiKey,
94
45
  baseUrl,
95
46
  fetch: fetchImpl,
96
- timeout: options.timeout || 3e4
47
+ timeout: options.timeout || 3e4,
48
+ xProject: options.xProject || "SeaVerse"
97
49
  };
98
50
  }
99
51
  function validateConfig(config) {
@@ -135,7 +87,7 @@ var SeacloudClient = class {
135
87
  */
136
88
  async createTask(endpoint, body) {
137
89
  const url = `${this.config.baseUrl}${endpoint}`;
138
- const currentToken = await getApiToken(this.providedApiKey);
90
+ const currentToken = getApiToken(this.providedApiKey);
139
91
  const controller = new AbortController();
140
92
  const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
141
93
  try {
@@ -182,7 +134,7 @@ var SeacloudClient = class {
182
134
  */
183
135
  async getTaskStatus(endpoint, taskId) {
184
136
  const url = `${this.config.baseUrl}${endpoint}/task/${taskId}`;
185
- const currentToken = await getApiToken(this.providedApiKey);
137
+ const currentToken = getApiToken(this.providedApiKey);
186
138
  const controller = new AbortController();
187
139
  const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
188
140
  try {
@@ -253,7 +205,8 @@ function initSeacloud(apiKeyOrConfig, options) {
253
205
  globalConfig.client = new SeacloudClient({
254
206
  apiKey: apiKey || "",
255
207
  baseUrl: config.baseUrl,
256
- timeout: config.timeout
208
+ timeout: config.timeout,
209
+ xProject: config.xProject
257
210
  });
258
211
  if (config.intervalMs !== void 0) {
259
212
  globalConfig.defaultPollingOptions.intervalMs = config.intervalMs;
@@ -279,7 +232,6 @@ async function llmChatCompletions(params) {
279
232
  const client = getClient();
280
233
  const config = client.getConfig();
281
234
  const url = `${config.baseUrl}/llm/chat/completions`;
282
- const token = await getApiToken(config.apiKey);
283
235
  const controller = new AbortController();
284
236
  const timeoutId = setTimeout(() => controller.abort(), config.timeout);
285
237
  try {
@@ -287,7 +239,7 @@ async function llmChatCompletions(params) {
287
239
  method: "POST",
288
240
  headers: {
289
241
  "Content-Type": "application/json",
290
- "Authorization": `Bearer ${token}`
242
+ "Authorization": `Bearer ${config.apiKey}`
291
243
  },
292
244
  body: JSON.stringify(params),
293
245
  signal: controller.signal
@@ -373,14 +325,16 @@ async function agentChatCompletions(params) {
373
325
  const controller = new AbortController();
374
326
  const timeoutId = setTimeout(() => controller.abort(), config.timeout);
375
327
  try {
328
+ const headers = {
329
+ "Content-Type": "application/json",
330
+ "Authorization": `Bearer ${config.apiKey}`
331
+ };
332
+ if (config.xProject) {
333
+ headers["X-Project"] = config.xProject;
334
+ }
376
335
  const response = await config.fetch(url, {
377
336
  method: "POST",
378
- headers: {
379
- "Content-Type": "application/json",
380
- "Authorization": `Bearer ${config.apiKey}`,
381
- "X-Project": "SeaArt"
382
- // Required header for agent API
383
- },
337
+ headers,
384
338
  body: JSON.stringify(requestBody),
385
339
  signal: controller.signal
386
340
  });
@@ -565,14 +519,17 @@ async function appSearch(params) {
565
519
  const timeoutId = setTimeout(() => controller.abort(), config.timeout);
566
520
  try {
567
521
  const requestId = `req-${Date.now()}-${Math.random().toString(36).substring(7)}`;
522
+ const headers = {
523
+ "Content-Type": "application/json",
524
+ "Authorization": `Bearer ${config.apiKey}`,
525
+ "X-Request-Id": requestId
526
+ };
527
+ if (config.xProject) {
528
+ headers["X-Project"] = config.xProject;
529
+ }
568
530
  const response = await config.fetch(url, {
569
531
  method: "POST",
570
- headers: {
571
- "Content-Type": "application/json",
572
- "Authorization": `Bearer ${config.apiKey}`,
573
- "X-Request-Id": requestId,
574
- "X-Project": "KIIRA"
575
- },
532
+ headers,
576
533
  body: JSON.stringify(params),
577
534
  signal: controller.signal
578
535
  });
@@ -588,73 +545,6 @@ async function appSearch(params) {
588
545
  throw error;
589
546
  }
590
547
  }
591
-
592
- // src/api/scan.ts
593
- async function scan(params) {
594
- if (!params.uri && !params.img_base64) {
595
- throw new SeacloudError("\u5FC5\u987B\u63D0\u4F9B uri \u6216 img_base64 \u4E2D\u7684\u81F3\u5C11\u4E00\u4E2A\u53C2\u6570");
596
- }
597
- if (params.is_video === 1 && params.img_base64) {
598
- throw new SeacloudError("\u89C6\u9891\u68C0\u6D4B\u4E0D\u652F\u6301 base64 \u8F93\u5165\uFF0C\u5FC5\u987B\u4F7F\u7528 uri \u53C2\u6570");
599
- }
600
- if (!params.risk_types || params.risk_types.length === 0) {
601
- throw new SeacloudError("\u5FC5\u987B\u63D0\u4F9B\u81F3\u5C11\u4E00\u4E2A\u98CE\u9669\u7C7B\u578B");
602
- }
603
- const client = getClient();
604
- const config = client.getConfig();
605
- const url = `${config.baseUrl}/scan`;
606
- const token = await getApiToken(config.apiKey);
607
- const controller = new AbortController();
608
- const timeoutId = setTimeout(() => controller.abort(), config.timeout);
609
- try {
610
- const response = await config.fetch(url, {
611
- method: "POST",
612
- headers: {
613
- "Content-Type": "application/json",
614
- "Authorization": `Bearer ${token}`
615
- },
616
- body: JSON.stringify(params),
617
- signal: controller.signal
618
- });
619
- clearTimeout(timeoutId);
620
- if (!response.ok) {
621
- const errorBody = await response.text();
622
- throw new SeacloudError(
623
- `HTTP ${response.status}: ${errorBody}`,
624
- response.status,
625
- errorBody
626
- );
627
- }
628
- const responseData = await response.json();
629
- let result;
630
- if (responseData.success !== void 0 && responseData.data) {
631
- result = responseData.data;
632
- } else {
633
- result = responseData;
634
- }
635
- if (!result.ok) {
636
- throw new SeacloudError(
637
- `\u5185\u5BB9\u5B89\u5168\u68C0\u6D4B\u4E1A\u52A1\u9519\u8BEF: ${result.error || "\u672A\u77E5\u9519\u8BEF"}`,
638
- void 0,
639
- result
640
- );
641
- }
642
- return result;
643
- } catch (error) {
644
- clearTimeout(timeoutId);
645
- if (error instanceof SeacloudError) {
646
- throw error;
647
- }
648
- if (error.name === "AbortError") {
649
- throw new SeacloudError(`Request timeout after ${config.timeout}ms`);
650
- }
651
- throw new SeacloudError(
652
- `Request failed: ${error.message}`,
653
- void 0,
654
- error
655
- );
656
- }
657
- }
658
548
  var __filename$1 = fileURLToPath(import.meta.url);
659
549
  dirname(__filename$1);
660
550
  function showHelp() {
@@ -668,8 +558,6 @@ Commands:
668
558
  llm <prompt> Chat with LLM models
669
559
  agent <prompt> Chat with Fast Agent (supports image/video generation)
670
560
  app <subcommand> App-related operations (search, generation)
671
- scan <uri> Content safety scan (image/video/audio)
672
- status <task-id> Query task status by task ID
673
561
  <model> Test specific model generation
674
562
 
675
563
  App Subcommands:
@@ -695,21 +583,11 @@ App Generation Options:
695
583
  --template-id <id> Template ID (required)
696
584
  --params <json> Input parameters as JSON string (required)
697
585
 
698
- Scan Options:
699
- --risk-types <types> Risk types (default: POLITY,EROTIC,VIOLENT,CHILD)
700
- --detected-age Enable age detection (default: false)
701
- --api-key <key> API key (or set API_SERVICE_TOKEN env var)
702
- --base-url <url> Base URL (default: http://proxy.sg.seaverse.dev)
703
-
704
586
  Model Generation Options:
705
587
  --api-key <key> API key (or set API_SERVICE_TOKEN env var)
706
588
  --base-url <url> Base URL (default: http://proxy.sg.seaverse.dev)
707
589
  --params <json> JSON parameters for the model
708
590
 
709
- Status Query Options:
710
- --api-key <key> API key (or set API_SERVICE_TOKEN env var)
711
- --base-url <url> Base URL (default: http://proxy.sg.seaverse.dev)
712
-
713
591
  Examples:
714
592
  # Chat with LLM (non-streaming)
715
593
  seacloud llm "What is the capital of France?"
@@ -733,18 +611,6 @@ Examples:
733
611
  # Create generation task (app generation)
734
612
  seacloud app generation --template-id "d26trpte878eqsnm3bjg" --params '[{"field":"prompt1","value":"hello"}]'
735
613
 
736
- # Query task status
737
- seacloud status d123456789abcdef
738
-
739
- # Scan image
740
- seacloud scan "https://example.com/image.jpg"
741
-
742
- # Scan video with custom risk types
743
- seacloud scan "https://example.com/video.mp4" --risk-types EROTIC,VIOLENT
744
-
745
- # Scan with age detection
746
- seacloud scan "https://example.com/photo.jpg" --detected-age
747
-
748
614
  # Test model generation
749
615
  seacloud flux_1_1_pro --params '{"prompt":"a beautiful sunset"}'
750
616
 
@@ -1043,167 +909,6 @@ async function runAppSearch(templateIdsStr, args) {
1043
909
  });
1044
910
  console.log(JSON.stringify(result, null, 2));
1045
911
  }
1046
- function detectMediaType(uri) {
1047
- const videoExtRegex = /\.(?:mp4|avi|mkv|mov|flv|wmv|webm|m4v|3gp|ts|mts|mpeg|mpg|vob|ogv|m2ts|divx|rm|rmvb|asf|f4v)(?:[^a-z0-9]|$)/i;
1048
- const audioExtRegex = /\.(?:mp3|wav|ogg|m4a|aac|flac|wma|m4b|m4p|m4r)(?:[^a-z0-9]|$)/i;
1049
- if (videoExtRegex.test(uri)) {
1050
- return { isVideo: 1, mediaType: "video" };
1051
- }
1052
- if (audioExtRegex.test(uri)) {
1053
- return { isVideo: 1, mediaType: "audio" };
1054
- }
1055
- return { isVideo: 0, mediaType: "image" };
1056
- }
1057
- async function runScan(uri, args) {
1058
- const options = {
1059
- riskTypes: ["POLITY", "EROTIC", "VIOLENT", "CHILD"],
1060
- detectedAge: false
1061
- };
1062
- for (let i = 0; i < args.length; i++) {
1063
- const arg = args[i];
1064
- if (arg === "--risk-types") {
1065
- options.riskTypes = args[++i].split(",").map((t) => t.trim());
1066
- } else if (arg === "--detected-age") {
1067
- options.detectedAge = true;
1068
- } else if (arg === "--api-key") {
1069
- options.apiKey = args[++i];
1070
- } else if (arg === "--base-url") {
1071
- options.baseUrl = args[++i];
1072
- }
1073
- }
1074
- const apiKey = options.apiKey || process.env.API_SERVICE_TOKEN || "";
1075
- const baseUrl = options.baseUrl || process.env.SEACLOUD_BASE_URL || "http://proxy.sg.seaverse.dev";
1076
- initSeacloud(apiKey, { baseUrl });
1077
- const { isVideo, mediaType } = detectMediaType(uri);
1078
- console.log(`\u8D44\u6E90\u5730\u5740: ${uri}`);
1079
- console.log(`\u5A92\u4F53\u7C7B\u578B: ${mediaType}`);
1080
- console.log(`\u98CE\u9669\u7C7B\u578B: ${options.riskTypes.join(", ")}`);
1081
- console.log(`\u5E74\u9F84\u68C0\u6D4B: ${options.detectedAge ? "\u542F\u7528" : "\u7981\u7528"}`);
1082
- console.log("");
1083
- try {
1084
- const result = await scan({
1085
- uri,
1086
- risk_types: options.riskTypes,
1087
- detected_age: options.detectedAge ? 1 : 0,
1088
- is_video: isVideo
1089
- });
1090
- console.log("\u2705 \u626B\u63CF\u5B8C\u6210!\n");
1091
- console.log(`\u8BF7\u6C42\u72B6\u6001: ${result.ok ? "\u6210\u529F" : "\u5931\u8D25"}`);
1092
- if (result.nsfw_level !== void 0) {
1093
- console.log(`\u98CE\u9669\u7EA7\u522B: ${result.nsfw_level} (0-6)`);
1094
- }
1095
- if (result.risk_types && result.risk_types.length > 0) {
1096
- console.log(`\u68C0\u6D4B\u5230\u7684\u98CE\u9669\u7C7B\u578B: ${result.risk_types.join(", ")}`);
1097
- }
1098
- if (result.age_group && result.age_group.length > 0) {
1099
- console.log(`\u5E74\u9F84\u7EC4: ${JSON.stringify(result.age_group)}`);
1100
- }
1101
- if (isVideo === 1) {
1102
- if (result.video_duration !== void 0) {
1103
- console.log(`\u89C6\u9891\u65F6\u957F: ${result.video_duration} \u79D2`);
1104
- }
1105
- if (result.frame_count !== void 0) {
1106
- console.log(`\u603B\u62BD\u5E27\u6570: ${result.frame_count}`);
1107
- }
1108
- if (result.frames_checked !== void 0) {
1109
- console.log(`\u5B9E\u9645\u68C0\u6D4B\u5E27\u6570: ${result.frames_checked}`);
1110
- }
1111
- if (result.max_risk_frame !== void 0) {
1112
- console.log(`\u6700\u9AD8\u98CE\u9669\u5E27\u7D22\u5F15: ${result.max_risk_frame}`);
1113
- }
1114
- if (result.early_exit !== void 0) {
1115
- console.log(`\u63D0\u524D\u9000\u51FA: ${result.early_exit ? "\u662F" : "\u5426"}`);
1116
- }
1117
- }
1118
- if (result.label_items && result.label_items.length > 0) {
1119
- console.log(`
1120
- \u68C0\u6D4B\u5230\u7684\u6807\u7B7E (${result.label_items.length} \u4E2A):`);
1121
- result.label_items.forEach((item, i) => {
1122
- console.log(` ${i + 1}. ${item.name}`);
1123
- console.log(` \u98CE\u9669\u7EA7\u522B: ${item.score}, \u7C7B\u578B: ${item.risk_type}`);
1124
- });
1125
- }
1126
- if (result.frame_results && result.frame_results.length > 0) {
1127
- console.log(`
1128
- \u5E27\u68C0\u6D4B\u7ED3\u679C (\u524D5\u5E27):`);
1129
- result.frame_results.slice(0, 5).forEach((frame) => {
1130
- console.log(` \u5E27 ${frame.frame_index}: \u98CE\u9669\u7EA7\u522B ${frame.nsfw_level}, \u6807\u7B7E\u6570 ${frame.label_items.length}`);
1131
- });
1132
- if (result.frame_results.length > 5) {
1133
- console.log(` ... \u8FD8\u6709 ${result.frame_results.length - 5} \u5E27\u7ED3\u679C`);
1134
- }
1135
- }
1136
- if (result.error) {
1137
- console.log(`
1138
- \u274C \u9519\u8BEF: ${result.error}`);
1139
- }
1140
- } catch (error) {
1141
- console.error("\n\u274C \u626B\u63CF\u5931\u8D25:", error.message);
1142
- process.exit(1);
1143
- }
1144
- }
1145
- async function runTaskStatus(taskId, args) {
1146
- const options = {};
1147
- for (let i = 0; i < args.length; i++) {
1148
- const arg = args[i];
1149
- if (arg === "--api-key") options.apiKey = args[++i];
1150
- else if (arg === "--base-url") options.baseUrl = args[++i];
1151
- }
1152
- const apiKey = options.apiKey || process.env.API_SERVICE_TOKEN || "";
1153
- const baseUrl = options.baseUrl || process.env.SEACLOUD_BASE_URL || "http://proxy.sg.seaverse.dev";
1154
- const client = new SeacloudClient({ apiKey, baseUrl });
1155
- console.log(`Querying task status...`);
1156
- console.log(`Task ID: ${taskId}`);
1157
- console.log(`Base URL: ${baseUrl}
1158
- `);
1159
- try {
1160
- const result = await client.getTaskStatus("/model/v1/generation", taskId);
1161
- console.log(`Status: ${result.status}`);
1162
- console.log(`Task ID: ${result.id}
1163
- `);
1164
- if (result.status === "completed") {
1165
- console.log("\u2705 Task completed successfully!\n");
1166
- console.log("Output:");
1167
- console.log(JSON.stringify(result.output, null, 2));
1168
- if (result.output) {
1169
- const urls = [];
1170
- for (const item of result.output) {
1171
- if (item.content) {
1172
- for (const resource of item.content) {
1173
- if (resource.url) {
1174
- urls.push(resource.url);
1175
- }
1176
- }
1177
- }
1178
- }
1179
- if (urls.length > 0) {
1180
- console.log("\nGenerated URLs:");
1181
- urls.forEach((url, i) => {
1182
- console.log(` ${i + 1}. ${url}`);
1183
- });
1184
- }
1185
- }
1186
- } else if (result.status === "failed") {
1187
- console.log("\u274C Task failed!\n");
1188
- console.log("Error:", JSON.stringify(result.error, null, 2));
1189
- } else if (result.status === "processing") {
1190
- console.log("\u23F3 Task is still processing...");
1191
- console.log("Please check again later.");
1192
- } else if (result.status === "pending") {
1193
- console.log("\u23F3 Task is pending...");
1194
- console.log("Please check again later.");
1195
- } else {
1196
- console.log("Full result:");
1197
- console.log(JSON.stringify(result, null, 2));
1198
- }
1199
- } catch (error) {
1200
- console.error("\nError querying task status:", error.message);
1201
- if (error.statusCode) {
1202
- console.error("HTTP Status Code:", error.statusCode);
1203
- }
1204
- process.exit(1);
1205
- }
1206
- }
1207
912
  async function main() {
1208
913
  const args = process.argv.slice(2);
1209
914
  if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
@@ -1226,20 +931,6 @@ async function main() {
1226
931
  process.exit(1);
1227
932
  }
1228
933
  await runAgent(args[1], args.slice(2));
1229
- } else if (command === "scan") {
1230
- if (args.length < 2) {
1231
- console.error("Error: URI required for scan command");
1232
- console.log('Usage: seacloud scan "<uri>" [options]');
1233
- process.exit(1);
1234
- }
1235
- await runScan(args[1], args.slice(2));
1236
- } else if (command === "status") {
1237
- if (args.length < 2) {
1238
- console.error("Error: task ID required for status command");
1239
- console.log("Usage: seacloud status <task-id> [options]");
1240
- process.exit(1);
1241
- }
1242
- await runTaskStatus(args[1], args.slice(2));
1243
934
  } else if (command === "app") {
1244
935
  const subcommand = args[1];
1245
936
  if (!subcommand) {