meetscribe 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 ADDED
@@ -0,0 +1,209 @@
1
+ # MeetScribe CLI
2
+
3
+ Command-line interface for MeetScribe - meeting transcription and protocol generation.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g meetscribe
9
+ ```
10
+
11
+ Or use without installing:
12
+
13
+ ```bash
14
+ npx meetscribe transcribe meeting.mp3
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ ```bash
20
+ # Authenticate
21
+ meetscribe login
22
+
23
+ # Transcribe a file
24
+ meetscribe transcribe meeting.mp3
25
+
26
+ # Get result as subtitles
27
+ meetscribe transcribe interview.mp4 --format srt -o subtitles.srt
28
+
29
+ # List your materials
30
+ meetscribe list
31
+
32
+ # Get meeting protocol
33
+ meetscribe protocol <material_id>
34
+ ```
35
+
36
+ ## Authentication
37
+
38
+ ### Browser Login (recommended)
39
+
40
+ ```bash
41
+ meetscribe login
42
+ ```
43
+
44
+ Opens your browser for authentication via MeetScribe website.
45
+
46
+ ### API Key
47
+
48
+ ```bash
49
+ # Enter key interactively
50
+ meetscribe login --key
51
+
52
+ # Or set directly
53
+ meetscribe config set-key sk_live_xxx
54
+
55
+ # Or use environment variable
56
+ export MEETSCRIBE_API_KEY=sk_live_xxx
57
+ ```
58
+
59
+ ## Commands
60
+
61
+ ### Transcribe
62
+
63
+ ```bash
64
+ meetscribe transcribe <file> [options]
65
+
66
+ Options:
67
+ -l, --language <lang> Language (ru, en, auto) [default: auto]
68
+ -s, --speakers <num> Number of speakers for diarization
69
+ -o, --output <file> Save output to file
70
+ -f, --format <format> Output format (json, txt, srt, vtt) [default: json]
71
+ --no-wait Return job ID immediately
72
+ ```
73
+
74
+ Examples:
75
+
76
+ ```bash
77
+ # Basic transcription
78
+ meetscribe transcribe meeting.mp3
79
+
80
+ # Russian language, 3 speakers
81
+ meetscribe transcribe meeting.mp4 -l ru -s 3
82
+
83
+ # Save as subtitles
84
+ meetscribe transcribe interview.mp4 -f srt -o subtitles.srt
85
+
86
+ # Non-blocking (for scripts)
87
+ JOB_ID=$(meetscribe transcribe large-file.mp4 --no-wait)
88
+ meetscribe status $JOB_ID
89
+ ```
90
+
91
+ ### List Materials
92
+
93
+ ```bash
94
+ meetscribe list [options]
95
+
96
+ Options:
97
+ -n, --limit <num> Number of items [default: 20]
98
+ --status <status> Filter by status
99
+ -f, --format <format> Output format (table, json)
100
+ ```
101
+
102
+ ### Get Protocol
103
+
104
+ ```bash
105
+ meetscribe protocol <material_id> [options]
106
+
107
+ Options:
108
+ -f, --format <format> Output format (json, markdown, txt)
109
+ -o, --output <file> Save to file
110
+ ```
111
+
112
+ ### Configuration
113
+
114
+ ```bash
115
+ # Show config
116
+ meetscribe config show
117
+
118
+ # Set API key
119
+ meetscribe config set-key <key>
120
+
121
+ # Set API URL
122
+ meetscribe config set-url <url>
123
+
124
+ # Set default language
125
+ meetscribe config set-language <ru|en|auto>
126
+
127
+ # Reset to defaults
128
+ meetscribe config reset
129
+ ```
130
+
131
+ ### Account
132
+
133
+ ```bash
134
+ # Show current user
135
+ meetscribe whoami
136
+
137
+ # Logout
138
+ meetscribe logout
139
+ ```
140
+
141
+ ## SDK Usage
142
+
143
+ ```javascript
144
+ import { MeetScribeClient } from 'meetscribe';
145
+
146
+ const client = new MeetScribeClient({
147
+ apiKey: process.env.MEETSCRIBE_API_KEY
148
+ });
149
+
150
+ // Transcribe a file
151
+ const job = await client.transcribe('./meeting.mp3', {
152
+ language: 'ru',
153
+ speakers: 3
154
+ });
155
+
156
+ // Wait for result
157
+ const result = await client.waitForJob(job.data.job_id);
158
+ console.log(result.data.transcript);
159
+
160
+ // Get protocol
161
+ const protocol = await client.getProtocol(result.data.material_id);
162
+ console.log(protocol.data.action_items);
163
+ ```
164
+
165
+ ## CI/CD Example
166
+
167
+ ```yaml
168
+ # GitHub Actions
169
+ jobs:
170
+ transcribe:
171
+ runs-on: ubuntu-latest
172
+ steps:
173
+ - uses: actions/checkout@v4
174
+
175
+ - name: Install MeetScribe
176
+ run: npm install -g meetscribe
177
+
178
+ - name: Transcribe
179
+ env:
180
+ MEETSCRIBE_API_KEY: ${{ secrets.MEETSCRIBE_API_KEY }}
181
+ run: |
182
+ meetscribe transcribe recording.mp3 -f txt -o transcript.txt
183
+
184
+ - uses: actions/upload-artifact@v4
185
+ with:
186
+ name: transcript
187
+ path: transcript.txt
188
+ ```
189
+
190
+ ## Exit Codes
191
+
192
+ | Code | Meaning |
193
+ |------|---------|
194
+ | 0 | Success |
195
+ | 1 | General error |
196
+ | 2 | Invalid arguments |
197
+ | 3 | Authentication error |
198
+ | 4 | API error |
199
+ | 5 | File not found |
200
+
201
+ ## Links
202
+
203
+ - [MeetScribe](https://meetscribe.ru)
204
+ - [API Documentation](https://meetscribe.ru/api-docs)
205
+ - [Support](https://t.me/meetscribe_bot)
206
+
207
+ ## License
208
+
209
+ MIT
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { cli } from '../src/cli/index.js';
4
+
5
+ cli();
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "meetscribe",
3
+ "version": "1.0.0",
4
+ "description": "MeetScribe CLI - Meeting transcription and protocol generation",
5
+ "keywords": [
6
+ "meetscribe",
7
+ "transcription",
8
+ "meeting",
9
+ "protocol",
10
+ "speech-to-text",
11
+ "cli",
12
+ "whisper"
13
+ ],
14
+ "homepage": "https://meetscribe.ru",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/meetscribe/meetscribe-cli"
18
+ },
19
+ "license": "MIT",
20
+ "author": "MeetScribe Team",
21
+ "type": "module",
22
+ "main": "src/index.js",
23
+ "types": "types/index.d.ts",
24
+ "bin": {
25
+ "meetscribe": "./bin/meetscribe.js"
26
+ },
27
+ "engines": {
28
+ "node": ">=18.0.0"
29
+ },
30
+ "scripts": {
31
+ "test": "node --test",
32
+ "lint": "eslint src/",
33
+ "start": "node bin/meetscribe.js"
34
+ },
35
+ "dependencies": {
36
+ "axios": "^1.7.0",
37
+ "chalk": "^5.3.0",
38
+ "commander": "^12.1.0",
39
+ "conf": "^13.0.0",
40
+ "form-data": "^4.0.0",
41
+ "mime-types": "^2.1.35",
42
+ "open": "^10.1.0",
43
+ "ora": "^8.0.0"
44
+ },
45
+ "devDependencies": {
46
+ "eslint": "^9.0.0"
47
+ }
48
+ }
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Config command - manage CLI configuration
3
+ */
4
+
5
+ import chalk from 'chalk';
6
+ import config, { getAllConfig, setApiKey, clearConfig } from '../utils/config.js';
7
+ import { success, error, info, table } from '../utils/output.js';
8
+
9
+ export function configCommand(action, value) {
10
+ switch (action) {
11
+ case 'show': {
12
+ console.log();
13
+ console.log(chalk.bold('MeetScribe CLI Configuration'));
14
+ console.log();
15
+
16
+ const cfg = getAllConfig();
17
+
18
+ table(
19
+ ['Setting', 'Value'],
20
+ [
21
+ ['API Key', cfg.apiKey],
22
+ ['API URL', cfg.apiUrl],
23
+ ['Default Language', cfg.defaultLanguage],
24
+ ['Default Format', cfg.defaultFormat],
25
+ ['Config Path', cfg.configPath]
26
+ ]
27
+ );
28
+ console.log();
29
+ break;
30
+ }
31
+
32
+ case 'set-key': {
33
+ if (!value) {
34
+ error('API key is required');
35
+ process.exit(1);
36
+ }
37
+
38
+ if (!value.startsWith('sk_live_') && !value.startsWith('sk_test_')) {
39
+ error('Invalid API key format. Key should start with sk_live_ or sk_test_');
40
+ process.exit(1);
41
+ }
42
+
43
+ setApiKey(value);
44
+ success('API key saved');
45
+ break;
46
+ }
47
+
48
+ case 'set-url': {
49
+ if (!value) {
50
+ error('URL is required');
51
+ process.exit(1);
52
+ }
53
+
54
+ try {
55
+ new URL(value);
56
+ } catch {
57
+ error('Invalid URL format');
58
+ process.exit(1);
59
+ }
60
+
61
+ config.set('apiUrl', value);
62
+ success(`API URL set to ${value}`);
63
+ break;
64
+ }
65
+
66
+ case 'set-language': {
67
+ const allowed = ['ru', 'en', 'auto'];
68
+ if (!allowed.includes(value)) {
69
+ error(`Invalid language. Allowed: ${allowed.join(', ')}`);
70
+ process.exit(1);
71
+ }
72
+
73
+ config.set('defaultLanguage', value);
74
+ success(`Default language set to ${value}`);
75
+ break;
76
+ }
77
+
78
+ case 'reset': {
79
+ clearConfig();
80
+ success('Configuration reset to defaults');
81
+ break;
82
+ }
83
+
84
+ default:
85
+ error(`Unknown config action: ${action}`);
86
+ process.exit(1);
87
+ }
88
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * List command - list transcribed materials
3
+ */
4
+
5
+ import chalk from 'chalk';
6
+ import ora from 'ora';
7
+
8
+ import { getApiKey, getApiUrl } from '../utils/config.js';
9
+ import { MeetScribeClient } from '../../sdk/client.js';
10
+ import { error, json, table, statusBadge, formatDate } from '../utils/output.js';
11
+
12
+ export async function listCommand(options, command) {
13
+ // Check auth
14
+ const apiKey = command?.parent?.opts()?.apiKey || getApiKey();
15
+ if (!apiKey) {
16
+ error('Not authenticated. Run `meetscribe login` first.');
17
+ process.exit(1);
18
+ }
19
+
20
+ const client = new MeetScribeClient({
21
+ apiKey,
22
+ baseUrl: command?.parent?.opts()?.apiUrl || getApiUrl()
23
+ });
24
+
25
+ const spinner = ora('Fetching materials...').start();
26
+
27
+ try {
28
+ const result = await client.listMaterials({
29
+ perPage: parseInt(options.limit) || 20,
30
+ status: options.status
31
+ });
32
+
33
+ spinner.stop();
34
+
35
+ const materials = result.data?.materials || [];
36
+ const pagination = result.data?.pagination || {};
37
+
38
+ if (options.format === 'json') {
39
+ json(result.data);
40
+ return;
41
+ }
42
+
43
+ console.log();
44
+
45
+ if (materials.length === 0) {
46
+ console.log(chalk.dim('No materials found'));
47
+ console.log();
48
+ return;
49
+ }
50
+
51
+ console.log(chalk.bold(`Materials (${pagination.total || materials.length} total)`));
52
+ console.log();
53
+
54
+ table(
55
+ ['ID', 'Title', 'Status', 'Created'],
56
+ materials.map(m => [
57
+ m.id?.slice(0, 12) + '...' || '-',
58
+ (m.title || 'Untitled').slice(0, 40),
59
+ m.status,
60
+ m.created_at ? formatDate(m.created_at) : '-'
61
+ ])
62
+ );
63
+
64
+ console.log();
65
+
66
+ if (pagination.total > materials.length) {
67
+ console.log(chalk.dim(`Showing ${materials.length} of ${pagination.total}. Use --limit to show more.`));
68
+ console.log();
69
+ }
70
+
71
+ } catch (err) {
72
+ spinner.fail('Failed to fetch materials');
73
+ error(err.message);
74
+ process.exit(1);
75
+ }
76
+ }
@@ -0,0 +1,191 @@
1
+ /**
2
+ * Login command - authenticate with MeetScribe
3
+ */
4
+
5
+ import chalk from 'chalk';
6
+ import ora from 'ora';
7
+ import open from 'open';
8
+ import readline from 'readline';
9
+
10
+ import config, { setApiKey, getApiKey } from '../utils/config.js';
11
+ import { MeetScribeClient } from '../../sdk/client.js';
12
+ import { success, error, info } from '../utils/output.js';
13
+
14
+ /**
15
+ * Interactive prompt for input
16
+ */
17
+ async function prompt(question) {
18
+ const rl = readline.createInterface({
19
+ input: process.stdin,
20
+ output: process.stdout
21
+ });
22
+
23
+ return new Promise((resolve) => {
24
+ rl.question(question, (answer) => {
25
+ rl.close();
26
+ resolve(answer.trim());
27
+ });
28
+ });
29
+ }
30
+
31
+ /**
32
+ * Login via API key input
33
+ */
34
+ async function loginWithKey() {
35
+ console.log();
36
+ info('Enter your API key from https://meetscribe.ru/api-settings');
37
+ console.log();
38
+
39
+ const key = await prompt('API Key: ');
40
+
41
+ if (!key) {
42
+ error('No API key provided');
43
+ process.exit(1);
44
+ }
45
+
46
+ // Validate key format
47
+ if (!key.startsWith('sk_live_') && !key.startsWith('sk_test_')) {
48
+ error('Invalid API key format. Key should start with sk_live_ or sk_test_');
49
+ process.exit(1);
50
+ }
51
+
52
+ // Test the key
53
+ const spinner = ora('Validating API key...').start();
54
+
55
+ try {
56
+ const client = new MeetScribeClient({ apiKey: key });
57
+ await client.getAccount();
58
+
59
+ setApiKey(key);
60
+ spinner.succeed('API key validated and saved');
61
+
62
+ console.log();
63
+ success(`Logged in successfully!`);
64
+ console.log(chalk.dim(`Config saved to: ${config.path}`));
65
+ } catch (err) {
66
+ spinner.fail('Invalid API key');
67
+ error(err.message);
68
+ process.exit(1);
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Login via browser OAuth
74
+ */
75
+ async function loginWithBrowser() {
76
+ const spinner = ora('Creating auth session...').start();
77
+
78
+ try {
79
+ // Create a temporary client without API key
80
+ const client = new MeetScribeClient({
81
+ baseUrl: config.get('apiUrl')
82
+ });
83
+
84
+ // Get session
85
+ const session = await client.createCliSession();
86
+ const authUrl = session.data?.auth_url;
87
+ const sessionId = session.data?.session_id;
88
+
89
+ if (!authUrl || !sessionId) {
90
+ spinner.fail('Failed to create auth session');
91
+ error('Server returned invalid response');
92
+ process.exit(1);
93
+ }
94
+
95
+ spinner.stop();
96
+
97
+ console.log();
98
+ info('Opening browser for authentication...');
99
+ console.log();
100
+ console.log(chalk.dim('If browser does not open, visit:'));
101
+ console.log(chalk.cyan(authUrl));
102
+ console.log();
103
+
104
+ // Open browser
105
+ await open(authUrl);
106
+
107
+ // Poll for token
108
+ const pollSpinner = ora('Waiting for authorization...').start();
109
+
110
+ const startTime = Date.now();
111
+ const timeout = 5 * 60 * 1000; // 5 minutes
112
+
113
+ while (true) {
114
+ try {
115
+ const result = await client.pollCliToken(sessionId);
116
+
117
+ if (result.data?.status === 'authorized' && result.data?.api_key) {
118
+ pollSpinner.succeed('Authorization successful');
119
+
120
+ setApiKey(result.data.api_key);
121
+
122
+ console.log();
123
+ success(`Logged in as ${result.data.user?.username || result.data.user?.name || 'user'}`);
124
+ console.log(chalk.dim(`Config saved to: ${config.path}`));
125
+
126
+ return;
127
+ }
128
+
129
+ if (result.data?.status === 'expired') {
130
+ pollSpinner.fail('Session expired');
131
+ error('Authorization session has expired. Please try again.');
132
+ process.exit(1);
133
+ }
134
+ } catch (err) {
135
+ // Ignore errors during polling, keep trying
136
+ }
137
+
138
+ if (Date.now() - startTime > timeout) {
139
+ pollSpinner.fail('Timeout');
140
+ error('Authorization timed out. Please try again.');
141
+ process.exit(1);
142
+ }
143
+
144
+ // Wait before next poll
145
+ await new Promise(resolve => setTimeout(resolve, 2000));
146
+ }
147
+ } catch (err) {
148
+ spinner.fail('Failed to start auth');
149
+ error(err.message);
150
+
151
+ // Fallback to key input
152
+ console.log();
153
+ info('Falling back to API key input...');
154
+ await loginWithKey();
155
+ }
156
+ }
157
+
158
+ /**
159
+ * Main login command handler
160
+ */
161
+ export async function loginCommand(options) {
162
+ // Check if already logged in
163
+ const existingKey = getApiKey();
164
+ if (existingKey) {
165
+ console.log();
166
+ info('You are already logged in');
167
+ console.log(chalk.dim(`API Key: ${existingKey.slice(0, 8)}...${existingKey.slice(-4)}`));
168
+ console.log();
169
+
170
+ const answer = await prompt('Do you want to re-login? (y/N): ');
171
+ if (answer.toLowerCase() !== 'y') {
172
+ return;
173
+ }
174
+ }
175
+
176
+ console.log();
177
+ console.log(chalk.bold('MeetScribe CLI Login'));
178
+ console.log();
179
+
180
+ if (options.key) {
181
+ await loginWithKey();
182
+ } else if (options.device) {
183
+ // Device flow - show code for manual entry
184
+ console.log();
185
+ info('Device flow not yet implemented. Using API key input...');
186
+ await loginWithKey();
187
+ } else {
188
+ // Default: browser OAuth
189
+ await loginWithBrowser();
190
+ }
191
+ }