Công Nghệ | Mục Đích |
---|---|
Next.js | Framework React hỗ trợ SSR và API routes |
React | Xây dựng giao diện người dùng |
Tailwind CSS | Framework CSS tiện ích để phát triển UI nhanh |
Sentry | Giám sát lỗi và hiệu suất ứng dụng |
NextUI | Thư viện UI React bổ sung (không bắt buộc) |
AI Model API | Dịch vụ sinh ảnh từ mô tả văn bản |
npm install tailwindcss@latest @sentry/nextjs@latest nextuinpx tailwindcss init -p
module.exports = { content: [ "./pages/**/*.{js,ts,jsx,tsx}", "./components/**/*.{js,ts,jsx,tsx}", ], theme: { extend: {} }, plugins: [],};
@tailwind base;@tailwind components;@tailwind utilities;
pages/index.js
:import { useState } from 'react';
export default function Home() { const [prompt, setPrompt] = useState(''); const [imageUrl, setImageUrl] = useState(''); const [loading, setLoading] = useState(false);
const generateImage = async () => { setLoading(true); const res = await fetch('/api/generate-image', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt }), }); const data = await res.json(); setImageUrl(data.imageUrl); setLoading(false); };
return ( <div className="min-h-screen flex flex-col items-center justify-center bg-gray-100 p-4"> <h1 className="text-3xl font-bold mb-4">NSFW AI Text-to-Image Generator</h1> <textarea className="w-80 p-2 border border-gray-300 rounded mb-4" placeholder="Nhập mô tả văn bản..." value={prompt} onChange={(e) => setPrompt(e.target.value)} /> <button className="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700 disabled:opacity-50" onClick={generateImage} disabled={loading || !prompt.trim()} > {loading ? 'Đang tạo ảnh...' : 'Tạo ảnh'} </button> {imageUrl && ( <div className="mt-4"> <img src={imageUrl} alt="Ảnh tạo từ AI" className="max-w-xs rounded shadow" /> </div> )} </div> );}
pages/api/generate-image.js
:export default async function handler(req, res) { if (req.method !== 'POST') { return res.status(405).json({ error: 'Phương thức không được hỗ trợ' }); }
const { prompt } = req.body;
try { const response = await fetch('https://api.example.com/v1/generate-image', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.AI_API_KEY}`, }, body: JSON.stringify({ prompt }), });
const data = await response.json();
if (!data || !data.imageUrl) { throw new Error('Không nhận được ảnh từ API'); }
return res.status(200).json({ imageUrl: data.imageUrl }); } catch (error) { console.error('Lỗi tạo ảnh:', error); return res.status(500).json({ error: 'Tạo ảnh thất bại' }); }}
.env.local
với nội dung:AI_API_KEY=your_actual_api_key_here
.env.local
vào .gitignore
để bảo mật.npm install @sentry/nextjs
sentry.client.config.js
:import * as Sentry from '@sentry/nextjs';
Sentry.init({ dsn: process.env.SENTRY_DSN, tracesSampleRate: 1.0,});
sentry.server.config.js
.import * as Sentry from '@sentry/nextjs';
try { // Mã có thể gây lỗi} catch (error) { Sentry.captureException(error); console.error(error);}