minstradamus commited on
Commit
60a0933
·
verified ·
1 Parent(s): 6e3d1dc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +2 -39
app.py CHANGED
@@ -1,4 +1,3 @@
1
- # app.py
2
  import os
3
  import tempfile
4
  from decimal import Decimal
@@ -14,9 +13,6 @@ from receipt_total_api import extract_total
14
 
15
  app = FastAPI()
16
 
17
- # ---------- Pydantic-модели под Go-структуры ----------
18
-
19
-
20
  class Transaction(BaseModel):
21
  date: str
22
  amount: Decimal
@@ -51,26 +47,17 @@ class ReceiptResponse(BaseModel):
51
  total: Optional[float]
52
 
53
 
54
- # ---------- Стартуем и заранее грузим модели ----------
55
-
56
  advice_tokenizer = None
57
  advice_model = None
58
 
59
 
60
  @app.on_event("startup")
61
  def load_models():
62
- """
63
- Загружаем Qwen один раз при старте сервиса.
64
- Donut для чеков грузится в receipt_total_api при первом импорте.
65
- """
66
  global advice_tokenizer, advice_model
67
  advice_tokenizer, advice_model = advice_load()
68
 
69
 
70
- # ---------- Эндпоинты ----------
71
-
72
-
73
- from datetime import datetime # вверху файла, если ещё не импортирован
74
 
75
  @app.post("/forecast", response_model=ForecastResponse)
76
  def forecast(req: ForecastRequest):
@@ -88,7 +75,6 @@ def forecast(req: ForecastRequest):
88
  inc_fc = fit_and_forecast(inc, steps, freq, method=method)
89
  exp_fc = fit_and_forecast(exp, steps, freq, method=method)
90
 
91
- # Преобразуем индексы в RFC3339: "YYYY-MM-DDT00:00:00Z"
92
  period_end = [
93
  d.strftime("%Y-%m-%dT%H:%M:%SZ")
94
  for d in inc_fc.index.to_pydatetime().tolist()
@@ -140,43 +126,22 @@ def advice(req: AdviceRequest):
140
  },
141
  ]
142
 
143
- # 1) детерминированный прогон
144
  raw = advice_gen(messages, advice_tokenizer, advice_model, det=True)
145
  text = _to_bullets(clean_ru(raw))
146
 
147
- # 2) если мало пунктов — пробуем стохастический прогон
148
  if text.count("\n") + 1 < 3:
149
  raw2 = advice_gen(messages, advice_tokenizer, advice_model, det=False)
150
  text2 = _to_bullets(clean_ru(raw2))
151
  if text2:
152
  text = text2
153
 
154
- # 3) Fallback: если всё равно пусто или там явный мусор — жёстко подставляем шаблон
155
- bad = not text.strip() or "Ты финансовый помощник" in text or "Мои данные за текущий месяц" in text
156
-
157
- if bad:
158
- # можно потом сделать это умнее и завязать на snap, но пока — вменяемый дефолт
159
- text = (
160
- "• Ограничьте траты на еду до 15–20% от дохода (для вас ≈ 15 000 ₽ в месяц) и ведите учёт покупок в одном приложении.\n"
161
- "• Введите недельный лимит на продукты (например, 3 500–4 000 ₽) и не выходите за него, планируя меню заранее.\n"
162
- "• Пересмотрите все платные подписки раз в месяц и отмените те, которыми не пользовались 30 дней и более.\n"
163
- "• Сгруппируйте подписки по важности: обязательные, полезные, «для развлечения» — и урежьте последнюю группу минимум на 50%.\n"
164
- "• Переключите часть подписок на семейные/годовые тарифы и делите стоимость с друзьями или партнёром.\n"
165
- "• Перенесите оплату подписок на один день месяца и установите напоминание за 3 дня до списания, чтобы успевать отменять лишнее.\n"
166
- "• Освободившиеся деньги (5–10% дохода) автоматически переводите на отдельный накопительный счёт сразу после зарплаты."
167
- )
168
-
169
  return AdviceResponse(advice=text)
170
 
171
 
172
 
173
  @app.post("/receipt-total-file", response_model=ReceiptResponse)
174
  async def receipt_total_file(file: UploadFile = File(...)):
175
- """
176
- Получает файл чека (multipart/form-data, field "file"),
177
- сохраняет во временный файл, вызывает extract_total и возвращает сумму.
178
- """
179
- # сохраняем во временный файл
180
  suffix = os.path.splitext(file.filename or "")[1] or ".jpg"
181
  with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as tmp:
182
  contents = await file.read()
@@ -192,8 +157,6 @@ async def receipt_total_file(file: UploadFile = File(...)):
192
  except OSError:
193
  pass
194
 
195
-
196
- # Для локального запуска, на HF Space это не используется
197
  if __name__ == "__main__":
198
  import uvicorn
199
 
 
 
1
  import os
2
  import tempfile
3
  from decimal import Decimal
 
13
 
14
  app = FastAPI()
15
 
 
 
 
16
  class Transaction(BaseModel):
17
  date: str
18
  amount: Decimal
 
47
  total: Optional[float]
48
 
49
 
 
 
50
  advice_tokenizer = None
51
  advice_model = None
52
 
53
 
54
  @app.on_event("startup")
55
  def load_models():
 
 
 
 
56
  global advice_tokenizer, advice_model
57
  advice_tokenizer, advice_model = advice_load()
58
 
59
 
60
+ from datetime import datetime
 
 
 
61
 
62
  @app.post("/forecast", response_model=ForecastResponse)
63
  def forecast(req: ForecastRequest):
 
75
  inc_fc = fit_and_forecast(inc, steps, freq, method=method)
76
  exp_fc = fit_and_forecast(exp, steps, freq, method=method)
77
 
 
78
  period_end = [
79
  d.strftime("%Y-%m-%dT%H:%M:%SZ")
80
  for d in inc_fc.index.to_pydatetime().tolist()
 
126
  },
127
  ]
128
 
 
129
  raw = advice_gen(messages, advice_tokenizer, advice_model, det=True)
130
  text = _to_bullets(clean_ru(raw))
131
 
 
132
  if text.count("\n") + 1 < 3:
133
  raw2 = advice_gen(messages, advice_tokenizer, advice_model, det=False)
134
  text2 = _to_bullets(clean_ru(raw2))
135
  if text2:
136
  text = text2
137
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  return AdviceResponse(advice=text)
139
 
140
 
141
 
142
  @app.post("/receipt-total-file", response_model=ReceiptResponse)
143
  async def receipt_total_file(file: UploadFile = File(...)):
144
+
 
 
 
 
145
  suffix = os.path.splitext(file.filename or "")[1] or ".jpg"
146
  with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as tmp:
147
  contents = await file.read()
 
157
  except OSError:
158
  pass
159
 
 
 
160
  if __name__ == "__main__":
161
  import uvicorn
162