/* DeepStudy Pro MAX โ Luxe UI * Same powerhouse features, premium UI polish for DeepSite. * Env: OPENAI_API_KEY, OPENAI_MODEL, JWT_SECRET, SMTP_*, APP_BASE_URL */ require('dotenv').config(); const path=require('path'),fs=require('fs'),os=require('os'); const express=require('express'),cors=require('cors'),bodyParser=require('body-parser'); const multer=require('multer'),pdfParse=require('pdf-parse'),mammoth=require('mammoth'); const {v4:uuidv4}=require('uuid'); const helmet=require('helmet'); const rateLimit=require('express-rate-limit'); const cookieParser=require('cookie-parser'); const nodemailer=require('nodemailer'); const bcrypt=require('bcryptjs'); const jwt=require('jsonwebtoken'); const OpenAI=require('openai'); const app=express(); app.use(helmet({contentSecurityPolicy:false})); app.use(cors({origin:true,credentials:true})); app.use(cookieParser()); app.use(bodyParser.json({limit:'16mb'})); app.use(rateLimit({windowMs:60_000,max:180})); const PORT=process.env.PORT||3000; const APP_BASE_URL=process.env.APP_BASE_URL||`http://localhost:${PORT}`; const JWT_SECRET=process.env.JWT_SECRET||'dev_change_me'; const DATA_DIR=path.join(process.cwd(),'data'); const USERS_PATH=path.join(DATA_DIR,'users.json'); const PACKS_PATH=path.join(DATA_DIR,'packs.json'); if(!fs.existsSync(DATA_DIR)) fs.mkdirSync(DATA_DIR); if(!fs.existsSync(USERS_PATH)) fs.writeFileSync(USERS_PATH,JSON.stringify([])); if(!fs.existsSync(PACKS_PATH)) fs.writeFileSync(PACKS_PATH,JSON.stringify([])); const readJSON=p=>{try{return JSON.parse(fs.readFileSync(p,'utf8'));}catch{return[];}}; const writeJSON=(p,v)=>fs.writeFileSync(p,JSON.stringify(v,null,2)); const readUsers=()=>readJSON(USERS_PATH), writeUsers=a=>writeJSON(USERS_PATH,a); const readPacks=()=>readJSON(PACKS_PATH), writePacks=a=>writeJSON(PACKS_PATH,a); let transporter=null; if(process.env.SMTP_HOST){ transporter=nodemailer.createTransport({host:process.env.SMTP_HOST,port:Number(process.env.SMTP_PORT||587),secure:false,auth:{user:process.env.SMTP_USER,pass:process.env.SMTP_PASS}}); } const openaiConfigured=!!process.env.OPENAI_API_KEY; const openaiClient=openaiConfigured? new OpenAI.OpenAI({apiKey:process.env.OPENAI_API_KEY}):null; const MODEL=process.env.OPENAI_MODEL||'gpt-4o-mini'; const sanitize=s=>(s||'').toString().replace(/\u0000/g,'').trim(); const safeParseJSON=s=>{try{return JSON.parse(s);}catch{return null;}}; const signToken=(payload,exp='7d')=>jwt.sign(payload,JWT_SECRET,{expiresIn:exp}); const verifyToken=t=>{try{return jwt.verify(t,JWT_SECRET);}catch{return null;}}; function authRequired(req,res,next){const t=req.cookies?.dsp_auth; if(!t) return res.status(401).json({ok:false,error:'ื ืืจืฉืช ืืชืืืจืืช'}); const dec=verifyToken(t); if(!dec) return res.status(401).json({ok:false,error:'ืืกืืืื ืื ืชืงืฃ'}); req.user=dec; next();} const upload=multer({dest:path.join(os.tmpdir(),'deepstudy_uploads'),limits:{fileSize:32*1024*1024}}); async function extractText(filePath,originalName){ const ext=(path.extname(originalName||'').toLowerCase()||'').slice(1); if(ext==='pdf'){const d=await pdfParse(fs.readFileSync(filePath)); return sanitize(d.text);} if(ext==='docx'){const {value}=await mammoth.extractRawText({path:filePath}); return sanitize(value);} if(ext==='txt'||ext===''){return sanitize(fs.readFileSync(filePath,'utf8'));} throw new Error(`ืคืืจืื ืื ื ืชืื: ${ext} (pdf/docx/txt)`); } function chunkText(str,targetTokens=1200,overlapTokens=120){ const txt=sanitize(str); const charsPerTok=3; const chunkChars=targetTokens*charsPerTok; const overlapChars=overlapTokens*charsPerTok; const out=[]; let i=0,idx=1; while(i
69a00c8
verified