test: vonage 语音

dev/voice
Lei OT 5 months ago
parent 229605a81a
commit c6024d0ab1

@ -12,25 +12,25 @@
"dependencies": { "dependencies": {
"@dckj/react-better-modal": "^0.1.2", "@dckj/react-better-modal": "^0.1.2",
"@lexical/react": "^0.20.0", "@lexical/react": "^0.20.0",
"@vonage/client-sdk": "^1.7.2", "@vonage/client-sdk": "^2.0.0",
"antd": "^5.22.2", "antd": "^5.22.2",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"dingtalk-jsapi": "^3.0.41", "dingtalk-jsapi": "^3.0.41",
"emoji-picker-react": "^4.12.0", "emoji-picker-react": "^4.12.0",
"lexical": "^0.20.0", "lexical": "^0.20.0",
"react": "^18.3.1", "react": "^18.3.1",
"react-chat-elements": "^12.0.17",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"react-router-dom": "^6.28.0", "react-router-dom": "^6.28.0",
"zustand": "^4.5.5",
"react-chat-elements": "^12.0.17",
"rxjs": "^7.8.1", "rxjs": "^7.8.1",
"uuid": "^9.0.1" "uuid": "^9.0.1",
"zustand": "^4.5.5"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^18.3.12", "@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1", "@types/react-dom": "^18.3.1",
"@vitejs/plugin-react": "^4.3.3", "@vitejs/plugin-react": "^4.3.3",
"@vonage/client-sdk": "^1.7.2", "@vonage/client-sdk": "^2.0.0",
"autoprefixer": "^10.4.20", "autoprefixer": "^10.4.20",
"eslint": "^8.45.0", "eslint": "^8.45.0",
"eslint-plugin-react": "^7.37.2", "eslint-plugin-react": "^7.37.2",

@ -6,7 +6,10 @@ import { VONAGE_URL, DATETIME_FORMAT } from "@/config";
import dayjs from "dayjs"; import dayjs from "dayjs";
const callCenterStore = create((set, get) => ({ const callCenterStore = create((set, get) => ({
client: new VonageClient({ apiUrl: "https://api-ap-3.vonage.com", websocketUrl: "wss://ws-ap-3.vonage.com" }), client: new VonageClient({
// region: "AP",
// apiUrl: "https://api-ap-3.vonage.com", websocketUrl: "wss://ws-ap-3.vonage.com"
}),
call_id: 0, call_id: 0,
loading: false, loading: false,
logs: "", logs: "",
@ -18,8 +21,9 @@ const callCenterStore = create((set, get) => ({
const fetchUrl = prepareUrl(VONAGE_URL + "/jwt") const fetchUrl = prepareUrl(VONAGE_URL + "/jwt")
.append("user_id", user_id) .append("user_id", user_id)
.build(); .build();
return fetchJSON(fetchUrl).then(json => { return fetchJSON(fetchUrl).then(res => {
if (json.status === 200) { const json = res.result;
if (json?.status === 200) {
let jwt = json.token; let jwt = json.token;
client client

@ -1 +1,25 @@
vonage的服务端用于生成jwt和应答语音视频请求 vonage的服务端用于生成jwt和应答语音视频请求
```sh
> vonage users create --display-name Highlights
✅ Creating User
User ID: USR-a778518f-6d94-43b8-ab3c-413e6af8f10a
Name: NAM-3f97db93-da89-4937-b457-14be72b7b62b
Display Name: Highlights
Image URL: Not Set
Time to Live: Not Set
Channels:
None Set
> vonage users list
✅ Fetching users
User ID Name Display Name
---------------------------------------- ---------------------------------------- ------------
USR-4476dbcc-8e2a-4048-ac8a-8ab49345167a HighlightsTravel
USR-a778518f-6d94-43b8-ab3c-413e6af8f10a NAM-3f97db93-da89-4937-b457-14be72b7b62b
USR-9f60dff4-78c3-40c8-9aad-f762df371728 NAM-c54db270-643a-43a6-883e-b8c28d292dbe
Done Listing users
```

@ -3,7 +3,7 @@
const express = require("express"); const express = require("express");
const fs = require("fs"); const fs = require("fs");
const { tokenGenerate } = require("@vonage/jwt"); const { tokenGenerate } = require("@vonage/jwt");
const privateKey = fs.readFileSync("gh-private.key"); const privateKey = fs.readFileSync("private20250417.key");
const aclPaths = { const aclPaths = {
paths: { paths: {
"/*/rtc/**": {}, "/*/rtc/**": {},
@ -21,7 +21,19 @@ const aclPaths = {
const app = express(); const app = express();
app.use(express.json()); app.use(express.json());
const vonageNumber = "12052553394"; //用于通话的号码,今后根据前端提交来做号码切换 const app_id = '503c548f-cb61-4a3a-8599-cd815680b390';
const api_key = '197c68c9';
const api_secret = 'Aa11be17f298dfd4118bdf23';
const vonageNumber = "12019751815"; //用于通话的号码,今后根据前端提交来做号码切换
const vonageUser = "HighlightsTravel"; // user name
const response = (data) => {
return {
errcode: 0,
errmsg: '',
result: data,
}
}
//设置跨域访问 //设置跨域访问
app.all("*", function (req, res, next) { app.all("*", function (req, res, next) {
@ -36,7 +48,7 @@ app.get("/voice/answer", (req, res) => {
console.log("NCCO request:"); console.log("NCCO request:");
console.log(` - callee: ${req.query.to}`); console.log(` - callee: ${req.query.to}`);
console.log("---"); console.log("---");
res.json([ const result = [
{ {
action: "talk", action: "talk",
text: "Please wait while we connect you.", text: "Please wait while we connect you.",
@ -50,24 +62,23 @@ app.get("/voice/answer", (req, res) => {
from: vonageNumber, from: vonageNumber,
endpoint: [{ type: "phone", number: req.query.to }], endpoint: [{ type: "phone", number: req.query.to }],
}, },
]); ];
res.json(result);
}); });
app.get("/jwt", (req, res) => { app.get("/jwt", (req, res) => {
console.log("jwt Generate:"); console.log("jwt Generate:");
const exp_time = new Date(Date.now() + 3 * 24 * 3600 * 1000); const exp_time = new Date(Date.now() + 3 * 24 * 3600 * 1000);
const token = tokenGenerate("39f32a2a-e343-4ca0-9d92-5946573af5ea", privateKey, { const token = tokenGenerate(app_id, privateKey, {
exp: Math.round(exp_time.getTime() / 1000), exp: Math.round(exp_time.getTime() / 1000),
sub: "hainatravel", sub: vonageUser,
acl: aclPaths, acl: aclPaths,
}); });
console.log(Math.round(exp_time.getTime() / 1000)); console.log(Math.round(exp_time.getTime() / 1000));
console.log(token); console.log(token.substring(0, 5));
console.log("---"); console.log("---");
res.json({ const result = response({ token, status: 200});
token: token, res.json(result);
status: 200,
});
}); });
app.all("/voice/event", (req, res) => { app.all("/voice/event", (req, res) => {

@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCXaDD9rLbsAWpr
r0Nz3vc04Q/w9WgSsmLW8fg08+4V604QQUwbyXYPQACIzNguEB5ggbvbyxL7j5Bf
+bXW6HCu5Gxw0+ciMyhaymR7aGrbzIWOP8abTQnb6+ljZWeCvD+R8Ow6xJrhTACJ
X48IrLPDN3kqFQWVjm0vV9GiviPF4ifDCmNW+78oPrEo5YHKwyoYrGBkr6pKMiER
m9pSu++owv8XUV/hQVTkq20khlvRy35bwx2qmbGbE9BgQsS4KNri9jHOIB413sFg
p8zcvdKTxtje99M5iPHUKgF8WrzRHFqvKFRyg90p22twNAUnvgc3eiUoW2Qv+A78
X9ZaaEQTAgMBAAECggEACEwzKyPfs9gcBKIf+JCxTETtV7pLUC2rPGEZxjp8GNgY
I3dApuEynCwDcNExI80fAmZPF6uYcxBEzE27c8yx/ZO9Ma3F+VouYv4ROwYs8mDS
DPVdJWkNGkVijrT2/Z44KapiIpJgc+pzY76d8Hluh0tZ/j7ABe3pTp0/JZkgDW8o
Q92TObC/cN5ZguIpNWlW2lQhKiJkwkcLFpxzm5QhStiQaahjWJBye6tvc9M3CSxm
69e9pPW0ZBTW6wyIU6OQHzfnT6+bwo3kbmV2Svx3OHL1yiJV1p4rbuH3XJKQ6d2O
zh2mew7zqXOuMggLotevDJXmRcrgmo4kxoxW6BKMuQKBgQDHkxlapdGuH1rZwPZj
KcQvy29Z0xRP5wbUlTRkthHPXUeUonZTeKfw/oSfz81rHV2z046Bp7tE5qshzLiS
RMl9U68t36t+i3vNiUFNtNT4Uu9w4KL2dwi0onBauc9m2xNSR0YHJlWTHkgauQaq
XoV/rQca6nBagXxQ9qeoJr4m1wKBgQDCNsuhm53503i74HYoVEOM3noAuqVW3usl
4QHsQsGuItFC5/sTLudvJv6wTZItDEf15eLqge3j6tjxG8+2RoYiCTSKdW848fLi
PUkIyCfMYmA3L7eIwJmDwPxG80E4tQWKPyENvXSKNmNS+Cnu7fPl9mOJIqHncC6r
UowBID6xJQKBgQCe59sqOBmqQMD/3QrRjjHttFem99CWhmcD4QFkpyurJqSWDn2U
nN9rndxPuw/el/VB99LiHYGYrOnZ8b2MiUS9i2JSbmOIUNt0njLnAnMIflC0Wcin
4cOGwEghlQ004n6R5ro1eypsB5J15JkQEk7NiCG+JqjrB2rKtHpuAtso5QKBgDLs
azhUtXdsG5wnntO0RIILU7IdPn0otj+YYAiy+FXQi04fxZWiFszuTJmtvUZSkgvH
21fh+Z5pVbjisfP5SfJit4QWhrNHvYfUyfGjicvtf4z41gbleVsynvN7lP5peKpn
IyOXKZeT6zc2GsirW+hQUokCq7EjmRkS6+LfsZCBAoGBAMAfhVcSz73yDqTR6YR3
+kzpm8+bEOBhUERxtidyvEdaF1255BoeDigFVgSophdk+tWdcIMFLmg8VkVD9FCa
3mVbmD6lNm1eJfUtsMQYja0x338PpSFmd6whBbWRb/8CUbyFJSP5wFlPe9G9qxN8
6HrZzqr1ydp2MWMoKFYCiiQR
-----END PRIVATE KEY-----
Loading…
Cancel
Save