File size: 3,940 Bytes
7564244
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import { useCallback, useEffect, useRef, useState } from 'react'
import { Box, Container, Flex, Grid, Loader, TextInput } from '@mantine/core'

import styles from './app.module.css'

export const App = () => {
  const [inputPrompt, setInputPrompt] = useState('')
  const [lastPrompt, setLastPrompt] = useState('')
  const [images, setImages] = useState(Array(16).fill('images/white.jpg'))
  const [isLoading, setIsLoading] = useState(false)
  const abortControllers = useRef<AbortController[]>([])

  const calculateEditDistance = (a: string, b: string) => {
    if (a.length === 0) return b.length
    if (b.length === 0) return a.length

    const matrix = []

    for (let i = 0; i <= b.length; i++) {
      matrix[i] = [i]
    }
    for (let i = 0; i <= a.length; i++) {
      matrix[0]![i] = i
    }

    for (let i = 1; i <= b.length; i++) {
      for (let j = 1; j <= a.length; j++) {
        if (b.charAt(i - 1) === a.charAt(j - 1)) {
          //@ts-ignore
          matrix[i][j] = matrix[i - 1][j - 1]
        } else {
          //@ts-ignore
          matrix[i][j] = Math.min(
            //@ts-ignore
            matrix[i - 1][j - 1] + 1,
            //@ts-ignore
            Math.min(matrix[i][j - 1] + 1, matrix[i - 1][j] + 1),
          )
        }
      }
    }

    //@ts-ignore
    return matrix[b.length][a.length]
  }

  const fetchImage = useCallback(
    async (index: number): Promise<void> => {
      abortControllers.current[index]?.abort()
      abortControllers.current[index] = new AbortController()
      const signal = abortControllers.current[index]?.signal

      setIsLoading(true)
      try {
        const response = await fetch('api/predict', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ prompt: inputPrompt }),
          signal,
        })
        const data = await response.json()
        const imageUrl = `data:image/jpeg;base64,${data.base64_image}`

        setImages((prevImages) => {
          const newImages = [...prevImages]
          newImages[index] = imageUrl
          return newImages
        })
      } catch (error) {
        if (error instanceof Error && error.name !== 'AbortError') {
          console.error('Error fetching image:', error)
        }
      } finally {
        setIsLoading(false)
      }
    },
    [inputPrompt],
  )

  const handlePromptChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
    const newPrompt = event.target.value
    setInputPrompt(newPrompt)
    const editDistance = calculateEditDistance(lastPrompt, newPrompt)

    if (editDistance && editDistance >= 4) {
      setLastPrompt(newPrompt)
      // setImages(Array(16).fill('images/white.jpg'));
      for (let i = 0; i < 16; i++) {
        fetchImage(i)
      }
    }
  }

  useEffect(() => {
    return () => {
      abortControllers.current.forEach((controller) => controller.abort())
    }
  }, [])

  return (
    <Box bg="#282c34" mih="100vh" w="100vw" p="lg">
      <Container className={styles.container}>
        <Flex direction="column" justify="center" align="center">
          <Grid w="100%" justify="center" align="center">
            {images.map((image, index) => (
              <Grid.Col
                span={3}
                key={index}
                style={{
                  textAlign: 'center',
                }}
              >
                <img
                  src={image}
                  alt={`Generated ${index}`}
                  style={{
                    maxWidth: '100%',
                    maxHeight: '150px',
                    borderRadius: '10px',
                  }}
                />
              </Grid.Col>
            ))}
          </Grid>
          <TextInput w="100%" size="lg" placeholder="Enter a prompt" value={inputPrompt} onChange={handlePromptChange} />
          {isLoading && <Loader />}
        </Flex>
      </Container>
    </Box>
  )
}