Amity123 commited on
Commit
994b6c2
·
verified ·
1 Parent(s): a26ab3c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +20 -45
app.py CHANGED
@@ -12,9 +12,8 @@ from openai import OpenAI
12
  from reportlab.lib import colors
13
  from reportlab.lib.pagesizes import A4
14
  from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer
15
- from reportlab.lib.styles import getSampleStyleSheet
16
  from reportlab.pdfbase import pdfmetrics
17
- from reportlab.pdfbase.ttfonts import TTFont
18
  from reportlab.pdfbase.cidfonts import UnicodeCIDFont
19
 
20
  # --------------------
@@ -26,7 +25,6 @@ FALLBACK_TEXT = """
26
  ### 1. 可能相關疾病
27
  - 胃食道逆流(GERD):胃酸回流到食道,可能引起燒灼感和胃痛。
28
  - 胃潰瘍:胃內部的黏膜受損,形成潰瘍,可能導致疼痛和不適。
29
- - 胃炎:胃黏膜的炎症,通常伴隨疼痛、噁心和消化不良。
30
  ### 2. 飲食營養建議
31
  - 纖維素:有助於消化,減少便秘和腸道不適。
32
  - 維生素C:幫助修復胃黏膜,增強免疫系統。
@@ -43,7 +41,7 @@ FALLBACK_TEXT = """
43
  """.strip()
44
 
45
  # --------------------
46
- # GPT 呼叫
47
  # --------------------
48
  def call_gpt_system(prompt: str) -> str:
49
  if client is None:
@@ -51,8 +49,9 @@ def call_gpt_system(prompt: str) -> str:
51
  try:
52
  resp = client.chat.completions.create(
53
  model="gpt-4o-mini",
 
 
54
  messages=[{"role": "user", "content": prompt}],
55
- temperature=0.7,
56
  )
57
  text = resp.choices[0].message.content
58
  return text if text and text.strip() else FALLBACK_TEXT
@@ -61,7 +60,7 @@ def call_gpt_system(prompt: str) -> str:
61
  return FALLBACK_TEXT
62
 
63
  # --------------------
64
- # 解析函式
65
  # --------------------
66
  def extract_block(text: str, starts: list, ends: list = None) -> str:
67
  if not text:
@@ -159,7 +158,7 @@ def robust_parse(text: str) -> Tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame]:
159
  return df_disease, df_nutrition, df_meals
160
 
161
  # --------------------
162
- # PDF 生成
163
  # --------------------
164
  def has_chinese(s: str) -> bool:
165
  return bool(re.search(r"[\u4e00-\u9fff]", str(s)))
@@ -175,12 +174,8 @@ def generate_pdf_file(df_disease, df_nutrition, df_meals, basic_info=None):
175
  df_nutrition = clean_dataframe(df_nutrition)
176
  df_meals = clean_dataframe(df_meals)
177
 
178
- font_name, font_ok = None, False
179
- try:
180
- pdfmetrics.registerFont(UnicodeCIDFont("STSong-Light"))
181
- font_name = "STSong-Light"; font_ok = True
182
- except:
183
- pass
184
 
185
  file_prefix = basic_info.get("name", "個人") if basic_info else "個人"
186
  safe_name = re.sub(r"[^\w\u4e00-\u9fff]", "_", file_prefix)
@@ -192,9 +187,9 @@ def generate_pdf_file(df_disease, df_nutrition, df_meals, basic_info=None):
192
  styles = getSampleStyleSheet()
193
  title_style = styles["Title"].clone("title")
194
  heading_style = styles["Heading2"].clone("h2")
195
- normal_style = styles["Normal"].clone("normal")
196
- if font_ok and font_name:
197
- title_style.fontName = heading_style.fontName = normal_style.fontName = font_name
198
 
199
  # 標題
200
  elements.append(Paragraph(f"健康分析與飲食建議報告 — {file_prefix}", title_style))
@@ -214,10 +209,8 @@ def generate_pdf_file(df_disease, df_nutrition, df_meals, basic_info=None):
214
  style = TableStyle([
215
  ("GRID", (0, 0), (-1, -1), 0.8, colors.black),
216
  ("BACKGROUND", (0, 0), (-1, 0), colors.lightgrey),
217
- ("VALIGN", (0, 0), (-1, -1), "TOP"),
218
  ])
219
- if font_ok:
220
- style.add("FONTNAME", (0, 0), (-1, -1), font_name)
221
  t.setStyle(style)
222
  elements.append(t)
223
  elements.append(Spacer(1, 16))
@@ -225,45 +218,27 @@ def generate_pdf_file(df_disease, df_nutrition, df_meals, basic_info=None):
225
  # 疾病表
226
  if not df_disease.empty:
227
  elements.append(Paragraph("一、可能相關疾病", heading_style))
228
- table_data = [df_disease.columns.tolist()] + df_disease.values.tolist()
229
  t = Table(table_data, colWidths=[150, 330])
230
- style = TableStyle([
231
- ("GRID", (0, 0), (-1, -1), 0.8, colors.black),
232
- ("BACKGROUND", (0, 0), (-1, 0), colors.lightgrey),
233
- ])
234
- if font_ok:
235
- style.add("FONTNAME", (0, 0), (-1, -1), font_name)
236
- t.setStyle(style)
237
  elements.append(t)
238
  elements.append(Spacer(1, 12))
239
 
240
  # 營養建議表
241
  if not df_nutrition.empty:
242
  elements.append(Paragraph("二、飲食營養建議", heading_style))
243
- table_data = [df_nutrition.columns.tolist()] + df_nutrition.values.tolist()
244
  t = Table(table_data, colWidths=[150, 330])
245
- style = TableStyle([
246
- ("GRID", (0, 0), (-1, -1), 0.8, colors.black),
247
- ("BACKGROUND", (0, 0), (-1, 0), colors.lightgrey),
248
- ])
249
- if font_ok:
250
- style.add("FONTNAME", (0, 0), (-1, -1), font_name)
251
- t.setStyle(style)
252
  elements.append(t)
253
  elements.append(Spacer(1, 12))
254
 
255
- # 餐點表
256
  if not df_meals.empty:
257
  elements.append(Paragraph("三、一日三餐(中式 / 西式)", heading_style))
258
- table_data = [df_meals.columns.tolist()] + df_meals.values.tolist()
259
  t = Table(table_data, colWidths=[240, 240])
260
- style = TableStyle([
261
- ("GRID", (0, 0), (-1, -1), 0.8, colors.black),
262
- ("BACKGROUND", (0, 0), (-1, 0), colors.lightgrey),
263
- ])
264
- if font_ok:
265
- style.add("FONTNAME", (0, 0), (-1, -1), font_name)
266
- t.setStyle(style)
267
  elements.append(t)
268
 
269
  doc.build(elements)
@@ -300,7 +275,7 @@ css_code = """
300
  """
301
 
302
  with gr.Blocks(css=css_code) as demo:
303
- gr.Markdown("## 🥗 AI 營養師 — 客製化飲建議")
304
  with gr.Row():
305
  with gr.Column(scale=1):
306
  gr.Markdown("### 請輸入基本資料")
 
12
  from reportlab.lib import colors
13
  from reportlab.lib.pagesizes import A4
14
  from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer
15
+ from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
16
  from reportlab.pdfbase import pdfmetrics
 
17
  from reportlab.pdfbase.cidfonts import UnicodeCIDFont
18
 
19
  # --------------------
 
25
  ### 1. 可能相關疾病
26
  - 胃食道逆流(GERD):胃酸回流到食道,可能引起燒灼感和胃痛。
27
  - 胃潰瘍:胃內部的黏膜受損,形成潰瘍,可能導致疼痛和不適。
 
28
  ### 2. 飲食營養建議
29
  - 纖維素:有助於消化,減少便秘和腸道不適。
30
  - 維生素C:幫助修復胃黏膜,增強免疫系統。
 
41
  """.strip()
42
 
43
  # --------------------
44
+ # GPT 呼叫(加速版)
45
  # --------------------
46
  def call_gpt_system(prompt: str) -> str:
47
  if client is None:
 
49
  try:
50
  resp = client.chat.completions.create(
51
  model="gpt-4o-mini",
52
+ max_tokens=500, # 限制字數以加快速度
53
+ temperature=0.6, # 適度隨機
54
  messages=[{"role": "user", "content": prompt}],
 
55
  )
56
  text = resp.choices[0].message.content
57
  return text if text and text.strip() else FALLBACK_TEXT
 
60
  return FALLBACK_TEXT
61
 
62
  # --------------------
63
+ # 區塊解析
64
  # --------------------
65
  def extract_block(text: str, starts: list, ends: list = None) -> str:
66
  if not text:
 
158
  return df_disease, df_nutrition, df_meals
159
 
160
  # --------------------
161
+ # PDF 生成(修正版:文字換行)
162
  # --------------------
163
  def has_chinese(s: str) -> bool:
164
  return bool(re.search(r"[\u4e00-\u9fff]", str(s)))
 
174
  df_nutrition = clean_dataframe(df_nutrition)
175
  df_meals = clean_dataframe(df_meals)
176
 
177
+ pdfmetrics.registerFont(UnicodeCIDFont("STSong-Light"))
178
+ font_name = "STSong-Light"
 
 
 
 
179
 
180
  file_prefix = basic_info.get("name", "個人") if basic_info else "個人"
181
  safe_name = re.sub(r"[^\w\u4e00-\u9fff]", "_", file_prefix)
 
187
  styles = getSampleStyleSheet()
188
  title_style = styles["Title"].clone("title")
189
  heading_style = styles["Heading2"].clone("h2")
190
+ normal_style = ParagraphStyle("normal", fontName=font_name, fontSize=10, leading=14)
191
+
192
+ title_style.fontName = heading_style.fontName = font_name
193
 
194
  # 標題
195
  elements.append(Paragraph(f"健康分析與飲食建議報告 — {file_prefix}", title_style))
 
209
  style = TableStyle([
210
  ("GRID", (0, 0), (-1, -1), 0.8, colors.black),
211
  ("BACKGROUND", (0, 0), (-1, 0), colors.lightgrey),
212
+ ("FONTNAME", (0, 0), (-1, -1), font_name),
213
  ])
 
 
214
  t.setStyle(style)
215
  elements.append(t)
216
  elements.append(Spacer(1, 16))
 
218
  # 疾病表
219
  if not df_disease.empty:
220
  elements.append(Paragraph("一、可能相關疾病", heading_style))
221
+ table_data = [df_disease.columns.tolist()] + [[Paragraph(str(c), normal_style) for c in row] for row in df_disease.values.tolist()]
222
  t = Table(table_data, colWidths=[150, 330])
223
+ t.setStyle(TableStyle([("GRID", (0, 0), (-1, -1), 0.8, colors.black), ("BACKGROUND", (0, 0), (-1, 0), colors.lightgrey), ("FONTNAME", (0, 0), (-1, -1), font_name)]))
 
 
 
 
 
 
224
  elements.append(t)
225
  elements.append(Spacer(1, 12))
226
 
227
  # 營養建議表
228
  if not df_nutrition.empty:
229
  elements.append(Paragraph("二、飲食營養建議", heading_style))
230
+ table_data = [df_nutrition.columns.tolist()] + [[Paragraph(str(c), normal_style) for c in row] for row in df_nutrition.values.tolist()]
231
  t = Table(table_data, colWidths=[150, 330])
232
+ t.setStyle(TableStyle([("GRID", (0, 0), (-1, -1), 0.8, colors.black), ("BACKGROUND", (0, 0), (-1, 0), colors.lightgrey), ("FONTNAME", (0, 0), (-1, -1), font_name)]))
 
 
 
 
 
 
233
  elements.append(t)
234
  elements.append(Spacer(1, 12))
235
 
236
+ # 餐點表(換行修正)
237
  if not df_meals.empty:
238
  elements.append(Paragraph("三、一日三餐(中式 / 西式)", heading_style))
239
+ table_data = [df_meals.columns.tolist()] + [[Paragraph(str(c), normal_style) for c in row] for row in df_meals.values.tolist()]
240
  t = Table(table_data, colWidths=[240, 240])
241
+ t.setStyle(TableStyle([("GRID", (0, 0), (-1, -1), 0.8, colors.black), ("BACKGROUND", (0, 0), (-1, 0), colors.lightgrey), ("FONTNAME", (0, 0), (-1, -1), font_name)]))
 
 
 
 
 
 
242
  elements.append(t)
243
 
244
  doc.build(elements)
 
275
  """
276
 
277
  with gr.Blocks(css=css_code) as demo:
278
+ gr.Markdown("## 🩺AI食療專家")
279
  with gr.Row():
280
  with gr.Column(scale=1):
281
  gr.Markdown("### 請輸入基本資料")