Flask

[Flask] Flask 리액트 연동

Puft 2024. 4. 4. 11:53

안녕하세요!

 

저번 시간에는 인공지능 모델을 만들어 봤는데요.

 

이번 시간에는 모델을 통해 얻은 데이터를 리액트와 연동시켜보는 시간을 가져보겠습니다.

 

먼저 Flask는 Python으로 웹 애플리케이션을 개발하기 위한 경량 프레임워크입니다.

 

NodeJS와 같은 서버 역할을 하게 됩니다.

 

설치를 하기 위해서 VScode에서 서버 디렉토리에서 터미널을 엽니다.

 

pip install Flask

 

를 입력해서 설치해줍니다.

 

다음은 중요한 포인트인 CORS설정입니다.

 

포트가 다를 때 포트 접근을 허용해주는 정책입니다.

 

from flask_cors import CORS
from flask import Flask, request, jsonify

app = Flask(__name__)
CORS(app)

 

이렇게 코드를 추가하면 CORS설정이 끝이납니다.

 

from flask import Flask, request, jsonify
import pandas as pd
import numpy as np
from flask_cors import CORS

app = Flask(__name__)
CORS(app)

# 데이터 로드
pill_data = pd.read_csv('Final_Pill_Standardization_Content_Dataset.csv', header=0, encoding='cp949')
food_data = pd.read_csv('food_dataset.csv', encoding='cp949')
daily_intake_data = pd.read_csv('연령별_일일_섭취량_데이터셋.csv', header=0, encoding='cp949')

child_pill_index = [2,33,40,50,63,69,85,87,89,106,129,142,143,148,161,164,
166,168,182,188,191,200,210,225,232,235,237,238,245,246,258,265,266,
269,271,274,296,304,308,315,343,348,350,353,376,383,386,394,395,397,
413,423,424,428,430,435,440,455,457,484,488,493,502,536,539,544,545,
594,604,614,617,621,624,639,647,648,649,665,678,679,684,701,712,725,
731,747,749,750,791,804,811,821,849,850,851,868,879,888,897,901,912,
921,933,937,946,962,974,999,1026,1030,1039,1040,1044,1061,1079,1086,
1095,1106,1107,1113,1118,1122,1126,1140,1144,1147,1173,1174,1176,1192,
1193,1195,1204,1212,1237,1240,1242,1245,1251,1258,1260,1266,1278,1281,
1286]

# 제외할 영양제 인덱스
except_list_index = [6,15,35,41,67,77,79,80,89,90,109,115,121,126,142,164,
202,213,237,255,259,276,277,278,285,290,298,319,324,333,336,337,339,341,
342,345,346,349,355,366,391,403,411,421,443,448,475,484,491,497,536,600,
608,627,629,632,634,636,644,647,648,649,651,655,656,660,668,689,690,701,
723,728,745,746,747,753,755,756,760,782,789,792,828,841,852,857,862,868,
869,874,879,885,886,904,916,935,946,968,974,1044,1061,1072,1073,1106,1109,
1113,1114,1115,1134,1147,1148,1153,1164,1169,1186,1188,1209,1226,1230,1231,
1240,1254,1263,1264,1266,1271,1286,1291]

# 임의로 정한 권장 섭취량 정보
recommended_intake = {
    '1인분칼로리(kcal)': 300.0,
    '탄수화물(g)': 80,
    '단백질(g)': 5,
    '지방(g)': 1.0,
    '콜레스트롤(g)': 0.0,
    '식이섬유(g)': 0.0,
    '나트륨(g)': 230.0,
}

# BMI 계산 함수
def bmicalc(x):
    if x < 18.5:
        y = "저체중"
    elif 18.5 <= x < 23:
        y = "정상 체중"
    elif 23 <= x < 25:
        y = "과체중"
    elif 25 <= x < 30:
        y = "경도 비만"
    else:
        y = "고도 비만"
       
    return y

def get_nutrient_info(food_name):
    nutrient_info = food_data[food_data['음식명'] == food_name].iloc[:, 1:].fillna(0).squeeze()
    return nutrient_info.to_dict() if not nutrient_info.empty else {}


# 부족한 영양소 찾는 함수
def find_deficient_nutrients(diet, recommended_intake):
    deficient_nutrients = {}
    for nutrient, intake in recommended_intake.items():
        if nutrient in diet:
            diff = intake - diet[nutrient]
            if diff > 0:
                deficient_nutrients[nutrient] = diff
    return deficient_nutrients

# 영양제 추천 함수
def recommend_pills(diet, recommended_intake):
    difference = {}
    for nutrient, intake in recommended_intake.items():
        difference[nutrient] = diet.get(nutrient, 0) - intake
   
    pill_distance_list = []
    for i in range(len(pill_data)):
        pill_distance_list.append(distance(pill_data.iloc[i], difference))
   
    recommendation = {}
    for idx, distance_val in sorted(enumerate(pill_distance_list), key=lambda x: x[1])[:3]:
        if idx not in child_pill_index and idx not in except_list_index:
            recommendation[f'pill_{idx}'] = distance_val
   
    return recommendation

# 거리 계산 메소드
def distance(x, y):
    x_values = x.values
    y_values = np.array(list(y.values()) + [0.0] * (len(x_values) - len(y)))
    a = np.linalg.norm(x_values - y_values)
    return a

# BMI 계산 메소드
def calc(vJson):
    height = vJson['height']
    height = int(height) / 100    
    weight = vJson['weight']  
    weight = int(weight)
    age = vJson['age']  
    age = int(age)
   
    BMI = weight / (height * height)
    bmi_string = bmicalc(BMI)
   
    vJson['BMI'] = {
        'value': round(BMI, 2),
        'status': bmi_string
    }
   
    return vJson

@app.route('/recommendation', methods=['POST'])
def get_recommendation():
    data = request.get_json()
    food_name = data['food_name']
    intake_amount = get_nutrient_info(food_name)
    deficient_nutrients = find_deficient_nutrients(intake_amount, recommended_intake)
    recommendation = recommend_pills(intake_amount, recommended_intake)
   
    response = {
        'food_name': food_name,
        'intake_amount': intake_amount,
        'deficient_nutrients': deficient_nutrients,
        'recommendation': recommendation
    }
   
    return jsonify(response)

if __name__ == '__main__':
    app.run(debug=True)

 

전체 코드입니다. 저번에 만든 모델에서 코드가 조금 추가되었습니다.

 

@app.route('/recommendation', methods=['POST'])
def get_recommendation():
    data = request.get_json()
    food_name = data['food_name']
    intake_amount = get_nutrient_info(food_name)
    deficient_nutrients = find_deficient_nutrients(intake_amount, recommended_intake)
    recommendation = recommend_pills(intake_amount, recommended_intake)
   
    response = {
        'food_name': food_name,
        'intake_amount': intake_amount,
        'deficient_nutrients': deficient_nutrients,
        'recommendation': recommendation
    }
   
    return jsonify(response)

 

/recommendation에 대한 Post 요청에 관한 코드입니다.

 

/recommendation 엔드 포인트에 접근 요청을 하면

 

식단(음식)을 클라이언트에서 넘겨주고

 

영양제 추천 로직을 적용한 뒤,

 

음식 이름, 섭취량, 부족한 영양소, 추천 영양제를 클라이언트에 넘겨줍니다.

 

 

 

 

그럼 Flask 서버를 실행시켜 봅시다.

 

터미널에 Python <파일 이름>

 

이렇게 입력하면 됩니다.

 

저 같은 경우는 Python apps.py 이렇게 입력해야합니다.

 

 

터미널에 이런 메세지가 뜨면 실행에 성공한 겁니다.

 

다음은 데이터를 가져올 페이지를 만들어 줍니다.

 

import React, { useState } from 'react';

function FoodInfoPage() {
  const [foodName, setFoodName] = useState('');
  const [result, setResult] = useState(null);

  const handleRecommendation = async () => {
    try {
      const response = await fetch("http://127.0.0.1:5000/recommendation", {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ food_name: foodName }),
      });
      const data = await response.json();
      setResult(data);
    } catch (error) {
      console.error('Error fetching recommendation:', error);
    }
  };

  return (
    <div>
      <input
        type="text"
        value={foodName}
        onChange={(e) => setFoodName(e.target.value)}
      />
      <button onClick={handleRecommendation}>Get Recommendation</button>
      {result && (
        <div>
          <h2>Food Name: {result.food_name}</h2>
          <h3>Intake Amount: {JSON.stringify(result.intake_amount)}</h3>
          <h3>Deficient Nutrients: {JSON.stringify(result.deficient_nutrients)}</h3>
          <h3>Recommendation: {JSON.stringify(result.recommendation)}</h3>
        </div>
      )}
    </div>
  );
}

export default FoodInfoPage;

 

임의로 chatGPT를 이용해서 만들었습니다.

 

인풋창에 식단을 입력하면 식단에 대한 영양제 추천 로직을 적용하여 페이지에 적용합니다.

 

const response = await fetch("http://127.0.0.1:5000/recommendation"

 

이때 엔드포인트는 Flask 서버 기본주소 + 만든 엔드포인트 입니다.

 

 

CSS를 하나도 신경 안썼지만 데이터 확인만 하면 되므로 입력해봅시다.

 

 

이렇게 Flask 서버에 있는 데이터셋에 해당하는 음식명을 입력하면

 

음식에 관한 로직을 적용하여 클라이언트로 데이터를 성공적으로 넘겨준 것을 확인할 수 있습니다.

 

오늘은 Flask를 사용해서 데이터를 넘겨오는 작업을 해봤습니다.

 

앞으로는 모델을 구체화하고 페이지의 UI도 개선할 예정입니다.

 

읽어주셔서 감사합니다!