"use client" import type React from "react" import { useState, useEffect } from "react" import { Wand2, ArrowUp, Loader2, Maximize2, Minimize2 } from "lucide-react" import { Button } from "@/components/ui/button" import { Textarea } from "@/components/ui/textarea" import { ColorPanel } from "./color-panel" import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip" import { FullscreenToggle } from "./ui/fullscreen-toggle" import { AuthErrorPopup } from "./auth-error-popup" import { getInferenceToken } from "@/lib/auth" import posthog from 'posthog-js' interface PromptInputProps { onSubmit: (prompt: string, colors: string[]) => Promise; isLoading?: boolean; initialPrompt?: string; onImproveError?: (error: string | null) => void; } export function PromptInput({ onSubmit, isLoading = false, initialPrompt = "", onImproveError }: PromptInputProps) { const [prompt, setPrompt] = useState(initialPrompt); const [isImprovingPrompt, setIsImprovingPrompt] = useState(false); const [isFullScreen, setIsFullScreen] = useState(false); const [selectedColors, setSelectedColors] = useState([]); const [improveError, setImproveError] = useState(null); const [showAuthError, setShowAuthError] = useState(false); // Update prompt when initialPrompt changes useEffect(() => { setPrompt(initialPrompt); }, [initialPrompt]); // 当 improveError 改变时通知父组件 useEffect(() => { if (onImproveError) { onImproveError(improveError); } }, [improveError, onImproveError]); const checkAuth = async (): Promise => { try { const token = await getInferenceToken(); return !!token; } catch (error) { setShowAuthError(true); return false; } } const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (prompt.trim() === '' || isLoading) return; // Check for authentication const isAuthenticated = await checkAuth(); if (!isAuthenticated) return; // Clear any previous errors setImproveError(null); await onSubmit(prompt, selectedColors); } const improvePrompt = async () => { if (prompt.trim() === '' || isImprovingPrompt || isLoading) return; // Check for authentication const isAuthenticated = await checkAuth(); if (!isAuthenticated) return; posthog.capture("Improve prompt", {}); // Clear previous errors setImproveError(null); setShowAuthError(false); setIsImprovingPrompt(true); try { const response = await fetch("/api/improve-prompt", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ prompt: prompt.trim() }), }) if (!response.ok) { posthog.capture("Improve prompt", {"type": "failed", "status": response.status}); // Handle auth error with openLogin flag if (response.status === 401) { const errorData = await response.json(); if (errorData.openLogin) { setShowAuthError(true); throw new Error('Authentication required'); } } const errorText = await response.text(); throw new Error(errorText || `Failed to improve prompt (${response.status})`); } if (!response.body) { throw new Error("Response body is null"); } // Handle streaming response const reader = response.body.getReader(); let improvedPrompt = ""; let textDecoder = new TextDecoder(); while (true) { const { done, value } = await reader.read(); if (done) break; const chunkText = textDecoder.decode(value, { stream: true }); let parsedChunk: any; let appended = false; try { // Parse the JSON response parsedChunk = JSON.parse(chunkText); } catch (parseError) { appended = true; // If JSON parsing fails, treat it as plain text (backwards compatibility) improvedPrompt += chunkText setPrompt(improvedPrompt) } if (parsedChunk && parsedChunk.type === "error") { throw new Error(parsedChunk.message || "An error occurred"); } else if (!appended) { improvedPrompt += chunkText setPrompt(improvedPrompt) } } } catch (error) { posthog.capture("Improve prompt", {"type": "failed", "error": error}); console.error("Error improving prompt:", error) setImproveError(error instanceof Error ? error.message : "Failed to improve prompt") } finally { setIsImprovingPrompt(false) } } const toggleFullScreen = () => { setIsFullScreen(!isFullScreen) } const handleColorsChange = (colors: string[]) => { setSelectedColors(colors); } const isPromptTooShort = prompt.length < 10 return (