/
twilio.ts
222 lines (211 loc) · 7.15 KB
/
twilio.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
import twilio from 'twilio';
import axios, { AxiosResponse } from 'axios';
import { S3Client, CompleteMultipartUploadCommandOutput, AbortMultipartUploadCommandOutput } from '@aws-sdk/client-s3';
import { Upload } from '@aws-sdk/lib-storage';
import {
TranscribeClient,
StartTranscriptionJobCommand,
StartTranscriptionJobCommandInput,
StartTranscriptionJobCommandOutput,
DeleteTranscriptionJobCommand,
DeleteTranscriptionJobCommandInput,
DeleteTranscriptionJobCommandOutput,
ListTranscriptionJobsCommand,
ListTranscriptionJobsCommandInput,
ListTranscriptionJobsCommandOutput,
} from '@aws-sdk/client-transcribe';
const twilioClient = twilio(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN);
const VoiceResponse = twilio.twiml.VoiceResponse;
export async function twilioCreateCall({
twimlString,
toPhoneNumber,
statusCallbackUrl = null,
}: {
twimlString: string;
toPhoneNumber: string;
statusCallbackUrl?: string;
}): Promise<any> {
const createCallObj = {
twiml: twimlString,
from: process.env.TWILIO_US_PHONE_NUMBER,
to: toPhoneNumber,
};
if (statusCallbackUrl) {
return twilioClient.calls.create({
...createCallObj,
statusCallback: statusCallbackUrl,
statusCallbackMethod: 'POST',
});
} else {
return twilioClient.calls.create(createCallObj);
}
}
export async function twilioSendSMS({ message, toPhoneNumber }: { message: string; toPhoneNumber: string }): Promise<any> {
return twilioClient.messages.create({
body: message,
from: process.env.TWILIO_US_PHONE_NUMBER,
to: toPhoneNumber,
});
}
export function gatherTwiml(actionUrl: string, src_user_display_name?: string, text?: string): string {
const twiml = new VoiceResponse();
// 番号をプッシュした時の受け取り先を指定
const gather = twiml.gather({
// 番号を押した時の受け取り先
action: actionUrl,
input: 'dtmf', // dtmf がいわゆる電話機の番号入植という意味 speech にしたら話している内容を文字に起こして入力される
finishOnKey: '#', // 入力終了のKey defaultは'#' 文字を空を指定したら全ての記号が乳力終了になる
method: 'POST',
timeout: 30, // 入力をうけつけてくれる秒数
numDigit: 1, // 相手からプッシュ操作を1桁待つ
});
const messageHead =
src_user_display_name && text
? `${src_user_display_name}さんから緊急のメッセージがきています!メッセージに反応してください!メッセージ内容は「${text}」です。`
: 'メッセージに反応してください!';
const message =
messageHead + '1を押したら電話をかけます。2を押したら要件の内容をメッセージに残してお伝えします。最後にシャープキーを押してください。';
gather.say(
{
language: 'ja-JP',
voice: 'woman',
},
message,
);
return twiml.toString();
}
export function dialTwiml({
toPhoneNumber,
dialCallbackUrl,
}: // referUrl,
{
toPhoneNumber: string;
dialCallbackUrl: string;
// referUrl: string;
}): string {
const twiml = new VoiceResponse();
// dialで電話を転送する
twiml.say(
{
language: 'ja-JP',
voice: 'woman',
},
'電話をかけます',
);
twiml.dial(
{
action: dialCallbackUrl,
method: 'POST',
// referUrl: referUrl,
// referMethod: 'POST',
},
toPhoneNumber,
);
return twiml.toString();
}
export function recordTwiml({
recordingStatusCallbackUrl,
transcribeCallbackUrl,
}: {
recordingStatusCallbackUrl: string;
transcribeCallbackUrl: string;
}): string {
const twiml = new VoiceResponse();
const timeoutSecond = 30;
// 録音するより前に言わせるにはrecordより前にsayの処理を書くようにする必要がある
twiml.say(
{
language: 'ja-JP',
voice: 'woman',
},
'ピーとなったら' + timeoutSecond.toString() + '秒で要件をお話しください',
);
twiml.record({
timeout: timeoutSecond,
playBeep: true,
transcribe: true,
recordingStatusCallbackMethod: 'POST',
recordingStatusCallback: recordingStatusCallbackUrl,
transcribeCallback: transcribeCallbackUrl,
});
return twiml.toString();
}
export async function downloadRecordingFileStream(recordingUrl: string): Promise<AxiosResponse<any, any>> {
return axios.get(recordingUrl, {
responseType: 'stream',
auth: {
username: process.env.TWILIO_ACCOUNT_SID,
password: process.env.TWILIO_AUTH_TOKEN,
},
});
}
export async function uploadToS3RecordingFileStream(
uploadKey: string,
streamData: any,
): Promise<CompleteMultipartUploadCommandOutput | AbortMultipartUploadCommandOutput> {
const s3Client = new S3Client({ region: process.env.AWS_REGION });
const upload = new Upload({
client: s3Client,
params: {
Bucket: process.env.S3_BUCKERT_NAME,
Key: uploadKey,
Body: streamData,
},
});
/*
upload.on('httpUploadProgress', (progress) => {
console.log(progress)
})
*/
return upload.done();
}
export async function transcribeRecordFile({
jobName,
inputKey,
outputKey,
languageCode = 'ja-JP',
mediaFormat = 'wav',
}: {
jobName: string;
inputKey: string;
outputKey: string;
languageCode?: string;
mediaFormat?: string;
}): Promise<StartTranscriptionJobCommandOutput> {
const transcribeClient = new TranscribeClient({ region: process.env.AWS_REGION });
// JobがダブルとStartさせる時にエラーになるのでダブりをチェックして、Jobがあったら消す
const jobList = await loadListTranscribeJobs({ containJobName: jobName });
if (jobList.TranscriptionJobSummaries.length > 0) {
const deleteTranscribePromises = [];
for (const summary of jobList.TranscriptionJobSummaries) {
deleteTranscribePromises.push(deleteTranscribeJob({ jobName: summary.TranscriptionJobName }));
}
await Promise.all(deleteTranscribePromises);
}
const params: StartTranscriptionJobCommandInput = {
TranscriptionJobName: jobName,
LanguageCode: languageCode,
MediaFormat: mediaFormat,
Media: { MediaFileUri: `s3://${process.env.S3_BUCKERT_NAME}/${inputKey}` },
OutputBucketName: process.env.S3_BUCKERT_NAME,
OutputKey: outputKey,
};
const command = new StartTranscriptionJobCommand(params);
return transcribeClient.send(command);
}
export async function deleteTranscribeJob({ jobName }: { jobName: string }): Promise<DeleteTranscriptionJobCommandOutput> {
const transcribeClient = new TranscribeClient({ region: process.env.AWS_REGION });
const params: DeleteTranscriptionJobCommandInput = {
TranscriptionJobName: jobName,
};
const command = new DeleteTranscriptionJobCommand(params);
return transcribeClient.send(command);
}
export async function loadListTranscribeJobs({ containJobName }: { containJobName: string }): Promise<ListTranscriptionJobsCommandOutput> {
const transcribeClient = new TranscribeClient({ region: process.env.AWS_REGION });
const params: ListTranscriptionJobsCommandInput = {
JobNameContains: containJobName,
};
const command = new ListTranscriptionJobsCommand(params);
return transcribeClient.send(command);
}