whisperai-sdk 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 +163 -0
- package/dist/client.d.ts +35 -0
- package/dist/constant.d.ts +9 -0
- package/dist/errors.d.ts +18 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +203 -0
- package/dist/types.d.ts +218 -0
- package/package.json +71 -0
package/README.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# whisperai-sdk
|
|
2
|
+
|
|
3
|
+
Unofficial TypeScript SDK for [WhisperAI](https://whisperai.com/). This package provides methods and interfaces for interacting with the WhisperAI service without external runtime dependencies (except axios).
|
|
4
|
+
|
|
5
|
+
**Disclaimer:** This is an unofficial implementation and is not affiliated with WhisperAI.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install whisperai-sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### Initialization
|
|
16
|
+
|
|
17
|
+
Initialize the client with your WhisperAI credentials.
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { WhisperClient } from 'whisperai-sdk';
|
|
21
|
+
|
|
22
|
+
const client = new WhisperClient({
|
|
23
|
+
login: {
|
|
24
|
+
email: "your-email@example.com",
|
|
25
|
+
password: "your-password"
|
|
26
|
+
},
|
|
27
|
+
// Optional: Override default settings
|
|
28
|
+
// whisperUrl: "https://whisperai.com",
|
|
29
|
+
// chunkSize: 8 * 1024 * 1024 // 8MB
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The client handles authentication automatically. It will log in on the first request and refresh the session if the token expires.
|
|
34
|
+
|
|
35
|
+
### Methods
|
|
36
|
+
|
|
37
|
+
#### User & Account
|
|
38
|
+
|
|
39
|
+
Get current user information, usage statistics, and subscription details.
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
// Get user info
|
|
43
|
+
const userInfo = await client.user();
|
|
44
|
+
console.log(`User: ${userInfo.firstName} ${userInfo.lastName}`);
|
|
45
|
+
|
|
46
|
+
// Get usage stats
|
|
47
|
+
const usage = await client.usage();
|
|
48
|
+
console.log(`Monthly Usage: ${usage.monthlyUsageMinutes} minutes`);
|
|
49
|
+
|
|
50
|
+
// Get subscription details
|
|
51
|
+
const subscription = await client.subscriptionDetails();
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
#### Uploading Audio
|
|
55
|
+
|
|
56
|
+
Upload audio files for transcription. The `upload` method handles file chunking automatically.
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import fs from 'fs';
|
|
60
|
+
|
|
61
|
+
// Read file buffer
|
|
62
|
+
const buffer = fs.readFileSync('./interview.mp3');
|
|
63
|
+
|
|
64
|
+
// Upload
|
|
65
|
+
const result = await client.upload(buffer, {
|
|
66
|
+
filename: 'interview.mp3',
|
|
67
|
+
durationSeconds: 120, // Total duration in seconds
|
|
68
|
+
mimeType: 'audio/mpeg', // Optional
|
|
69
|
+
title: 'Interview with John Doe', // Optional
|
|
70
|
+
enableSpeakerDetection: true, // Optional
|
|
71
|
+
speakerCount: 'auto' // Optional: 'auto' or number
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
console.log(`Uploaded recording ID: ${result.id}`);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
#### Transcription
|
|
78
|
+
|
|
79
|
+
Manage transcriptions for uploaded recordings.
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
const recordingId = 12345;
|
|
83
|
+
|
|
84
|
+
// Start/Request transcription
|
|
85
|
+
const transcriptionJob = await client.transcription(recordingId);
|
|
86
|
+
|
|
87
|
+
// Check recording status and get transcription result
|
|
88
|
+
const recording = await client.recording(recordingId);
|
|
89
|
+
|
|
90
|
+
if (recording.status === 'completed' && recording.transcription) {
|
|
91
|
+
console.log(recording.transcription.content);
|
|
92
|
+
|
|
93
|
+
// Access segments with timestamps
|
|
94
|
+
recording.transcription.segments.forEach(segment => {
|
|
95
|
+
console.log(`[${segment.start} - ${segment.end}]: ${segment.text}`);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
#### Translation
|
|
101
|
+
|
|
102
|
+
Translate a recording to another language.
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
const recordingId = 12345;
|
|
106
|
+
|
|
107
|
+
// Translate to Spanish
|
|
108
|
+
const translation = await client.translate(recordingId, 'es');
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
#### Recordings Management
|
|
112
|
+
|
|
113
|
+
List and retrieve recordings.
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
// Get a specific recording by ID
|
|
117
|
+
const recording = await client.recording(recordingId);
|
|
118
|
+
|
|
119
|
+
// List recordings (paginated)
|
|
120
|
+
const recordingsList = await client.recordings({
|
|
121
|
+
limit: 10,
|
|
122
|
+
page: 1,
|
|
123
|
+
// search: "interview", // Optional search query
|
|
124
|
+
// status: "completed" // Optional status filter
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
console.log(`Found ${recordingsList.meta.totalItems} recordings`);
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### Analytics
|
|
131
|
+
|
|
132
|
+
Get a summary of your activity.
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
const summary = await client.summary();
|
|
136
|
+
console.log(`Total recordings: ${summary.recordings.total}`);
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Error Handling
|
|
140
|
+
|
|
141
|
+
The SDK throws specific errors for different failure scenarios.
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
import { WhisperAuthError, WhisperNetworkError, WhisperApiError } from 'whisperai-sdk/errors';
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
await client.user();
|
|
148
|
+
} catch (error) {
|
|
149
|
+
if (error instanceof WhisperAuthError) {
|
|
150
|
+
console.error("Authentication failed. Check credentials.");
|
|
151
|
+
} else if (error instanceof WhisperNetworkError) {
|
|
152
|
+
console.error("Network issue.");
|
|
153
|
+
} else if (error instanceof WhisperApiError) {
|
|
154
|
+
console.error(`API Error ${error.status}: ${JSON.stringify(error.data)}`);
|
|
155
|
+
} else {
|
|
156
|
+
console.error("Unknown error:", error);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## License
|
|
162
|
+
|
|
163
|
+
MIT
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { ClientOptions, UserInfo, UsageInfo, InitMetaFile, InitChunkResponse, UploadChunkResponse, FinalizeChunkResponse, TranscriptionResponse, TranslateResponse, SummaryResponse, RecordingResponse, RecordingsQuery, RecordingsResponse, SubscriptionDetailsResponse } from "./types.js";
|
|
2
|
+
export declare class WhisperClient {
|
|
3
|
+
private cookies?;
|
|
4
|
+
private readonly clientOptions;
|
|
5
|
+
constructor(clientOptions: ClientOptions);
|
|
6
|
+
login(): Promise<UserInfo>;
|
|
7
|
+
user(): Promise<UserInfo>;
|
|
8
|
+
usage(): Promise<UsageInfo>;
|
|
9
|
+
subscriptionDetails(): Promise<SubscriptionDetailsResponse>;
|
|
10
|
+
upload(fileBuffer: Uint8Array, meta: InitMetaFile): Promise<FinalizeChunkResponse>;
|
|
11
|
+
initChunk(fileBuffer: Uint8Array, meta: InitMetaFile): Promise<InitChunkResponse>;
|
|
12
|
+
uploadChunk(fileBuffer: Uint8Array, recordingId: number, chunkIndex: number): Promise<UploadChunkResponse>;
|
|
13
|
+
finalizeChunk(recordingId: number): Promise<FinalizeChunkResponse>;
|
|
14
|
+
transcription(recordingId: number): Promise<TranscriptionResponse>;
|
|
15
|
+
translate(recordingId: number, language: string): Promise<TranslateResponse>;
|
|
16
|
+
recording(recordingId: number): Promise<RecordingResponse>;
|
|
17
|
+
recordings(query?: RecordingsQuery): Promise<RecordingsResponse>;
|
|
18
|
+
summary(): Promise<SummaryResponse>;
|
|
19
|
+
private get loginLink();
|
|
20
|
+
private get userLink();
|
|
21
|
+
private get usageLink();
|
|
22
|
+
private get subscriptionDetailsLink();
|
|
23
|
+
private get initChunkLink();
|
|
24
|
+
private get uploadChunkLink();
|
|
25
|
+
private get finalizeChunkLink();
|
|
26
|
+
private get transcriptionLink();
|
|
27
|
+
private get summaryLink();
|
|
28
|
+
private translateLink;
|
|
29
|
+
private recordingLink;
|
|
30
|
+
private get recordingsLink();
|
|
31
|
+
private getCountChunks;
|
|
32
|
+
private get requestOptions();
|
|
33
|
+
private recall;
|
|
34
|
+
private handleRequest;
|
|
35
|
+
}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare abstract class WhisperError extends Error {
|
|
2
|
+
abstract readonly code: string;
|
|
3
|
+
protected constructor(message: string);
|
|
4
|
+
}
|
|
5
|
+
export declare class WhisperApiError extends WhisperError {
|
|
6
|
+
readonly status: number;
|
|
7
|
+
readonly response: unknown;
|
|
8
|
+
readonly code = "API_ERROR";
|
|
9
|
+
constructor(status: number, response: unknown);
|
|
10
|
+
}
|
|
11
|
+
export declare class WhisperAuthError extends WhisperError {
|
|
12
|
+
readonly code = "AUTH_ERROR";
|
|
13
|
+
constructor();
|
|
14
|
+
}
|
|
15
|
+
export declare class WhisperNetworkError extends WhisperError {
|
|
16
|
+
readonly code = "NETWORK_ERROR";
|
|
17
|
+
constructor(cause?: unknown);
|
|
18
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
// src/client.ts
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
|
|
4
|
+
// src/errors.ts
|
|
5
|
+
class WhisperError extends Error {
|
|
6
|
+
constructor(message) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = new.target.name;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
class WhisperApiError extends WhisperError {
|
|
13
|
+
status;
|
|
14
|
+
response;
|
|
15
|
+
code = "API_ERROR";
|
|
16
|
+
constructor(status, response) {
|
|
17
|
+
super(`Whisper API error (${status})`);
|
|
18
|
+
this.status = status;
|
|
19
|
+
this.response = response;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
class WhisperAuthError extends WhisperError {
|
|
24
|
+
code = "AUTH_ERROR";
|
|
25
|
+
constructor() {
|
|
26
|
+
super("Authentication failed");
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
class WhisperNetworkError extends WhisperError {
|
|
31
|
+
code = "NETWORK_ERROR";
|
|
32
|
+
constructor(cause) {
|
|
33
|
+
super("Network error");
|
|
34
|
+
this.cause = cause;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/client.ts
|
|
39
|
+
class WhisperClient {
|
|
40
|
+
cookies;
|
|
41
|
+
clientOptions;
|
|
42
|
+
constructor(clientOptions) {
|
|
43
|
+
this.clientOptions = {
|
|
44
|
+
whisperUrl: "https://whisperai.com",
|
|
45
|
+
chunkSize: 8 * 1024 * 1024,
|
|
46
|
+
...clientOptions
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
login() {
|
|
50
|
+
return this.handleRequest(axios.post(this.loginLink, this.clientOptions.login));
|
|
51
|
+
}
|
|
52
|
+
user() {
|
|
53
|
+
return this.recall(() => axios.get(this.userLink, this.requestOptions));
|
|
54
|
+
}
|
|
55
|
+
usage() {
|
|
56
|
+
return this.recall(() => axios.get(this.usageLink, this.requestOptions));
|
|
57
|
+
}
|
|
58
|
+
subscriptionDetails() {
|
|
59
|
+
return this.recall(() => axios.get(this.subscriptionDetailsLink, this.requestOptions));
|
|
60
|
+
}
|
|
61
|
+
upload(fileBuffer, meta) {
|
|
62
|
+
const totalChunks = this.getCountChunks(fileBuffer.length);
|
|
63
|
+
return this.initChunk(fileBuffer, meta).then((response) => Promise.all(Array.from({ length: totalChunks }, (_, i) => this.uploadChunk(fileBuffer, response.recordingId, i))).then(() => this.finalizeChunk(response.recordingId)));
|
|
64
|
+
}
|
|
65
|
+
initChunk(fileBuffer, meta) {
|
|
66
|
+
return this.recall(() => axios.post(this.initChunkLink, {
|
|
67
|
+
filename: meta.filename,
|
|
68
|
+
durationSeconds: meta.durationSeconds,
|
|
69
|
+
totalSize: fileBuffer.length,
|
|
70
|
+
mimeType: meta.mimeType ?? "",
|
|
71
|
+
title: meta.title ?? meta.filename,
|
|
72
|
+
enableSpeakerDetection: meta.enableSpeakerDetection ?? false,
|
|
73
|
+
speakerCount: meta.speakerCount ?? "auto",
|
|
74
|
+
language: meta.language ?? "",
|
|
75
|
+
totalChunks: this.getCountChunks(fileBuffer.length)
|
|
76
|
+
}, this.requestOptions));
|
|
77
|
+
}
|
|
78
|
+
uploadChunk(fileBuffer, recordingId, chunkIndex) {
|
|
79
|
+
const start = chunkIndex * this.clientOptions.chunkSize;
|
|
80
|
+
const end = Math.min(start + this.clientOptions.chunkSize, fileBuffer.length);
|
|
81
|
+
const chunk = fileBuffer.slice(start, end);
|
|
82
|
+
const blob = new Blob([chunk], { type: "application/octet-stream" });
|
|
83
|
+
const formData = new FormData;
|
|
84
|
+
formData.append("chunk", blob, `chunk_${chunkIndex}`);
|
|
85
|
+
formData.append("recordingId", recordingId.toString());
|
|
86
|
+
formData.append("chunkIndex", chunkIndex.toString());
|
|
87
|
+
return this.recall(() => axios.post(this.uploadChunkLink, formData, this.requestOptions));
|
|
88
|
+
}
|
|
89
|
+
finalizeChunk(recordingId) {
|
|
90
|
+
return this.recall(() => axios.post(this.finalizeChunkLink, { recordingId }, this.requestOptions));
|
|
91
|
+
}
|
|
92
|
+
transcription(recordingId) {
|
|
93
|
+
return this.recall(() => axios.post(this.transcriptionLink, { recordingId }, this.requestOptions));
|
|
94
|
+
}
|
|
95
|
+
translate(recordingId, language) {
|
|
96
|
+
return this.recall(() => axios.post(this.translateLink(recordingId), { targetLanguage: language }, this.requestOptions));
|
|
97
|
+
}
|
|
98
|
+
recording(recordingId) {
|
|
99
|
+
return this.recall(() => axios.get(this.recordingLink(recordingId), this.requestOptions));
|
|
100
|
+
}
|
|
101
|
+
recordings(query) {
|
|
102
|
+
return this.recall(() => axios.get(this.recordingsLink, {
|
|
103
|
+
...this.requestOptions,
|
|
104
|
+
params: { page: 1, limit: 5, ...query ?? {} }
|
|
105
|
+
}));
|
|
106
|
+
}
|
|
107
|
+
summary() {
|
|
108
|
+
return this.recall(() => axios.get(this.summaryLink, this.requestOptions));
|
|
109
|
+
}
|
|
110
|
+
get loginLink() {
|
|
111
|
+
return `${this.clientOptions.whisperUrl}/api/login`;
|
|
112
|
+
}
|
|
113
|
+
get userLink() {
|
|
114
|
+
return `${this.clientOptions.whisperUrl}/api/user`;
|
|
115
|
+
}
|
|
116
|
+
get usageLink() {
|
|
117
|
+
return `${this.clientOptions.whisperUrl}/api/usage`;
|
|
118
|
+
}
|
|
119
|
+
get subscriptionDetailsLink() {
|
|
120
|
+
return `${this.clientOptions.whisperUrl}/api/subscription-details`;
|
|
121
|
+
}
|
|
122
|
+
get initChunkLink() {
|
|
123
|
+
return `${this.clientOptions.whisperUrl}/api/v2/recordings/chunked/init`;
|
|
124
|
+
}
|
|
125
|
+
get uploadChunkLink() {
|
|
126
|
+
return `${this.clientOptions.whisperUrl}/api/v2/recordings/chunked/upload`;
|
|
127
|
+
}
|
|
128
|
+
get finalizeChunkLink() {
|
|
129
|
+
return `${this.clientOptions.whisperUrl}/api/v2/recordings/chunked/finalize`;
|
|
130
|
+
}
|
|
131
|
+
get transcriptionLink() {
|
|
132
|
+
return `${this.clientOptions.whisperUrl}/api/v2/transcription`;
|
|
133
|
+
}
|
|
134
|
+
get summaryLink() {
|
|
135
|
+
return `${this.clientOptions.whisperUrl}/api/analytics/summary`;
|
|
136
|
+
}
|
|
137
|
+
translateLink(recordingId) {
|
|
138
|
+
return `${this.clientOptions.whisperUrl}/api/v2/translation/${recordingId}/translate`;
|
|
139
|
+
}
|
|
140
|
+
recordingLink(recordingId) {
|
|
141
|
+
return `${this.clientOptions.whisperUrl}/api/recordings/${recordingId}`;
|
|
142
|
+
}
|
|
143
|
+
get recordingsLink() {
|
|
144
|
+
return `${this.clientOptions.whisperUrl}/api/recordings-paginated`;
|
|
145
|
+
}
|
|
146
|
+
getCountChunks(size) {
|
|
147
|
+
return Math.ceil(size / this.clientOptions.chunkSize);
|
|
148
|
+
}
|
|
149
|
+
get requestOptions() {
|
|
150
|
+
return {
|
|
151
|
+
headers: {
|
|
152
|
+
Cookie: this.cookies
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
async recall(call) {
|
|
157
|
+
try {
|
|
158
|
+
if (typeof this.cookies !== "string")
|
|
159
|
+
await this.login();
|
|
160
|
+
return await this.handleRequest(call());
|
|
161
|
+
} catch (error) {
|
|
162
|
+
if (error.code !== "AUTH_ERROR") {
|
|
163
|
+
throw error;
|
|
164
|
+
}
|
|
165
|
+
await this.login();
|
|
166
|
+
return this.handleRequest(call());
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
async handleRequest(request) {
|
|
170
|
+
try {
|
|
171
|
+
const response = await request;
|
|
172
|
+
this.cookies = (response.headers["set-cookie"] ?? []).join("; ");
|
|
173
|
+
return response.data;
|
|
174
|
+
} catch (err) {
|
|
175
|
+
console.log("err", err);
|
|
176
|
+
if (axios.isAxiosError(err)) {
|
|
177
|
+
if (!err.response) {
|
|
178
|
+
throw new WhisperNetworkError(err);
|
|
179
|
+
}
|
|
180
|
+
if (err.response.status === 401) {
|
|
181
|
+
throw new WhisperAuthError;
|
|
182
|
+
}
|
|
183
|
+
throw new WhisperApiError(err.response.status, err.response.data);
|
|
184
|
+
}
|
|
185
|
+
throw err;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// src/constant.ts
|
|
190
|
+
var WhisperStatus;
|
|
191
|
+
((WhisperStatus2) => {
|
|
192
|
+
WhisperStatus2["PENDING"] = "pending";
|
|
193
|
+
WhisperStatus2["VALIDATING"] = "validating";
|
|
194
|
+
WhisperStatus2["UPLOADING"] = "uploading";
|
|
195
|
+
WhisperStatus2["PROCESSING"] = "processing";
|
|
196
|
+
WhisperStatus2["COMPLETED"] = "completed";
|
|
197
|
+
WhisperStatus2["FAILED"] = "failed";
|
|
198
|
+
WhisperStatus2["CANCELLED"] = "cancelled";
|
|
199
|
+
})(WhisperStatus ||= {});
|
|
200
|
+
export {
|
|
201
|
+
WhisperStatus,
|
|
202
|
+
WhisperClient
|
|
203
|
+
};
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { WhisperStatus } from "./constant.js";
|
|
2
|
+
export interface ClientOptions {
|
|
3
|
+
login: {
|
|
4
|
+
email: string;
|
|
5
|
+
password: string;
|
|
6
|
+
};
|
|
7
|
+
chunkSize?: number;
|
|
8
|
+
whisperUrl?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface RequestError {
|
|
11
|
+
message: string;
|
|
12
|
+
path: string;
|
|
13
|
+
}
|
|
14
|
+
export interface UserInfo {
|
|
15
|
+
id: number;
|
|
16
|
+
username: string | null;
|
|
17
|
+
email: string;
|
|
18
|
+
firstName: string;
|
|
19
|
+
lastName: string;
|
|
20
|
+
profileImageUrl: string | null;
|
|
21
|
+
subscriptionTier: "free" | "premium";
|
|
22
|
+
stripeSubscriptionId: string | null;
|
|
23
|
+
stripeCustomerId: string | null;
|
|
24
|
+
trialStartDate: string | null;
|
|
25
|
+
trialEndDate: string | null;
|
|
26
|
+
hasUsedTrial: boolean;
|
|
27
|
+
monthlyUsageMinutes: number;
|
|
28
|
+
usageResetDate: string;
|
|
29
|
+
deletedMinutesThisCycle: number;
|
|
30
|
+
subscriptionStatus: "past_due" | "active";
|
|
31
|
+
subscriptionEndDate: string | null;
|
|
32
|
+
cancellationOffered: boolean;
|
|
33
|
+
unsubscribed: boolean;
|
|
34
|
+
hearAboutUs: string | null;
|
|
35
|
+
industry: "Healthcare & Medical" | "Legal & Compliance" | "Education & Research" | "Media & Entertainment" | "Technology & Software" | "Consulting & Professional Services" | "Financial Services (Banking, Insurance, Accounting)" | "Government & Nonprofit" | "Sales & Marketing / Advertising" | "Real Estate & Construction" | "Manufacturing & Engineering" | "Human Resources & Recruiting" | "Customer Support / Call Centers" | "Student" | string;
|
|
36
|
+
totalMinutes: number;
|
|
37
|
+
recordingsCount: number;
|
|
38
|
+
subscriptionPausedUntil: string | null;
|
|
39
|
+
subscriptionPauseStarts: string | null;
|
|
40
|
+
subscriptionOriginalTier: string | null;
|
|
41
|
+
discountCodeApplied: string | null;
|
|
42
|
+
retentionOfferShown: string | null;
|
|
43
|
+
billingFrequency: "monthly" | "weekly";
|
|
44
|
+
hasSeenTutorial: boolean;
|
|
45
|
+
lastLoginAt: string | null;
|
|
46
|
+
createdAt: string;
|
|
47
|
+
updatedAt: string;
|
|
48
|
+
}
|
|
49
|
+
export interface UsageInfo {
|
|
50
|
+
monthlyUsageMinutes: number;
|
|
51
|
+
subscriptionTier: "free" | "premium";
|
|
52
|
+
limits: {
|
|
53
|
+
monthlyMinutes: number;
|
|
54
|
+
dailyMinutes: number;
|
|
55
|
+
maxFileSize: number;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export interface InitMetaFile {
|
|
59
|
+
filename: string;
|
|
60
|
+
durationSeconds: number;
|
|
61
|
+
title?: string;
|
|
62
|
+
mimeType?: string;
|
|
63
|
+
totalSize?: number;
|
|
64
|
+
language?: number;
|
|
65
|
+
enableSpeakerDetection?: boolean;
|
|
66
|
+
speakerCount?: "auto" | number;
|
|
67
|
+
}
|
|
68
|
+
export interface InitChunkResponse {
|
|
69
|
+
sessionId: string;
|
|
70
|
+
recordingId: number;
|
|
71
|
+
}
|
|
72
|
+
export interface UploadChunkResponse {
|
|
73
|
+
success: boolean;
|
|
74
|
+
chunkIndex: number;
|
|
75
|
+
uploadedChunks: number;
|
|
76
|
+
totalChunks: number;
|
|
77
|
+
}
|
|
78
|
+
export interface FinalizeChunkResponse {
|
|
79
|
+
id: number;
|
|
80
|
+
userId: number;
|
|
81
|
+
title: string;
|
|
82
|
+
originalFilename: string;
|
|
83
|
+
fileExtension: string;
|
|
84
|
+
mimeType: string;
|
|
85
|
+
audioUrl: string;
|
|
86
|
+
duration: number;
|
|
87
|
+
language: string;
|
|
88
|
+
status: WhisperStatus;
|
|
89
|
+
speakerDetectionEnabled: boolean;
|
|
90
|
+
speakerCount: number | null;
|
|
91
|
+
totalChunks: number;
|
|
92
|
+
metadata: Record<string, unknown> | null;
|
|
93
|
+
idempotencyKey: string | null;
|
|
94
|
+
uploadSessionId: string;
|
|
95
|
+
createdAt: string;
|
|
96
|
+
updatedAt: string;
|
|
97
|
+
}
|
|
98
|
+
export interface TranscriptionResponse {
|
|
99
|
+
id: number;
|
|
100
|
+
recordingId: number;
|
|
101
|
+
status: "queued" | "processing" | "completed" | "failed" | "canceled";
|
|
102
|
+
createdAt: string;
|
|
103
|
+
updatedAt: string;
|
|
104
|
+
}
|
|
105
|
+
export interface TranslateResponse {
|
|
106
|
+
success: true;
|
|
107
|
+
message: string;
|
|
108
|
+
translation: {
|
|
109
|
+
id: number;
|
|
110
|
+
transcriptionId: number;
|
|
111
|
+
targetLanguage: string;
|
|
112
|
+
content: string;
|
|
113
|
+
status: string;
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
export interface SummaryResponse {
|
|
117
|
+
usage: {
|
|
118
|
+
monthlyMinutes: number;
|
|
119
|
+
monthlyLimit: number;
|
|
120
|
+
percentage: number;
|
|
121
|
+
};
|
|
122
|
+
recordings: {
|
|
123
|
+
total: number;
|
|
124
|
+
thisMonth: number;
|
|
125
|
+
totalMinutes: number;
|
|
126
|
+
averageDuration: number;
|
|
127
|
+
};
|
|
128
|
+
activity: {
|
|
129
|
+
dailyCounts: Record<string, number>;
|
|
130
|
+
mostActiveDay: string;
|
|
131
|
+
currentStreak: number;
|
|
132
|
+
};
|
|
133
|
+
insights: {
|
|
134
|
+
shouldUpgrade: boolean;
|
|
135
|
+
suggestedTier: string;
|
|
136
|
+
upgradeReason: string;
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
export interface RecordingResponse {
|
|
140
|
+
id: number;
|
|
141
|
+
userId: number;
|
|
142
|
+
title: string;
|
|
143
|
+
originalFilename: string;
|
|
144
|
+
fileExtension: string;
|
|
145
|
+
mimeType: string;
|
|
146
|
+
audioUrl: string;
|
|
147
|
+
duration: number;
|
|
148
|
+
language: string;
|
|
149
|
+
status: string;
|
|
150
|
+
speakerDetectionEnabled: boolean;
|
|
151
|
+
speakerCount: number | null;
|
|
152
|
+
totalChunks: number;
|
|
153
|
+
metadata: Record<string, unknown> | null;
|
|
154
|
+
idempotencyKey: string | null;
|
|
155
|
+
uploadSessionId: string;
|
|
156
|
+
accessToken: string;
|
|
157
|
+
accessTokenExpiry: string;
|
|
158
|
+
createdAt: string;
|
|
159
|
+
updatedAt: string;
|
|
160
|
+
transcription: {
|
|
161
|
+
id: number;
|
|
162
|
+
userId: number;
|
|
163
|
+
recordingId: number;
|
|
164
|
+
content: string;
|
|
165
|
+
editedContent: string | null;
|
|
166
|
+
confidence: number;
|
|
167
|
+
segments: Array<{
|
|
168
|
+
id: number;
|
|
169
|
+
start: number;
|
|
170
|
+
end: number;
|
|
171
|
+
text: string;
|
|
172
|
+
}>;
|
|
173
|
+
translations: Array<{
|
|
174
|
+
id: number;
|
|
175
|
+
transcriptionId: number;
|
|
176
|
+
targetLanguage: string;
|
|
177
|
+
content: string;
|
|
178
|
+
status: string;
|
|
179
|
+
createdAt: string;
|
|
180
|
+
}>;
|
|
181
|
+
timestamps: {
|
|
182
|
+
words: unknown[];
|
|
183
|
+
duration: number;
|
|
184
|
+
language: string;
|
|
185
|
+
segments: Array<{
|
|
186
|
+
id: number;
|
|
187
|
+
start: number;
|
|
188
|
+
end: number;
|
|
189
|
+
text: string;
|
|
190
|
+
}>;
|
|
191
|
+
};
|
|
192
|
+
speakers: unknown | null;
|
|
193
|
+
speakerNames: Record<string, unknown>;
|
|
194
|
+
createdAt: string;
|
|
195
|
+
updatedAt: string;
|
|
196
|
+
summary: unknown | null;
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
export interface RecordingsQuery {
|
|
200
|
+
page?: number;
|
|
201
|
+
limit?: number;
|
|
202
|
+
}
|
|
203
|
+
export interface RecordingsResponse {
|
|
204
|
+
data: RecordingResponse[];
|
|
205
|
+
total: string;
|
|
206
|
+
page: number;
|
|
207
|
+
limit: number;
|
|
208
|
+
pages: number;
|
|
209
|
+
hasNext: boolean;
|
|
210
|
+
hasPrev: boolean;
|
|
211
|
+
}
|
|
212
|
+
export interface SubscriptionDetailsResponse {
|
|
213
|
+
isPaidPlan: boolean;
|
|
214
|
+
isTrialActive: boolean;
|
|
215
|
+
nextBillingDate: string | null;
|
|
216
|
+
billingAmount: number | null;
|
|
217
|
+
subscriptionStatus: string;
|
|
218
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "whisperai-sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "TypeScript SDK for WhisperAI: methods and interfaces for interacting with the service without external runtime dependencies.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"whisper",
|
|
7
|
+
"speech-to-text",
|
|
8
|
+
"transcription",
|
|
9
|
+
"typescript",
|
|
10
|
+
"sdk"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://whisperai.com/",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/iHaiduk/whisperai/issues"
|
|
15
|
+
},
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/iHaiduk/whisperai.git"
|
|
19
|
+
},
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"author": "Igor Haiduk",
|
|
22
|
+
"type": "module",
|
|
23
|
+
"exports": {
|
|
24
|
+
".": {
|
|
25
|
+
"types": "./dist/index.d.ts",
|
|
26
|
+
"import": "./dist/index.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"main": "./dist/index.js",
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"files": [
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "npm run clean && bun build ./src/index.ts --outdir ./dist --target=node --format=esm --external axios && tsc --emitDeclarationOnly",
|
|
36
|
+
"format": "prettier --write \"src/**/*.ts\"",
|
|
37
|
+
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
|
|
38
|
+
"clean": "rm -rf dist",
|
|
39
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
40
|
+
"release": "semantic-release"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"axios": "^1.13.2"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@commitlint/cli": "20.2.0",
|
|
47
|
+
"@commitlint/config-conventional": "20.2.0",
|
|
48
|
+
"@eslint/js": "9.39.2",
|
|
49
|
+
"@semantic-release/changelog": "6.0.3",
|
|
50
|
+
"@semantic-release/exec": "7.1.0",
|
|
51
|
+
"@semantic-release/git": "10.0.1",
|
|
52
|
+
"@semantic-release/github": "12.0.2",
|
|
53
|
+
"@semantic-release/npm": "13.1.3",
|
|
54
|
+
"@types/bun": "^1.3.5",
|
|
55
|
+
"@types/node": "25.0.3",
|
|
56
|
+
"@typescript-eslint/eslint-plugin": "8.50.1",
|
|
57
|
+
"@typescript-eslint/parser": "8.50.1",
|
|
58
|
+
"conventional-changelog-conventionalcommits": "9.1.0",
|
|
59
|
+
"eslint": "9.39.2",
|
|
60
|
+
"eslint-config-prettier": "10.1.8",
|
|
61
|
+
"eslint-plugin-prettier": "5.5.4",
|
|
62
|
+
"prettier": "3.7.4",
|
|
63
|
+
"semantic-release": "25.0.2",
|
|
64
|
+
"typescript": "5.9.3",
|
|
65
|
+
"typescript-eslint": "8.50.1"
|
|
66
|
+
},
|
|
67
|
+
"engines": {
|
|
68
|
+
"node": ">=22.0.0"
|
|
69
|
+
},
|
|
70
|
+
"module": "./dist/index.js"
|
|
71
|
+
}
|