seacloud-sdk 0.9.6 → 0.9.8

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,7 +13,51 @@ var SeacloudError = class extends Error {
13
13
  };
14
14
 
15
15
  // src/core/config.ts
16
- function getApiToken(providedApiKey) {
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) {
17
61
  if (providedApiKey) {
18
62
  return providedApiKey;
19
63
  }
@@ -29,19 +73,24 @@ function getApiToken(providedApiKey) {
29
73
  if (typeof process !== "undefined" && process.env?.API_SERVICE_TOKEN) {
30
74
  return process.env.API_SERVICE_TOKEN;
31
75
  }
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
- );
76
+ if (typeof globalThis.window !== "undefined") {
77
+ const parentToken = await getTokenFromParent();
78
+ if (parentToken) {
79
+ return parentToken;
80
+ }
81
+ }
82
+ return "";
35
83
  }
36
84
  function createConfig(options = {}) {
37
- const apiKey = getApiToken(options.apiKey);
85
+ const apiKey = options.apiKey;
38
86
  const baseUrl = options.baseUrl || (typeof process !== "undefined" ? process.env?.SEACLOUD_BASE_URL : void 0) || "https://proxy-rs.seaverse.ai";
39
87
  const fetchImpl = options.fetch || (globalThis.fetch ? globalThis.fetch.bind(globalThis) : void 0);
40
88
  if (!fetchImpl) {
41
89
  throw new Error("fetch is not available. Please provide a fetch implementation in config or upgrade to Node.js 18+");
42
90
  }
43
91
  return {
44
- apiKey,
92
+ apiKey: apiKey || "",
93
+ // 提供默认空字符串,实际请求时会动态获取
45
94
  baseUrl,
46
95
  fetch: fetchImpl,
47
96
  timeout: options.timeout || 3e4
@@ -86,7 +135,7 @@ var SeacloudClient = class {
86
135
  */
87
136
  async createTask(endpoint, body) {
88
137
  const url = `${this.config.baseUrl}${endpoint}`;
89
- const currentToken = getApiToken(this.providedApiKey);
138
+ const currentToken = await getApiToken(this.providedApiKey);
90
139
  const controller = new AbortController();
91
140
  const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
92
141
  try {
@@ -133,7 +182,7 @@ var SeacloudClient = class {
133
182
  */
134
183
  async getTaskStatus(endpoint, taskId) {
135
184
  const url = `${this.config.baseUrl}${endpoint}/task/${taskId}`;
136
- const currentToken = getApiToken(this.providedApiKey);
185
+ const currentToken = await getApiToken(this.providedApiKey);
137
186
  const controller = new AbortController();
138
187
  const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
139
188
  try {
@@ -230,6 +279,7 @@ async function llmChatCompletions(params) {
230
279
  const client = getClient();
231
280
  const config = client.getConfig();
232
281
  const url = `${config.baseUrl}/llm/chat/completions`;
282
+ const token = await getApiToken(config.apiKey);
233
283
  const controller = new AbortController();
234
284
  const timeoutId = setTimeout(() => controller.abort(), config.timeout);
235
285
  try {
@@ -237,7 +287,7 @@ async function llmChatCompletions(params) {
237
287
  method: "POST",
238
288
  headers: {
239
289
  "Content-Type": "application/json",
240
- "Authorization": `Bearer ${config.apiKey}`
290
+ "Authorization": `Bearer ${token}`
241
291
  },
242
292
  body: JSON.stringify(params),
243
293
  signal: controller.signal
@@ -505,6 +555,39 @@ function createTextMessage(role, text) {
505
555
  content: [{ type: "text", text }]
506
556
  };
507
557
  }
558
+
559
+ // src/api/app_search.ts
560
+ async function appSearch(params) {
561
+ const client = getClient();
562
+ const config = client.getConfig();
563
+ const url = `${config.baseUrl}/model/v1/template/specs`;
564
+ const controller = new AbortController();
565
+ const timeoutId = setTimeout(() => controller.abort(), config.timeout);
566
+ try {
567
+ const requestId = `req-${Date.now()}-${Math.random().toString(36).substring(7)}`;
568
+ const response = await config.fetch(url, {
569
+ method: "POST",
570
+ headers: {
571
+ "Content-Type": "application/json",
572
+ "Authorization": `Bearer ${config.apiKey}`,
573
+ "X-Request-Id": requestId,
574
+ "X-Project": "KIIRA"
575
+ },
576
+ body: JSON.stringify(params),
577
+ signal: controller.signal
578
+ });
579
+ clearTimeout(timeoutId);
580
+ if (!response.ok) {
581
+ const errorBody = await response.text();
582
+ throw new Error(`HTTP ${response.status}: ${errorBody}`);
583
+ }
584
+ const result = await response.json();
585
+ return result;
586
+ } catch (error) {
587
+ clearTimeout(timeoutId);
588
+ throw error;
589
+ }
590
+ }
508
591
  var __filename$1 = fileURLToPath(import.meta.url);
509
592
  dirname(__filename$1);
510
593
  function showHelp() {
@@ -517,8 +600,13 @@ Usage:
517
600
  Commands:
518
601
  llm <prompt> Chat with LLM models
519
602
  agent <prompt> Chat with Fast Agent (supports image/video generation)
603
+ app <subcommand> App-related operations (search, generation)
520
604
  <model> Test specific model generation
521
605
 
606
+ App Subcommands:
607
+ app search <ids> Query template specifications by template IDs
608
+ app generation Create generation task from template
609
+
522
610
  LLM Options:
523
611
  --model <name> Model name (default: seaart-mix-sonnet-4-5)
524
612
  --stream Enable streaming mode
@@ -531,6 +619,13 @@ Agent Options:
531
619
  --stream Enable streaming mode
532
620
  --session-id <id> Session ID for multi-turn conversation
533
621
 
622
+ App Search Options:
623
+ --type <type> Template type (default: comfyui)
624
+
625
+ App Generation Options:
626
+ --template-id <id> Template ID (required)
627
+ --params <json> Input parameters as JSON string (required)
628
+
534
629
  Model Generation Options:
535
630
  --api-key <key> API key (or set API_SERVICE_TOKEN env var)
536
631
  --base-url <url> Base URL (default: http://proxy.sg.seaverse.dev)
@@ -552,6 +647,13 @@ Examples:
552
647
  # Chat with Agent (streaming)
553
648
  seacloud agent "Create a cat image" --stream
554
649
 
650
+ # Query template specifications (app search)
651
+ seacloud app search "template-id-1,template-id-2"
652
+ seacloud app search "template-abc" --type comfyui
653
+
654
+ # Create generation task (app generation)
655
+ seacloud app generation --template-id "d26trpte878eqsnm3bjg" --params '[{"field":"prompt1","value":"hello"}]'
656
+
555
657
  # Test model generation
556
658
  seacloud flux_1_1_pro --params '{"prompt":"a beautiful sunset"}'
557
659
 
@@ -591,7 +693,7 @@ function parseArgs(args) {
591
693
  }
592
694
  async function testModel(model, options) {
593
695
  const apiKey = options.apiKey || process.env.API_SERVICE_TOKEN || "";
594
- const baseUrl = options.baseUrl || process.env.API_BASE_URL || "http://localhost:8080";
696
+ const baseUrl = options.baseUrl || process.env.SEACLOUD_BASE_URL || "http://proxy.sg.seaverse.dev";
595
697
  if (!options.params) {
596
698
  console.error("Error: --params required. Provide JSON parameters for the model");
597
699
  process.exit(1);
@@ -761,6 +863,95 @@ async function runAgent(prompt, args) {
761
863
  console.log("Message ID:", response.msg_id);
762
864
  }
763
865
  }
866
+ async function runAppGeneration(args) {
867
+ const options = {};
868
+ for (let i = 0; i < args.length; i++) {
869
+ const arg = args[i];
870
+ if (arg === "--template-id") options.templateId = args[++i];
871
+ else if (arg === "--params") {
872
+ try {
873
+ options.params = JSON.parse(args[++i]);
874
+ } catch (e) {
875
+ console.error("Error: --params must be valid JSON array");
876
+ console.error(`Example: --params '[{"field":"prompt1","value":"hello"}]'`);
877
+ process.exit(1);
878
+ }
879
+ } else if (arg === "--api-key") options.apiKey = args[++i];
880
+ else if (arg === "--base-url") options.baseUrl = args[++i];
881
+ }
882
+ if (!options.templateId) {
883
+ console.error("Error: --template-id required");
884
+ console.error("Usage: seacloud app generation --template-id <id> --params <json>");
885
+ process.exit(1);
886
+ }
887
+ if (!options.params) {
888
+ console.error("Error: --params required");
889
+ console.error("Usage: seacloud app generation --template-id <id> --params <json>");
890
+ console.error(`Example: --params '[{"field":"prompt1","value":"hello"}]'`);
891
+ process.exit(1);
892
+ }
893
+ const apiKey = options.apiKey || process.env.API_SERVICE_TOKEN || "";
894
+ const baseUrl = options.baseUrl || process.env.SEACLOUD_BASE_URL || "http://proxy.sg.seaverse.dev";
895
+ const client = new SeacloudClient({ apiKey, baseUrl });
896
+ try {
897
+ console.log("Creating task...");
898
+ const task = await client.createTask("/model/v1/generation", {
899
+ model: "comfyui",
900
+ input: [{ params: { template_id: options.templateId, inputs: options.params } }]
901
+ });
902
+ console.log(`Task created: ${task.id}`);
903
+ console.log(`Initial status: ${task.status}`);
904
+ console.log("");
905
+ if (task.status === "failed") {
906
+ console.error("Task failed immediately:", task.error);
907
+ process.exit(1);
908
+ }
909
+ console.log("Polling for results...");
910
+ let attempt = 0;
911
+ const maxAttempts = 120;
912
+ const intervalMs = 3e3;
913
+ while (attempt < maxAttempts) {
914
+ attempt++;
915
+ const result = await client.getTaskStatus("/model/v1/generation", task.id);
916
+ process.stdout.write(`\rAttempt ${attempt}/${maxAttempts} - Status: ${result.status} `);
917
+ if (result.status === "completed") {
918
+ console.log("\n\nTask completed!");
919
+ console.log("\nResults:");
920
+ console.log(JSON.stringify(result, null, 2));
921
+ process.exit(0);
922
+ }
923
+ if (result.status === "failed") {
924
+ console.log("\n\nTask failed!");
925
+ console.error("Error:", result.error);
926
+ process.exit(1);
927
+ }
928
+ await new Promise((resolve) => setTimeout(resolve, intervalMs));
929
+ }
930
+ console.log("\n\nTimeout: Task did not complete within the time limit");
931
+ process.exit(1);
932
+ } catch (error) {
933
+ console.error("\nError:", error.message);
934
+ process.exit(1);
935
+ }
936
+ }
937
+ async function runAppSearch(templateIdsStr, args) {
938
+ const options = { type: "comfyui" };
939
+ for (let i = 0; i < args.length; i++) {
940
+ const arg = args[i];
941
+ if (arg === "--type") options.type = args[++i];
942
+ else if (arg === "--api-key") options.apiKey = args[++i];
943
+ else if (arg === "--base-url") options.baseUrl = args[++i];
944
+ }
945
+ const apiKey = options.apiKey || process.env.API_SERVICE_TOKEN || "";
946
+ const baseUrl = options.baseUrl || process.env.SEACLOUD_BASE_URL || "http://proxy.sg.seaverse.dev";
947
+ initSeacloud(apiKey, { baseUrl });
948
+ const templateIds = templateIdsStr.split(",").map((id) => id.trim());
949
+ const result = await appSearch({
950
+ type: options.type,
951
+ template_ids: templateIds
952
+ });
953
+ console.log(JSON.stringify(result, null, 2));
954
+ }
764
955
  async function main() {
765
956
  const args = process.argv.slice(2);
766
957
  if (args.length === 0 || args[0] === "--help" || args[0] === "-h") {
@@ -783,6 +974,28 @@ async function main() {
783
974
  process.exit(1);
784
975
  }
785
976
  await runAgent(args[1], args.slice(2));
977
+ } else if (command === "app") {
978
+ const subcommand = args[1];
979
+ if (!subcommand) {
980
+ console.error("Error: subcommand required for app command");
981
+ console.log("Usage: seacloud app <subcommand> [options]");
982
+ console.log("Subcommands: search, generation");
983
+ process.exit(1);
984
+ }
985
+ if (subcommand === "search") {
986
+ if (args.length < 3) {
987
+ console.error("Error: template IDs required for app search command");
988
+ console.log('Usage: seacloud app search "<id1,id2,...>" [options]');
989
+ process.exit(1);
990
+ }
991
+ await runAppSearch(args[2], args.slice(3));
992
+ } else if (subcommand === "generation") {
993
+ await runAppGeneration(args.slice(2));
994
+ } else {
995
+ console.error(`Error: unknown subcommand '${subcommand}'`);
996
+ console.log("Available subcommands: search, generation");
997
+ process.exit(1);
998
+ }
786
999
  } else {
787
1000
  const model = command;
788
1001
  if (model.startsWith("--")) {