Spaces:
Running
Running
Update main.py
Browse files
main.py
CHANGED
|
@@ -564,10 +564,12 @@ def create_project():
|
|
| 564 |
print(traceback.format_exc())
|
| 565 |
return jsonify({'error': f"An error occurred: {e}"}), 500
|
| 566 |
|
|
|
|
| 567 |
@app.route('/api/projects/<string:project_id>/approve', methods=['PUT'])
|
| 568 |
def approve_project_plan(project_id):
|
| 569 |
uid = verify_token(request.headers.get('Authorization'))
|
| 570 |
-
if not uid:
|
|
|
|
| 571 |
|
| 572 |
project_ref = db_ref.child(f'projects/{project_id}')
|
| 573 |
project_data = project_ref.get()
|
|
@@ -575,19 +577,14 @@ def approve_project_plan(project_id):
|
|
| 575 |
return jsonify({'error': 'Project not found or access denied'}), 404
|
| 576 |
|
| 577 |
selected_option = request.json.get('selectedOption')
|
| 578 |
-
|
| 579 |
-
# 1) Download & compress the user’s image before sending it off to Gemini
|
| 580 |
response = requests.get(project_data['userImageURL'])
|
| 581 |
-
pil_image = Image.open(io.BytesIO(response.content)).convert(
|
| 582 |
-
pil_image.thumbnail((1024, 1024)) # max‐side 1024px
|
| 583 |
-
buf = io.BytesIO()
|
| 584 |
-
pil_image.save(buf, format='JPEG', quality=75, optimize=True)
|
| 585 |
-
buf.seek(0)
|
| 586 |
-
compressed_image = Image.open(buf)
|
| 587 |
|
| 588 |
-
context = (
|
| 589 |
-
|
| 590 |
-
|
|
|
|
|
|
|
| 591 |
|
| 592 |
detailed_prompt = f"""
|
| 593 |
You are a DIY expert. The user wants to proceed with the project titled "{project_data['projectTitle']}".
|
|
@@ -609,26 +606,24 @@ def approve_project_plan(project_id):
|
|
| 609 |
model=GENERATION_MODEL,
|
| 610 |
config=types.GenerateContentConfig(response_modalities=["Text", "Image"])
|
| 611 |
)
|
| 612 |
-
full_resp = chat.send_message([detailed_prompt,
|
| 613 |
-
|
| 614 |
gen_parts = full_resp.candidates[0].content.parts
|
|
|
|
| 615 |
combined_text = ""
|
| 616 |
inline_images = []
|
| 617 |
-
|
| 618 |
for part in gen_parts:
|
| 619 |
-
if part.text:
|
| 620 |
combined_text += part.text + "\n"
|
| 621 |
-
if part.inline_data:
|
| 622 |
-
img = Image.open(BytesIO(part.inline_data.data)).convert(
|
| 623 |
-
# 2) Immediately downscale each AI‐generated image
|
| 624 |
-
img.thumbnail((800, 800))
|
| 625 |
inline_images.append(img)
|
|
|
|
| 626 |
combined_text = combined_text.strip()
|
| 627 |
|
| 628 |
-
# parse out tools + steps
|
| 629 |
tools_section = re.search(r"TOOLS AND MATERIALS:\s*(.*?)\s*STEPS:", combined_text, re.DOTALL).group(1).strip()
|
| 630 |
steps_section = re.search(r"STEPS:\s*(.*)", combined_text, re.DOTALL).group(1).strip()
|
| 631 |
-
|
|
|
|
| 632 |
parsed_steps = parse_numbered_steps(steps_section)
|
| 633 |
|
| 634 |
if len(parsed_steps) != len(inline_images):
|
|
@@ -636,28 +631,12 @@ def approve_project_plan(project_id):
|
|
| 636 |
|
| 637 |
final_steps = []
|
| 638 |
for i, step_info in enumerate(parsed_steps):
|
| 639 |
-
# 3) Save JPEG at 70% quality
|
| 640 |
img_byte_arr = io.BytesIO()
|
| 641 |
-
inline_images[i].save(
|
| 642 |
-
img_byte_arr,
|
| 643 |
-
format='JPEG',
|
| 644 |
-
quality=70,
|
| 645 |
-
optimize=True
|
| 646 |
-
)
|
| 647 |
img_path = f"users/{uid}/projects/{project_id}/steps/step_{i+1}_image.jpg"
|
| 648 |
img_url = upload_to_storage(img_byte_arr.getvalue(), img_path, 'image/jpeg')
|
| 649 |
|
| 650 |
-
|
| 651 |
-
raw_audio = generate_tts_audio(step_info['text']) # returns raw bytes
|
| 652 |
-
from pydub import AudioSegment
|
| 653 |
-
sound = AudioSegment.from_file(io.BytesIO(raw_audio), format="wav")
|
| 654 |
-
mp3_buf = io.BytesIO()
|
| 655 |
-
sound.export(mp3_buf, format="mp3", bitrate="64k")
|
| 656 |
-
mp3_buf.seek(0)
|
| 657 |
-
narration_url = upload_to_storage(mp3_buf.read(),
|
| 658 |
-
f"users/{uid}/projects/{project_id}/steps/step_{i+1}_tts.mp3",
|
| 659 |
-
'audio/mpeg')
|
| 660 |
-
|
| 661 |
step_info.update({
|
| 662 |
"imageUrl": img_url,
|
| 663 |
"narrationUrl": narration_url,
|
|
@@ -673,6 +652,7 @@ def approve_project_plan(project_id):
|
|
| 673 |
"selectedOption": selected_option or ""
|
| 674 |
}
|
| 675 |
project_ref.update(update_data)
|
|
|
|
| 676 |
return jsonify({"success": True, **update_data})
|
| 677 |
|
| 678 |
except Exception as e:
|
|
|
|
| 564 |
print(traceback.format_exc())
|
| 565 |
return jsonify({'error': f"An error occurred: {e}"}), 500
|
| 566 |
|
| 567 |
+
|
| 568 |
@app.route('/api/projects/<string:project_id>/approve', methods=['PUT'])
|
| 569 |
def approve_project_plan(project_id):
|
| 570 |
uid = verify_token(request.headers.get('Authorization'))
|
| 571 |
+
if not uid:
|
| 572 |
+
return jsonify({'error': 'Unauthorized'}), 401
|
| 573 |
|
| 574 |
project_ref = db_ref.child(f'projects/{project_id}')
|
| 575 |
project_data = project_ref.get()
|
|
|
|
| 577 |
return jsonify({'error': 'Project not found or access denied'}), 404
|
| 578 |
|
| 579 |
selected_option = request.json.get('selectedOption')
|
|
|
|
|
|
|
| 580 |
response = requests.get(project_data['userImageURL'])
|
| 581 |
+
pil_image = Image.open(io.BytesIO(response.content)).convert('RGB')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 582 |
|
| 583 |
+
context = (
|
| 584 |
+
f"The user chose the upcycling project: '{selected_option}'."
|
| 585 |
+
if selected_option
|
| 586 |
+
else f"The user has approved the plan for '{project_data['projectTitle']}'."
|
| 587 |
+
)
|
| 588 |
|
| 589 |
detailed_prompt = f"""
|
| 590 |
You are a DIY expert. The user wants to proceed with the project titled "{project_data['projectTitle']}".
|
|
|
|
| 606 |
model=GENERATION_MODEL,
|
| 607 |
config=types.GenerateContentConfig(response_modalities=["Text", "Image"])
|
| 608 |
)
|
| 609 |
+
full_resp = chat.send_message([detailed_prompt, pil_image])
|
|
|
|
| 610 |
gen_parts = full_resp.candidates[0].content.parts
|
| 611 |
+
|
| 612 |
combined_text = ""
|
| 613 |
inline_images = []
|
|
|
|
| 614 |
for part in gen_parts:
|
| 615 |
+
if part.text is not None:
|
| 616 |
combined_text += part.text + "\n"
|
| 617 |
+
if part.inline_data is not None:
|
| 618 |
+
img = Image.open(io.BytesIO(part.inline_data.data)).convert('RGB')
|
|
|
|
|
|
|
| 619 |
inline_images.append(img)
|
| 620 |
+
|
| 621 |
combined_text = combined_text.strip()
|
| 622 |
|
|
|
|
| 623 |
tools_section = re.search(r"TOOLS AND MATERIALS:\s*(.*?)\s*STEPS:", combined_text, re.DOTALL).group(1).strip()
|
| 624 |
steps_section = re.search(r"STEPS:\s*(.*)", combined_text, re.DOTALL).group(1).strip()
|
| 625 |
+
|
| 626 |
+
tools_list = [line.strip("- ").strip() for line in tools_section.split('\n') if line.strip()]
|
| 627 |
parsed_steps = parse_numbered_steps(steps_section)
|
| 628 |
|
| 629 |
if len(parsed_steps) != len(inline_images):
|
|
|
|
| 631 |
|
| 632 |
final_steps = []
|
| 633 |
for i, step_info in enumerate(parsed_steps):
|
|
|
|
| 634 |
img_byte_arr = io.BytesIO()
|
| 635 |
+
inline_images[i].save(img_byte_arr, format='JPEG', optimize=True, quality=70)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 636 |
img_path = f"users/{uid}/projects/{project_id}/steps/step_{i+1}_image.jpg"
|
| 637 |
img_url = upload_to_storage(img_byte_arr.getvalue(), img_path, 'image/jpeg')
|
| 638 |
|
| 639 |
+
narration_url = generate_tts_audio_and_upload(step_info['text'], uid, project_id, i + 1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 640 |
step_info.update({
|
| 641 |
"imageUrl": img_url,
|
| 642 |
"narrationUrl": narration_url,
|
|
|
|
| 652 |
"selectedOption": selected_option or ""
|
| 653 |
}
|
| 654 |
project_ref.update(update_data)
|
| 655 |
+
|
| 656 |
return jsonify({"success": True, **update_data})
|
| 657 |
|
| 658 |
except Exception as e:
|