fixing ai's fk up
This commit is contained in:
parent
81a9d3c7b3
commit
49e40872a1
7 changed files with 147 additions and 16 deletions
|
|
@ -13,7 +13,25 @@ import { config } from "./config.js";
|
||||||
|
|
||||||
export function createApp() {
|
export function createApp() {
|
||||||
const app = express();
|
const app = express();
|
||||||
app.use(cors({ origin: config.webBaseUrl }));
|
app.use(cors({
|
||||||
|
origin: [
|
||||||
|
"http://localhost:5173",
|
||||||
|
"http://localhost:5174",
|
||||||
|
"http://localhost:5175",
|
||||||
|
"http://localhost:5176",
|
||||||
|
"http://localhost:5177",
|
||||||
|
"http://localhost:5178",
|
||||||
|
"http://localhost:5179",
|
||||||
|
"http://127.0.0.1:5173",
|
||||||
|
"http://127.0.0.1:5174",
|
||||||
|
"http://127.0.0.1:5175",
|
||||||
|
"http://127.0.0.1:5176",
|
||||||
|
"http://127.0.0.1:5177",
|
||||||
|
"http://127.0.0.1:5178",
|
||||||
|
"http://127.0.0.1:5179",
|
||||||
|
],
|
||||||
|
credentials: true
|
||||||
|
}));
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
|
|
||||||
app.get("/health", (_req, res) => res.json({ ok: true }));
|
app.get("/health", (_req, res) => res.json({ ok: true }));
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,13 @@
|
||||||
import dotenv from "dotenv";
|
import dotenv from "dotenv";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
import { dirname } from "node:path";
|
||||||
|
|
||||||
// .env lives at the monorepo root, two levels above apps/server/
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
dotenv.config({ path: path.resolve(process.cwd(), "../../.env") });
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
|
const envPath = path.resolve(__dirname, "../../../.env");
|
||||||
|
dotenv.config({ path: envPath });
|
||||||
|
|
||||||
const required = (key: string, fallback?: string): string => {
|
const required = (key: string, fallback?: string): string => {
|
||||||
const value = process.env[key] ?? fallback;
|
const value = process.env[key] ?? fallback;
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,12 @@ async function bootstrap() {
|
||||||
console.log(`Server listening on :${config.port}`);
|
console.log(`Server listening on :${config.port}`);
|
||||||
});
|
});
|
||||||
scheduler.start();
|
scheduler.start();
|
||||||
await discordService.start().catch((err) => {
|
try {
|
||||||
console.error("[discord] Failed to connect — bot features unavailable:", err.message);
|
await discordService.start();
|
||||||
});
|
} catch (err) {
|
||||||
|
console.error("[discord] Failed to connect — bot features unavailable:", err);
|
||||||
|
console.error("[discord] Server will continue running without Discord features.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bootstrap().catch((err) => {
|
bootstrap().catch((err) => {
|
||||||
|
|
|
||||||
|
|
@ -49,19 +49,41 @@ class TranscriptionBuffer {
|
||||||
const userBuffers = new Map<string, TranscriptionBuffer>();
|
const userBuffers = new Map<string, TranscriptionBuffer>();
|
||||||
const activeTranscriptions = new Map<string, NodeJS.Timeout>();
|
const activeTranscriptions = new Map<string, NodeJS.Timeout>();
|
||||||
|
|
||||||
async function transcribeWithWhisper(audioBuffer: Buffer): Promise<TranscriptionResult> {
|
function createWavBuffer(pcmData: Buffer, sampleRate: number = 48000): Buffer {
|
||||||
if (!config.openaiApiKey) {
|
const numChannels = 1;
|
||||||
throw new Error("OpenAI API key not configured for transcription");
|
const bitsPerSample = 16;
|
||||||
|
const byteRate = (sampleRate * numChannels * bitsPerSample) / 8;
|
||||||
|
const blockAlign = (numChannels * bitsPerSample) / 8;
|
||||||
|
const dataSize = pcmData.length * 2;
|
||||||
|
|
||||||
|
const header = Buffer.alloc(44);
|
||||||
|
header.write('RIFF', 0);
|
||||||
|
header.writeUInt32LE(36 + dataSize, 4);
|
||||||
|
header.write('WAVE', 8);
|
||||||
|
header.write('fmt ', 12);
|
||||||
|
header.writeUInt32LE(16, 16);
|
||||||
|
header.writeUInt16LE(1, 20);
|
||||||
|
header.writeUInt16LE(numChannels, 22);
|
||||||
|
header.writeUInt32LE(sampleRate, 24);
|
||||||
|
header.writeUInt32LE(byteRate, 28);
|
||||||
|
header.writeUInt16LE(blockAlign, 32);
|
||||||
|
header.writeUInt16LE(bitsPerSample, 34);
|
||||||
|
header.write('data', 36);
|
||||||
|
header.writeUInt32LE(dataSize, 40);
|
||||||
|
|
||||||
|
return Buffer.concat([header, pcmData]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function transcribeWithWhisper(audioBuffer: Buffer): Promise<TranscriptionResult> {
|
||||||
|
const wavBuffer = createWavBuffer(audioBuffer);
|
||||||
const form = new FormData();
|
const form = new FormData();
|
||||||
form.append("file", audioBuffer, { filename: "audio.wav", contentType: "audio/wav" });
|
form.append("audio_file", wavBuffer, { filename: "audio.wav", contentType: "audio/wav" });
|
||||||
form.append("model", config.whisperModel);
|
|
||||||
form.append("language", config.whisperLanguage);
|
form.append("language", config.whisperLanguage);
|
||||||
|
form.append("task", "transcribe");
|
||||||
|
form.append("output", "json");
|
||||||
|
|
||||||
const response = await new Promise<Response>((resolve, reject) => {
|
const response = await new Promise<Response>((resolve, reject) => {
|
||||||
const req = form.submit(`${config.whisperBaseUrl}/audio/transcriptions`);
|
const req = form.submit(`${config.whisperBaseUrl}/asr`);
|
||||||
req.setHeader("Authorization", `Bearer ${config.openaiApiKey}`);
|
|
||||||
|
|
||||||
req.on("response", (res) => {
|
req.on("response", (res) => {
|
||||||
const chunks: Buffer[] = [];
|
const chunks: Buffer[] = [];
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ import react from "@vitejs/plugin-react";
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
server: {
|
server: {
|
||||||
port: 5173
|
port: 5173,
|
||||||
|
strictPort: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,10 @@
|
||||||
"apps/web"
|
"apps/web"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "concurrently -n server,web -c cyan,magenta \"npm run dev -w @dnd-hub/server\" \"npm run dev -w @dnd-hub/web\"",
|
"dev": "bash scripts/dev.sh",
|
||||||
|
"dev:manual": "concurrently -n server,web -c cyan,magenta --kill-others \"npm run dev -w @dnd-hub/server\" \"npm run dev -w @dnd-hub/web\"",
|
||||||
|
"dev:server": "cd apps/server && tsx watch src/main.ts",
|
||||||
|
"dev:web": "cd apps/web && vite",
|
||||||
"build": "npm run build -w @dnd-hub/server && npm run build -w @dnd-hub/web",
|
"build": "npm run build -w @dnd-hub/server && npm run build -w @dnd-hub/web",
|
||||||
"test": "npm run test -w @dnd-hub/server && npm run test -w @dnd-hub/web"
|
"test": "npm run test -w @dnd-hub/server && npm run test -w @dnd-hub/web"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
79
scripts/dev.sh
Normal file
79
scripts/dev.sh
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Kill existing processes on our ports using PowerShell - with retry
|
||||||
|
kill_port() {
|
||||||
|
local port=$1
|
||||||
|
for i in 1 2 3; do
|
||||||
|
powershell -Command "Get-NetTCPConnection -LocalPort $port -ErrorAction SilentlyContinue | ForEach-Object { Stop-Process -Id \$_.OwningProcess -Force -ErrorAction SilentlyContinue }" 2>/dev/null
|
||||||
|
sleep 1
|
||||||
|
# Check if port is free
|
||||||
|
if ! powershell -Command "Get-NetTCPConnection -LocalPort $port -ErrorAction SilentlyContinue" 2>/dev/null | grep -q LISTENING; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Cleaning up existing processes..."
|
||||||
|
kill_port 4000
|
||||||
|
kill_port 5173
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# Get the script directory and resolve to absolute Windows path
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||||
|
|
||||||
|
# Start server in background
|
||||||
|
cd "$ROOT_DIR/apps/server"
|
||||||
|
nohup npx tsx watch src/main.ts > "$ROOT_DIR/data/server.log" 2>&1 &
|
||||||
|
SERVER_PID=$!
|
||||||
|
echo "Server started (PID: $SERVER_PID)"
|
||||||
|
|
||||||
|
# Start web in background
|
||||||
|
cd "$ROOT_DIR/apps/web"
|
||||||
|
nohup npm run dev > "$ROOT_DIR/data/web.log" 2>&1 &
|
||||||
|
WEB_PID=$!
|
||||||
|
echo "Web started (PID: $WEB_PID)"
|
||||||
|
|
||||||
|
# Wait for both to be ready
|
||||||
|
echo "Waiting for services to start..."
|
||||||
|
sleep 6
|
||||||
|
|
||||||
|
# Check health
|
||||||
|
sleep 2
|
||||||
|
if curl -s http://127.0.0.1:4000/health 2>/dev/null | grep -q "ok"; then
|
||||||
|
echo "✓ Server is running on http://localhost:4000"
|
||||||
|
else
|
||||||
|
echo "✗ Server failed to start"
|
||||||
|
echo "Server log:"
|
||||||
|
cat "$ROOT_DIR/data/server.log" 2>/dev/null | tail -20
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if curl -s http://127.0.0.1:5173/ 2>/dev/null | grep -qi "campaign"; then
|
||||||
|
echo "✓ Web is running on http://localhost:5173"
|
||||||
|
else
|
||||||
|
# Fallback: check if port is listening
|
||||||
|
if netstat -ano 2>/dev/null | grep -q ":5173.*LISTENING"; then
|
||||||
|
echo "✓ Web is running on http://localhost:5173"
|
||||||
|
else
|
||||||
|
echo "✗ Web failed to start"
|
||||||
|
echo "Web log:"
|
||||||
|
cat "$ROOT_DIR/data/web.log" 2>/dev/null | tail -10
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Both services running. Press Ctrl+C to stop."
|
||||||
|
|
||||||
|
# Handle Ctrl+C
|
||||||
|
cleanup() {
|
||||||
|
echo "Stopping services..."
|
||||||
|
taskkill //F //PID $SERVER_PID 2>/dev/null
|
||||||
|
taskkill //F //PID $WEB_PID 2>/dev/null
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
trap cleanup INT TERM
|
||||||
|
|
||||||
|
# Keep script running
|
||||||
|
wait
|
||||||
Loading…
Add table
Reference in a new issue