wiamotion 1.0.0
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/README.md +43 -0
- package/bin/wiamotion.js +134 -0
- package/package.json +13 -0
package/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# wiamotion
|
|
2
|
+
|
|
3
|
+
**WIA Motion CLI** — create AI vertical video campaigns from the command line.
|
|
4
|
+
명령줄에서 AI 세로영상 캠페인을 만듭니다.
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
npx wiamotion packages # no key needed / 키 없이
|
|
8
|
+
npx wiamotion create --prompt "new product, 30s" --package starter
|
|
9
|
+
npx wiamotion status <id>
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Commands
|
|
13
|
+
|
|
14
|
+
| | |
|
|
15
|
+
|---|---|
|
|
16
|
+
| `packages` | List packages and credits. **No API key needed.** |
|
|
17
|
+
| `create --prompt "<text>"` | Create a campaign |
|
|
18
|
+
| `status <id>` | Check progress, get the video URL |
|
|
19
|
+
|
|
20
|
+
## Options
|
|
21
|
+
|
|
22
|
+
- `--key <key>` — API key (or set `WIAMOTION_API_KEY`)
|
|
23
|
+
- `--package <name>` — `trial` \| `starter` \| `launch` \| `story` \| `longform` (default `trial`)
|
|
24
|
+
- `--lang <code>` — video language (default `ko`)
|
|
25
|
+
- `--json` — raw JSON output
|
|
26
|
+
- `-v`, `--version`, `-h`, `--help` — help is auto ko/en by your locale
|
|
27
|
+
|
|
28
|
+
## Exit codes
|
|
29
|
+
|
|
30
|
+
`2` no/invalid key · `3` out of credits · `4` rate limited · `5` not found
|
|
31
|
+
|
|
32
|
+
Useful in scripts: `npx wiamotion status $ID || echo "not ready"`
|
|
33
|
+
|
|
34
|
+
## Get a key
|
|
35
|
+
|
|
36
|
+
<https://wiamotion.ai/#account>
|
|
37
|
+
|
|
38
|
+
This CLI is a thin wrapper over `api.wiamotion.ai` — generation and billing live in the
|
|
39
|
+
service, not here.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
© SmileStory Co., Ltd. · <https://wiamotion.ai>
|
package/bin/wiamotion.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* wiamotion — WIA Motion CLI
|
|
4
|
+
* ============================================================================
|
|
5
|
+
* api.wiamotion.ai 를 부르는 얇은 래퍼다. 생성 로직·과금은 전부 API 쪽에 있고 여기는
|
|
6
|
+
* 명령줄 껍데기일 뿐이다 — 같은 규칙을 두 곳에 구현하면 반드시 한쪽이 뒤처진다
|
|
7
|
+
* (wiamotion-mcp 와 동일한 원칙).
|
|
8
|
+
*/
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const API = process.env.WIAMOTION_API_BASE || 'https://api.wiamotion.ai';
|
|
12
|
+
const SITE = 'https://wiamotion.ai';
|
|
13
|
+
const VERSION = require('../package.json').version;
|
|
14
|
+
const KO = /ko/i.test(process.env.LC_ALL || process.env.LANG || process.env.LANGUAGE || '');
|
|
15
|
+
const t = (ko, en) => (KO ? ko : en);
|
|
16
|
+
|
|
17
|
+
function help() {
|
|
18
|
+
console.log(`
|
|
19
|
+
wiamotion v${VERSION} — ${t('AI 세로영상 캠페인', 'AI vertical video campaigns')}
|
|
20
|
+
|
|
21
|
+
${t('사용법', 'Usage')}:
|
|
22
|
+
npx wiamotion <${t('명령', 'command')}> [${t('옵션', 'options')}]
|
|
23
|
+
|
|
24
|
+
${t('명령', 'Commands')}:
|
|
25
|
+
packages ${t('요금제와 크레딧 보기 (키 불필요)', 'list packages and credits (no key needed)')}
|
|
26
|
+
create --prompt "<${t('내용', 'text')}>" ${t('캠페인 만들기', 'create a campaign')}
|
|
27
|
+
status <id> ${t('진행 상태 보기', 'check a campaign')}
|
|
28
|
+
|
|
29
|
+
${t('옵션', 'Options')}:
|
|
30
|
+
--key <${t('키', 'key')}> ${t('API 키 (또는 환경변수 WIAMOTION_API_KEY)', 'API key (or WIAMOTION_API_KEY env)')}
|
|
31
|
+
--package <${t('이름', 'name')}> ${t('요금제 (기본 trial)', 'package (default: trial)')}
|
|
32
|
+
--lang <${t('코드', 'code')}> ${t('영상 언어 (기본 ko)', 'video language (default: ko)')}
|
|
33
|
+
--json ${t('결과를 JSON 으로', 'print raw JSON')}
|
|
34
|
+
-v, --version / -h, --help
|
|
35
|
+
|
|
36
|
+
${t('예시', 'Examples')}:
|
|
37
|
+
npx wiamotion packages
|
|
38
|
+
npx wiamotion create --prompt "${t('신제품 소개 30초', 'new product, 30s')}" --package starter
|
|
39
|
+
npx wiamotion status abc123
|
|
40
|
+
|
|
41
|
+
${t('키 발급', 'Get a key')}: ${SITE}/#account
|
|
42
|
+
`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function arg(argv, name) {
|
|
46
|
+
const i = argv.indexOf(name);
|
|
47
|
+
return i >= 0 && argv[i + 1] ? argv[i + 1] : null;
|
|
48
|
+
}
|
|
49
|
+
function fail(msg, code) { console.error('\n' + msg + '\n'); process.exit(code || 1); }
|
|
50
|
+
|
|
51
|
+
async function call(path, key, opts) {
|
|
52
|
+
const headers = Object.assign({ Accept: 'application/json' }, (opts || {}).headers || {});
|
|
53
|
+
if (key) headers.Authorization = 'Bearer ' + key;
|
|
54
|
+
let res;
|
|
55
|
+
try { res = await fetch(API + path, Object.assign({}, opts, { headers })); }
|
|
56
|
+
catch (e) { fail(t(`서버에 닿지 못했습니다: ${e.message}`, `Could not reach the server: ${e.message}`)); }
|
|
57
|
+
let body = null;
|
|
58
|
+
try { body = await res.json(); } catch (e) { /* 비-JSON 응답 */ }
|
|
59
|
+
return { status: res.status, body };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** 어느 명령에서든 같은 말투로 안내한다 — 사용자는 어느 명령을 쳤든 같은 벽을 만난다. */
|
|
63
|
+
function guard(r, key) {
|
|
64
|
+
if (r.status === 401) fail(t(`API 키가 올바르지 않거나 만료됐습니다.\n 키 발급: ${SITE}/#account`,
|
|
65
|
+
`The API key is invalid or expired.\n Get one: ${SITE}/#account`), 2);
|
|
66
|
+
if (r.status === 402) fail(t(`크레딧이 모자랍니다.\n 충전: ${SITE}/#pricing`,
|
|
67
|
+
`Not enough credits.\n Top up: ${SITE}/#pricing`), 3);
|
|
68
|
+
if (r.status === 429) fail(t('요청이 너무 잦습니다. 잠시 후 다시 시도해 주세요.',
|
|
69
|
+
'Too many requests. Please try again shortly.'), 4);
|
|
70
|
+
if (r.status >= 400) fail(t(`실패했습니다 (${r.status}): ${(r.body && r.body.error) || t('알 수 없는 오류','unknown error')}`,
|
|
71
|
+
`Failed (${r.status}): ${(r.body && r.body.error) || 'unknown error'}`));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function main() {
|
|
75
|
+
const argv = process.argv.slice(2);
|
|
76
|
+
if (!argv.length || argv.includes('-h') || argv.includes('--help')) return help();
|
|
77
|
+
if (argv.includes('-v') || argv.includes('--version')) return console.log(VERSION);
|
|
78
|
+
|
|
79
|
+
const cmd = argv[0];
|
|
80
|
+
const json = argv.includes('--json');
|
|
81
|
+
const key = arg(argv, '--key') || process.env.WIAMOTION_API_KEY || '';
|
|
82
|
+
|
|
83
|
+
if (cmd === 'packages') {
|
|
84
|
+
const r = await call('/v1/packages', null);
|
|
85
|
+
guard(r, key);
|
|
86
|
+
if (json) return console.log(JSON.stringify(r.body, null, 2));
|
|
87
|
+
const list = (r.body && r.body.packages) || [];
|
|
88
|
+
console.log(t('\n요금제\n', '\nPackages\n'));
|
|
89
|
+
for (const p of list) {
|
|
90
|
+
console.log(` ${String(p.package).padEnd(10)} ${String(p.credits).padStart(4)} ${t('크레딧','credits')} ` +
|
|
91
|
+
`${p.resolution} ${p.videos}${t('편','video(s)')} ${p.duration_s}s` +
|
|
92
|
+
(p.note ? ` — ${p.note}` : ''));
|
|
93
|
+
}
|
|
94
|
+
console.log(t(`\n키 발급: ${SITE}/#account\n`, `\nGet a key: ${SITE}/#account\n`));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (cmd === 'create') {
|
|
99
|
+
if (!key) fail(t(`API 키가 필요합니다.\n npx wiamotion create --key <키> --prompt "..."\n 또는 WIAMOTION_API_KEY 환경변수\n 키 발급: ${SITE}/#account`,
|
|
100
|
+
`An API key is required.\n npx wiamotion create --key <key> --prompt "..."\n or set WIAMOTION_API_KEY\n Get one: ${SITE}/#account`), 2);
|
|
101
|
+
const prompt = arg(argv, '--prompt');
|
|
102
|
+
if (!prompt) fail(t('--prompt 로 만들 내용을 알려주세요.', 'Tell me what to make with --prompt.'));
|
|
103
|
+
const form = new FormData();
|
|
104
|
+
form.append('prompt', prompt);
|
|
105
|
+
form.append('package', arg(argv, '--package') || 'trial');
|
|
106
|
+
form.append('language', arg(argv, '--lang') || 'ko');
|
|
107
|
+
const r = await call('/v1/campaigns', key, { method: 'POST', body: form });
|
|
108
|
+
guard(r, key);
|
|
109
|
+
if (json) return console.log(JSON.stringify(r.body, null, 2));
|
|
110
|
+
const id = (r.body && (r.body.id || r.body.campaign_id)) || '?';
|
|
111
|
+
console.log(t(`\n✅ 시작했습니다 — ${id}\n 진행 확인: npx wiamotion status ${id}\n`,
|
|
112
|
+
`\n✅ Started — ${id}\n Check it: npx wiamotion status ${id}\n`));
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (cmd === 'status') {
|
|
117
|
+
const id = argv[1];
|
|
118
|
+
if (!id) fail(t('캠페인 id 를 주세요. npx wiamotion status <id>', 'Give me a campaign id. npx wiamotion status <id>'));
|
|
119
|
+
if (!key) fail(t(`API 키가 필요합니다. 키 발급: ${SITE}/#account`, `An API key is required. Get one: ${SITE}/#account`), 2);
|
|
120
|
+
const r = await call('/v1/campaigns/' + encodeURIComponent(id), key);
|
|
121
|
+
if (r.status === 404) fail(t('그 id 의 캠페인을 찾지 못했습니다.', 'No campaign with that id.'), 5);
|
|
122
|
+
guard(r, key);
|
|
123
|
+
if (json) return console.log(JSON.stringify(r.body, null, 2));
|
|
124
|
+
const b = r.body || {};
|
|
125
|
+
console.log(`\n ${id} ${b.status || '?'}` + (b.progress != null ? ` ${b.progress}%` : ''));
|
|
126
|
+
if (b.video_url) console.log(t(` 영상: ${b.video_url}`, ` Video: ${b.video_url}`));
|
|
127
|
+
console.log('');
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
fail(t(`모르는 명령입니다: ${cmd}\n npx wiamotion --help`, `Unknown command: ${cmd}\n npx wiamotion --help`));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
main().catch((e) => fail(t(`예상치 못한 오류: ${e.message}`, `Unexpected error: ${e.message}`)));
|
package/package.json
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "wiamotion",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "WIA Motion CLI — create AI vertical video campaigns from the command line. 설치 없이: npx wiamotion packages",
|
|
5
|
+
"bin": { "wiamotion": "bin/wiamotion.js" },
|
|
6
|
+
"type": "commonjs",
|
|
7
|
+
"engines": { "node": ">=18" },
|
|
8
|
+
"files": ["bin/", "README.md"],
|
|
9
|
+
"keywords": ["wiamotion", "video", "ai", "shorts", "cli", "wia", "smilestory"],
|
|
10
|
+
"homepage": "https://wiamotion.ai",
|
|
11
|
+
"license": "UNLICENSED",
|
|
12
|
+
"author": "SmileStory Co., Ltd."
|
|
13
|
+
}
|