PS C:\Users\Administrator\Desktop\New folder\quest-v8\services> node api.js
Server running at http://192.168.2.5:3006
Cache MISS for key: search:damages:noexclude
Database connection established.
Executing SQL Query:
            SELECT Filename
            FROM indexed_files
            WHERE CONTAINS(PdfData, @searchTerms)

Search terms: damages
Error processing search: RequestError: Invalid object name 'indexed_files'.
    at handleError (C:\Users\Administrator\Desktop\New folder\quest-v8\node_modules\mssql\lib\tedious\request.js:384:15)
    at Connection.emit (node:events:519:28)
    at Connection.emit (C:\Users\Administrator\Desktop\New folder\quest-v8\node_modules\tedious\lib\connection.js:970:18)
    at RequestTokenHandler.onErrorMessage (C:\Users\Administrator\Desktop\New folder\quest-v8\node_modules\tedious\lib\token\handler.js:284:21)
    at Readable.<anonymous> (C:\Users\Administrator\Desktop\New folder\quest-v8\node_modules\tedious\lib\token\token-stream-parser.js:19:33)
    at Readable.emit (node:events:519:28)
    at addChunk (node:internal/streams/readable:559:12)
    at readableAddChunkPushObjectMode (node:internal/streams/readable:536:3)
    at Readable.push (node:internal/streams/readable:391:5)
    at nextAsync (node:internal/streams/from:194:22) {
  code: 'EREQUEST',
  originalError: Error: Invalid object name 'indexed_files'.
      at handleError (C:\Users\Administrator\Desktop\New folder\quest-v8\node_modules\mssql\lib\tedious\request.js:382:19)
      at Connection.emit (node:events:519:28)
      at Connection.emit (C:\Users\Administrator\Desktop\New folder\quest-v8\node_modules\tedious\lib\connection.js:970:18)        
      at RequestTokenHandler.onErrorMessage (C:\Users\Administrator\Desktop\New folder\quest-v8\node_modules\tedious\lib\token\handler.js:284:21)
      at Readable.<anonymous> (C:\Users\Administrator\Desktop\New folder\quest-v8\node_modules\tedious\lib\token\token-stream-parser.js:19:33)
      at Readable.emit (node:events:519:28)
      at addChunk (node:internal/streams/readable:559:12)
      at readableAddChunkPushObjectMode (node:internal/streams/readable:536:3)
      at Readable.push (node:internal/streams/readable:391:5)
      at nextAsync (node:internal/streams/from:194:22) {
    info: ErrorMessageToken {
      name: 'ERROR',
      handlerName: 'onErrorMessage',
      number: 208,
      state: 1,
      class: 16,
      message: "Invalid object name 'indexed_files'.",
      serverName: 'WEBPORTAL',
      procName: '',
      lineNumber: 2
    }
  },
  number: 208,
  lineNumber: 2,
  state: 1,
  class: 16,
  serverName: 'WEBPORTAL',
  procName: '',
  precedingErrors: []
}
  getting this when trying to run  
const express = require('express');
const sql = require('mssql');
const cors = require('cors');
const NodeCache = require('node-cache');
const fs = require('fs').promises;
const path = require('path');
const pdfParse = require('pdf-parse');
const { Worker } = require('worker_threads');
const os = require('os');

const app = express();
app.use(cors());
app.use(express.json());

// SQL Server Configuration
const sqlconfig = {
    server: '192.168.13.30',
    database: 'ocr',
    user: 'sa',
    password: 'sa@12345',
    options: {
        encrypt: false,
        trustServerCertificate: true,
    },
    pool: {
        max: 10,
        min: 0,
        idleTimeoutMillis: 30000,
    },
    requestTimeout: 50000,
};

// Caching Setup - increased TTL and max size
const searchCache = new NodeCache({
    stdTTL: 604800, // 7 days
    checkperiod: 3600, // Check every hour
    maxKeys: 1000 // Store more results
});

// Connect to SQL Server
const pool = new sql.ConnectionPool(sqlconfig);
const poolConnect = pool.connect();

pool.on('error', (err) => {
    console.error('SQL Pool Error: ', err);
});

// Get optimal batch size based on system resources
function getOptimalBatchSize() {
    const cpuCount = os.cpus().length;
    const freeMemoryGB = os.freemem() / (1024 * 1024 * 1024);
    
    // Simple formula - adjust based on your needs
    const baseBatchSize = Math.min(cpuCount * 2, Math.floor(freeMemoryGB * 5));
    return Math.max(10, Math.min(50, baseBatchSize));
}

// Helper Functions
const getRelativePath = (fullPath) => {
    const basePath = '\\\\192.168.13.30\\c$\\GGN Office Repository\\';
    return fullPath.startsWith(basePath)
        ? fullPath.slice(basePath.length).replace(/\\/g, '/')
        : fullPath.replace(/\\/g, '/');
};

const getSnippet = (text, keyword, contextLength = 100) => {
    const lowerText = text.toLowerCase();
    const lowerKeyword = keyword.toLowerCase();
    const startIndex = lowerText.indexOf(lowerKeyword);

    if (startIndex === -1) return null;

    const snippetStart = Math.max(0, startIndex - contextLength);
    const snippetEnd = Math.min(text.length, startIndex + keyword.length + contextLength);
    const snippet = text.substring(snippetStart, snippetEnd);

    return `...${snippet}...`;
};

// Process PDF in a worker thread for better performance
function processPdfInWorker(pdfPath, keywords) {
    return new Promise((resolve, reject) => {
        // Create a path to the worker script
        const workerPath = path.join(__dirname, 'pdfWorker.js');
        
        // Check if worker file exists, if not create it
        fs.access(workerPath).catch(async () => {
            // Worker file doesn't exist, create it
            const workerCode = `
                const { workerData, parentPort } = require('worker_threads');
                const fs = require('fs').promises;
                const pdfParse = require('pdf-parse');

                async function processFile() {
                    const { pdfPath, keywords } = workerData;
                    
                    try {
                        const dataBuffer = await fs.readFile(pdfPath);
                        const pdfData = await pdfParse(dataBuffer);
                        const pages = pdfData.text.split('\\n\\n');
                        
                        let matches = [];
                        
                        for (let pageIndex = 0; pageIndex < pages.length; pageIndex++) {
                            const pageText = pages[pageIndex];
                            
                            keywords.forEach(keyword => {
                                if (pageText.toLowerCase().includes(keyword.toLowerCase())) {
                                    matches.push({
                                        page: pageIndex,
                                        keyword,
                                        snippet: getSnippet(pageText, keyword, 100)
                                    });
                                }
                            });
                        }
                        
                        parentPort.postMessage(matches);
                    } catch (error) {
                        parentPort.postMessage([]);
                    }
                }

                function getSnippet(text, keyword, contextLength = 100) {
                    const lowerText = text.toLowerCase();
                    const lowerKeyword = keyword.toLowerCase();
                    const startIndex = lowerText.indexOf(lowerKeyword);
                    
                    if (startIndex === -1) return null;
                    
                    const snippetStart = Math.max(0, startIndex - contextLength);
                    const snippetEnd = Math.min(text.length, startIndex + keyword.length + contextLength);
                    const snippet = text.substring(snippetStart, snippetEnd);
                    
                    return \`...\${snippet}...\`;
                }

                processFile();
            `;
            
            await fs.writeFile(workerPath, workerCode);
        });

        const worker = new Worker(workerPath, {
            workerData: { pdfPath, keywords }
        });
        
        worker.on('message', resolve);
        worker.on('error', reject);
        worker.on('exit', (code) => {
            if (code !== 0)
                reject(new Error(`Worker stopped with exit code ${code}`));
        });
    });
}

// Extract keyword matches from a PDF using parallel processing
const extractKeywordMatches = async (pdfPath, keywords) => {
    console.log(`Starting extraction of keywords in: ${pdfPath}`);
    
    try {
        await fs.access(pdfPath);
        
        if (path.extname(pdfPath).toLowerCase() !== '.pdf') {
            console.warn(`File is not a PDF: ${pdfPath}`);
            return [];
        }
        
        // Use worker thread to process PDF in parallel
        const matches = await processPdfInWorker(pdfPath, keywords);
        console.log(`Matches found in ${pdfPath}: ${matches.length}`);
        return matches;
    } catch (error) {
        console.error(`Error extracting keywords from PDF: ${pdfPath}`, error);
        return [];
    }
};

// Search endpoint with optimized full-text search
app.get('/search', async (req, res) => {
    const { keyword, exclude } = req.query;

    if (!keyword || keyword.trim() === '') {
        return res.status(400).json({ error: 'No search keyword provided.' });
    }

    const cacheKey = `search:${keyword}:${exclude || 'noexclude'}`;
    const cachedResults = searchCache.get(cacheKey);

    if (cachedResults) {
        console.log(`Cache HIT for key: ${cacheKey}`);
        return res.json(cachedResults);
    }

    console.log(`Cache MISS for key: ${cacheKey}`);

    try {
        await poolConnect;
        console.log('Database connection established.');

        // Extract quoted phrases
        const quotedPhrases = [];
        let remainingKeyword = keyword;
        const quoteRegex = /"([^"]*)"/g;
        let match;
        
        while ((match = quoteRegex.exec(keyword)) !== null) {
            if (match[1].trim()) {
                quotedPhrases.push(match[1].trim());
            }
            // Remove the quoted phrase from remaining keyword
            remainingKeyword = remainingKeyword.replace(match[0], '');
        }
        
        // Get individual terms from remaining text
        const terms = remainingKeyword
            .replace(/[^\w\s\+\-]/g, '')
            .trim()
            .split(/\s+/)
            .filter(Boolean);
        
        // Build CONTAINS expression for SQL full-text search
        let containsExpr = '';
        
        // Add quoted phrases as exact matches
        quotedPhrases.forEach((phrase, index) => {
            if (containsExpr) containsExpr += ' AND ';
            containsExpr += `"${phrase}"`;
        });
        
        // Add individual terms
        terms.forEach(term => {
            if (containsExpr) containsExpr += ' AND ';
            containsExpr += term;
        });
        
        // Handle excluded terms
        if (exclude && exclude.trim() !== '') {
            const excludedWords = exclude.split(/\s+/).filter(Boolean);
            excludedWords.forEach(word => {
                containsExpr += ` AND NOT "${word}"`;
            });
        }
        
        // Build the SQL query using full-text search
        const request = pool.request();
        request.input('searchTerms', sql.NVarChar, containsExpr);
        
        const query = `
            SELECT Filename 
            FROM indexed_files 
            WHERE CONTAINS(PdfData, @searchTerms)
        `;
        
        console.log('Executing SQL Query:', query);
        console.log('Search terms:', containsExpr);
        
        const result = await request.query(query);
        console.log(`Total files to process: ${result.recordset.length}`);

        const responseData = [];
        const BATCH_SIZE = getOptimalBatchSize();  // Dynamic batch size based on system resources
        console.log(`Using batch size: ${BATCH_SIZE}`);
        
        let fileProcessingPromises = [];

        for (let i = 0; i < result.recordset.length; i++) {
            const record = result.recordset[i];
            const fullPath = record.Filename;

            console.log(`Processing file ${i+1}/${result.recordset.length}: ${fullPath}`);

            if (path.extname(fullPath).toLowerCase() !== '.pdf') {
                console.log(`Skipping non-PDF file: ${fullPath}`);
                continue;
            }

            const relativePath = fullPath.replace('\\\\192.168.13.30\\c$\\GGN Office Repository\\', '');
            const absolutePath = path.join('\\\\192.168.13.30\\c$\\GGN Office Repository', relativePath);

            // Combine quoted phrases and terms for keyword extraction
            const searchTerms = [...terms, ...quotedPhrases];

            fileProcessingPromises.push(
                extractKeywordMatches(absolutePath, searchTerms).then(matches => {
                    if (matches.length > 0) {
                        console.log(`Matches found for file: ${fullPath}`);
                        return {
                            Filename: fullPath,
                            relativePath,
                            matches,
                        };
                    }
                    return null;
                }).catch(error => {
                    console.error(`Error processing file ${fullPath}:`, error);
                    return null;
                })
            );

            if (fileProcessingPromises.length >= BATCH_SIZE || i === result.recordset.length - 1) {
                const results = await Promise.all(fileProcessingPromises);
                responseData.push(...results.filter(record => record));
                fileProcessingPromises = []; // Reset for the next batch
                console.log(`Processed batch of ${BATCH_SIZE} files. Total results so far: ${responseData.length}`);
            }
        }

        console.log(`Search completed. Found ${responseData.length} files with matches.`);
        searchCache.set(cacheKey, responseData);
        res.json(responseData);

    } catch (error) {
        console.error('Error processing search:', error);
        res.status(500).json({ error: 'An error occurred while processing your search.' });
    }
});

// File serving
app.get('/files/*', (req, res) => {
    const relativePath = req.params[0];
    const basePath = '\\\\192.168.13.30\\c$\\GGN Office Repository';
    const filePath = path.join(basePath, relativePath);

    console.log(`Requesting information for: ${filePath}`);

    fs.stat(filePath)
        .then(stats => {
            if (stats.isDirectory()) {
                console.log(`Accessing directory: ${filePath}`);
                return fs.readdir(filePath)
                    .then(files => {
                        const fileLinks = files.map(file => {
                            return `<li><a href="/files/${path.join(relativePath, file).replace(/\\/g, '/')}">${file}</a></li>`;
                        }).join('');

                        res.send(`
                            <h1>Contents of ${relativePath}</h1>
                            <ul>${fileLinks}</ul>
                        `);
                    });
            } else if (stats.isFile()) {
                console.log(`Sending file: ${filePath}`);
                res.sendFile(filePath, (err) => {
                    if (err) {
                        console.error(`Error sending file: ${filePath}`, err);
                        res.status(500).json({ error: 'Error sending file' });
                    }
                });
            } else {
                console.warn(`Path is neither a file nor a directory: ${filePath}`);
                res.status(400).json({ error: 'Neither a file nor a directory' });
            }
        })
        .catch(err => {
            console.error(`Error accessing path: ${filePath}`, err);
            res.status(404).json({ error: 'Path not found or inaccessible' });
        });
});

const PORT = process.env.PORT || 3006;
app.listen(PORT, '192.168.7.181', () => {
    console.log(`Server running at http://192.168.2.5:${PORT}`);
});    also in my sql manager ihave a database IndexDB inside which i have a table indexed_files still getting this