Erster Commit
This commit is contained in:
166
frontend/src/pages/GenerateIt.tsx
Normal file
166
frontend/src/pages/GenerateIt.tsx
Normal file
@@ -0,0 +1,166 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import ObjectsList from '../components/ObjectsList'
|
||||
import DetailsPanel from '../components/DetailsPanel'
|
||||
import SentencesList from '../components/SentencesList'
|
||||
import { getImages, getObjects, generateDetails, generateSentence, getSentences } from '../api'
|
||||
import type { ObjectMeta, Sentence } from '../types'
|
||||
|
||||
export default function GenerateIt() {
|
||||
const navigate = useNavigate()
|
||||
|
||||
const [imageList, setImageList] = useState<string[]>([])
|
||||
const [currentIndex, setCurrentIndex] = useState(-1)
|
||||
const [objects, setObjects] = useState<ObjectMeta[]>([])
|
||||
const [selectedObj, setSelectedObj] = useState<ObjectMeta | null>(null)
|
||||
const [sentences, setSentences] = useState<Sentence[]>([])
|
||||
const [isGeneratingDetails, setIsGeneratingDetails] = useState(false)
|
||||
const [isGeneratingSentence, setIsGeneratingSentence] = useState(false)
|
||||
|
||||
const currentFilename =
|
||||
currentIndex >= 0 && currentIndex < imageList.length ? imageList[currentIndex] : null
|
||||
|
||||
useEffect(() => {
|
||||
getImages('generate')
|
||||
.then(imgs => {
|
||||
setImageList(imgs)
|
||||
setCurrentIndex(imgs.length - 1)
|
||||
})
|
||||
.catch(console.error)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (!currentFilename) {
|
||||
setObjects([])
|
||||
setSelectedObj(null)
|
||||
setSentences([])
|
||||
return
|
||||
}
|
||||
getObjects(currentFilename)
|
||||
.then(objs => {
|
||||
setObjects(objs)
|
||||
if (objs.length > 0) {
|
||||
setSelectedObj(objs[0])
|
||||
loadSentences(objs[0].id)
|
||||
} else {
|
||||
setSelectedObj(null)
|
||||
setSentences([])
|
||||
}
|
||||
})
|
||||
.catch(console.error)
|
||||
}, [currentFilename])
|
||||
|
||||
const loadSentences = async (objId: string) => {
|
||||
try {
|
||||
const s = await getSentences(objId)
|
||||
setSentences(s)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
|
||||
const handleGenerateDetails = async () => {
|
||||
const target = selectedObj ?? objects[0]
|
||||
if (!target) return
|
||||
setIsGeneratingDetails(true)
|
||||
try {
|
||||
const data = await generateDetails(target.id)
|
||||
const updated = { ...target, ...data }
|
||||
setSelectedObj(updated)
|
||||
setObjects(prev => prev.map(o => o.id === target.id ? updated : o))
|
||||
} catch (e) {
|
||||
alert(e instanceof Error ? e.message : 'Fehler bei KI-Details')
|
||||
} finally {
|
||||
setIsGeneratingDetails(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleGenerateSentence = async () => {
|
||||
const target = selectedObj ?? objects[0]
|
||||
if (!target) return
|
||||
setIsGeneratingSentence(true)
|
||||
try {
|
||||
const data = await generateSentence(target.id)
|
||||
setSentences(prev => [...prev, data.sentence])
|
||||
setSelectedObj(prev => prev ? { ...prev, latest_sentence: data.sentence } : prev)
|
||||
} catch (e) {
|
||||
alert(e instanceof Error ? e.message : 'Fehler bei KI-Sentence')
|
||||
} finally {
|
||||
setIsGeneratingSentence(false)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
<h1>GenerateIt</h1>
|
||||
|
||||
<div className="panel image-nav">
|
||||
<div className="image-nav-left">
|
||||
<button
|
||||
onClick={() => setCurrentIndex(i => i - 1)}
|
||||
disabled={currentIndex <= 0}
|
||||
>
|
||||
⬅️
|
||||
</button>
|
||||
<span>Bild: <code>{currentFilename || '–'}</code></span>
|
||||
<button
|
||||
onClick={() => setCurrentIndex(i => i + 1)}
|
||||
disabled={currentIndex >= imageList.length - 1}
|
||||
>
|
||||
➡️
|
||||
</button>
|
||||
<button
|
||||
onClick={handleGenerateDetails}
|
||||
disabled={isGeneratingDetails || !selectedObj}
|
||||
>
|
||||
{isGeneratingDetails ? '⏳ KI-Details...' : '✨ KI-Details'}
|
||||
</button>
|
||||
<button
|
||||
onClick={handleGenerateSentence}
|
||||
disabled={isGeneratingSentence || !selectedObj}
|
||||
>
|
||||
{isGeneratingSentence ? '⏳ KI-Sentence...' : '💬 KI-Sentence'}
|
||||
</button>
|
||||
</div>
|
||||
<div className="page-switch">
|
||||
<select value="/generate" onChange={e => navigate(e.target.value)}>
|
||||
<option value="/draw">DrawIt</option>
|
||||
<option value="/generate">GenerateIt</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="main-layout">
|
||||
<div className="objects-pane sidebar-section">
|
||||
<h2>Objekte zu diesem Bild</h2>
|
||||
<ObjectsList
|
||||
objects={objects}
|
||||
selectedObjectId={selectedObj?.id ?? null}
|
||||
onSelect={id => {
|
||||
const obj = objects.find(o => o.id === id)
|
||||
if (obj) {
|
||||
setSelectedObj(obj)
|
||||
loadSentences(obj.id)
|
||||
}
|
||||
}}
|
||||
onObjectsChange={setObjects}
|
||||
isGeneratePage={true}
|
||||
onShowDetails={obj => setSelectedObj(obj)}
|
||||
onLoadSentences={loadSentences}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="right-pane">
|
||||
<DetailsPanel obj={selectedObj} objects={objects} sentences={sentences} />
|
||||
</div>
|
||||
|
||||
<div className="sentences-pane">
|
||||
<div className="sidebar-section">
|
||||
<h2>Alle Sätze</h2>
|
||||
<SentencesList sentences={sentences} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user