Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file modified .devcontainer/install-dependencies.sh
100644 β†’ 100755
Empty file.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,6 @@ AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false

VITE_APP_NAME="${APP_NAME}"

# OpenAI API Key for Chat Helper
OPENAI_API_KEY=
41 changes: 41 additions & 0 deletions CHAT_HELPER_README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Chat Helper Feature

This feature adds a simple chat interface where users can ask questions about PHP and web development, and get responses from an AI assistant.

## Features

- Simple chat interface with plain HTML and JavaScript
- No authentication required - all messages are public
- Integration with OpenAI's GPT model for intelligent responses
- Focused on PHP and web development questions

## Setup

1. Make sure you have an OpenAI API key. If you don't have one, you can get it from [OpenAI's website](https://platform.openai.com/).

2. Add your OpenAI API key to the `.env` file:
```
OPENAI_API_KEY=your_api_key_here
```

3. The chat helper is available at the `/chat-helper` route.

## How It Works

1. Users can visit the `/chat-helper` page without authentication
2. They can type their PHP or web development questions in the input field
3. The question is sent to the server, which forwards it to OpenAI's API
4. The AI response is displayed in the chat interface

## Technical Implementation

- The feature uses a simple Blade template for the frontend (no React)
- JavaScript fetch API is used to communicate with the backend
- The backend uses Laravel's HTTP client to communicate with OpenAI
- The AI is instructed to only answer PHP and web development questions

## Limitations

- The AI will respond with "I can't help you" for questions not related to PHP or web development
- All messages are public and visible to everyone
- There's no message history persistence (messages are lost on page refresh)
74 changes: 74 additions & 0 deletions app/Http/Controllers/ChatHelperController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;

class ChatHelperController extends Controller
{
/**
* Send a message to OpenAI and get a response
*
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function sendMessage(Request $request)
{
$request->validate([
'message' => 'required|string|max:1000',
]);

$userMessage = $request->input('message');

// Prepare the prompt for OpenAI
$prompt = "You are PHP developer assistant. Answer only to questions related to PHP and Web development. Answer shortly. If question is not relevant answer with one phrase \"I can't help you\". There is the user message: \n$userMessage";

try {
// Get API key from environment
$apiKey = env('OPENAI_API_KEY');

if (!$apiKey) {
return response()->json([
'error' => 'OpenAI API key not configured'
], 500);
}

// Call OpenAI API
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . $apiKey,
'Content-Type' => 'application/json',
])->post('https://api.openai.com/v1/chat/completions', [
'model' => 'gpt-3.5-turbo',
'messages' => [
[
'role' => 'system',
'content' => 'You are PHP developer assistant. Answer only to questions related to PHP and Web development. Answer shortly. If question is not relevant answer with one phrase "I can\'t help you".'
],
[
'role' => 'user',
'content' => $userMessage
]
],
'temperature' => 0.7,
]);

if ($response->successful()) {
$aiResponse = $response->json()['choices'][0]['message']['content'] ?? 'Sorry, I could not generate a response.';

return response()->json([
'message' => $userMessage,
'response' => $aiResponse
]);
} else {
return response()->json([
'error' => 'Failed to get response from OpenAI: ' . ($response->json()['error']['message'] ?? 'Unknown error')
], $response->status());
}
} catch (\Exception $e) {
return response()->json([
'error' => 'An error occurred: ' . $e->getMessage()
], 500);
}
}
}
218 changes: 218 additions & 0 deletions resources/views/chat-helper.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>Chat Helper - {{ config('app.name', 'Laravel') }}</title>
<style>
body {
font-family: 'Instrument Sans', sans-serif;
line-height: 1.6;
margin: 0;
padding: 20px;
color: #333;
background-color: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
padding: 20px;
}
h1 {
text-align: center;
margin-bottom: 20px;
}
.chat-container {
height: 400px;
overflow-y: auto;
border: 1px solid #ddd;
border-radius: 4px;
padding: 10px;
margin-bottom: 20px;
background-color: #f9f9f9;
}
.message {
margin-bottom: 15px;
padding: 10px;
border-radius: 4px;
}
.user-message {
background-color: #e3f2fd;
margin-left: 20px;
border-left: 4px solid #2196F3;
}
.ai-message {
background-color: #f1f8e9;
margin-right: 20px;
border-left: 4px solid #8bc34a;
}
.message-form {
display: flex;
gap: 10px;
}
.message-input {
flex-grow: 1;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px;
}
.send-button {
padding: 10px 20px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
.send-button:hover {
background-color: #45a049;
}
.message-header {
font-weight: bold;
margin-bottom: 5px;
}
.loading {
text-align: center;
padding: 10px;
font-style: italic;
color: #666;
display: none;
}
.error {
color: #f44336;
margin-top: 10px;
padding: 10px;
background-color: #ffebee;
border-radius: 4px;
display: none;
}
.home-link {
display: block;
text-align: center;
margin-top: 20px;
color: #2196F3;
text-decoration: none;
}
.home-link:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<h1>Chat with PHP Assistant</h1>

<div class="chat-container" id="chatContainer">
<div class="message ai-message">
<div class="message-header">PHP Assistant:</div>
<div>Hello! I'm your PHP development assistant. Ask me any questions about PHP or web development.</div>
</div>
</div>

<div class="loading" id="loading">Thinking...</div>
<div class="error" id="errorMessage"></div>

<form class="message-form" id="messageForm">
<input type="text" class="message-input" id="messageInput" placeholder="Type your question here..." required>
<button type="submit" class="send-button">Send</button>
</form>

<a href="{{ route('home') }}" class="home-link">Back to Home</a>
</div>

<script>
document.addEventListener('DOMContentLoaded', function() {
const messageForm = document.getElementById('messageForm');
const messageInput = document.getElementById('messageInput');
const chatContainer = document.getElementById('chatContainer');
const loading = document.getElementById('loading');
const errorMessage = document.getElementById('errorMessage');

// Get CSRF token
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');

messageForm.addEventListener('submit', function(e) {
e.preventDefault();

const message = messageInput.value.trim();
if (!message) return;

// Add user message to chat
addMessage('You', message, 'user-message');

// Clear input
messageInput.value = '';

// Show loading indicator
loading.style.display = 'block';
errorMessage.style.display = 'none';

// Send message to server
fetch('{{ route("chat-helper.send") }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': csrfToken
},
body: JSON.stringify({ message: message })
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
// Hide loading indicator
loading.style.display = 'none';

// Add AI response to chat
if (data.response) {
addMessage('PHP Assistant', data.response, 'ai-message');
} else if (data.error) {
showError(data.error);
}
})
.catch(error => {
// Hide loading indicator
loading.style.display = 'none';

// Show error
showError('Failed to send message: ' + error.message);
});
});

function addMessage(sender, content, className) {
const messageDiv = document.createElement('div');
messageDiv.className = 'message ' + className;

const headerDiv = document.createElement('div');
headerDiv.className = 'message-header';
headerDiv.textContent = sender + ':';

const contentDiv = document.createElement('div');
contentDiv.textContent = content;

messageDiv.appendChild(headerDiv);
messageDiv.appendChild(contentDiv);

chatContainer.appendChild(messageDiv);

// Scroll to bottom
chatContainer.scrollTop = chatContainer.scrollHeight;
}

function showError(message) {
errorMessage.textContent = message;
errorMessage.style.display = 'block';
}
});
</script>
</body>
</html>
8 changes: 8 additions & 0 deletions routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,13 @@
})->name('dashboard');
});

// Chat Helper route - no auth required
Route::get('/chat-helper', function () {
return view('chat-helper');
})->name('chat-helper');

// Chat API endpoint
Route::post('/chat-helper/send', 'App\Http\Controllers\ChatHelperController@sendMessage')->name('chat-helper.send');

require __DIR__.'/settings.php';
require __DIR__.'/auth.php';