Athspi commited on
Commit
19af451
·
verified ·
1 Parent(s): b0a339e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +87 -68
app.py CHANGED
@@ -19,24 +19,26 @@ os.makedirs(UPLOAD_FOLDER, exist_ok=True)
19
  os.makedirs(RESULT_FOLDER, exist_ok=True)
20
 
21
  def upload_image(image_data_url):
22
- """Helper function to upload image to Gemini"""
23
  try:
24
  header, encoded = image_data_url.split(',', 1)
25
- except ValueError:
26
- raise ValueError("Invalid image data")
27
-
28
- binary_data = base64.b64decode(encoded)
29
- ext = ".png" if "png" in header.lower() else ".jpg"
30
- temp_filename = secure_filename("temp_image" + ext)
31
- temp_filepath = os.path.join(UPLOAD_FOLDER, temp_filename)
32
-
33
- with open(temp_filepath, "wb") as f:
34
- f.write(binary_data)
 
35
 
36
- return client.files.upload(file=temp_filepath)
 
37
 
38
  def is_prohibited_request(uploaded_file, object_type):
39
- """Check if request is to remove person/animal using gemini-2.0-flash-lite"""
40
  model = "gemini-2.0-flash-lite"
41
  parts = [
42
  types.Part.from_uri(file_uri=uploaded_file.uri, mime_type=uploaded_file.mime_type),
@@ -46,14 +48,23 @@ def is_prohibited_request(uploaded_file, object_type):
46
  contents = [types.Content(role="user", parts=parts)]
47
 
48
  generate_content_config = types.GenerateContentConfig(
49
- system_instruction=[
50
- types.Part.from_text(text="""Determine if the user wants to remove a person or animal.
51
- Respond ONLY with 'Yes' or 'No'. Consider these examples:
52
- - Remove person Yes
53
- - Remove dog → Yes
54
- - Remove sunglasses → No
55
- - Remove background → No""")
56
- ],
 
 
 
 
 
 
 
 
 
57
  temperature=0.0,
58
  max_output_tokens=1,
59
  )
@@ -66,49 +77,53 @@ def is_prohibited_request(uploaded_file, object_type):
66
  )
67
  if response.candidates and response.candidates[0].content.parts:
68
  return response.candidates[0].content.parts[0].text.strip().lower() == "yes"
69
- return False
70
  except Exception as e:
71
- print(f"Prohibition check error: {str(e)}")
72
- return False
73
 
74
- def generate_gemini_output(object_type, uploaded_file):
75
- """Generate image using gemini-2.0-flash-exp-image-generation"""
76
  model = "gemini-2.0-flash-exp-image-generation"
77
  parts = [
78
  types.Part.from_uri(file_uri=uploaded_file.uri, mime_type=uploaded_file.mime_type),
79
- types.Part.from_text(text=f"Remove {object_type} from the image")
80
  ]
81
 
82
  contents = [types.Content(role="user", parts=parts)]
83
 
84
  generate_content_config = types.GenerateContentConfig(
85
- temperature=1,
86
- top_p=0.95,
87
- top_k=40,
88
- max_output_tokens=8192,
89
- response_modalities=["image", "text"],
90
  safety_settings=[
91
- types.SafetySetting(category="HARM_CATEGORY_CIVIC_INTEGRITY", threshold="OFF"),
92
- ],
 
93
  )
94
 
95
- result_image = None
96
- for chunk in client.models.generate_content_stream(
97
- model=model,
98
- contents=contents,
99
- config=generate_content_config,
100
- ):
101
- if chunk.candidates and chunk.candidates[0].content.parts:
102
- part = chunk.candidates[0].content.parts[0]
103
- if part.inline_data:
104
- file_extension = mimetypes.guess_extension(part.inline_data.mime_type) or ".png"
105
- output_filename = secure_filename("generated_output" + file_extension)
106
- result_image_path = os.path.join(RESULT_FOLDER, output_filename)
107
- with open(result_image_path, "wb") as f:
108
- f.write(part.inline_data.data)
109
- result_image = result_image_path
110
-
111
- return result_image
 
 
 
 
112
 
113
  @app.route("/")
114
  def index():
@@ -117,36 +132,40 @@ def index():
117
  @app.route("/process", methods=["POST"])
118
  def process():
119
  try:
120
- data = request.get_json(force=True)
121
- image_data = data.get("image")
122
- object_type = data.get("objectType", "").strip()
 
 
 
123
 
124
- if not image_data or not object_type:
125
- return jsonify({"success": False, "message": "Missing required data"}), 400
126
 
127
- # Upload image once
128
  uploaded_file = upload_image(image_data)
129
 
130
- # Check for prohibited requests
131
  if is_prohibited_request(uploaded_file, object_type):
132
  return jsonify({
133
  "success": False,
134
- "message": "Sorry, I can't assist with removing people or animals."
135
- }), 400
136
-
137
- # Generate output if allowed
138
- result_image = generate_gemini_output(object_type, uploaded_file)
139
 
140
- if not result_image:
 
 
141
  return jsonify({"success": False, "message": "Failed to generate image"}), 500
142
 
143
  return jsonify({
144
  "success": True,
145
- "resultPath": f"/static/{os.path.basename(result_image)}"
146
  })
147
-
 
 
148
  except Exception as e:
149
- return jsonify({"success": False, "message": f"Error: {str(e)}"}), 500
150
 
151
  if __name__ == "__main__":
152
- app.run(host="0.0.0.0", port=7860)
 
19
  os.makedirs(RESULT_FOLDER, exist_ok=True)
20
 
21
  def upload_image(image_data_url):
22
+ """Handle base64 image upload and Gemini file upload"""
23
  try:
24
  header, encoded = image_data_url.split(',', 1)
25
+ binary_data = base64.b64decode(encoded)
26
+ ext = ".png" if "png" in header.lower() else ".jpg"
27
+ temp_filename = secure_filename(f"temp_{os.urandom(8).hex()}{ext}")
28
+ temp_filepath = os.path.join(UPLOAD_FOLDER, temp_filename)
29
+
30
+ with open(temp_filepath, "wb") as f:
31
+ f.write(binary_data)
32
+
33
+ uploaded_file = client.files.upload(file=temp_filepath)
34
+ os.remove(temp_filepath) # Clean up temporary file
35
+ return uploaded_file
36
 
37
+ except Exception as e:
38
+ raise ValueError(f"Image processing error: {str(e)}")
39
 
40
  def is_prohibited_request(uploaded_file, object_type):
41
+ """Check if request involves people/animals or their belongings"""
42
  model = "gemini-2.0-flash-lite"
43
  parts = [
44
  types.Part.from_uri(file_uri=uploaded_file.uri, mime_type=uploaded_file.mime_type),
 
48
  contents = [types.Content(role="user", parts=parts)]
49
 
50
  generate_content_config = types.GenerateContentConfig(
51
+ system_instruction=[types.Part.from_text(text="""Analyze image and request to detect:
52
+ 1. Direct removal of people/animals
53
+ 2. Removal of items attached to/worn by people/animals
54
+ 3. Removal of body parts or personal belongings
55
+
56
+ Prohibited examples:
57
+ - Person, dog, cat
58
+ - Sunglasses on face, mask, hat
59
+ - Phone in hand, watch on wrist
60
+ - Eyes, hands, hair
61
+
62
+ Allowed examples:
63
+ - Background, car, tree
64
+ - Sunglasses on table
65
+ - Phone on desk
66
+
67
+ Respond ONLY with 'Yes' or 'No'""")],
68
  temperature=0.0,
69
  max_output_tokens=1,
70
  )
 
77
  )
78
  if response.candidates and response.candidates[0].content.parts:
79
  return response.candidates[0].content.parts[0].text.strip().lower() == "yes"
80
+ return True # Default to safe mode if uncertain
81
  except Exception as e:
82
+ print(f"Safety check failed: {str(e)}")
83
+ return True # Block if check fails
84
 
85
+ def generate_modified_image(uploaded_file, object_type):
86
+ """Generate image with object removed using experimental model"""
87
  model = "gemini-2.0-flash-exp-image-generation"
88
  parts = [
89
  types.Part.from_uri(file_uri=uploaded_file.uri, mime_type=uploaded_file.mime_type),
90
+ types.Part.from_text(text=f"Completely remove {object_type} from the image without leaving traces")
91
  ]
92
 
93
  contents = [types.Content(role="user", parts=parts)]
94
 
95
  generate_content_config = types.GenerateContentConfig(
96
+ temperature=0.5,
97
+ top_p=0.9,
98
+ max_output_tokens=1024,
99
+ response_modalities=["image"],
 
100
  safety_settings=[
101
+ types.SafetySetting(category="HARM_CATEGORY_CIVIC_INTEGRITY", threshold="BLOCK_NONE"),
102
+ types.SafetySetting(category="HARM_CATEGORY_VIOLENCE", threshold="BLOCK_NONE")
103
+ ]
104
  )
105
 
106
+ try:
107
+ for chunk in client.models.generate_content_stream(
108
+ model=model,
109
+ contents=contents,
110
+ config=generate_content_config,
111
+ ):
112
+ if chunk.candidates and chunk.candidates[0].content.parts:
113
+ part = chunk.candidates[0].content.parts[0]
114
+ if part.inline_data:
115
+ ext = mimetypes.guess_extension(part.inline_data.mime_type) or ".png"
116
+ output_filename = secure_filename(f"result_{os.urandom(4).hex()}{ext}")
117
+ output_path = os.path.join(RESULT_FOLDER, output_filename)
118
+
119
+ with open(output_path, "wb") as f:
120
+ f.write(part.inline_data.data)
121
+
122
+ return output_path
123
+ return None
124
+ except Exception as e:
125
+ print(f"Image generation failed: {str(e)}")
126
+ return None
127
 
128
  @app.route("/")
129
  def index():
 
132
  @app.route("/process", methods=["POST"])
133
  def process():
134
  try:
135
+ data = request.get_json()
136
+ if not data or "image" not in data or "objectType" not in data:
137
+ return jsonify({"success": False, "message": "Invalid request format"}), 400
138
+
139
+ image_data = data["image"]
140
+ object_type = data["objectType"].strip().lower()
141
 
142
+ if not object_type:
143
+ return jsonify({"success": False, "message": "Please specify an object to remove"}), 400
144
 
145
+ # Process image upload
146
  uploaded_file = upload_image(image_data)
147
 
148
+ # Safety check
149
  if is_prohibited_request(uploaded_file, object_type):
150
  return jsonify({
151
  "success": False,
152
+ "message": "Cannot remove people, animals, or personal items"
153
+ }), 403
 
 
 
154
 
155
+ # Generate modified image
156
+ result_path = generate_modified_image(uploaded_file, object_type)
157
+ if not result_path:
158
  return jsonify({"success": False, "message": "Failed to generate image"}), 500
159
 
160
  return jsonify({
161
  "success": True,
162
+ "resultUrl": f"/static/{os.path.basename(result_path)}"
163
  })
164
+
165
+ except ValueError as e:
166
+ return jsonify({"success": False, "message": str(e)}), 400
167
  except Exception as e:
168
+ return jsonify({"success": False, "message": "Internal server error"}), 500
169
 
170
  if __name__ == "__main__":
171
+ app.run(host="0.0.0.0", port=7860,)