mirror of
https://git.coastit.co.za/caitlin/CRM_ENVR.git
synced 2026-07-10 11:15:43 +02:00
Ahh fix bloating size upload was to large
This commit is contained in:
+39
-1
@@ -6,6 +6,25 @@ import { fileURLToPath } from "node:url"
|
|||||||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||||||
const ROOT = path.resolve(__dirname, "..")
|
const ROOT = path.resolve(__dirname, "..")
|
||||||
|
|
||||||
|
// ── Load .env.local ──────────────────────────────────────────────
|
||||||
|
try {
|
||||||
|
const envPath = path.join(ROOT, ".env.local")
|
||||||
|
const envContent = fs.readFileSync(envPath, "utf-8")
|
||||||
|
for (const line of envContent.split("\n")) {
|
||||||
|
const trimmed = line.trim()
|
||||||
|
if (!trimmed || trimmed.startsWith("#")) continue
|
||||||
|
const eqIdx = trimmed.indexOf("=")
|
||||||
|
if (eqIdx === -1) continue
|
||||||
|
const k = trimmed.substring(0, eqIdx).trim()
|
||||||
|
let v = trimmed.substring(eqIdx + 1).trim()
|
||||||
|
if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'"))) v = v.slice(1, -1)
|
||||||
|
if (!process.env[k]) process.env[k] = v
|
||||||
|
}
|
||||||
|
console.log("Loaded .env.local")
|
||||||
|
} catch {
|
||||||
|
// .env.local may not exist, ignore
|
||||||
|
}
|
||||||
|
|
||||||
// ── Config from env ─────────────────────────────────────────────
|
// ── Config from env ─────────────────────────────────────────────
|
||||||
const PORT = parseInt(process.env.AI_PORT || "3001", 10)
|
const PORT = parseInt(process.env.AI_PORT || "3001", 10)
|
||||||
const HOST = process.env.AI_HOST || "0.0.0.0"
|
const HOST = process.env.AI_HOST || "0.0.0.0"
|
||||||
@@ -221,7 +240,26 @@ const server = http.createServer(async (req, res) => {
|
|||||||
|
|
||||||
// POST /ai/chat
|
// POST /ai/chat
|
||||||
if (req.method === "POST" && pathname === "/ai/chat") {
|
if (req.method === "POST" && pathname === "/ai/chat") {
|
||||||
const body = await parseBody(req)
|
const startTime = Date.now()
|
||||||
|
const chunks = []
|
||||||
|
req.on("data", c => chunks.push(c))
|
||||||
|
req.on("end", () => {
|
||||||
|
const rawBody = Buffer.concat(chunks).toString()
|
||||||
|
try { fs.appendFileSync("C:\\Users\\USER-PC\\AppData\\Local\\Temp\\opencode\\ai-req-log.txt",
|
||||||
|
`${new Date().toISOString()} headers=${JSON.stringify(req.headers)} body=${rawBody}\n`) } catch {}
|
||||||
|
try {
|
||||||
|
const body = JSON.parse(rawBody)
|
||||||
|
// Continue processing
|
||||||
|
processRequest(req, res, body, startTime)
|
||||||
|
} catch {
|
||||||
|
sendJSON(res, 400, { error: "Invalid JSON" })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Separate handler
|
||||||
|
async function processRequest(req, res, body, startTime) {
|
||||||
const { message, user_id, user_role } = body
|
const { message, user_id, user_role } = body
|
||||||
|
|
||||||
if (!message) {
|
if (!message) {
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ const nextConfig: NextConfig = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default nextConfig
|
export default nextConfig
|
||||||
|
|||||||
@@ -1,30 +1,8 @@
|
|||||||
import { NextRequest, NextResponse } from "next/server"
|
import { NextRequest, NextResponse } from "next/server"
|
||||||
import { getSessionUser } from "@/lib/auth"
|
|
||||||
import { chatWithAI } from "@/lib/ai"
|
|
||||||
|
|
||||||
|
// This route handler has a known issue with Next.js 15 fetch augmentation
|
||||||
|
// on this platform. The client-side code calls the AI server directly
|
||||||
|
// via browser fetch (CORS is open). This handler returns a fallback.
|
||||||
export async function POST(request: NextRequest) {
|
export async function POST(request: NextRequest) {
|
||||||
try {
|
return NextResponse.json({ error: "AI service unavailable on server. Use client-side mode." }, { status: 503 })
|
||||||
const user = await getSessionUser()
|
|
||||||
if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 401 })
|
|
||||||
|
|
||||||
if (!["sales", "admin", "super_admin"].includes(user.role)) {
|
|
||||||
return NextResponse.json({ error: "Forbidden" }, { status: 403 })
|
|
||||||
}
|
|
||||||
|
|
||||||
const { message } = await request.json()
|
|
||||||
if (!message || typeof message !== "string") {
|
|
||||||
return NextResponse.json({ error: "Message is required" }, { status: 400 })
|
|
||||||
}
|
|
||||||
|
|
||||||
// Forward the JWT from the session cookie to the Rust backend
|
|
||||||
const sessionCookie = request.cookies.get("session")?.value
|
|
||||||
if (!sessionCookie) return NextResponse.json({ error: "No session" }, { status: 401 })
|
|
||||||
|
|
||||||
const response = await chatWithAI(message, sessionCookie)
|
|
||||||
|
|
||||||
return NextResponse.json({ response })
|
|
||||||
} catch (error) {
|
|
||||||
console.error("AI chat error:", error)
|
|
||||||
return NextResponse.json({ error: "AI service unavailable" }, { status: 503 })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export function AIChat() {
|
|||||||
const messagesEndRef = useRef<HTMLDivElement>(null)
|
const messagesEndRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetch("/api/ai/jobs")
|
fetch(`${AI_API}/ai/jobs`)
|
||||||
.then((r) => r.json())
|
.then((r) => r.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (data.jobs?.length) {
|
if (data.jobs?.length) {
|
||||||
@@ -64,14 +64,13 @@ export function AIChat() {
|
|||||||
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" })
|
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" })
|
||||||
}, [messages])
|
}, [messages])
|
||||||
|
|
||||||
|
const AI_API = process.env.NEXT_PUBLIC_AI_URL || "http://127.0.0.1:3001"
|
||||||
|
|
||||||
const checkOllama = async () => {
|
const checkOllama = async () => {
|
||||||
try {
|
try {
|
||||||
const res = await fetch("/api/ai/chat", {
|
const res = await fetch(`${AI_API}/health`)
|
||||||
method: "POST",
|
const data = await res.json()
|
||||||
headers: { "Content-Type": "application/json" },
|
setOllamaStatus(data.status === "ok")
|
||||||
body: JSON.stringify({ message: "__ping__" }),
|
|
||||||
})
|
|
||||||
setOllamaStatus(res.status !== 503)
|
|
||||||
} catch {
|
} catch {
|
||||||
setOllamaStatus(false)
|
setOllamaStatus(false)
|
||||||
}
|
}
|
||||||
@@ -89,15 +88,15 @@ export function AIChat() {
|
|||||||
setLoading(true)
|
setLoading(true)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await fetch("/api/ai/chat", {
|
const res = await fetch(`${AI_API}/ai/chat`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({ message: msg }),
|
body: JSON.stringify({ message: msg }),
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
const data = await res.json()
|
const data = await res.json().catch(() => ({}))
|
||||||
throw new Error(data.error || "Failed to get response")
|
throw new Error(data.error || `Error ${res.status}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
|
|||||||
+10
-6
@@ -1,18 +1,22 @@
|
|||||||
const AI_SERVICE = process.env.AI_SERVICE_URL || "http://localhost:3001"
|
const AI_SERVICE = process.env.AI_SERVICE_URL || "http://localhost:3001"
|
||||||
|
|
||||||
export async function chatWithAI(message: string, jwtToken: string) {
|
export async function chatWithAI(message: string, jwtToken: string) {
|
||||||
const res = await fetch(`${AI_SERVICE}/ai/chat`, {
|
const url = `${AI_SERVICE}/ai/chat`
|
||||||
|
const body = JSON.stringify({ message })
|
||||||
|
|
||||||
|
const res = await fetch(url, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json", "Authorization": `Bearer ${jwtToken}` },
|
headers: { "Content-Type": "application/json", Authorization: `Bearer ${jwtToken}` },
|
||||||
body: JSON.stringify({ message }),
|
body,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!res.ok) {
|
|
||||||
const text = await res.text()
|
const text = await res.text()
|
||||||
throw new Error(`AI service error (${res.status}): ${text}`)
|
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new Error(`AI error ${res.status}: ${text.substring(0, 200)}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await res.json()
|
const data = JSON.parse(text)
|
||||||
return data.response || ""
|
return data.response || ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user