Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -1987,125 +1987,159 @@ async def analyze_only(files: List[UploadFile] = File(...)):
|
|
| 1987 |
raise HTTPException(status_code=500, detail=str(e))
|
| 1988 |
|
| 1989 |
|
| 1990 |
-
|
| 1991 |
-
|
| 1992 |
-
|
| 1993 |
-
|
| 1994 |
|
| 1995 |
-
|
| 1996 |
-
|
| 1997 |
-
|
| 1998 |
-
return None, "Please upload at least one PDF file"
|
| 1999 |
|
| 2000 |
-
|
| 2001 |
-
|
| 2002 |
-
|
| 2003 |
-
|
| 2004 |
-
|
| 2005 |
-
|
| 2006 |
-
|
| 2007 |
-
|
| 2008 |
-
|
| 2009 |
-
|
| 2010 |
-
|
| 2011 |
-
|
| 2012 |
-
|
| 2013 |
-
|
| 2014 |
-
|
| 2015 |
-
|
| 2016 |
-
|
| 2017 |
-
|
| 2018 |
-
|
| 2019 |
-
|
| 2020 |
-
|
| 2021 |
-
|
| 2022 |
-
|
| 2023 |
-
|
| 2024 |
-
|
| 2025 |
-
|
| 2026 |
-
|
| 2027 |
-
|
| 2028 |
-
|
| 2029 |
-
|
| 2030 |
-
|
| 2031 |
-
|
| 2032 |
-
|
| 2033 |
-
|
| 2034 |
-
|
| 2035 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2036 |
|
| 2037 |
-
|
| 2038 |
-
|
| 2039 |
-
|
| 2040 |
-
|
| 2041 |
-
|
| 2042 |
-
|
| 2043 |
-
|
| 2044 |
-
|
| 2045 |
-
|
| 2046 |
-
|
| 2047 |
-
|
| 2048 |
-
|
| 2049 |
-
|
| 2050 |
-
file_types=[".pdf", ".xlsx", ".xls"], # Added .xlsx and .xls
|
| 2051 |
-
type="filepath"
|
| 2052 |
-
)
|
| 2053 |
-
|
| 2054 |
-
process_btn = gr.Button("Generate Financial Model", variant="primary", size="lg")
|
| 2055 |
-
|
| 2056 |
-
with gr.Column(scale=1):
|
| 2057 |
-
gr.Markdown("""
|
| 2058 |
-
### ๐ Supported Formats
|
| 2059 |
-
- **PDF**: Offering Memorandum, Reports
|
| 2060 |
-
- **XLSX/XLS**: Financial statements, data tables
|
| 2061 |
-
|
| 2062 |
-
### ๐ Required Documents
|
| 2063 |
-
- Offering Memorandum (PDF/XLSX)
|
| 2064 |
-
- Operating Expenses Summary (PDF/XLSX)
|
| 2065 |
-
- Sales Comps (PDF/XLSX)
|
| 2066 |
-
- Rent Comps (PDF/XLSX)
|
| 2067 |
-
- Market Report (PDF/XLSX)
|
| 2068 |
-
- Demographics Overview (PDF/XLSX)
|
| 2069 |
-
|
| 2070 |
-
### โก Features
|
| 2071 |
-
- Automated data extraction
|
| 2072 |
-
- Formula calculations
|
| 2073 |
-
- Professional Excel output
|
| 2074 |
-
- Multiple analysis sheets
|
| 2075 |
-
""")
|
| 2076 |
-
|
| 2077 |
-
with gr.Row():
|
| 2078 |
-
output_text = gr.Textbox(
|
| 2079 |
-
label="Processing Results",
|
| 2080 |
-
lines=12,
|
| 2081 |
-
interactive=False
|
| 2082 |
)
|
| 2083 |
-
|
| 2084 |
-
|
| 2085 |
-
|
| 2086 |
-
|
|
|
|
| 2087 |
)
|
| 2088 |
|
| 2089 |
-
|
| 2090 |
-
|
| 2091 |
-
|
| 2092 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2093 |
)
|
| 2094 |
-
|
| 2095 |
-
gr.Markdown("""
|
| 2096 |
-
---
|
| 2097 |
-
### ๐ก Tips
|
| 2098 |
-
- Ensure PDF files are readable and not scanned images
|
| 2099 |
-
- Use descriptive filenames (e.g., "Offering_Memorandum.pdf")
|
| 2100 |
-
- Processing may take 30-60 seconds depending on file sizes
|
| 2101 |
-
""")
|
| 2102 |
|
| 2103 |
-
|
| 2104 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2105 |
app = gr.mount_gradio_app(app, demo, path="/")
|
|
|
|
|
|
|
| 2106 |
uvicorn.run(
|
| 2107 |
-
app,
|
| 2108 |
-
host="0.0.0.0",
|
| 2109 |
port=7860,
|
| 2110 |
log_level="info"
|
| 2111 |
)
|
|
|
|
| 1987 |
raise HTTPException(status_code=500, detail=str(e))
|
| 1988 |
|
| 1989 |
|
| 1990 |
+
def process_pdfs(pdf_files):
|
| 1991 |
+
"""Process uploaded PDFs and return Excel file"""
|
| 1992 |
+
if not pdf_files:
|
| 1993 |
+
return None, "โ ๏ธ Please upload at least one PDF/XLSX file"
|
| 1994 |
|
| 1995 |
+
try:
|
| 1996 |
+
# Create temporary directory for PDFs
|
| 1997 |
+
temp_dir = tempfile.mkdtemp()
|
|
|
|
| 1998 |
|
| 1999 |
+
# Save uploaded PDFs to temp directory
|
| 2000 |
+
for pdf_file in pdf_files:
|
| 2001 |
+
if pdf_file is None:
|
| 2002 |
+
continue
|
| 2003 |
+
dest_path = Path(temp_dir) / Path(pdf_file.name).name
|
| 2004 |
+
shutil.copy(pdf_file.name, dest_path)
|
| 2005 |
+
|
| 2006 |
+
# Initialize pipeline with hardcoded API key
|
| 2007 |
+
pipeline = RealEstateModelPipeline(GEMINI_API_KEY)
|
| 2008 |
+
|
| 2009 |
+
# Create output file in temp directory
|
| 2010 |
+
output_file = Path(temp_dir) / "Real_Estate_Financial_Model.xlsx"
|
| 2011 |
+
|
| 2012 |
+
# Run pipeline
|
| 2013 |
+
result = pipeline.run_full_pipeline(temp_dir, str(output_file))
|
| 2014 |
+
|
| 2015 |
+
# Generate summary text
|
| 2016 |
+
r = pipeline.formula_results
|
| 2017 |
+
irr_val = r.get('IRR_TO_LP', 0)
|
| 2018 |
+
if isinstance(irr_val, complex):
|
| 2019 |
+
irr_val = irr_val.real
|
| 2020 |
+
|
| 2021 |
+
summary = f"""โ
**Processing Complete!**
|
| 2022 |
+
|
| 2023 |
+
๐ **Key Metrics:**
|
| 2024 |
+
โข Total Project Cost: ${r.get('TOTAL_FINANCING_CONTINGENCY_AND_RESERVES', 0):,.0f}
|
| 2025 |
+
โข Total Debt: ${r.get('TOTAL_DEBT', 0):,.0f}
|
| 2026 |
+
โข Total Equity: ${r.get('TOTAL_EQUITY', 0):,.0f}
|
| 2027 |
+
โข NOI: ${r.get('NET_OPERATING_INCOME', 0):,.0f}
|
| 2028 |
+
โข Yield on Cost: {r.get('YIELD_ON_COST_PERCENTAGE', 0):.2%}
|
| 2029 |
+
โข LP IRR: {float(irr_val):.2f}%
|
| 2030 |
+
|
| 2031 |
+
โจ Download your Excel file below โฌ๏ธ
|
| 2032 |
+
"""
|
| 2033 |
+
|
| 2034 |
+
return str(output_file), summary
|
| 2035 |
+
|
| 2036 |
+
except Exception as e:
|
| 2037 |
+
import traceback
|
| 2038 |
+
error_msg = f"โ **Error occurred:**\n\n{str(e)}\n\n**Details:**\n{traceback.format_exc()}"
|
| 2039 |
+
return None, error_msg
|
| 2040 |
+
|
| 2041 |
+
# Create Gradio interface with better styling
|
| 2042 |
+
with gr.Blocks(
|
| 2043 |
+
title="Real Estate Financial Model Generator",
|
| 2044 |
+
theme=gr.themes.Soft(),
|
| 2045 |
+
css="""
|
| 2046 |
+
.gradio-container {
|
| 2047 |
+
max-width: 1200px !important;
|
| 2048 |
+
}
|
| 2049 |
+
.output-text {
|
| 2050 |
+
font-family: monospace;
|
| 2051 |
+
}
|
| 2052 |
+
"""
|
| 2053 |
+
) as demo:
|
| 2054 |
|
| 2055 |
+
gr.Markdown("""
|
| 2056 |
+
# ๐ข Real Estate Financial Model Generator
|
| 2057 |
+
|
| 2058 |
+
Upload your PDF/XLSX documents and generate a comprehensive financial model in Excel format.
|
| 2059 |
+
""")
|
| 2060 |
+
|
| 2061 |
+
with gr.Row():
|
| 2062 |
+
with gr.Column(scale=2):
|
| 2063 |
+
pdf_input = gr.File(
|
| 2064 |
+
label="๐ Upload PDF/XLSX Files",
|
| 2065 |
+
file_count="multiple",
|
| 2066 |
+
file_types=[".pdf", ".xlsx", ".xls"],
|
| 2067 |
+
type="filepath"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2068 |
)
|
| 2069 |
+
|
| 2070 |
+
process_btn = gr.Button(
|
| 2071 |
+
"๐ Generate Financial Model",
|
| 2072 |
+
variant="primary",
|
| 2073 |
+
size="lg"
|
| 2074 |
)
|
| 2075 |
|
| 2076 |
+
with gr.Column(scale=1):
|
| 2077 |
+
gr.Markdown("""
|
| 2078 |
+
### ๐ Supported Formats
|
| 2079 |
+
- **PDF**: Offering Memorandum, Reports
|
| 2080 |
+
- **XLSX/XLS**: Financial statements, data tables
|
| 2081 |
+
|
| 2082 |
+
### ๐ Required Documents
|
| 2083 |
+
- Offering Memorandum
|
| 2084 |
+
- Operating Expenses Summary
|
| 2085 |
+
- Sales Comps
|
| 2086 |
+
- Rent Comps
|
| 2087 |
+
- Market Report
|
| 2088 |
+
- Demographics Overview
|
| 2089 |
+
|
| 2090 |
+
### โก Features
|
| 2091 |
+
- โจ Automated data extraction
|
| 2092 |
+
- ๐งฎ Formula calculations
|
| 2093 |
+
- ๐ Professional Excel output
|
| 2094 |
+
- ๐ Multiple analysis sheets
|
| 2095 |
+
""")
|
| 2096 |
+
|
| 2097 |
+
with gr.Row():
|
| 2098 |
+
output_text = gr.Textbox(
|
| 2099 |
+
label="๐ Processing Results",
|
| 2100 |
+
lines=15,
|
| 2101 |
+
interactive=False,
|
| 2102 |
+
elem_classes=["output-text"]
|
| 2103 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2104 |
|
| 2105 |
+
with gr.Row():
|
| 2106 |
+
excel_output = gr.File(
|
| 2107 |
+
label="๐ Download Excel File",
|
| 2108 |
+
interactive=False
|
| 2109 |
+
)
|
| 2110 |
+
|
| 2111 |
+
# Connect the button
|
| 2112 |
+
process_btn.click(
|
| 2113 |
+
fn=process_pdfs,
|
| 2114 |
+
inputs=[pdf_input],
|
| 2115 |
+
outputs=[excel_output, output_text],
|
| 2116 |
+
api_name="process"
|
| 2117 |
+
)
|
| 2118 |
+
|
| 2119 |
+
gr.Markdown("""
|
| 2120 |
+
---
|
| 2121 |
+
### ๐ก Tips
|
| 2122 |
+
- Ensure PDF files are readable and not scanned images
|
| 2123 |
+
- Use descriptive filenames (e.g., "Offering_Memorandum.pdf")
|
| 2124 |
+
- Processing may take 30-60 seconds depending on file sizes
|
| 2125 |
+
- Check the **Processing Results** section for detailed feedback
|
| 2126 |
+
|
| 2127 |
+
### ๐ง API Endpoints
|
| 2128 |
+
- `POST /api/generate-model` - Generate Excel only
|
| 2129 |
+
- `POST /api/generate-model-with-summary` - Generate Excel + JSON summary
|
| 2130 |
+
- `POST /api/analyze-only` - Generate JSON summary only
|
| 2131 |
+
- `GET /api/health` - Health check
|
| 2132 |
+
""")
|
| 2133 |
+
|
| 2134 |
+
# ============= Mount and Launch =============
|
| 2135 |
+
if __name__ == "__main__":
|
| 2136 |
+
# Mount Gradio to FastAPI
|
| 2137 |
app = gr.mount_gradio_app(app, demo, path="/")
|
| 2138 |
+
|
| 2139 |
+
# Launch with proper configuration
|
| 2140 |
uvicorn.run(
|
| 2141 |
+
app,
|
| 2142 |
+
host="0.0.0.0",
|
| 2143 |
port=7860,
|
| 2144 |
log_level="info"
|
| 2145 |
)
|