-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
1,366 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# OPENAI_API_KEY=你的OpenAI API密钥 | ||
OPENAI_API_KEY=sk-你的OpenAI API密钥 | ||
# 设置代理服务器地址 | ||
HTTP_PROXY=http://127.0.0.1:26001 | ||
HTTPS_PROXY=http://127.0.0.1:26001 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,97 @@ | ||
# openai-Realtime-API-with-WebRTC | ||
openai-Realtime-API-with-WebRTC | ||
# WebRTC OpenAI 实时通信应用 | ||
|
||
Coming soon | ||
这是一个使用 WebRTC 技术与 OpenAI API 进行实时通信的 Web 应用程序。该应用支持通过数据通道与 OpenAI 进行实时数据交换。 | ||
|
||
the app with the openai-Realtime-API-with-WebRTC | ||
## 功能特点 | ||
|
||
- 使用 WebRTC 建立点对点连接 | ||
- 集成 OpenAI API | ||
- 支持代理设置,解决网络访问问题 | ||
- 实时数据通信 | ||
- 简洁的用户界面 | ||
|
||
## 技术栈 | ||
|
||
- Node.js | ||
- Express.js | ||
- WebRTC | ||
- OpenAI API | ||
- WebSocket | ||
|
||
## 前置要求 | ||
|
||
- Node.js 18.0.0 或更高版本 | ||
- npm 包管理器 | ||
- OpenAI API 密钥 | ||
- 可用的代理服务器(如果需要) | ||
|
||
## 安装步骤 | ||
|
||
1. 克隆仓库: | ||
```bash | ||
git clone https://github.com/BarryYin/openai-Realtime-API-with-WebRTC.git | ||
cd openai-Realtime-API-with-WebRTC | ||
``` | ||
|
||
2. 安装依赖: | ||
```bash | ||
npm install | ||
``` | ||
|
||
3. 配置环境变量: | ||
- 复制 `.env.example` 文件为 `.env` | ||
- 在 `.env` 文件中设置你的 OpenAI API 密钥和代理设置: | ||
``` | ||
OPENAI_API_KEY=你的OpenAI API密钥 | ||
HTTP_PROXY=http://127.0.0.1:你的代理端口 | ||
HTTPS_PROXY=http://127.0.0.1:你的代理端口 | ||
``` | ||
## 运行应用 | ||
1. 启动服务器: | ||
```bash | ||
npm start | ||
``` | ||
|
||
2. 在浏览器中打开: | ||
``` | ||
http://localhost:3000 | ||
``` | ||
|
||
## 使用说明 | ||
|
||
1. 打开应用后,点击"开始连接"按钮建立 WebRTC 连接 | ||
2. 连接成功后,状态会显示"已连接" | ||
3. 使用"发送测试消息"按钮测试通信 | ||
4. 需要断开连接时,点击"断开连接"按钮 | ||
|
||
## 文件结构 | ||
|
||
- `getapi.js`: Express 服务器和 OpenAI API 集成 | ||
- `init.js`: WebRTC 连接初始化和管理 | ||
- `main.js`: 数据通道通信逻辑 | ||
- `index.html`: 用户界面 | ||
- `.env`: 环境变量配置 | ||
|
||
## 注意事项 | ||
|
||
- 确保 OpenAI API 密钥有效且有足够的配额 | ||
- 如果遇到连接问题,检查代理设置是否正确 | ||
- 保持浏览器控制台打开以查看详细日志 | ||
|
||
## 故障排除 | ||
|
||
1. 连接超时 | ||
- 检查 API 密钥是否正确 | ||
- 确认代理服务器是否正常运行 | ||
- 验证网络连接是否稳定 | ||
|
||
2. 发送消息失败 | ||
- 确保 WebRTC 连接已建立 | ||
- 检查数据通道是否开启 | ||
- 查看浏览器控制台是否有错误信息 | ||
|
||
## License | ||
|
||
ISC |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import express from "express"; | ||
import dotenv from "dotenv"; | ||
import { fileURLToPath } from 'url'; | ||
import { dirname } from 'path'; | ||
import path from 'path'; | ||
import fetch from 'node-fetch'; | ||
import https from 'https'; | ||
import { HttpsProxyAgent } from 'https-proxy-agent'; | ||
|
||
// 获取当前文件的目录路径 | ||
const __filename = fileURLToPath(import.meta.url); | ||
const __dirname = dirname(__filename); | ||
|
||
// 加载环境变量 | ||
dotenv.config(); | ||
|
||
const app = express(); | ||
|
||
// 创建自定义的 HTTPS agent,设置更长的超时时间 | ||
const httpsAgent = new https.Agent({ | ||
timeout: 30000, // 30 秒超时 | ||
keepAlive: true | ||
}); | ||
|
||
// 创建代理 agent | ||
const proxyUrl = process.env.HTTPS_PROXY || process.env.HTTP_PROXY || 'http://127.0.0.1:26001'; // 系统代理端口 | ||
const proxyAgent = new HttpsProxyAgent(proxyUrl); | ||
|
||
// 添加错误处理中间件 | ||
app.use((err, req, res, next) => { | ||
console.error(err.stack); | ||
res.status(500).send('Something broke!'); | ||
}); | ||
|
||
// 设置静态文件服务 | ||
app.use(express.static(__dirname)); | ||
|
||
// 添加CORS支持 | ||
app.use((req, res, next) => { | ||
res.header('Access-Control-Allow-Origin', '*'); | ||
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization'); | ||
next(); | ||
}); | ||
|
||
// 重试函数 | ||
async function fetchWithRetry(url, options, maxRetries = 3) { | ||
for (let i = 0; i < maxRetries; i++) { | ||
try { | ||
console.log(`尝试连接 OpenAI API (第 ${i + 1} 次尝试)...`); | ||
console.log('使用代理:', proxyUrl); | ||
const response = await fetch(url, { | ||
...options, | ||
agent: proxyAgent, | ||
timeout: 30000 // 30 秒超时 | ||
}); | ||
return response; | ||
} catch (error) { | ||
if (i === maxRetries - 1) throw error; | ||
console.log(`尝试失败,等待重试... (${error.message})`); | ||
await new Promise(resolve => setTimeout(resolve, 2000)); // 等待2秒后重试 | ||
} | ||
} | ||
} | ||
|
||
// An endpoint which would work with the client code above - it returns | ||
// the contents of a REST API request to this protected endpoint | ||
app.get("/session", async (req, res) => { | ||
try { | ||
if (!process.env.OPENAI_API_KEY) { | ||
throw new Error('OpenAI API key is not set'); | ||
} | ||
|
||
console.log('使用的 API 密钥:', process.env.OPENAI_API_KEY.substring(0, 10) + '...'); | ||
console.log('尝试创建 OpenAI 会话...'); | ||
|
||
// 使用重试机制的 fetch | ||
const r = await fetchWithRetry("https://api.openai.com/v1/realtime/sessions", { | ||
method: "POST", | ||
headers: { | ||
"Authorization": `Bearer ${process.env.OPENAI_API_KEY}`, | ||
"Content-Type": "application/json", | ||
}, | ||
body: JSON.stringify({ | ||
model: "gpt-4o-realtime-preview-2024-12-17", | ||
voice: "verse", | ||
}), | ||
}); | ||
|
||
const responseText = await r.text(); | ||
console.log('OpenAI API 响应:', responseText); | ||
|
||
if (!r.ok) { | ||
throw new Error(`OpenAI API 返回 ${r.status}: ${responseText}`); | ||
} | ||
|
||
const data = JSON.parse(responseText); | ||
console.log('会话创建成功'); | ||
res.json(data); | ||
} catch (error) { | ||
console.error('会话创建错误:', error); | ||
res.status(500).json({ | ||
error: error.message, | ||
details: error.stack | ||
}); | ||
} | ||
}); | ||
|
||
const port = process.env.PORT || 3000; | ||
app.listen(port, () => { | ||
console.log(`服务器运行在端口 ${port}`); | ||
console.log('OpenAI API 密钥:', process.env.OPENAI_API_KEY ? '已设置' : '未设置'); | ||
console.log('使用代理:', proxyUrl); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>WebRTC OpenAI Demo</title> | ||
<style> | ||
body { | ||
font-family: Arial, sans-serif; | ||
max-width: 800px; | ||
margin: 0 auto; | ||
padding: 20px; | ||
} | ||
button { | ||
padding: 10px 20px; | ||
margin: 10px; | ||
font-size: 16px; | ||
} | ||
#status { | ||
margin: 20px 0; | ||
padding: 10px; | ||
border-radius: 5px; | ||
} | ||
#log { | ||
background-color: #f5f5f5; | ||
padding: 10px; | ||
border-radius: 5px; | ||
height: 200px; | ||
overflow-y: auto; | ||
margin-top: 20px; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<h1>WebRTC OpenAI Demo</h1> | ||
<button id="connectButton" onclick="init()">开始连接</button> | ||
<button id="disconnectButton" style="display: none;">断开连接</button> | ||
<button id="sendButton" onclick="sendMessage()" disabled>发送测试消息</button> | ||
<div id="status">状态:未连接</div> | ||
<div id="log"></div> | ||
|
||
<script> | ||
// 重写console.log来显示在页面上 | ||
const oldLog = console.log; | ||
console.log = function() { | ||
const args = Array.from(arguments); | ||
const message = args.map(arg => | ||
typeof arg === 'object' ? JSON.stringify(arg, null, 2) : arg | ||
).join(' '); | ||
|
||
const logDiv = document.getElementById('log'); | ||
if (logDiv) { | ||
logDiv.innerHTML += message + '<br>'; | ||
logDiv.scrollTop = logDiv.scrollHeight; | ||
} | ||
oldLog.apply(console, arguments); | ||
}; | ||
</script> | ||
<script src="init.js"></script> | ||
<script src="main.js"></script> | ||
</body> | ||
</html> |
Oops, something went wrong.