Persano commited on
Commit
838468c
·
verified ·
1 Parent(s): 865072d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +252 -208
app.py CHANGED
@@ -1,193 +1,131 @@
1
  import os
2
  os.environ['FONTCONFIG_PATH'] = '/tmp/fontconfig'
3
  os.makedirs('/tmp/fontconfig', exist_ok=True)
4
-
5
-
6
  from flask import Flask, render_template, request, send_file
 
7
  import pandas as pd
8
  import io
9
- import matplotlib.pyplot as plt
10
- from reportlab.lib.pagesizes import A4
11
- from reportlab.pdfgen import canvas
12
- from reportlab.lib.utils import ImageReader
13
- from reportlab.lib import colors
14
- from reportlab.platypus import Table, TableStyle, Paragraph, Spacer
15
- from reportlab.lib.styles import getSampleStyleSheet
16
 
17
  app = Flask(__name__)
18
 
19
- def calcula_investimentos(capital, studio_ret, valorizacao, franquia_ret, acoes_ret, renda_fixa, inflacao, anos=5):
20
- # capital inicial
21
- dados = []
22
- # Valores iniciais
23
- studio_valor = capital
24
- franquia_valor = capital
25
- acoes_valor = capital
26
- renda_valor = capital
27
-
28
- # Para calcular valor patrimonial do studio: considera valorização acumulada (sem renda)
29
- studio_valor_patrimonial = capital
30
-
31
- for ano in range(1, anos+1):
32
- # Studio: valor patrimonial aumenta pela valorização anual
33
- studio_valor_patrimonial *= (1 + valorizacao / 100)
34
- # Renda mensal acumulada convertida para anual, reinvestida mensalmente - simplificamos usando juros compostos anualizados aproximados
35
- studio_valor *= (1 + studio_ret / 100) ** 12
36
- studio_valor *= (1 + valorizacao / 100) # valor patrimonial cresce
37
-
38
- # Franquia: apenas retorno anual fixo somado
39
- franquia_valor += franquia_ret
40
-
41
- # Ações: cresce pelo retorno anual
42
- acoes_valor *= (1 + acoes_ret / 100)
43
-
44
- # Renda fixa: cresce pelo retorno anual
45
- renda_valor *= (1 + renda_fixa / 100)
46
-
47
- # Ajuste pela inflação para valores reais (opcional)
48
- # Para esse exemplo, só mostramos valores nominais
49
-
50
- dados.append({
51
- 'Ano': ano,
52
- 'Studio Valor Total (R$)': round(studio_valor, 2),
53
- 'Studio Valor Patrimonial (R$)': round(studio_valor_patrimonial, 2),
54
- 'Franquia Valor Total (R$)': round(franquia_valor, 2),
55
- 'Ações Valor Total (R$)': round(acoes_valor, 2),
56
- 'Renda Fixa Valor Total (R$)': round(renda_valor, 2),
57
- })
58
-
59
- df = pd.DataFrame(dados)
60
- return df, studio_valor_patrimonial, studio_valor
61
-
62
- def gera_grafico(df):
63
- plt.switch_backend('Agg')
64
- plt.figure(figsize=(8,5))
65
- plt.plot(df['Ano'], df['Studio Valor Total (R$)'], label='Studio Total')
66
- plt.plot(df['Ano'], df['Franquia Valor Total (R$)'], label='Franquia Total')
67
- plt.plot(df['Ano'], df['Ações Valor Total (R$)'], label='Ações Total')
68
- plt.plot(df['Ano'], df['Renda Fixa Valor Total (R$)'], label='Renda Fixa Total')
69
- plt.title('Evolução do Investimento ao Longo dos Anos')
70
- plt.xlabel('Ano')
71
- plt.ylabel('Valor (R$)')
72
- plt.legend()
73
- plt.grid(True)
74
- buf = io.BytesIO()
75
- plt.savefig(buf, format='PNG')
76
- plt.close()
77
- buf.seek(0)
78
- return buf
79
-
80
- def gera_pdf(df, grafico_buf, params, valor_patrimonial, analise_final):
81
- buffer = io.BytesIO()
82
- c = canvas.Canvas(buffer, pagesize=A4)
83
- width, height = A4
84
- styles = getSampleStyleSheet()
85
- normal_style = styles["Normal"]
86
- title_style = styles["Title"]
87
-
88
- c.setFont("Helvetica-Bold", 16)
89
- c.drawString(50, height-50, "Relatório de Investimentos")
90
-
91
- y = height - 80
92
-
93
- # Mostrar dados de entrada
94
- c.setFont("Helvetica-Bold", 12)
95
- c.drawString(50, y, "Parâmetros de Entrada:")
96
- y -= 20
97
- c.setFont("Helvetica", 10)
98
- for k,v in params.items():
99
- c.drawString(55, y, f"{k}: {v}")
100
- y -= 15
101
-
102
- y -= 15
103
-
104
- # Mostrar explicação do valor patrimonial do Studio
105
- c.setFont("Helvetica-Bold", 12)
106
- c.drawString(50, y, "Valor Patrimonial do Studio:")
107
- y -= 15
108
- text = ("O valor patrimonial do Studio é o valor acumulado do aumento do patrimônio, "
109
- "considerando apenas a valorização do imóvel, sem a renda gerada.")
110
- p = Paragraph(text, normal_style)
111
- w, h = p.wrap(width - 100, y)
112
- p.drawOn(c, 50, y - h)
113
- y -= h + 10
114
-
115
- c.setFont("Helvetica", 10)
116
- c.drawString(50, y, f"Valor Patrimonial estimado após 5 anos: R$ {valor_patrimonial:,.2f}".replace(",", "X").replace(".", ",").replace("X", "."))
117
- y -= 30
118
-
119
- # Inserir gráfico
120
- img = ImageReader(grafico_buf)
121
- c.drawImage(img, 50, y - 250, width=500, height=250)
122
- y -= 260
123
-
124
- # Criar tabela com dados
125
- data = [df.columns.to_list()] + df.round(2).astype(str).values.tolist()
126
-
127
- # Formatar números para formato brasileiro (vírgula)
128
- for i in range(1, len(data)):
129
- for j in range(1, len(data[i])):
130
- data[i][j] = data[i][j].replace('.', ',')
131
-
132
- table = Table(data, colWidths=[50, 100, 110, 110, 110, 110])
133
- style = TableStyle([
134
- ('BACKGROUND', (0,0), (-1,0), colors.HexColor('#2E7D32')),
135
- ('TEXTCOLOR', (0,0), (-1,0), colors.white),
136
- ('ALIGN', (1,1), (-1,-1), 'RIGHT'),
137
- ('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
138
- ('GRID', (0,0), (-1,-1), 0.5, colors.grey),
139
- ('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.whitesmoke, colors.lightgrey]),
140
- ])
141
- table.setStyle(style)
142
-
143
- w, h = table.wrapOn(c, width-100, y)
144
- if y - h < 50:
145
- c.showPage()
146
- y = height - 50
147
- table.drawOn(c, 50, y - h)
148
- y -= h + 20
149
-
150
- # Análise final
151
- p2 = Paragraph(f"<b>Considerações finais:</b><br/>{analise_final}", normal_style)
152
- w2, h2 = p2.wrap(width - 100, y)
153
- if y - h2 < 50:
154
- c.showPage()
155
- y = height - 50
156
- p2.drawOn(c, 50, y - h2)
157
-
158
- c.save()
159
- buffer.seek(0)
160
- return buffer
161
 
162
  @app.route("/", methods=["GET", "POST"])
163
  def index():
164
  if request.method == "POST":
165
- capital = float(request.form.get("capital"))
166
- studio_ret = float(request.form.get("studio_ret"))
167
- valorizacao = float(request.form.get("valorizacao"))
168
- franquia_ret = float(request.form.get("franquia_ret"))
169
- acoes_ret = float(request.form.get("acoes_ret"))
170
- renda_fixa = float(request.form.get("renda_fixa"))
171
- inflacao = float(request.form.get("inflacao"))
172
-
173
- df, valor_patrimonial, valor_total_studio = calcula_investimentos(
174
- capital, studio_ret, valorizacao, franquia_ret, acoes_ret, renda_fixa, inflacao
175
- )
176
-
177
- # Construir tabela HTML simples para mostrar na página
178
- tabela_html = df.to_html(classes="table table-striped table-bordered", index=False, float_format="R$ {:,.2f}".format)
179
-
180
- # Identificar maior retorno final
181
- max_valor = max(df.iloc[-1][1:])
182
- max_col = df.columns[(df.iloc[-1][1:] == max_valor).idxmax()]
183
-
184
- analise_final = (f"Após análise dos cenários projetados para 5 anos, o investimento Studio apresenta o melhor desempenho, "
185
- f"com um valor final estimado de R$ {valor_total_studio:,.2f}. "
186
- f"Isto representa um retorno significativo sobre o capital inicial.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
 
188
  return render_template(
189
  "index.html",
190
- tabela=tabela_html,
191
  capital=capital,
192
  studio_ret=studio_ret,
193
  valorizacao=valorizacao,
@@ -195,49 +133,155 @@ def index():
195
  acoes_ret=acoes_ret,
196
  renda_fixa=renda_fixa,
197
  inflacao=inflacao,
 
 
 
 
 
198
  analise_final=analise_final,
199
- investimento_mais_valorizado=max_col,
200
- valor_mais_alto=max_valor
201
  )
202
- else:
203
- return render_template("index.html")
204
 
205
  @app.route("/download_pdf", methods=["POST"])
206
  def download_pdf():
207
- capital = float(request.form.get("capital"))
208
- studio_ret = float(request.form.get("studio_ret"))
209
- valorizacao = float(request.form.get("valorizacao"))
210
- franquia_ret = float(request.form.get("franquia_ret"))
211
- acoes_ret = float(request.form.get("acoes_ret"))
212
- renda_fixa = float(request.form.get("renda_fixa"))
213
- inflacao = float(request.form.get("inflacao"))
214
-
215
- df, valor_patrimonial, valor_total_studio = calcula_investimentos(
216
- capital, studio_ret, valorizacao, franquia_ret, acoes_ret, renda_fixa, inflacao
217
- )
218
-
219
- analise_final = (f"Após análise dos cenários projetados para 5 anos, o investimento Studio apresenta o melhor desempenho, "
220
- f"com um valor final estimado de R$ {valor_total_studio:,.2f}, equivalente a um retorno significativo sobre o capital inicial.")
221
-
222
- grafico_buf = gera_grafico(df)
223
-
224
- params = {
225
- "Capital Inicial (R$)": f"R$ {capital:,.2f}",
226
- "Retorno Mensal Studio (%)": f"{studio_ret}%",
227
- "Valorização Anual Studio (%)": f"{valorizacao}%",
228
- "Retorno Anual Franquia (R$)": f"R$ {franquia_ret:,.2f}",
229
- "Retorno Anual Ações (%)": f"{acoes_ret}%",
230
- "Retorno Anual Renda Fixa (%)": f"{renda_fixa}%",
231
- "Inflação Anual Estimada (%)": f"{inflacao}%"
232
  }
 
233
 
234
- pdf_buffer = gera_pdf(df, grafico_buf, params, valor_patrimonial, analise_final)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
 
236
- return send_file(pdf_buffer, as_attachment=True, download_name="relatorio_investimentos.pdf", mimetype="application/pdf")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
 
238
  if __name__ == "__main__":
239
- app.run(debug=True)
 
 
 
240
 
241
- if __name__ == '__main__':
242
- app.run(host='0.0.0.0', port=7860, debug=True)
243
 
 
1
  import os
2
  os.environ['FONTCONFIG_PATH'] = '/tmp/fontconfig'
3
  os.makedirs('/tmp/fontconfig', exist_ok=True)
4
+ import os
 
5
  from flask import Flask, render_template, request, send_file
6
+ import matplotlib.pyplot as plt
7
  import pandas as pd
8
  import io
9
+ import base64
10
+ from matplotlib.ticker import FuncFormatter
11
+ from xhtml2pdf import pisa
12
+ from datetime import datetime
 
 
 
13
 
14
  app = Flask(__name__)
15
 
16
+ def formatar_brl(valor):
17
+ return f"R$ {valor:,.2f}".replace(",", "X").replace(".", ",").replace("X", ".")
18
+
19
+ def gerar_analise(investimentos_finais, capital, patrimonio_studio_final):
20
+ melhor = max(investimentos_finais, key=investimentos_finais.get)
21
+ valor_melhor = investimentos_finais[melhor]
22
+ retorno_pct = ((valor_melhor - capital) / capital) * 100
23
+ texto = f"""
24
+ Após análise dos cenários projetados para 5 anos, o investimento <strong>{melhor}</strong> apresenta o melhor desempenho,
25
+ com um valor final estimado de <strong>{formatar_brl(valor_melhor)}</strong>, equivalente a um retorno de <strong>{retorno_pct:.1f}%</strong>.
26
+ <br><br>
27
+ O valor patrimonial do Studio, conforme normas contábeis e profissionais de investimento, representa o valor acumulado do imóvel sem considerar a renda gerada,
28
+ ou seja, é o aumento do patrimônio bruto estimado. Neste cenário, o valor patrimonial final do Studio é <strong>{formatar_brl(patrimonio_studio_final)}</strong>.
29
+ """
30
+ return texto
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
  @app.route("/", methods=["GET", "POST"])
33
  def index():
34
  if request.method == "POST":
35
+ capital = float(request.form["capital"])
36
+ studio_ret = float(request.form["studio_ret"])
37
+ valorizacao = float(request.form["valorizacao"])
38
+ franquia_ret = float(request.form["franquia_ret"])
39
+ acoes_ret = float(request.form["acoes_ret"])
40
+ renda_fixa = float(request.form["renda_fixa"])
41
+ inflacao = float(request.form["inflacao"])
42
+
43
+ anos = list(range(1, 6))
44
+
45
+ patrimonio_studio = [capital * ((1 + valorizacao / 100) ** ano) for ano in anos]
46
+ renda_acumulada_studio = [capital * (((1 + studio_ret / 100) ** (12 * ano)) - 1) for ano in anos]
47
+ studio_total = [p + r for p, r in zip(patrimonio_studio, renda_acumulada_studio)]
48
+
49
+ franquia = [capital + (franquia_ret * ano) for ano in anos]
50
+ acoes = [capital * ((1 + acoes_ret / 100) ** ano) for ano in anos]
51
+ renda_fixa_valores = [capital * ((1 + renda_fixa / 100) ** ano) for ano in anos]
52
+
53
+ dados = {
54
+ "Ano": anos,
55
+ "Studio (Patrimônio + Renda)": studio_total,
56
+ "Franquia": franquia,
57
+ "Ações": acoes,
58
+ "Renda Fixa": renda_fixa_valores
59
+ }
60
+ df = pd.DataFrame(dados)
61
+
62
+ investimentos_finais = {
63
+ "Studio": studio_total[-1],
64
+ "Franquia": franquia[-1],
65
+ "Ações": acoes[-1],
66
+ "Renda Fixa": renda_fixa_valores[-1],
67
+ }
68
+
69
+ investimento_mais_valorizado = max(investimentos_finais, key=investimentos_finais.get)
70
+ valor_mais_alto = investimentos_finais[investimento_mais_valorizado]
71
+
72
+ # Gráfico para mostrar no browser
73
+ plt.figure(figsize=(8, 5))
74
+ plt.plot(anos, studio_total, label="Studio (Patrimônio + Renda)", marker="o")
75
+ plt.plot(anos, franquia, label="Franquia", marker="o")
76
+ plt.plot(anos, acoes, label="Ações", marker="o")
77
+ plt.plot(anos, renda_fixa_valores, label="Renda Fixa", marker="o")
78
+ plt.title("Projeção de Investimentos (5 anos)")
79
+ plt.xlabel("Ano")
80
+ plt.ylabel("Valor (R$)")
81
+ plt.legend()
82
+ plt.grid(True)
83
+
84
+ def formatar_moeda(x, _):
85
+ return f"R${x:,.0f}".replace(",", ".")
86
+
87
+ plt.gca().yaxis.set_major_formatter(FuncFormatter(formatar_moeda))
88
+ plt.tight_layout()
89
+
90
+ buf = io.BytesIO()
91
+ plt.savefig(buf, format="png")
92
+ buf.seek(0)
93
+ grafico_base64 = base64.b64encode(buf.getvalue()).decode("utf-8")
94
+ buf.close()
95
+ plt.close()
96
+
97
+ # Tabela com valores formatados para exibir no browser
98
+ df_formatado = df.copy()
99
+ for col in df.columns:
100
+ if col != "Ano":
101
+ df_formatado[col] = df_formatado[col].apply(formatar_brl)
102
+ tabela = df_formatado.to_html(index=False, classes="table table-striped table-sm", border=0)
103
+
104
+ analise_final = gerar_analise(investimentos_finais, capital, patrimonio_studio[-1])
105
+
106
+ resumo = []
107
+ for nome, valor_final in investimentos_finais.items():
108
+ retorno_abs = valor_final - capital
109
+ retorno_pct = (retorno_abs / capital) * 100
110
+ resumo.append({
111
+ "Investimento": nome,
112
+ "Valor Final": formatar_brl(valor_final),
113
+ "Retorno Absoluto": formatar_brl(retorno_abs),
114
+ "Retorno (%)": f"{retorno_pct:.1f}%"
115
+ })
116
+ resumo = sorted(resumo, key=lambda x: float(x["Retorno (%)"].replace("%", "").replace(",", ".")), reverse=True)
117
+
118
+ diferenca_pct = float(resumo[0]["Retorno (%)"].replace("%", "").replace(",", ".")) - float(resumo[1]["Retorno (%)"].replace("%", "").replace(",", "."))
119
+ comentario_extra = ""
120
+ if diferenca_pct < 5:
121
+ comentario_extra = f"""
122
+ Apesar do <strong>{resumo[0]['Investimento']}</strong> ter se destacado, a diferença em relação ao segundo colocado
123
+ (<strong>{resumo[1]['Investimento']}</strong>) foi de apenas {diferenca_pct:.1f} pontos percentuais.
124
+ Isso indica que ambas as estratégias podem ser consideradas, dependendo do perfil de risco e objetivos do investidor.
125
+ """
126
 
127
  return render_template(
128
  "index.html",
 
129
  capital=capital,
130
  studio_ret=studio_ret,
131
  valorizacao=valorizacao,
 
133
  acoes_ret=acoes_ret,
134
  renda_fixa=renda_fixa,
135
  inflacao=inflacao,
136
+ anos=anos,
137
+ tabela=tabela,
138
+ grafico=grafico_base64,
139
+ investimento_mais_valorizado=investimento_mais_valorizado,
140
+ valor_mais_alto=valor_mais_alto,
141
  analise_final=analise_final,
142
+ comentario_extra=comentario_extra,
143
+ resumo=resumo
144
  )
145
+ return render_template("index.html")
146
+
147
 
148
  @app.route("/download_pdf", methods=["POST"])
149
  def download_pdf():
150
+ capital = float(request.form["capital"])
151
+ studio_ret = float(request.form["studio_ret"])
152
+ valorizacao = float(request.form["valorizacao"])
153
+ franquia_ret = float(request.form["franquia_ret"])
154
+ acoes_ret = float(request.form["acoes_ret"])
155
+ renda_fixa = float(request.form["renda_fixa"])
156
+ inflacao = float(request.form["inflacao"])
157
+
158
+ anos = list(range(1, 6))
159
+
160
+ patrimonio_studio = [capital * ((1 + valorizacao / 100) ** ano) for ano in anos]
161
+ renda_acumulada_studio = [capital * (((1 + studio_ret / 100) ** (12 * ano)) - 1) for ano in anos]
162
+ studio_total = [p + r for p, r in zip(patrimonio_studio, renda_acumulada_studio)]
163
+ franquia = [capital + (franquia_ret * ano) for ano in anos]
164
+ acoes = [capital * ((1 + acoes_ret / 100) ** ano) for ano in anos]
165
+ renda_fixa_valores = [capital * ((1 + renda_fixa / 100) ** ano) for ano in anos]
166
+
167
+ dados = {
168
+ "Ano": anos,
169
+ "Studio (Patrimônio + Renda)": studio_total,
170
+ "Franquia": franquia,
171
+ "Ações": acoes,
172
+ "Renda Fixa": renda_fixa_valores
 
 
173
  }
174
+ df = pd.DataFrame(dados)
175
 
176
+ investimentos_finais = {
177
+ "Studio": studio_total[-1],
178
+ "Franquia": franquia[-1],
179
+ "Ações": acoes[-1],
180
+ "Renda Fixa": renda_fixa_valores[-1],
181
+ }
182
+ investimento_mais_valorizado = max(investimentos_finais, key=investimentos_finais.get)
183
+ valor_mais_alto = investimentos_finais[investimento_mais_valorizado]
184
+
185
+ # Gráfico PNG para PDF
186
+ plt.figure(figsize=(8, 5))
187
+ plt.plot(anos, studio_total, label="Studio (Patrimônio + Renda)", marker="o")
188
+ plt.plot(anos, franquia, label="Franquia", marker="o")
189
+ plt.plot(anos, acoes, label="Ações", marker="o")
190
+ plt.plot(anos, renda_fixa_valores, label="Renda Fixa", marker="o")
191
+ plt.title("Projeção de Investimentos (5 anos)")
192
+ plt.xlabel("Ano")
193
+ plt.ylabel("Valor (R$)")
194
+ plt.legend()
195
+ plt.grid(True)
196
+ plt.gca().yaxis.set_major_formatter(FuncFormatter(lambda x, _: f"R${x:,.0f}".replace(",", ".")))
197
+ plt.tight_layout()
198
+
199
+ img_buf = io.BytesIO()
200
+ plt.savefig(img_buf, format='png')
201
+ img_buf.seek(0)
202
+ img_base64 = base64.b64encode(img_buf.getvalue()).decode("utf-8")
203
+ img_buf.close()
204
+ plt.close()
205
 
206
+ df_formatado = df.copy()
207
+ for col in df.columns:
208
+ if col != "Ano":
209
+ df_formatado[col] = df_formatado[col].apply(formatar_brl)
210
+ tabela_html = df_formatado.to_html(index=False, border=1, classes="table-pdf")
211
+
212
+ analise = gerar_analise(investimentos_finais, capital, patrimonio_studio[-1])
213
+
214
+ # Tabela de entrada de dados (para relatório)
215
+ tabela_entrada = f"""
216
+ <table border="1" class="table-pdf" style="border-collapse: collapse; width: 100%;">
217
+ <thead>
218
+ <tr style="background-color: #f0f0f0;">
219
+ <th>Parâmetro</th>
220
+ <th>Valor</th>
221
+ </tr>
222
+ </thead>
223
+ <tbody>
224
+ <tr><td>Capital Inicial</td><td>{formatar_brl(capital)}</td></tr>
225
+ <tr><td>Retorno Mensal Studio (%)</td><td>{studio_ret:.2f}%</td></tr>
226
+ <tr><td>Valorização Anual Studio (%)</td><td>{valorizacao:.2f}%</td></tr>
227
+ <tr><td>Retorno Anual Franquia (R$)</td><td>{formatar_brl(franquia_ret)}</td></tr>
228
+ <tr><td>Retorno Anual Ações (%)</td><td>{acoes_ret:.2f}%</td></tr>
229
+ <tr><td>Retorno Anual Renda Fixa (%)</td><td>{renda_fixa:.2f}%</td></tr>
230
+ <tr><td>Inflação Anual (%)</td><td>{inflacao:.2f}%</td></tr>
231
+ </tbody>
232
+ </table>
233
+ """
234
+
235
+ html = f"""
236
+ <html>
237
+ <head>
238
+ <meta charset="utf-8">
239
+ <style>
240
+ body {{ font-family: Arial, sans-serif; font-size: 14px; color: #333; }}
241
+ h2 {{ color: #2c3e50; }}
242
+ table.table-pdf {{ width: 100%; border-collapse: collapse; margin-top: 15px; }}
243
+ table.table-pdf th, table.table-pdf td {{ border: 1px solid #ccc; padding: 6px; text-align: right; }}
244
+ table.table-pdf th {{ background-color: #f0f0f0; }}
245
+ .destaque {{ background: #e8f5e9; padding: 10px; margin-top: 20px; border-left: 6px solid #2e7d32; font-size: 14px; }}
246
+ img {{ margin-top: 20px; max-width: 100%; height: auto; }}
247
+ </style>
248
+ </head>
249
+ <body>
250
+ <h2>Relatório de Simulação de Investimentos</h2>
251
+ <p>Data da Simulação: {datetime.today().strftime('%d/%m/%Y')}</p>
252
+
253
+ <h3>Dados de Entrada</h3>
254
+ {tabela_entrada}
255
+
256
+ <div class="destaque">{analise}</div>
257
+
258
+ <h3>Projeção Gráfica</h3>
259
+ <img src="data:image/png;base64,{img_base64}" />
260
+
261
+ <h3>Evolução dos Investimentos (Ano a Ano)</h3>
262
+ {tabela_html}
263
+ </body>
264
+ </html>
265
+ """
266
+
267
+ pdf_buffer = io.BytesIO()
268
+ pisa_status = pisa.CreatePDF(io.StringIO(html), dest=pdf_buffer)
269
+
270
+ if pisa_status.err:
271
+ return "Erro ao gerar PDF", 500
272
+
273
+ pdf_buffer.seek(0)
274
+ return send_file(
275
+ pdf_buffer,
276
+ mimetype="application/pdf",
277
+ as_attachment=True,
278
+ download_name="relatorio_investimentos.pdf"
279
+ )
280
 
281
  if __name__ == "__main__":
282
+ # Porta 7860 padrão do Hugging Face Spaces
283
+ port = int(os.environ.get("PORT", 7860))
284
+ app.run(host="0.0.0.0", port=port)
285
+
286
 
 
 
287