Certainly! Below is the complete code for each file in the ChatGPT-like web application with React for the frontend and Node.js (Express) for the backend, including enhancements for file uploads, error handling, and UI improvements.

---

## Project Structure

```
/chatgpt-app
├── /chatgpt-backend
│   ├── config/
│   │   └── config.js
│   ├── controllers/
│   │   └── ChatController.js
│   ├── routes/
│   │   └── chatRoutes.js
│   ├── uploads/
│   ├── node_modules/
│   ├── .env
│   ├── .gitignore
│   ├── index.js
│   ├── package.json
│   └── package-lock.json
└── /chatgpt-react-app
    ├── node_modules/
    ├── public/
    │   ├── index.html
    ├── src/
    │   ├── components/
    │   │   ├── FileUpload.jsx
    │   │   ├── FileUpload.css
    │   │   ├── Message.jsx
    │   │   ├── Message.css
    │   ├── App.jsx
    │   ├── App.css
    │   ├── index.js
    ├── .env
    ├── .gitignore
    ├── package.json
    └── package-lock.json
```

---

## Backend Code (Node.js + Express)

### 1. chatgpt-backend/config/config.js

```javascript
const dotenv = require('dotenv');
dotenv.config();

const SUPPORTED_MODELS = process.env.SUPPORTED_MODELS ? process.env.SUPPORTED_MODELS.split(',').map(model => model.trim()) : ['gpt-3.5-turbo'];

module.exports = {
    OPENAI_API_KEY: process.env.OPENAI_API_KEY,
    PORT: process.env.PORT || 5000,
    FRONTEND_URL: process.env.FRONTEND_URL || 'http://localhost:3000',
    SUPPORTED_MODELS,
};
```

### 2. chatgpt-backend/controllers/ChatController.js

```javascript
const axios = require('axios');
const fs = require('fs');
const path = require('path');
const pdfParse = require('pdf-parse');
const { OPENAI_API_KEY, SUPPORTED_MODELS } = require('../config/config');

const chatWithGPT = async (req, res) => {
    const { message, model } = req.body;
    let imageDataUrls = [];
    let pdfTexts = [];
    
    if (!message && !req.file) {
        return res.status(400).json({ error: 'No message or file provided.' });
    }
    
    const selectedModel = model || 'gpt-3.5-turbo';
    if (!SUPPORTED_MODELS.includes(selectedModel)) {
        return res.status(400).json({ error: 'Unsupported model selected.' });
    }

    if (req.file) {
        const file = req.file;
        const filePath = path.join(__dirname, '..', 'uploads', file.filename);
        try {
            if (file.mimetype.startsWith('image/')) {
                const imageBuffer = fs.readFileSync(filePath);
                const base64Image = imageBuffer.toString('base64');
                const dataUrl = `data:${file.mimetype};base64,${base64Image}`;
                imageDataUrls.push(dataUrl);
            } else if (file.mimetype === 'application/pdf') {
                const pdfBuffer = fs.readFileSync(filePath);
                const pdfData = await pdfParse(pdfBuffer);
                const text = pdfData.text.trim();
                if (text.length > 0) {
                    pdfTexts.push(text);
                } else {
                    return res.status(400).json({ error: 'PDF contains no extractable text.' });
                }
            }
        } catch (err) {
            console.error('Error processing uploaded file:', err);
            return res.status(500).json({ error: 'Failed to process the uploaded file.' });
        }
    }

    const messagesToSend = [];
    if (message) {
        messagesToSend.push({ role: 'user', content: message });
    }

    imageDataUrls.forEach((dataUrl) => {
        messagesToSend.push({
            role: 'user',
            content: [
                { type: 'text', text: 'Here is an image for you to analyze.' },
                { type: 'image_url', image_url: { url: dataUrl, detail: 'high' } },
            ],
        });
    });

    pdfTexts.forEach((text) => {
        messagesToSend.push({ role: 'user', content: text });
    });

    try {
        const response = await axios.post(
            'https://api.openai.com/v1/chat/completions',
            { model: selectedModel, messages: messagesToSend, temperature: 0.7 },
            { headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${OPENAI_API_KEY}` } }
        );
        const botReply = response.data.choices[0].message.content.trim();
        res.json({ reply: botReply });
    } catch (error) {
        console.error('Error communicating with OpenAI:', error.response?.data || error.message);
        res.status(500).json({ error: 'Failed to fetch response from OpenAI.' });
    }
};

module.exports = { chatWithGPT };
```

### 3. chatgpt-backend/routes/chatRoutes.js

```javascript
const express = require('express');
const { chatWithGPT } = require('../controllers/ChatController');
const { SUPPORTED_MODELS } = require('../config/config');
const multer = require('multer');
const { v4: uuidv4 } = require('uuid');

const router = express.Router();

const storage = multer.diskStorage({
    destination: (req, file, cb) => {
        cb(null, 'uploads/');
    },
    filename: (req, file, cb) => {
        const uniqueSuffix = uuidv4();
        const extension = path.extname(file.originalname);
        cb(null, `${uniqueSuffix}${extension}`);
    },
});

const ALLOWED_MIME_TYPES = [
    'image/jpeg',
    'image/png',
    'image/gif',
    'application/pdf',
];

const upload = multer({
    storage: storage,
    limits: { fileSize: 10 * 1024 * 1024 },
    fileFilter: (req, file, cb) => {
        if (ALLOWED_MIME_TYPES.includes(file.mimetype)) {
            cb(null, true);
        } else {
            cb(new multer.MulterError('LIMIT_UNEXPECTED_FILE', 'Only JPEG, PNG, GIF images and PDF files are allowed!'));
        }
    },
});

router.post('/chat', upload.single('file'), chatWithGPT);

router.get('/models', (req, res) => {
    res.json({ models: SUPPORTED_MODELS });
});

// Error handling middleware
router.use((err, req, res, next) => {
    if (err instanceof multer.MulterError) {
        if (err.code === 'LIMIT_FILE_SIZE') {
            return res.status(400).json({ error: 'File size exceeds the limit of 10MB.' });
        }
        if (err.code === 'LIMIT_UNEXPECTED_FILE') {
            return res.status(400).json({ error: err.message });
        }
    }
    console.error('Unhandled error:', err);
    res.status(500).json({ error: 'An unexpected error occurred.' });
});

module.exports = router;
```

### 4. chatgpt-backend/index.js

```javascript
const express = require('express');
const cors = require('cors');
const chatRoutes = require('./routes/chatRoutes');
const { PORT, FRONTEND_URL } = require('./config/config');
const path = require('path');

const app = express();

// Middleware
app.use(cors({ origin: FRONTEND_URL, optionsSuccessStatus: 200 }));
app.use(express.json());
app.use('/uploads', express.static(path.join(__dirname, 'uploads')));

// Routes
app.use('/api', chatRoutes);

// Test Route
app.get('/', (req, res) => {
    res.send('ChatGPT Backend is Running');
});

// Error handling middleware for general errors
app.use((err, req, res, next) => {
    console.error(err.stack);
    res.status(500).send('Something broke!');
});

// Start Server
app.listen(PORT, () => {
    console.log(`Server is running on http://localhost:${PORT}`);
});
```

### 5. chatgpt-backend/.env

```
OPENAI_API_KEY=your_openai_api_key_here
PORT=5000
FRONTEND_URL=http://localhost:3000
SUPPORTED_MODELS=gpt-3.5-turbo,gpt-4
```

### 6. chatgpt-backend/.gitignore

```
node_modules/
uploads/
.env
```

---

## Frontend Code (React)

### 1. chatgpt-react-app/src/components/FileUpload.jsx

```javascript
import React from 'react';
import { useDropzone } from 'react-dropzone';
import './FileUpload.css';

const FileUpload = ({ onFileDrop }) => {
    const { getRootProps, getInputProps, isDragActive } = useDropzone({
        accept: {
            'image/jpeg': ['.jpeg', '.jpg'],
            'image/png': ['.png'],
            'image/gif': ['.gif'],
            'application/pdf': ['.pdf'],
        },
        multiple: false,
        onDrop: (acceptedFiles) => {
            if (acceptedFiles && acceptedFiles.length > 0) {
                onFileDrop(acceptedFiles[0]);
            }
        },
    });

    return (
        <div {...getRootProps()} className={`dropzone ${isDragActive ? 'active' : ''}`}>
            <input {...getInputProps()} />
            {isDragActive ? (
                <p>Drop the file here...</p>
            ) : (
                <p>Drag & drop an image or PDF here, or click to select one</p>
            )}
        </div>
    );
};

export default FileUpload;
```

### 2. chatgpt-react-app/src/components/FileUpload.css

```css
.dropzone {
    border: 2px dashed #cccccc;
    border-radius: 10px;
    padding: 20px;
    text-align: center;
    color: #666666;
    cursor: pointer;
    transition: border-color 0.3s ease;
    margin-bottom: 15px;
}

.dropzone.active {
    border-color: #4caf50;
    color: #4caf50;
}
```

### 3. chatgpt-react-app/src/components/Message.jsx

```javascript
import React from 'react';
import ReactMarkdown from 'react-markdown';
import remarkMath from 'remark-math';
import rehypeKatex from 'rehype-katex';
import 'katex/dist/katex.min.css';
import './Message.css';

const Message = ({ content, isUser }) => {
    const isImage = (typeof content === 'string' && content.startsWith('data:image/')) ||
                    (content && content.type === 'image_url');

    return (
        <div className={`message ${isUser ? 'user' : 'bot'}`}>
            {isImage ? (
                <img src={content} alt="User uploaded" className="message-image" />
            ) : (
                <ReactMarkdown children={content} remarkPlugins={[remarkMath]} rehypePlugins={[rehypeKatex]} />
            )}
        </div>
    );
};

export default Message;
```

### 4. chatgpt-react-app/src/components/Message.css

```css
.message {
    margin-bottom: 15px;
    max-width: 80%;
    padding: 10px;
    border-radius: 10px;
}

.message.user {
    align-self: flex-end;
    background-color: #daf1da;
}

.message.bot {
    align-self: flex-start;
    background-color: #ffffff;
}

.message-image {
    max-width: 100%;
    border-radius: 10px;
}
```

### 5. chatgpt-react-app/src/App.jsx

```javascript
import React, { useState, useRef, useEffect } from 'react';
import axios from 'axios';
import Message from './components/Message';
import FileUpload from './components/FileUpload';
import './App.css';

function App() {
    const [messages, setMessages] = useState([{ content: 'Hello! How can I assist you today?', isUser: false }]);
    const [input, setInput] = useState('');
    const [file, setFile] = useState(null);
    const [loading, setLoading] = useState(false);
    const [selectedModel, setSelectedModel] = useState('');
    const [availableModels, setAvailableModels] = useState([]);
    const [error, setError] = useState('');
    const chatWindowRef = useRef(null);

    useEffect(() => {
        const fetchModels = async () => {
            try {
                const response = await axios.get(`${process.env.REACT_APP_BACKEND_URL}/api/models`);
                setAvailableModels(response.data.models);
                setSelectedModel(response.data.models[0]);
            } catch (error) {
                console.error('Error fetching models:', error);
            }
        };
        fetchModels();
    }, []);

    const sendMessage = async () => {
        if (input.trim() === '' && !file) return;
        if (!selectedModel) return;

        const userMessages = [];
        if (input.trim() !== '') {
            userMessages.push({ content: input, isUser: true });
        }

        if (file) {
            userMessages.push({ content: `User uploaded a file: ${file.name}`, isUser: true });
        }

        setMessages((prev) => [...prev, ...userMessages]);
        setInput('');
        setFile(null);
        setLoading(true);
        setError('');

        const formData = new FormData();
        formData.append('model', selectedModel);
        if (input.trim() !== '') {
            formData.append('message', input);
        }
        if (file) {
            formData.append('file', file);
        }

        try {
            const response = await axios.post(`${process.env.REACT_APP_BACKEND_URL}/api/chat`, formData, {
                headers: { 'Content-Type': 'multipart/form-data' }
            });
            const botMessage = { content: response.data.reply, isUser: false };
            setMessages((prev) => [...prev, botMessage]);
        } catch (error) {
            console.error('Error fetching response:', error);
            let errorMsg = 'Sorry, there was an error processing your request.';
            if (error.response && error.response.data && error.response.data.error) {
                errorMsg = error.response.data.error;
            }
            setError(errorMsg);
            const errorMessage = { content: errorMsg, isUser: false };
            setMessages((prev) => [...prev, errorMessage]);
        } finally {
            setLoading(false);
        }
    };

    const handleKeyPress = (e) => {
        if (e.key === 'Enter' && !e.shiftKey) {
            e.preventDefault();
            sendMessage();
        }
    };

    const handleFileDrop = (droppedFile) => {
        setFile(droppedFile);
    };

    useEffect(() => {
        if (chatWindowRef.current) {
            chatWindowRef.current.scrollTop = chatWindowRef.current.scrollHeight;
        }
    }, [messages, loading]);

    return (
        <div className="app">
            <div className="settings">
                <label htmlFor="model-select">Select Model:</label>
                <select id="model-select" value={selectedModel} onChange={(e) => setSelectedModel(e.target.value)} disabled={loading || availableModels.length === 0}>
                    {availableModels.map((model) => (
                        <option key={model} value={model}>
                            {model === 'gpt-3.5-turbo' ? 'GPT-3.5 Turbo' : 'GPT-4'}
                        </option>
                    ))}
                </select>
            </div>
            <div className="chat-window" ref={chatWindowRef}>
                {messages.map((msg, index) => (
                    <Message key={index} content={msg.content} isUser={msg.isUser} />
                ))}
                {loading && <div className="loading">Loading...</div>}
                {error && <div className="error-message">{error}</div>}
            </div>
            <div className="input-area">
                <FileUpload onFileDrop={handleFileDrop} />
                <textarea placeholder="Type your message..." value={input} onChange={(e) => setInput(e.target.value)} onKeyPress={handleKeyPress} rows={2} disabled={loading} />
                <button onClick={sendMessage} disabled={loading}> Send </button>
            </div>
        </div>
    );
}

export default App;
```

### 6. chatgpt-react-app/src/App.css

```css
.app {
    display: flex;
    flex-direction: column;
    height: 100vh;
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background-color: #e5ddd5;
}

.settings {
    padding: 10px;
    background-color: #ddd;
    display: flex;
    align-items: center;
}

.settings label {
    margin-right: 10px;
    font-weight: bold;
}

.settings select {
    padding: 5px;
    border: 1px solid #ccc;
    border-radius: 4px;
}

.chat-window {
    flex: 1;
    padding: 20px;
    overflow-y: auto;
    background-color: #f5f5f5;
}

.message {
    margin-bottom: 15px;
    max-width: 80%;
    padding: 10px;
    border-radius: 10px;
}

.message.user {
    align-self: flex-end;
    background-color: #daf1da;
}

.message.bot {
    align-self: flex-start;
    background-color: #ffffff;
}

.message-image {
    max-width: 100%;
    border-radius: 10px;
}

.input-area {
    display: flex;
    flex-direction: column;
    padding: 10px;
    background-color: #ddd;
}

.input-area textarea {
    width: 100%;
    padding: 10px;
    border: none;
    border-radius: 5px;
    resize: none;
    font-family: inherit;
    margin-bottom: 10px;
}

.input-area button {
    align-self: flex-end;
    padding: 10px 20px;
    border: none;
    background-color: #4caf50;
    color: white;
    border-radius: 5px;
    cursor: pointer;
    transition: background-color 0.3s ease;
}

.input-area button:hover:not(:disabled) {
    background-color: #45a049;
}

.input-area button:disabled {
    background-color: #9e9e9e;
    cursor: not-allowed;
}

/* Scrollbar Styling */
.chat-window::-webkit-scrollbar {
    width: 8px;
}

.chat-window::-webkit-scrollbar-track {
    background: #f1f1f1;
}

.chat-window::-webkit-scrollbar-thumb {
    background: #888;
    border-radius: 4px;
}

.chat-window::-webkit-scrollbar-thumb:hover {
    background: #555;
}

/* Loading Indicator */
.loading {
    text-align: center;
    color: #555;
    font-style: italic;
    margin-top: 10px;
}

/* Error Message Styling */
.error-message {
    color: red;
    text-align: center;
    margin-top: 10px;
    font-weight: bold;
}
```

### 7. chatgpt-react-app/src/index.js

```javascript
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css';

ReactDOM.render(
    <React.StrictMode>
        <App />
    </React.StrictMode>,
    document.getElementById('root')
);
```

### 8. chatgpt-react-app/.env

```
REACT_APP_BACKEND_URL=http://localhost:5000
```

### 9. chatgpt-react-app/.gitignore

```
node_modules/
.env
build/
```

---

## Installation and Set-Up Guide

Once you've created the folder structure and added all the above files into their respective folders, follow these steps to set up both the backend and frontend applications:

### Prerequisites

Ensure you have the following installed on your system:

- Node.js (v18.x or higher)
- npm (comes with Node.js)
- Git

### Backend Setup (Node.js)

1. **Navigate to the `chatgpt-backend` directory**:
    ```bash
    cd ~/Documents/Code/chatgpt-backend
    ```

2. **Install the required dependencies**:
    ```bash
    npm install express cors axios dotenv multer pdf-parse uuid
    ```

3. **Start the backend server**:
    ```bash
    npm run dev
    ```

   You should see:
   ```
   Server is running on http://localhost:5000
   ```

### Frontend Setup (React)

1. **Navigate to the `chatgpt-react-app` directory**:
    ```bash
    cd ~/Documents/Code/chatgpt-react-app
    ```

2. **Install the required dependencies**:
    ```bash
    npm install axios react-dropzone react-markdown remark-math rehype-katex katex
    ```

3. **Start the frontend server**:
    ```bash
    npm start
    ```

   You should see the application open in your default web browser at `http://localhost:3000`.

### Testing File Uploads

1. **Test text messages**: Type a simple message and click "Send".
2. **Upload images**: Drag and drop an image file and send it.
3. **Upload PDFs**: Drag and drop a PDF file and send it.
4. **Check for unsupported file types**: Attempt to upload a file type not allowed and see the appropriate error message.

---

### Conclusion
You've created a full-fledged ChatGPT-like application that handles text, images, and PDFs, complete with error handling and UI enhancements. These enhancements improve usability and enrich the user experience while engaging with your application.

If you have further questions or need assistance with specific features, feel free to ask!

make the ui look better and files uploaded are not shown, fix that