import { useState, useEffect } from "react"; import { useAuth } from "../contexts/AuthContext"; import { getNPCCharacters, createNPCCharacter, updateNPCCharacter, deleteNPCCharacter, } from "../services/api"; import { generateAvatarUrl } from "../services/imageGen"; import type { NPCCharacter, CharacterAge, CharacterGender } from "../types"; import "./NPCPage.css"; const AGE_OPTIONS: { value: CharacterAge; label: string }[] = [ { value: "child", label: "Ребёнок" }, { value: "teenager", label: "Подросток" }, { value: "adult", label: "Взрослый" }, { value: "elderly", label: "Пожилой" }, ]; const ROLE_OPTIONS = [ "Союзник", "Злодей", "Наставник", "Романс", "Нейтральный NPC", "Антагонист", "Комик", ]; const GENDER_OPTIONS: { value: CharacterGender; label: string }[] = [ { value: "female", label: "Женский" }, { value: "male", label: "Мужской" }, ]; export default function NPCPage() { const { user } = useAuth(); const [npcs, setNpcs] = useState([]); const [loading, setLoading] = useState(true); const [showForm, setShowForm] = useState(false); const [editingNpc, setEditingNpc] = useState(null); const [generatingAvatar, setGeneratingAvatar] = useState(false); // Форма const [name, setName] = useState(""); const [description, setDescription] = useState(""); const [role, setRole] = useState("Союзник"); const [age, setAge] = useState("adult"); const [gender, setGender] = useState("female"); const [isNsfw, setIsNsfw] = useState(false); const [avatarUrl, setAvatarUrl] = useState(""); const [customPrompt, setCustomPrompt] = useState(""); useEffect(() => { loadNPCs(); }, []); const loadNPCs = async () => { setLoading(true); const data = await getNPCCharacters(); setNpcs(data); setLoading(false); }; const resetForm = () => { setName(""); setDescription(""); setRole("Союзник"); setAge("adult"); setGender("female"); setIsNsfw(false); setAvatarUrl(""); setCustomPrompt(""); setEditingNpc(null); setShowForm(false); }; const openEditForm = (npc: NPCCharacter) => { setName(npc.name); setDescription(npc.description); setRole(npc.role); setAge(npc.age); setGender(npc.gender || "female"); setIsNsfw(npc.isNsfw || false); setAvatarUrl(npc.avatarUrl || ""); setEditingNpc(npc); setShowForm(true); }; const handleGenerateAvatar = async () => { // Если нет ни кастомного промпта, ни описания - ошибка if (!customPrompt.trim() && !description.trim()) { alert("Введите промпт или описание персонажа"); return; } setGeneratingAvatar(true); try { const url = await generateAvatarUrl({ description, name, age, gender, customPrompt: customPrompt.trim() || undefined, isNsfw, }); setAvatarUrl(url); } catch (error) { console.error("Ошибка генерации аватара:", error); alert("Ошибка генерации аватара: " + (error as Error).message); } finally { setGeneratingAvatar(false); } }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!name.trim() || !description.trim()) { alert("Заполните имя и описание"); return; } const npcData = { name: name.trim(), description: description.trim(), role, age, gender, isNsfw, avatarUrl: avatarUrl || undefined, }; if (editingNpc) { const success = await updateNPCCharacter(editingNpc.id, npcData); if (success) { await loadNPCs(); resetForm(); } else { alert("Ошибка обновления NPC"); } } else { const created = await createNPCCharacter(npcData); if (created) { await loadNPCs(); resetForm(); } else { alert("Ошибка создания NPC"); } } }; const handleDelete = async (id: string) => { if (!confirm("Удалить этого NPC?")) return; const success = await deleteNPCCharacter(id); if (success) { await loadNPCs(); } else { alert("Ошибка удаления"); } }; if (!user) { return (

Требуется авторизация

Войдите через Discord для доступа к NPC персонажам

); } return (

🎭 NPC Персонажи

Создавайте и управляйте NPC для ваших историй

{showForm && (
resetForm()}>
e.stopPropagation()}>

{editingNpc ? "Редактировать NPC" : "Создать NPC"}

setName(e.target.value)} placeholder="Введите имя..." required />