first commit 稳定版本,已知该版本存在问题,前端未对数据进行校验,没有集成导出excel

This commit is contained in:
赖力诚 committed 2026-04-09 14:56:12 +08:00
commit e5030abf39
40 files changed
+5186

No files matched your search

+174
View File
@@ -0,0 +1,174 @@
import json
from collections import defaultdict
class NutritionService:
def __init__(self, food_db_path, config_path):
with open(food_db_path, "r", encoding="utf-8") as f:
self.food_db = json.load(f)
with open(config_path, "r", encoding="utf-8") as f:
self.config = json.load(f)
def build_report_data(self, front_json):
meals = front_json.get("meals", [])
merged_meals = self._merge_meals(meals)
food_details, nutrition_total = self._calculate_nutrition(merged_meals)
category_result = self._build_category_result_from_foods(food_details)
suggestions = self._generate_suggestions(category_result)
return {
"user": front_json.get("user", {}),
"date": front_json.get("date"),
"foods": food_details,
"category_result": category_result,
"suggestions": suggestions,
"nutrition": nutrition_total
}
def _merge_meals(self, meals):
meal_sum = defaultdict(float)
for item in meals:
name = str(item.get("name", "")).strip()
amount = item.get("amount", 0)
if not name:
continue
try:
amount = float(amount)
except Exception:
amount = 0
meal_sum[name] += amount
return meal_sum
def _calculate_nutrition(self, merged_meals):
details = []
total_energy = 0.0
total_protein = 0.0
total_fat = 0.0
total_carb = 0.0
total_calcium = 0.0
for food_name, grams in merged_meals.items():
food_info = self.food_db.get(food_name)
if not food_info:
# 如果没匹配到食物库,可以先跳过
continue
factor = grams / 100.0
energy = self._safe_float(food_info.get("energy")) * factor
protein = self._safe_float(food_info.get("protein")) * factor
fat = self._safe_float(food_info.get("fat")) * factor
carbohydrate = self._safe_float(food_info.get("carbohydrate")) * factor
calcium = self._safe_float(food_info.get("calcium")) * factor
total_energy += energy
total_protein += protein
total_fat += fat
total_carb += carbohydrate
total_calcium += calcium
details.append({
"name": food_name,
"amount": round(grams, 1),
"category": food_info.get("category", ""),
"nutrition": {
"energy": round(energy, 2),
"protein": round(protein, 2),
"fat": round(fat, 2),
"carbohydrate": round(carbohydrate, 2),
"calcium": round(calcium, 2)
}
})
nutrition_total = {
"energy": {
"value": round(total_energy, 2),
"evaluation": self._eval_nutrition(total_energy, "energy")
},
"protein": round(total_protein, 2),
"fat": round(total_fat, 2),
"carbohydrate": round(total_carb, 2),
"calcium": {
"value": round(total_calcium, 2),
"evaluation": self._eval_nutrition(total_calcium, "calcium")
}
}
return details, nutrition_total
def _build_category_result_from_foods(self, food_details):
# 1. 先把配置里的所有分类都初始化为 0
category_sum = {
category: 0.0
for category in self.config["food_category_map"].keys()
}
# 2. 把实际食物摄入量累加进去
for item in food_details:
category = item.get("category", "").strip()
amount = self._safe_float(item.get("amount", 0))
if category in category_sum:
category_sum[category] += amount
# 3. 所有分类都生成评价结果
result = {}
for cat, val in category_sum.items():
result[cat] = {
"value": round(val, 1),
"evaluation": self._evaluate_category(cat, val)
}
return result
def _evaluate_category(self, category, value):
rules = self.config["category_evaluation"].get(
category,
self.config["category_evaluation"].get("default", [])
)
for r in rules:
if r["min"] <= value <= r["max"]:
return r["label"]
return "-"
def _generate_suggestions(self, category_result):
rules = self.config["suggestion_rules"]
res = []
for cat, info in category_result.items():
label = info["evaluation"]
if label in rules and rules[label]:
res.append(rules[label].replace("{category}", cat))
return res
def _eval_nutrition(self, value, key):
rules = self.config["nutrition_eval"][key]
try:
value = float(value)
except Exception:
return "-"
for r in rules:
if r["min"] <= value <= r["max"]:
return r["label"]
return "-"
def _safe_float(self, value, default=0.0):
try:
return float(value)
except Exception:
return default
+19
View File
@@ -0,0 +1,19 @@
import os
from services.nutrition_service import NutritionService
from pdf_builder import NutritionPDFBuilder
class NutritionReportService:
def __init__(self):
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
food_db_path = os.path.join(base_dir, "food_db.json")
config_path = os.path.join(base_dir, "config", "nutrition_template.json")
self.nutrition_service = NutritionService(food_db_path, config_path)
self.pdf_builder = NutritionPDFBuilder()
def generate_report_from_json(self, front_json, output_path):
report_data = self.nutrition_service.build_report_data(front_json)
self.pdf_builder.build(report_data, output_path)
return report_data