SouravSaha26 commited on
Commit
78fe8a9
·
verified ·
1 Parent(s): 8c76677

Upload 6 files

Browse files
Files changed (6) hide show
  1. Dockerfile +32 -0
  2. main.py +43 -0
  3. requirements.txt +9 -0
  4. static/script.js +47 -0
  5. static/style.css +214 -0
  6. templates/index.html +28 -0
Dockerfile ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use official Python slim image
2
+ FROM python:3.10-slim
3
+
4
+ # Ensure /app is writable (important!)
5
+ RUN mkdir -p /app/cache && chmod -R 777 /app
6
+
7
+
8
+ # Set environment variables
9
+ ENV PYTHONDONTWRITEBYTECODE=1
10
+ ENV PYTHONUNBUFFERED=1
11
+
12
+ # Set working directory
13
+ WORKDIR /app
14
+
15
+ # Install system dependencies
16
+ RUN apt-get update && \
17
+ apt-get install -y git libgl1 libglib2.0-0 && \
18
+ apt-get clean && \
19
+ rm -rf /var/lib/apt/lists/*
20
+
21
+ # Install Python dependencies
22
+ COPY requirements.txt .
23
+ RUN pip install --upgrade pip && pip install -r requirements.txt
24
+
25
+ # Copy your Flask app and other files
26
+ COPY . /app
27
+
28
+ # Expose the port your Flask app will run on
29
+ EXPOSE 7860
30
+
31
+ # Run your Flask app
32
+ CMD ["python", "main.py"]
main.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from diffusers import DiffusionPipeline
3
+ import torch
4
+ from flask import Flask, request, jsonify, render_template
5
+ from PIL import Image
6
+ from io import BytesIO
7
+ import base64
8
+
9
+ app = Flask(__name__)
10
+
11
+ # ✅ Safe local cache directory inside the app folder
12
+ hf_cache_dir = os.path.join(os.getcwd(), "cache")
13
+ os.makedirs(hf_cache_dir, exist_ok=True)
14
+ os.environ["HF_HOME"] = hf_cache_dir
15
+
16
+ # Load model
17
+ model_repo_id = "stabilityai/sdxl-turbo"
18
+ torch_dtype = torch.float16 if torch.cuda.is_available() else torch.float32
19
+
20
+ pipe = DiffusionPipeline.from_pretrained(
21
+ model_repo_id,
22
+ torch_dtype=torch_dtype,
23
+ cache_dir=hf_cache_dir
24
+ )
25
+ pipe.to("cuda" if torch.cuda.is_available() else "cpu")
26
+
27
+ @app.route("/")
28
+ def index():
29
+ return render_template("index.html")
30
+
31
+ @app.route("/generate", methods=["POST"])
32
+ def generate():
33
+ prompt = request.json["prompt"]
34
+ image = pipe(prompt).images[0]
35
+
36
+ buffered = BytesIO()
37
+ image.save(buffered, format="PNG")
38
+ img_str = base64.b64encode(buffered.getvalue()).decode("utf-8")
39
+
40
+ return jsonify({"image": img_str})
41
+
42
+ if __name__ == "__main__":
43
+ app.run(host="0.0.0.0", port=7860)
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ accelerate
2
+ diffusers
3
+ invisible_watermark
4
+ torch
5
+ transformers
6
+ xformers
7
+ flask
8
+ Pillow
9
+ numpy
static/script.js ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ async function generateImage() {
2
+ const prompt = document.getElementById("prompt").value;
3
+ const imageContainer = document.getElementById("generatedImage");
4
+ const downloadSection = document.getElementById("downloadSection");
5
+
6
+ imageContainer.innerHTML = "<p class='placeholder-text'>Generating...</p>";
7
+ downloadSection.style.display = "none";
8
+
9
+ try {
10
+ const response = await fetch("/generate", {
11
+ method: "POST",
12
+ headers: {
13
+ "Content-Type": "application/json"
14
+ },
15
+ body: JSON.stringify({ prompt })
16
+ });
17
+
18
+ const data = await response.json();
19
+
20
+ if (data.image) {
21
+ const img = new Image();
22
+ img.id = "generatedImg";
23
+ img.src = `data:image/png;base64,${data.image}`;
24
+ img.alt = "Generated Image";
25
+ imageContainer.innerHTML = "";
26
+ imageContainer.appendChild(img);
27
+ downloadSection.style.display = "block";
28
+ } else {
29
+ imageContainer.innerHTML = "<p class='placeholder-text'>Failed to generate image.</p>";
30
+ }
31
+ } catch (error) {
32
+ console.error("Error:", error);
33
+ imageContainer.innerHTML = "<p class='placeholder-text'>An error occurred.</p>";
34
+ }
35
+ }
36
+
37
+ function downloadImage() {
38
+ const img = document.getElementById("generatedImg");
39
+ if (!img) return;
40
+
41
+ const link = document.createElement("a");
42
+ link.href = img.src;
43
+ link.download = "ai_generated_image.png";
44
+ document.body.appendChild(link);
45
+ link.click();
46
+ document.body.removeChild(link);
47
+ }
static/style.css ADDED
@@ -0,0 +1,214 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ body {
2
+ font-family: 'Roboto', Arial, sans-serif;
3
+ margin: 0;
4
+ padding: 0;
5
+ display: flex;
6
+ justify-content: center;
7
+ align-items: center;
8
+ min-height: 100vh;
9
+ color: #333333;
10
+ }
11
+
12
+ .container {
13
+ background-color:#e2d3eb;
14
+ border: 3px solid #9344c7;
15
+ border-radius: 12px;
16
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
17
+ width: 90%;
18
+ max-width: 600px; /* Increased container width */
19
+ padding: 30px;
20
+ box-sizing: border-box;
21
+ display: flex;
22
+ flex-direction: column;
23
+ align-items: center;
24
+ }
25
+
26
+ h1 {
27
+ font-family:'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
28
+ font-size: 24px;
29
+ margin: 0 0 20px 0;
30
+ text-align: center;
31
+ font-weight:bolder;
32
+ color:#9344c7 ;
33
+ }
34
+
35
+ .input-container {
36
+ width: 100%; /* Takes full width of container */
37
+ max-width: 550px;/* Specific width for the textarea */
38
+ }
39
+
40
+ .input-container textarea {
41
+ width: 100%;
42
+ height: 120px;
43
+ padding: 15px;
44
+ border: 1px solid #ddd;
45
+ border-radius: 8px;
46
+ font-size: 16px;
47
+ resize: none;
48
+ margin-bottom: 20px;
49
+ box-sizing: border-box;
50
+ font-family: inherit;
51
+ }
52
+
53
+ .input-container textarea::placeholder {
54
+ color: #999;
55
+ }
56
+
57
+ .button-container {
58
+ width: 50%;
59
+ max-width: 550px; /* Match textarea width */
60
+ margin-bottom: 25px;
61
+ }
62
+
63
+ .generate-btn {
64
+ width: 100%;
65
+ padding: 15px;
66
+ background-color: #9344c7;
67
+ font-family:'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
68
+ font-weight: bolder;
69
+ color: white;
70
+ border: none;
71
+ border-radius: 8px;
72
+ font-size: 20px;
73
+ font-weight: 500;
74
+ cursor: pointer;
75
+ transition: background-color 0.2s;
76
+ }
77
+
78
+ .generate-btn:hover {
79
+ background-color:#5c1988;
80
+ }
81
+
82
+ .image-container {
83
+ width: 256px;
84
+ height:256px;
85
+ border: 1px dashed #ccc;
86
+ border-radius: 8px;
87
+ display: flex;
88
+ justify-content: center;
89
+ align-items: center;
90
+ background-color: #f9f9f9;
91
+ overflow: hidden;
92
+ }
93
+
94
+ .placeholder-text {
95
+ color: #999;
96
+ font-size: 16px;
97
+ text-align: center;
98
+ }
99
+
100
+ /* When an image is generated */
101
+ .image-container img {
102
+ width: 100%;
103
+ height: 100%;
104
+ object-fit: cover;
105
+ }
106
+ .download-container {
107
+ width: 50%;
108
+ max-width: 550px;
109
+ margin-top: 10px;
110
+ }
111
+
112
+ .download-btn {
113
+ width: 100%;
114
+ padding: 14px;
115
+ background-color: #5c1988;
116
+ color: white;
117
+ border: none;
118
+ border-radius: 8px;
119
+ font-size: 18px;
120
+ font-family:'Franklin Gothic Medium', 'Arial Narrow', Arial, sans-serif;
121
+ font-weight: bolder;
122
+ cursor: pointer;
123
+ transition: background-color 0.3s;
124
+ }
125
+
126
+ .download-btn:hover {
127
+ background-color: #3b0f5c;
128
+ }
129
+
130
+ /* Media Queries for Responsiveness */
131
+ @media (max-width: 768px) {
132
+ .container {
133
+ padding: 20px;
134
+ }
135
+
136
+ h1 {
137
+ font-size: 22px;
138
+ }
139
+
140
+ .input-container textarea {
141
+ height: 100px;
142
+ font-size: 15px;
143
+ }
144
+
145
+ .generate-btn {
146
+ padding: 12px;
147
+ font-size: 15px;
148
+ }
149
+
150
+ .placeholder-text {
151
+ font-size: 15px;
152
+ }
153
+ }
154
+
155
+ @media (max-width: 480px) {
156
+ .container {
157
+ padding: 15px;
158
+ border-radius: 8px;
159
+ }
160
+
161
+ h1 {
162
+ font-size: 20px;
163
+ margin-bottom: 15px;
164
+ }
165
+
166
+ .input-container textarea {
167
+ height: 80px;
168
+ font-size: 14px;
169
+ padding: 12px;
170
+ margin-bottom: 15px;
171
+ }
172
+
173
+ .generate-btn {
174
+ padding: 10px;
175
+ font-size: 14px;
176
+ }
177
+
178
+ .button-container {
179
+ margin-bottom: 20px;
180
+ }
181
+
182
+ .placeholder-text {
183
+ font-size: 14px;
184
+ }
185
+ }
186
+
187
+ @media (max-width: 350px) {
188
+ .container {
189
+ padding: 12px;
190
+ }
191
+
192
+ h1 {
193
+ font-size: 18px;
194
+ }
195
+
196
+ .input-container textarea {
197
+ height: 70px;
198
+ font-size: 13px;
199
+ }
200
+ }
201
+
202
+ @media (max-width: 768px) {
203
+ .download-btn {
204
+ font-size: 15px;
205
+ padding: 12px;
206
+ }
207
+ }
208
+
209
+ @media (max-width: 480px) {
210
+ .download-btn {
211
+ font-size: 14px;
212
+ padding: 10px;
213
+ }
214
+ }
templates/index.html ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!-- Save as templates/index.html -->
2
+ <!DOCTYPE html>
3
+ <html lang="en">
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
7
+ <title>AI Image Generator</title>
8
+ <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
9
+ </head>
10
+ <body>
11
+ <div class="container">
12
+ <h1>AI Image Generator</h1>
13
+ <div class="input-container">
14
+ <textarea id="prompt" placeholder="Describe your imagination in detail..."></textarea>
15
+ </div>
16
+ <div class="button-container">
17
+ <button class="generate-btn" onclick="generateImage()">Generate</button>
18
+ </div>
19
+ <div class="image-container" id="generatedImage">
20
+ <p class="placeholder-text">Your generated image will appear here</p>
21
+ </div>
22
+ <div class="button-container download-container" id="downloadSection" style="display: none;">
23
+ <button class="download-btn" onclick="downloadImage()">Download</button>
24
+ </div>
25
+ </div>
26
+ <script src="{{ url_for('static', filename='script.js') }}"></script>
27
+ </body>
28
+ </html>