soiz commited on
Commit
700fd72
1 Parent(s): 1fb1361

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +129 -44
app.py CHANGED
@@ -1,14 +1,12 @@
1
- from flask import Flask, request, jsonify, send_file, render_template_string
2
  import requests
3
  import io
4
  import os
5
  import random
6
  from PIL import Image
7
  from deep_translator import GoogleTranslator
8
- from flask_cors import CORS # 追加
9
 
10
  app = Flask(__name__)
11
- CORS(app) # 追加: CORS を有効にする
12
 
13
  API_URL = "https://api-inference.huggingface.co/models/black-forest-labs/FLUX.1-dev"
14
  API_TOKEN = os.getenv("HF_READ_TOKEN")
@@ -62,16 +60,85 @@ def query(prompt, negative_prompt="", steps=35, cfg_scale=7, sampler="DPM++ 2M K
62
  except Exception as e:
63
  return None, f"Error when trying to open the image: {e}"
64
 
65
- # HTML template for the index page (unchanged)
66
- index_html = """
 
 
 
 
 
 
 
 
 
67
 
 
 
68
  <!DOCTYPE html>
69
  <html lang="ja">
70
  <head>
71
  <meta charset="UTF-8">
72
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
73
  <title>FLUX.1-Dev Image Generator</title>
 
 
 
 
 
 
 
 
 
 
 
 
74
  <script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75
  async function generateImage() {
76
  const prompt = document.getElementById("prompt").value;
77
  const negative_prompt = document.getElementById("negative_prompt").value;
@@ -99,10 +166,14 @@ index_html = """
99
  seed
100
  });
101
 
 
 
 
102
  try {
103
- const response = await fetch(`https://soiz-flux-1-dev-serverless.hf.space/generate?${params.toString()}`);
104
  if (!response.ok) {
105
- throw new Error('画像生成に失敗しました');
 
106
  }
107
  const imageBlob = await response.blob();
108
  const reader = new FileReader();
@@ -110,6 +181,18 @@ index_html = """
110
  const img = document.getElementById("generated-image");
111
  img.src = reader.result; // dataURLを設定
112
  img.style.display = 'block'; // 画像を表示
 
 
 
 
 
 
 
 
 
 
 
 
113
  };
114
  reader.readAsDataURL(imageBlob);
115
  } catch (error) {
@@ -145,48 +228,54 @@ index_html = """
145
  <h1>FLUX.1-Dev Image Generator</h1>
146
  <form onsubmit="event.preventDefault(); generateImage();">
147
  <label for="prompt">Prompt:</label><br>
148
- <textarea id="prompt" name="prompt" rows="4" cols="50" placeholder="Enter your prompt" required></textarea><br><br>
149
 
150
  <label for="negative_prompt">Negative Prompt:</label><br>
151
  <textarea id="negative_prompt" name="negative_prompt" rows="4" cols="50" placeholder="Enter negative prompt (optional)"></textarea><br><br>
152
-
153
  <label for="width">Width:</label>
154
- <input type="number" id="width" name="width" value="1024" min="64" max="2048" step="8" style="width:250px" oninput="syncWidth(this.value)">
155
- <input type="range" id="width-slider" name="width-slider" min="64" max="2048" value="1024" step="8" style="width:250px; display: inline-block;" oninput="updateWidthInput()"><br><br>
156
-
157
  <label for="height">Height:</label>
158
- <input type="number" id="height" name="height" value="1024" min="64" max="2048" step="8" oninput="syncHeight(this.value)">
159
- <input type="range" id="height-slider" name="height-slider" min="64" max="2048" value="1024" step="8" style="width:250px; display: inline-block;" oninput="updateHeightInput()"><br><br>
160
-
161
- <label for="steps">Sampling Steps:</label>
162
- <input type="number" id="steps" name="steps" value="35"><br><br>
163
-
164
  <label for="cfgs">CFG Scale:</label>
165
- <input type="number" id="cfgs" name="cfgs" value="7"><br><br>
166
-
167
- <label for="sampler">Sampling Method:</label>
168
- <select id="sampler" name="sampler">
169
- <option value="DPM++ 2M Karras">DPM++ 2M Karras</option>
170
- <option value="DPM++ SDE Karras">DPM++ SDE Karras</option>
171
- <option value="Euler">Euler</option>
172
- <option value="Euler a">Euler a</option>
173
- <option value="Heun">Heun</option>
174
- <option value="DDIM">DDIM</option>
175
- </select><br><br>
176
-
177
  <label for="strength">Strength:</label>
178
- <input type="number" id="strength" name="strength" value="0.7" step="0.01" min="0" max="1"><br><br>
179
-
180
- <label for="seed">Seed:</label>
181
- <input type="number" id="seed" name="seed" value="-1" step="1"><br><br>
182
-
183
- <button type="submit" id="generate-button">Generate Image</button>
 
 
 
 
 
184
  </form>
185
 
186
- <div id="error-message" style="color: red;"></div>
187
-
188
  <h2>Generated Image:</h2>
189
- <img id="generated-image" src="" alt="Generated Image" style="max-width: 100%; height: auto; display: none;">
 
 
 
 
 
 
 
 
 
 
190
  </body>
191
  </html>
192
  """
@@ -197,7 +286,6 @@ def index():
197
 
198
  @app.route('/generate', methods=['GET'])
199
  def generate_image():
200
- # Retrieve query parameters
201
  prompt = request.args.get("prompt", "")
202
  negative_prompt = request.args.get("negative_prompt", "")
203
  steps = int(request.args.get("steps", 35))
@@ -208,13 +296,11 @@ def generate_image():
208
  width = int(request.args.get("width", 1024))
209
  height = int(request.args.get("height", 1024))
210
 
211
- # Call the query function to generate the image
212
  image, error = query(prompt, negative_prompt, steps, cfg_scale, sampler, seed, strength, width, height)
213
-
214
  if error:
215
  return jsonify({"error": error}), 400
216
 
217
- # Save the image to a BytesIO object and return it
218
  img_bytes = io.BytesIO()
219
  image.save(img_bytes, format='PNG')
220
  img_bytes.seek(0)
@@ -222,4 +308,3 @@ def generate_image():
222
 
223
  if __name__ == "__main__":
224
  app.run(host='0.0.0.0', port=7860)
225
-
 
1
+ from flask import Flask, request, jsonify, send_file, render_template_string, make_response
2
  import requests
3
  import io
4
  import os
5
  import random
6
  from PIL import Image
7
  from deep_translator import GoogleTranslator
 
8
 
9
  app = Flask(__name__)
 
10
 
11
  API_URL = "https://api-inference.huggingface.co/models/black-forest-labs/FLUX.1-dev"
12
  API_TOKEN = os.getenv("HF_READ_TOKEN")
 
60
  except Exception as e:
61
  return None, f"Error when trying to open the image: {e}"
62
 
63
+ # Content-Security-Policyヘッダーを設定するための関数
64
+ @app.after_request
65
+ def add_security_headers(response):
66
+ response.headers['Content-Security-Policy'] = (
67
+ "default-src 'self'; "
68
+ "connect-src 'self' https://[a-zA-Z0-9\\-]+\\.[a-zA-Z0-9\\-]+/; "
69
+ "img-src 'self' data:; "
70
+ "style-src 'self' 'unsafe-inline'; "
71
+ "script-src 'self' 'unsafe-inline'; "
72
+ )
73
+ return response
74
 
75
+ # HTML template for the index page
76
+ index_html = """
77
  <!DOCTYPE html>
78
  <html lang="ja">
79
  <head>
80
  <meta charset="UTF-8">
81
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
82
  <title>FLUX.1-Dev Image Generator</title>
83
+ <style>
84
+ #canvas {
85
+ position: absolute;
86
+ top: 0;
87
+ left: 0;
88
+ cursor: crosshair;
89
+ }
90
+ #container {
91
+ position: relative;
92
+ display: inline-block;
93
+ }
94
+ </style>
95
  <script>
96
+ let isDrawing = false;
97
+ let lastX = 0;
98
+ let lastY = 0;
99
+ let penSize = 5;
100
+ let penColor = '#000000';
101
+
102
+ function startDrawing(event) {
103
+ isDrawing = true;
104
+ [lastX, lastY] = getMousePos(event);
105
+ }
106
+
107
+ function draw(event) {
108
+ if (!isDrawing) return;
109
+
110
+ const canvas = document.getElementById('canvas');
111
+ const ctx = canvas.getContext('2d');
112
+ const [newX, newY] = getMousePos(event);
113
+
114
+ ctx.beginPath();
115
+ ctx.moveTo(lastX, lastY);
116
+ ctx.lineTo(newX, newY);
117
+ ctx.strokeStyle = penColor;
118
+ ctx.lineWidth = penSize;
119
+ ctx.stroke();
120
+ ctx.closePath();
121
+
122
+ [lastX, lastY] = [newX, newY]; // 新しい位置を保存
123
+ }
124
+
125
+ function stopDrawing() {
126
+ isDrawing = false;
127
+ }
128
+
129
+ function getMousePos(event) {
130
+ const rect = document.getElementById('canvas').getBoundingClientRect();
131
+ return [event.clientX - rect.left, event.clientY - rect.top];
132
+ }
133
+
134
+ function setPenSize(value) {
135
+ penSize = value;
136
+ }
137
+
138
+ function setPenColor(value) {
139
+ penColor = value;
140
+ }
141
+
142
  async function generateImage() {
143
  const prompt = document.getElementById("prompt").value;
144
  const negative_prompt = document.getElementById("negative_prompt").value;
 
166
  seed
167
  });
168
 
169
+ const reqURL = `https://soiz-flux-1-dev-serverless.hf.space/generate?${params.toString()}`;
170
+ document.getElementById("reqURL").value = reqURL; // URLを設定
171
+
172
  try {
173
+ const response = await fetch(reqURL);
174
  if (!response.ok) {
175
+ const errorText = await response.text(); // エラーメッセージを取得
176
+ throw new Error(`画像生成に失敗しました: ${errorText}`);
177
  }
178
  const imageBlob = await response.blob();
179
  const reader = new FileReader();
 
181
  const img = document.getElementById("generated-image");
182
  img.src = reader.result; // dataURLを設定
183
  img.style.display = 'block'; // 画像を表示
184
+
185
+ // 画像をキャンバスに描画
186
+ const canvas = document.getElementById('canvas');
187
+ const ctx = canvas.getContext('2d');
188
+ ctx.clearRect(0, 0, canvas.width, canvas.height); // キャンバスをクリア
189
+ const imgElement = new Image();
190
+ imgElement.src = reader.result;
191
+ imgElement.onload = function () {
192
+ canvas.width = imgElement.width;
193
+ canvas.height = imgElement.height;
194
+ ctx.drawImage(imgElement, 0, 0);
195
+ };
196
  };
197
  reader.readAsDataURL(imageBlob);
198
  } catch (error) {
 
228
  <h1>FLUX.1-Dev Image Generator</h1>
229
  <form onsubmit="event.preventDefault(); generateImage();">
230
  <label for="prompt">Prompt:</label><br>
231
+ <textarea id="prompt" name="prompt" rows="4" cols="50" placeholder="Enter your prompt" required>real, sky, blue, clouds, light blue, light blue sky, sun, 32K, many islands floating in the sky, Ghibli, many islands, many islands in the sky, islands in the clouds, old islands, fog, high quality, cool</textarea><br><br>
232
 
233
  <label for="negative_prompt">Negative Prompt:</label><br>
234
  <textarea id="negative_prompt" name="negative_prompt" rows="4" cols="50" placeholder="Enter negative prompt (optional)"></textarea><br><br>
235
+
236
  <label for="width">Width:</label>
237
+ <input type="number" id="width" name="width" value="1024" required>
238
+ <input type="range" id="width-slider" min="512" max="2048" value="1024" oninput="updateWidthInput()"><br><br>
239
+
240
  <label for="height">Height:</label>
241
+ <input type="number" id="height" name="height" value="1024" required>
242
+ <input type="range" id="height-slider" min="512" max="2048" value="1024" oninput="updateHeightInput()"><br><br>
243
+
244
+ <label for="steps">Steps:</label>
245
+ <input type="number" id="steps" name="steps" value="35" required><br><br>
246
+
247
  <label for="cfgs">CFG Scale:</label>
248
+ <input type="number" id="cfgs" name="cfgs" value="7" step="0.1" required><br><br>
249
+
250
+ <label for="sampler">Sampler:</label>
251
+ <input type="text" id="sampler" name="sampler" value="DPM++ 2M Karras" required><br><br>
252
+
 
 
 
 
 
 
 
253
  <label for="strength">Strength:</label>
254
+ <input type="number" id="strength" name="strength" value="0.7" step="0.1" required><br><br>
255
+
256
+ <label for="seed">Seed (optional):</label>
257
+ <input type="number" id="seed" name="seed" value="-1"><br><br>
258
+
259
+ <button id="generate-button" type="submit">Generate Image</button><br><br>
260
+
261
+ <label for="reqURL">Request URL (for debugging):</label><br>
262
+ <input type="text" id="reqURL" name="reqURL" size="100"><br><br>
263
+
264
+ <span id="error-message" style="color: red;"></span>
265
  </form>
266
 
 
 
267
  <h2>Generated Image:</h2>
268
+ <img id="generated-image" src="" alt="Generated Image" style="display:none; width: 100%; height: auto;"><br><br>
269
+
270
+ <h2>Draw on Canvas:</h2>
271
+ <div id="container">
272
+ <canvas id="canvas" width="1024" height="1024" style="border:1px solid black;" onmousedown="startDrawing(event)" onmousemove="draw(event)" onmouseup="stopDrawing()" onmouseleave="stopDrawing()"></canvas><br><br>
273
+ <label for="pen-size">Pen Size:</label>
274
+ <input type="number" id="pen-size" name="pen-size" value="5" min="1" max="50" oninput="setPenSize(this.value)"><br><br>
275
+
276
+ <label for="pen-color">Pen Color:</label>
277
+ <input type="color" id="pen-color" name="pen-color" value="#000000" onchange="setPenColor(this.value)"><br><br>
278
+ </div>
279
  </body>
280
  </html>
281
  """
 
286
 
287
  @app.route('/generate', methods=['GET'])
288
  def generate_image():
 
289
  prompt = request.args.get("prompt", "")
290
  negative_prompt = request.args.get("negative_prompt", "")
291
  steps = int(request.args.get("steps", 35))
 
296
  width = int(request.args.get("width", 1024))
297
  height = int(request.args.get("height", 1024))
298
 
 
299
  image, error = query(prompt, negative_prompt, steps, cfg_scale, sampler, seed, strength, width, height)
300
+
301
  if error:
302
  return jsonify({"error": error}), 400
303
 
 
304
  img_bytes = io.BytesIO()
305
  image.save(img_bytes, format='PNG')
306
  img_bytes.seek(0)
 
308
 
309
  if __name__ == "__main__":
310
  app.run(host='0.0.0.0', port=7860)