Spaces:
Running
Running
| import React, { useState, useEffect } from 'react'; | |
| import axios from 'axios'; | |
| const filterOptions = ["real", "ai", "futanari", "vanilla"]; | |
| const SearchPage = () => { | |
| const [query, setQuery] = useState(''); | |
| const [filters, setFilters] = useState({ | |
| real: true, ai: true, futanari: false, vanilla: false, | |
| }); | |
| const [result, setResult] = useState(null); | |
| const [history, setHistory] = useState([]); | |
| const token = localStorage.getItem("token"); | |
| const runSearch = async (customQuery) => { | |
| try { | |
| const res = await axios.post( | |
| "https://your-hf-space.hf.space/search", | |
| { query: customQuery || query, filters }, | |
| { headers: { Authorization: `Bearer ${token}` } } | |
| ); | |
| setResult(res.data); | |
| } catch { | |
| alert("Error or Unauthorized."); | |
| } | |
| }; | |
| useEffect(() => { | |
| const fetchHistory = async () => { | |
| try { | |
| const res = await axios.get("https://your-hf-space.hf.space/history", { | |
| headers: { Authorization: `Bearer ${token}` }, | |
| }); | |
| setHistory(res.data); | |
| } catch { | |
| // ignore | |
| } | |
| }; | |
| fetchHistory(); | |
| }, [token]); | |
| const handleCheckbox = (e) => { | |
| const { name, checked } = e.target; | |
| setFilters((prev) => ({ ...prev, [name]: checked })); | |
| }; | |
| const clearHistory = async () => { | |
| if (!window.confirm("Are you sure you want to clear your search history?")) return; | |
| try { | |
| await axios.delete("https://your-hf-space.hf.space/history", { | |
| headers: { Authorization: `Bearer ${token}` }, | |
| }); | |
| setHistory([]); | |
| } catch { | |
| alert("Could not clear history."); | |
| } | |
| }; | |
| return ( | |
| <div className="max-w-2xl mx-auto p-6"> | |
| <h1 className="text-3xl font-bold mb-6">NSFW AI Search</h1> | |
| <div className="mb-4"> | |
| <h3 className="text-sm font-semibold mb-1">Filters:</h3> | |
| <div className="flex flex-wrap gap-4"> | |
| {filterOptions.map((f) => ( | |
| <label key={f} className="flex items-center gap-1 text-sm"> | |
| <input | |
| type="checkbox" | |
| name={f} | |
| checked={filters[f]} | |
| onChange={handleCheckbox} | |
| className="accent-purple-600" | |
| /> | |
| {f.charAt(0).toUpperCase() + f.slice(1)} | |
| </label> | |
| ))} | |
| </div> | |
| </div> | |
| <div className="flex space-x-4 mb-4"> | |
| <input | |
| type="text" | |
| placeholder="Enter fantasy or prompt" | |
| className="flex-1 px-4 py-2 border rounded-lg" | |
| value={query} onChange={e => setQuery(e.target.value)} | |
| /> | |
| <button | |
| className="bg-purple-600 text-white px-4 py-2 rounded-lg hover:bg-purple-700" | |
| onClick={() => runSearch()} | |
| > | |
| Search | |
| </button> | |
| </div> | |
| {result && ( | |
| <div className="bg-white rounded-xl p-4 shadow-md space-y-3"> | |
| <h2 className="text-xl font-bold">Preview:</h2> | |
| <img src={result.ai_preview} alt="AI preview" className="w-full rounded-xl" /> | |
| <h2 className="text-xl font-bold mt-4">Links:</h2> | |
| <ul> | |
| {result.results.map((r, idx) => ( | |
| <li key={idx}> | |
| <a href={r.url} target="_blank" className="text-blue-500 underline">{r.title}</a> | |
| </li> | |
| ))} | |
| </ul> | |
| </div> | |
| )} | |
| <div className="mt-8"> | |
| <div className="flex justify-between items-center mb-2"> | |
| <h2 className="text-xl font-semibold">Search History</h2> | |
| <button | |
| onClick={clearHistory} | |
| className="text-sm bg-red-500 text-white px-3 py-1 rounded hover:bg-red-600" | |
| > | |
| Clear History | |
| </button> | |
| </div> | |
| <ul className="space-y-1 text-sm"> | |
| {history.map((h, i) => ( | |
| <li | |
| key={i} | |
| onClick={() => { | |
| setQuery(h.query); | |
| runSearch(h.query); | |
| }} | |
| className="text-blue-600 cursor-pointer hover:underline flex justify-between items-center" | |
| > | |
| <span>{h.query}</span> | |
| <span className="text-gray-400 text-xs">{new Date(h.timestamp).toLocaleString()}</span> | |
| </li> | |
| ))} | |
| </ul> | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| export default SearchPage; | |