Spaces:
Sleeping
Sleeping
Commit ·
b5ef3ac
1
Parent(s): 3d6ba25
Enhance proposal generation by fetching architecture diagrams from Mermaid API and improving image handling
Browse files- src/app.py +32 -15
src/app.py
CHANGED
|
@@ -1,14 +1,13 @@
|
|
| 1 |
import re
|
| 2 |
import tempfile
|
|
|
|
|
|
|
| 3 |
from enum import Enum
|
| 4 |
-
from langchain_core.runnables.graph_mermaid import draw_mermaid_png
|
| 5 |
-
|
| 6 |
-
import pypandoc
|
| 7 |
from fastapi import FastAPI, HTTPException
|
| 8 |
from pydantic import BaseModel
|
| 9 |
from docx import Document
|
| 10 |
-
from docx.shared import Pt
|
| 11 |
-
|
| 12 |
|
| 13 |
from src.utils import EmailClient
|
| 14 |
|
|
@@ -24,7 +23,6 @@ class Email(str, Enum):
|
|
| 24 |
munish = "munish@sifars.com"
|
| 25 |
jatin = "jatin@sifars.com"
|
| 26 |
|
| 27 |
-
|
| 28 |
class ProposalRequest(BaseModel):
|
| 29 |
project_name: str
|
| 30 |
project_overview: str
|
|
@@ -43,28 +41,47 @@ class ProposalRequest(BaseModel):
|
|
| 43 |
architecture_diagram: str
|
| 44 |
recipient_email: Email
|
| 45 |
|
| 46 |
-
|
| 47 |
async def generate_proposal(data: dict):
|
| 48 |
|
| 49 |
-
# Generate architecture diagram
|
| 50 |
mermaid_code = data.get("architecture_diagram", "")
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
|
| 55 |
for para in DOC.paragraphs:
|
| 56 |
for key, value in data.items():
|
| 57 |
if f"{{{key}}}" in para.text:
|
| 58 |
if key == "architecture_diagram":
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
|
|
|
| 62 |
else:
|
| 63 |
para.text = para.text.replace(f"{{{key}}}", value)
|
| 64 |
for run in para.runs:
|
| 65 |
run.font.size = Pt(14)
|
| 66 |
run.font.name = "Arial"
|
| 67 |
|
|
|
|
| 68 |
with tempfile.NamedTemporaryFile(delete=False, suffix=".docx") as temp_file:
|
| 69 |
DOC.save(temp_file.name)
|
| 70 |
docx_file_path = temp_file.name
|
|
@@ -72,7 +89,7 @@ async def generate_proposal(data: dict):
|
|
| 72 |
attachments = [docx_file_path]
|
| 73 |
recipient_email = data.get("recipient_email", "sukhwinder@sifars.com")
|
| 74 |
subject = f"Proposal for {data.get('project_name')}"
|
| 75 |
-
body =
|
| 76 |
|
| 77 |
async with EmailClient() as email_client:
|
| 78 |
await email_client.send_email(
|
|
|
|
| 1 |
import re
|
| 2 |
import tempfile
|
| 3 |
+
import base64
|
| 4 |
+
import httpx # Add this import
|
| 5 |
from enum import Enum
|
|
|
|
|
|
|
|
|
|
| 6 |
from fastapi import FastAPI, HTTPException
|
| 7 |
from pydantic import BaseModel
|
| 8 |
from docx import Document
|
| 9 |
+
from docx.shared import Pt, Inches # Ensure Inches is imported
|
| 10 |
+
import pypandoc
|
| 11 |
|
| 12 |
from src.utils import EmailClient
|
| 13 |
|
|
|
|
| 23 |
munish = "munish@sifars.com"
|
| 24 |
jatin = "jatin@sifars.com"
|
| 25 |
|
|
|
|
| 26 |
class ProposalRequest(BaseModel):
|
| 27 |
project_name: str
|
| 28 |
project_overview: str
|
|
|
|
| 41 |
architecture_diagram: str
|
| 42 |
recipient_email: Email
|
| 43 |
|
|
|
|
| 44 |
async def generate_proposal(data: dict):
|
| 45 |
|
|
|
|
| 46 |
mermaid_code = data.get("architecture_diagram", "")
|
| 47 |
+
architecture_diagram_path = None
|
| 48 |
+
|
| 49 |
+
if mermaid_code.strip():
|
| 50 |
+
graphbytes = mermaid_code.encode("utf8")
|
| 51 |
+
base64_bytes = base64.urlsafe_b64encode(graphbytes)
|
| 52 |
+
base64_str = base64_bytes.decode("ascii")
|
| 53 |
+
url = f"https://mermaid.ink/img/{base64_str}"
|
| 54 |
+
|
| 55 |
+
try:
|
| 56 |
+
async with httpx.AsyncClient() as client:
|
| 57 |
+
response = await client.get(url)
|
| 58 |
+
response.raise_for_status()
|
| 59 |
+
|
| 60 |
+
# Save image to temp file
|
| 61 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix=".png") as temp_file:
|
| 62 |
+
temp_file.write(response.content)
|
| 63 |
+
architecture_diagram_path = temp_file.name
|
| 64 |
+
except httpx.HTTPError as e:
|
| 65 |
+
raise HTTPException(
|
| 66 |
+
status_code=500,
|
| 67 |
+
detail=f"Failed to generate architecture diagram: {str(e)}"
|
| 68 |
+
)
|
| 69 |
|
| 70 |
for para in DOC.paragraphs:
|
| 71 |
for key, value in data.items():
|
| 72 |
if f"{{{key}}}" in para.text:
|
| 73 |
if key == "architecture_diagram":
|
| 74 |
+
if architecture_diagram_path:
|
| 75 |
+
para.clear()
|
| 76 |
+
run = para.add_run()
|
| 77 |
+
run.add_picture(architecture_diagram_path, width=Inches(6))
|
| 78 |
else:
|
| 79 |
para.text = para.text.replace(f"{{{key}}}", value)
|
| 80 |
for run in para.runs:
|
| 81 |
run.font.size = Pt(14)
|
| 82 |
run.font.name = "Arial"
|
| 83 |
|
| 84 |
+
# Save DOCX and send email (unchanged)
|
| 85 |
with tempfile.NamedTemporaryFile(delete=False, suffix=".docx") as temp_file:
|
| 86 |
DOC.save(temp_file.name)
|
| 87 |
docx_file_path = temp_file.name
|
|
|
|
| 89 |
attachments = [docx_file_path]
|
| 90 |
recipient_email = data.get("recipient_email", "sukhwinder@sifars.com")
|
| 91 |
subject = f"Proposal for {data.get('project_name')}"
|
| 92 |
+
body = "Hello,\n\nPlease find the proposal attached.\n\nBest,\nProposal Bot"
|
| 93 |
|
| 94 |
async with EmailClient() as email_client:
|
| 95 |
await email_client.send_email(
|