안경잡이개발자

728x90
반응형

치트 엔진(Cheat Engine) 튜토리얼(Tutorial) 4단계

나동빈


  이번 시간은 치트 엔진 튜토리얼의 4단계를 풀어 볼 것입니다. 지난 시간에는 문제를 풀 때 자료형이 정수형인 것만 감안하였습니다. 이번 시간에는 찾아야 하는 데이터가 단순히 정수형이 아니라 실수형입니다. C언어 계열의 프로그램에서는 크게 2가지 실수형이 많이 사용됩니다. 작은 크기의 실수형을 나타낼 때 사용하는 Float큰 크기의 실수형을 나타낼 때 사용하는 Double입니다.



  문제를 확인해보니 Float과 Double의 두 변수가 존재하며 이 두 개의 값을 모두 5000 이상으로 올리면 된다고 합니다.



  따라서 바로 치트 엔진에서 해당 튜토리얼 프로그램을 열어 주시고 자료형이 Float이면서 100의 값을 가지는 변수를 스캔해보겠습니다.


  (실수형은 정수형보다 수치 정확도가 낮으므로 혹여나 검색이 잘 안 된다면 '범위로 검색'하는 방법도 있습니다.)



  이제 Float 변수를 찾기 위해 Hit me 버튼을 클릭해 값을 변경시켜봅시다.



  그러면 위와 같이 93.5로 값이 변경된 하나의 변수가 발견됩니다. 우클릭하여 주소 리스트에 추가합니다.



  마찬가지로 Double 형을 가지는 변수도 검색 해주시면 됩니다.



  마찬가지로 버튼을 누르니 값이 변경되는 군요.



  Double형 변수도 스캔이 완료되면 주소 리스트에 추가합니다.



  이제 두 값을 모두 5000으로 바꾸어주시면 됩니다.



  그러면 다음과 같이 성공적으로 문제를 풀어낸 것을 확인할 수 있습니다.



728x90
반응형

728x90
반응형

치트 엔진(Cheat Engine) 튜토리얼(Tutorial) 3단계

나동빈


  이번 시간에는 치트 엔진 튜토리얼 3단계를 풀어보도록 할 것입니다. 이 예제도 실제 게임 해킹에 있어서 매우 매우 많이 사용되는 예제이므로 반드시 튜토리얼을 익히고 넘어가시는 것을 추천드립니다.


  3단계 문제 요약: 0부터 500 사이의 숨겨진 변수가 있고, 버튼을 누를 때마다 이 변수의 값이 일정 부분 감소합니다. 이 때 그 변수의 값을 5000으로 만드는 문제입니다.



  문제가 다소 길게 쓰여있지만 위에 요약된 내용과 일치합니다.



  기본적으로 현재 변수의 값이 정확히 무엇인지 모르므로 'Unknown initial value'로 설정하여 메모리 내에 존재하는 모든 변수를 스캔해야 합니다. First Scan 버튼을 눌러서 스캔을 진행하세요.


※ 팁(Tip)



  (만약에 이미 어떤 작업을 하고 있던 도중이었다면 'New Scan' 버튼을 눌러서 새롭게 스캔을 시작해야 합니다.)


  아무튼 First Scan을 눌러서 전체 변수를 스캔하면 다음과 같이 매우 많은 변수의 개수가 보입니다.



  이제 이 상태에서 '감소하는 변수'의 값을 찾아내기 위해 다음과 같이 Hit me 버튼을 클릭합니다.



  그러면 일시적으로 총 얼마만큼의 값이 감소했는지 위와 같이 나옵니다. 정확히 2만큼 감소했네요.



  그러면 이전과 대비했을 때 2만큼 감소한 변수를 찾기 위해 'Decreased value by'로 설정하고 2를 입력하여 스캔을 진행합니다.



  그러면 위와 같이 29개의 변수로 매우 좁혀지는 것을 알 수 있습니다. 이런식으로 반복하여 스캔하면 결국 하나의 변수만이 남게 됩니다.



  한 번 더 Hit me를 눌렀을 때 10이 감소하였으므로 다음과 같이 10만큼 줄어든 변수로 이어서 스캔해주시면 됩니다.



  결과적으로 저는 01732CDC 주소의 변수가 제가 찾던 변수임을 확인할 수 있었습니다.



  해당 변수 라인을 우클릭하여 바로 'Change value of selected addresses'를 눌러 값을 변경하시면 됩니다.



  저는 문제에서 요구한 대로 5000이라는 값을 넣어주었습니다.



  넣어주자마자 바로 다음과 같이 Next 버튼이 활성화 되며 문제가 풀린 것을 알 수 있습니다.


728x90
반응형

728x90
반응형

치트 엔진(Cheat Engine) 튜토리얼(Tutorial) 2단계

나동빈


  이번 시간은 치트 엔진 튜토리얼의 2단계입니다. 사실 2단계는 정말 쉽지만 가장 많이 사용되는 기능에 대해서 물어보는 것입니다. 바로 컴퓨터 메모리 내의 특정 변수의 값을 변경하는 것입니다. 실제로 우리가 게임 소프트웨어를 실행하여 게임을 하면 체력(Health) 정보 등은 모두 메모리에 저장됩니다. 이 때 치트 엔진을 활용하면 동적 분석을 진행하면서 그러한 변수의 값을 원하는 대로 조작할 수 있습니다.


  2단계 요약: 처음에 100으로 설정이 되어 있는 체력(Health) 값을 1000으로 바꾸기



  기본적으로 2단계를 풀기 전에 치트 엔진에서 Tutorial 프로세스를 열고 있는 상태여야 합니다. 보시면 Health의 값이 100으로 초기화가 되어 있는데 이를 1000으로 바꾸라고 나오는 것을 알 수 있습니다.



  그러면 바로 현재 메모리 내에서 100이라는 값을 가지는 변수를 찾으시면 됩니다. 값(Value)에 100을 넣고 First Scan을 수행합니다.


  이 때 자료형(Value Type)을 지정하여 검색할 수 있습니다. 일반적으로 컴퓨터 프로그래머가 프로그램을 작성할 때는 정수를 4 Byte 변수로 가장 많이 이용합니다. 옛날에 만들어진 프로그램들은 2 Byte짜리도 많이 존재하므로 이를 적절히 고려하여 변수를 찾아내야 합니다.



  그러면 현재 튜토리얼 프로그램 내에서 100이라는 값을 가지는 많은 주소 공간이 나오는 것을 알 수 있습니다. 이 중에서 정확히 체력(Health) 정보를 가지는 주소가 무엇인지 알기 위해서는 어떻게 해야 할까요?



Hit me 버튼을 누르면 체력 값이 변경되는 것을 알 수 있습니다. 즉 100이라는 값을 가지고 있던 상태에서 97로 값이 변경된 것입니다.



  치트 엔진은 동적 분석 도구이므로 이렇게 값이 변경되는 것을 캐치할 수 있습니다. 바로 97을 입력한 뒤에 Next Scan을 눌러봅시다. 그러면 아까 결과로 나왔던 주소 값 중에서 '현재 값이 97인 주소만 추출'이 됩니다.



  위와 같이 주소 017D31C8에 저장되어 있는 값이 97인 것을 확인할 수 있습니다.



  그러면 해당 라인을 더블 클릭하시면 아래 쪽 탭에 해당 정보가 기입되는 것을 알 수 있습니다.



  Value 속성을 더블 클릭하여 값을 1000으로 바꾸어 봅시다.



  그러면 위와 같이 값이 1000으로 변경된 것을 알 수 있습니다.



  값을 변경했을 때 프로그램에 즉시 반영이 되는 경우도 있고, 그렇지 않은 경우도 있습니다. 현재 우리의 프로그램에서는 'Next' 버튼에는 즉시 반영이 되었으나 'Health' 값에는 즉시 반영이 되지는 않은 것 같네요. 따라서 Hit me 버튼을 눌러서 값을 갱신해보시면 쉽게 알 수 있습니다.



  그러면 위와 같이 값이 갱신이 되는 것을 알 수 있습니다. 정확히 1000을 맞추기 위해서는 몇 번의 시도가 더 필요할 수는 있겠네요. 아무튼 이와 같이 간단히 메모리 내의 특정한 변수의 값을 변경하는 방법에 대해 알아보는 시간을 가졌습니다.


※ 알아두면 좋은 상식 ※


  일반적으로 게임은 C언어 및 C++로 가장 많이 작성됩니다. C언어 계열에서는 정수를 나타낼 때 다음과 같은 자료형을 많이 사용합니다.


  Integer: 4 Bytes의 공간을 차지하며 대략 -20억부터 +20억까지의 범위를 표현할 수 있습니다.

  Short: 2 Bytes의 공간을 차지하며 대략 -3만부터 +3만까지의 범위를 표현할 수 있습니다.


  또한 최근에는 유니티(Unity)나 언리얼 등의 게임 엔진을 이용해서 다양한 게임을 개발합니다. 이러한 게임 엔진에서는 실수를 나타내는 Float형 및 Double형도 매우 자주 사용되기 때문에 적절히 변수의 자료형을 고려하여 동적 분석을 수행해야 합니다.


728x90
반응형

728x90
반응형

치트 엔진(Cheat Engine) 튜토리얼(Tutorial) 1단계

나동빈


  치트 엔진 소프트웨어를 설치하면 자동으로 딸려오는 튜토리얼을 함께 풀어보도록 합시다. 가장 먼저 1단계입니다. 튜토리얼 프로그램은 정말 튜토리얼을 목적으로 만들어진 프로그램이므로 큰 부담 없이 튜토리얼에서 요구하는 대로 진행하시면 됩니다.



  튜토리얼 프로그램에서는 위와 같은 메시지가 쓰여 있습니다. 요약하자면 '치트 엔진에서 튜토리얼 프로그램을 열어보기(Open)'입니다. 치트 엔진은 특정한 프로그램을 대상으로 하여 분석을 진행할 수 있도록 도와주는데, 튜토리얼 프로그램도 하나의 프로그램이기 때문에 치트 엔진의 분석 대상이 될 수 있습니다.



  따라서 위와 같이 프로세스 리스트 항목을 열어서 Tutorial 프로세스를 선택하여 열어주시면 됩니다.



  그러면 위와 같이 현재 열려 있는 분석 대상이 Tutorial 프로그램이 된 것을 알 수 있습니다.



  이제 Next 버튼을 눌러서 다음 단계로 넘어가시면 됩니다. 보시면 패스워드(Password)라는 것이 있습니다. 치트 엔진의 튜토리얼 문제들은 각 문제마다 패스워드 값을 가지고 있으므로 나중에 다시 튜토리얼을 실행했을 때 최근까지 풀었던 문제로 바로 이동할 수 있도록 패스워드 값을 제공하는 것입니다.


※ 알아두면 좋은 상식 ※


  프로세스(Process)컴퓨터 내에서 현재 실행중인 프로그램

728x90
반응형

728x90
반응형

치트 엔진(Cheat Engine)의 개요와 설치

나동빈


  치트 엔진(Cheat Engine)시스템 메모리 내의 데이터를 수정할 수 있도록 도와주는 소프트웨어입니다. 프로그램의 디버깅이나 게임 해킹을 함에 있어서 우리에게 간단하지만 매우 강력한 기능을 지원합니다. 최신 버전의 치트 엔진은 공식 웹 사이트에서 다운로드 할 수 있습니다.


  치트 엔진 공식 사이트https://www.cheatengine.org/



  게임은 일반적으로 윈도우 운영체제에서 돌리는 경우가 많다는 점에서 치트 엔진 소프트웨어는 윈도우 버전이 가장 많이 사용되고 있습니다. 웹 사이트에서 Download Cheat Engine 버튼을 누르면 치트 엔진 다운로드가 시작됩니다. 치트 엔진 설치는 다음과 같은 단순한 과정으로 수행할 수 있습니다. 웬만하면 기본 설정에 따라서 다음(Next) 버튼을 눌러 설치를 진행하시면 됩니다.








  (중간에 Avast Free Antivirus 소프트웨어 광고가 붙어 있는데요. 저는 '설치하지 않음'을 선택했습니다.)




  설치가 완료되면 위와 같이 바로 치트 엔진을 구동시킬 수 있도록 합니다.



  치트 엔진을 처음 실행하면 튜토리얼(Tutorial)부터 해보는 것을 강력하게 권장드립니다. 치트 엔진은 매우 잘 만들어진 소프트웨어라서 튜토리얼만 잘 따라오셔도 대부분의 기능을 이용하는데 큰 어려움이 없을 겁니다.



  위와 같이 기본적으로 튜토리얼 창이 뜰 것이구요. 보이지 않는다면 다음과 같이 'Help' - 'Cheat Engine Tutorial'로 들어가서 치트 엔진 튜토리얼 창을 실행할 수 있습니다.



  아무튼 성공적으로 치트 엔진 설치까지 다루어보았습니다. 다음 장에서부터는 치트 엔진의 튜토리얼 문제를 함께 풀어보겠습니다.


※ 알아두면 좋은 상식 ※


  치트 엔진은 기본적으로 자신의 컴퓨터 내에 설치된 게임 프로그램을 해킹하는 도구입니다. 다시 말해 '클라이언트 동적 분석 도구'라고 할 수 있습니다. 최근에는 게임 보안이 많이 향상되어 클라이언트 해킹으로 실 서버에 타격이 가지 않도록 많은 보안 처리가 이루어지고 있습니다. 하지만 과거에는 치트 엔진으로 유명 RPG 게임까지 다수 해킹이 가능하곤 했습니다.

728x90
반응형

728x90
반응형

다이얼로그 플로우(Diaolg Flow)와 플라스크(Flask)를 카카오톡 플러스친구에 연동하기


  지난 시간에는 다이얼로그 플로우(Dialog Flow)와 플라스크(Flask) 웹 서버와 연동하는 방법에 대해 알아보는 시간을 가졌습니다. 이번 시간에는 플라스크 웹 서버와 카카오톡 플러스 친구를 연동하는 방법을 알아보도록 하겠습니다.


※ 카카오톡 플러스친구 만들기 ※


  ▶ 플러스친구 관리자 센터: https://center-pf.kakao.com/


  당연히 카카오톡 플러스친구부터 만들어야 합니다. 위 사이트에 접속한 뒤에 로그인을 하시고 '플러스친구 만들기'를 누르시면 됩니다.



  기본적으로 플러스친구 관리자로 가입을 하셔야 자신의 플러스친구를 제대로 관리할 수 있습니다.




  이후에 저는 다음과 같이 'my_flask_test'라는 이름으로 플러스친구를 개설보았습니다.



  위와 같이 간단하게 이름만 설정하고 바로 생성할 수 있습니다.



  이후에 기본적으로 플러스친구는 비공개 설정이 되어 있으므로 '공개 설정하러 가기'를 눌러 공개 설정을 해주셔야 합니다.



  이후에 위와 같이 '홈 공개'와 '검색 허용'ON으로 설정해주시면 됩니다.



  이제 '스마트채팅' 탭에서 'API형'으로 설정해주시면 됩니다. API 형으로 설정하면 자유자재로 우리가 원하는 형태로 카카오톡 플러스 친구를 개발할 수 있습니다. 대신 우리의 전용 웹 API를 직접 개발해야 하지만 그만큼 활용도가 매우 높아집니다. 즉, 지난 시간에 만들었던 것과 같이 플라스크(Flask) 웹 서버 등을 직접 만들 수 있는 사람이 사용할 수 있는 선택지입니다.


※ 구름 IDE에서 플라스크 웹 서버 구현하기 ※


  구름 IDE 서비스: https://ide.goorm.io/


  구름 IDE 서비스는 제가 현재 알고 있는 클라우드 서비스 중에서 가장 쉽고 빠르게 테스트 목적의 웹 서버를 구축할 수 있는 서비스입니다. 실제로 사용해 보시면 순식간에 일정 시간 동안 사용할 수 있는 공인 IP 주소와 웹 서비스를 구축할 수 있습니다. (무료 버전에서는 시간 제한이 있습니다.)


  바로 구름 IDE 서비스에 접속하신 이후에 회원가입 및 로그인을 하시고 'Flask 프로젝트'로 새로운 컨테이너를 생성해주시면 됩니다.



  만든 이후에는 index.py 파일이 기본적으로 생성이 되어 있습니다. 'python index.py 5000' 명령어로 서버를 구동시킬 수 있습니다. 기본적으로 플라스크는 5000번 포트로 동작시킵니다.



  그러면 다음과 같이 서버가 동작이 되고 있다는 메시지가 출력됩니다.



  이후에 구름 IDE는 '포트포워딩' 설정을 해주셔야 외부에서 공인 IP로 접속할 수 있습니다.



  저는 위와 같이 내부 포트 5000번을 열어주어서 13.124.201.44:57706으로 접속할 수 있게 되었습니다.



  실제로 위와 같이 접속해보니 환영 메시지가 출려된 것을 확인할 수 있었습니다.


※ 카카오톡 플러스친구와 연동하기 ※


  카카오톡 플러스친구를 웹 서버와 바로 연동하기 위해서는 두 가지 중요한 API 키워드만 알고 있으면 됩니다. 구체적인 내용은 다음과 같이 API 명세서에서 확인할 수 있습니다.




  요약하면 두 가지 키워드는 'keyboard'와 'message'입니다. keyboard는 이용자가 최초로 채팅방에 들어올 때 명령어의 목록을 보여줄 때 사용하는 기능입니다. message는 실질적으로 사용자가 입력한 명령어를 웹 서버가 처리하도록 해주는 기능입니다. 따라서 기존의 소스코드에 다음의 두 가지 처리 로직을 추가해주시면 됩니다.


@app.route("/keyboard")

def keyboard():


    res = {

        'type': 'buttons',

        'buttons': ['대화하기']

    }


    return jsonify(res)


@app.route('/message', methods=['POST'])

def message():


    req = request.get_json()

    content = req['content']

    user_key = req['user_key']


    if content == u"대화하기":

        res = {

            'message': {

                'text': "영어로 대화를 시작하시면 됩니다."

            }

        }

    else:

        res = {

            'message': {

                'text': get_answer(content, user_key)

            }

        }

    

    return jsonify(res)


  이후에 다시 서버를 동작시킨 뒤에 기존에 포트포워딩으로 열어 놓은 공인 IP 주소로 테스트를 해봅시다.



  위와 같이 keyboard 경로로 들어가면 '대화하기'라고 카카오톡 챗봇에 나올 메시지가 출력되는 것을 알 수 있습니다. 이제 이러한 웹 서버에 카카오톡의 크롤러가 자동으로 연동할 수 있게 된 것입니다.



  앱 URL에 우리의 웹 서버 URL을 입력하여 'API 테스트'를 해보시면 위와 같이 OK 메시지가 출력됩니다.



  이제 위와 같이 전화번호로 인증을 한 뒤에 저장하시면 됩니다.



  이제 '시작하기'를 눌러서 구동시키면 됩니다. 구동 이후에는 다음과 같이 스마트 폰에서 검색이 되는 것을 확인할 수 있습니다.



  이제 다음과 같이 카카오톡 챗봇과 자유롭게 대화를 할 수 있는 것을 알 수 있습니다.


 


※ 전체 플라스크 소스코드 ※


# -*- encoding: utf-8 -*-

import requests

import json


from flask import Flask, request, jsonify


def get_answer(text, user_key):

    

    data_send = { 

        'query': text,

        'sessionId': user_key,

        'lang': 'ko',

    }

    

    data_header = {

        'Authorization': 'Bearer CLIENT ACCESS TOKEN',

        'Content-Type': 'application/json; charset=utf-8'

    }

    

    dialogflow_url = 'https://api.dialogflow.com/v1/query?v=20150910'

    

    res = requests.post(dialogflow_url, data=json.dumps(data_send), headers=data_header)


    if res.status_code != requests.codes.ok:

        return '오류가 발생했습니다.'

    

    data_receive = res.json()

    answer = data_receive['result']['fulfillment']['speech'] 

    

    return answer


app = Flask(__name__)

app.config['JSON_AS_ASCII'] = False


@app.route('/', methods=['POST', 'GET'])

def webhook():


    content = request.args.get('content')

    userid = request.args.get('userid')


    return get_answer(content, userid)


@app.route("/keyboard")

def keyboard():

    res = {

        'type': 'buttons',

        'buttons': ['대화하기']

    }

    return jsonify(res)


@app.route('/message', methods=['POST'])

def message():

    

    req = request.get_json()

    content = req['content']

    user_key = req['user_key']


    if content == u"대화하기":

        res = {

            'message': {

                'text': "영어로 대화를 시작하시면 됩니다."

            }

        }

    else:

        res = {

            'message': {

                'text': get_answer(content, user_key)

            }

        }

    

    return jsonify(res)

    

if __name__ == '__main__':

    app.run(host='0.0.0.0')

728x90
반응형

728x90
반응형

  다이얼로그 플로우(Dialog Flow)로 챗봇(Chat Bot)을 개발한 뒤에 이를 실제 상용 서비스에서 활용하기 위해서는 웹 서버와 함께 사용하는 것이 가장 효과적입니다. 웹 서버 중에서는 가장 가벼우면서도 빠르게 구현할 수 있는 플라스크(Flask)를 이용하면 효율적입니다. 따라서 아래 과정을 차근차근 따라하면서 자신만의 플라스크 웹 서버에서 다이얼로그 플로우를 사용할 수 있도록 하세요.


※ 다이얼로그 플로우 API V1 테스트하기 ※


  먼저 자신이 사용하고자 하는 에이전트(Agent) 프로젝트의 클라이언트 액세스 토큰(Client Access Token)을 확인합니다.



  이후에 API를 어떻게 사용할 수 있는지 확인해 봅시다.


  Dialog Flow API V1 문서: https://dialogflow.com/docs/reference/agent/query


  기본적으로 다이얼로그 플로우는 매우 간단하게 초기 버전의 API를 사용할 수 있습니다. 가장 중요한 부분만 추출하면 다음과 같습니다.



  먼저 POST 방식 전송 예제는 위와 같습니다. 헤더에 CLIENT ACCESS TOKEN을 넣은 뒤에 아래쪽에 'query'로 실질적인 질의문을 넣는 것을 알 수 있습니다. 이제 이를 파이썬을 이용해 동일하게 동작하는 클라이언트를 작성하면 됩니다. 전체 Flask 웹 서버의 소스코드는 다음과 같습니다.



  위 사진은 결과 예제 사진입니다. 보시면 JSON 형태로 'result' -> 'fulflilment' -> 'speech'에 결과 값이 담겨 오는 것을 알 수 있습니다. 따라서 요청 데이터를 보낸 이후에 결과 값에서 이를 파싱하도록 소스코드를 작성하면 됩니다.


※ Flask 웹 서버의 소스코드


# -*- encoding: utf-8 -*-

import requests

import json


from flask import Flask, request, jsonify


def get_answer(text, user_key):

    

    data_send = { 

        'query': text,

        'sessionId': user_key,

        'lang': 'ko',

    }

    

    data_header = {

        'Authorization': 'Bearer CLIENT ACCESS TOKEN',

        'Content-Type': 'application/json; charset=utf-8'

    }

    

    dialogflow_url = 'https://api.dialogflow.com/v1/query?v=20150910'

    

    res = requests.post(dialogflow_url, data=json.dumps(data_send), headers=data_header)


    if res.status_code != requests.codes.ok:

        return '오류가 발생했습니다.'

    

    data_receive = res.json()

    answer = data_receive['result']['fulfillment']['speech'] 

    

    return answer


app = Flask(__name__)

app.config['JSON_AS_ASCII'] = False


@app.route('/', methods=['POST', 'GET'])

def webhook():


    content = request.args.get('content')

    userid = request.args.get('userid')


    return get_answer(content, userid)


if __name__ == '__main__':

    app.run(host='0.0.0.0')    


  위와 같이 API 문서의 내용을 그대로 따라 작성한 것을 알 수 있습니다. 대신에 자신의 웹 서버에서는 'content'와 'userid'라는 두 파라미터로 값을 받습니다. 이후에 해당 소스코드를 실행하고 자신의 로컬 환경에서 테스트를 진행하면 됩니다.


728x90
반응형

728x90
반응형

  인텔리J (IntelliJ) 개발환경을 이용하다 보면 다른 에디터와는 다르게 글자 크기를 바꾸는 방법을 몰라 헤맬 수 있습니다. 일반적인 에디터(Editor) 소프트웨어의 경우 글자 크기를 키우고자 하는 영역에 마우스를 데고 컨트롤(Ctrl)을 누르면서 휠을 굴리면 크기를 쉽게 바꿀 수 있습니다. 인텔리J에서는 이와 다르게 '설정(Setting)' 부분에 들어가서 글자 크기를 바꾸기 위한 설정을 해주셔야 합니다.



  일반적으로 위와 같이 글자 크기가 매우 작습니다.



  이 때 File -> Settings로 갑니다.



  그러면 Editor 부분에 General로 가시면 'Change font size (Zoom) with Ctrl+Mouse Wheel' 이라는 부분이 있는데, 이를 눌러 마우스 휠로 글자 크기를 바꿀 수 있게 됩니다.


[ 추가 내용 ]


  단순히 에디터 안에서의 글자 크기 말고 콘솔(Console) 창의 글자 크기를 바꾸고 싶다면 'Console Font'로 가서 크기를 변경하시면 됩니다.



728x90
반응형

728x90
반응형

다변인 선형회귀를 활용한 배추 가격 예측 AI 개발하기 7강 - 플라스크와 텐서플로우 연동하기

나동빈


  이번 시간에는 플라스크 웹 서버에서 텐서플로우(Tensorflow) 기반의 학습 모델을 이용해 '배추 가격을 예측'하는 서버 기능을 삽입해보도록 하겠습니다. 지난 시간에 이미 학습 모델을 파일 형태로 저장하는 방법에 대해서 알아보았으므로 수월하게 따라올 수 있을 겁니다.


※ 웹 클라이언트 소스코드 변경하기 ※


  가장 먼저 사용자로부터 '평균 온도', '최소 온도', '최대 온도', '강수량'을 입력 받을 수 있도록 웹 클라이언트 HTML 소스코드를 변경합니다. <form> 태그를 이용하면 플라스크 웹 서버에서 처리할 수 있도록 손쉽게 파라미터를 전달할 수 있습니다.


      <section>

        <h3 class="h3 text-center mb-5">배추 가격 예측하기</h3>

        <div class="row wow fadeIn">

          <div class="col-lg-6 col-md-12 px-4">

            <form action="/" method="post">

              <div class="form-group">

                <label for="formGroupExampleInput">평균 온도</label>

                <input type="text" name="avg_temp" class="form-control" placeholder="평균 온도를 입력하세요.">

              </div>

              <div class="form-group">

                <label for="formGroupExampleInput">최소 온도</label>

                <input type="text" name="min_temp" class="form-control" placeholder="최소 온도를 입력하세요.">

              </div>

              <div class="form-group">

                <label for="formGroupExampleInput">최대 온도</label>

                <input type="text" name="max_temp" class="form-control" placeholder="최대 온도를 입력하세요.">

              </div>

              <div class="form-group">

                <label for="formGroupExampleInput">강수량</label>

                <input type="text" name="rain_fall" class="form-control" placeholder="강수량을 입력하세요.">

              </div>

              <button type="submit" class="btn btn-primary btn-md pull-right">예측하기</button>

            </form>

          </div>

          <div class="col-lg-6 col-md-12">

            {% if price %}

              <h5 class="text-center mt-3">결과: {{ price }}</h5>

            {% endif %}

          </div>

        </div>

      </section>



  참고로 저는 아톰(Atom) 에디터를 이용하고 있습니다.



  이제 위와 같이 플라스크 웹 서버의 루트 폴더에 'model' 폴더를 생성하여 학습 모델이 담길 수 있도록 합시다.



  이제 사용자로부터 배추 가격 예측 요청(Request)이 들어오면 그 결과를 반환하도록 서버 소스코드를 수정합니다.


※ 플라스크 서버 소스코드 ※


# -*- coding: utf-8 -*-

from flask import Flask, render_template, request


import datetime

import tensorflow as tf

import numpy as np


app = Flask(__name__)


# 플레이스 홀더를 설정합니다.

X = tf.placeholder(tf.float32, shape=[None, 4])

Y = tf.placeholder(tf.float32, shape=[None, 1])


W = tf.Variable(tf.random_normal([4, 1]), name="weight")

b = tf.Variable(tf.random_normal([1]), name="bias")


# 가설을 설정합니다.

hypothesis = tf.matmul(X, W) + b


# 저장된 모델을 불러오는 객체를 선언합니다.

saver = tf.train.Saver()

model = tf.global_variables_initializer()


# 세션 객체를 생성합니다.

sess = tf.Session()

sess.run(model)


# 저장된 모델을 세션에 적용합니다.

save_path = "./model/saved.cpkt"

saver.restore(sess, save_path)


@app.route("/", methods=['GET', 'POST'])

def index():

    if request.method == 'GET':

        return render_template('index.html')

    if request.method == 'POST':

        # 파라미터를 전달 받습니다.

        avg_temp = float(request.form['avg_temp'])

        min_temp = float(request.form['min_temp'])

        max_temp = float(request.form['max_temp'])

        rain_fall = float(request.form['rain_fall'])


        # 배추 가격 변수를 선언합니다.

        price = 0


        # 입력된 파라미터를 배열 형태로 준비합니다.

        data = ((avg_temp, min_temp, max_temp, rain_fall), (0, 0, 0, 0))

        arr = np.array(data, dtype=np.float32)


        # 입력 값을 토대로 예측 값을 찾아냅니다.

        x_data = arr[0:4]

        dict = sess.run(hypothesis, feed_dict={X: x_data})

            

        # 결과 배추 가격을 저장합니다.

        price = dict[0]


        return render_template('index.html', price=price)


if __name__ == '__main__':

   app.run(debug = True)



  서버 소스코드를 수정한 이후에는 다시 서버를 재구동하시면 됩니다. 다만 혹시 위와 같이 'UTF-8' 인코딩 관련 오류가 발생한다면 다음과 같이 서버 소스코드 파일을 'UTF-8' 인코딩으로 저장해주도록 하세요.



※ 테스트 하기 ※


  이제 완성된 프로젝트를 테스트 하기 위해 먼저 서버를 구동시킵니다.



  웹 사이트를 새로고침 해서 임의의 온도 및 강수량 정보를 넣어 보겠습니다.



  예측 결과는 다음과 같이 정상적으로 잘 출력됩니다.



  이상으로 미니 프로젝트를 마치도록 하겠습니다.


728x90
반응형

728x90
반응형

다변인 선형회귀를 활용한 배추 가격 예측 AI 개발하기 6강 - 플라스크 웹 서버와 웹 디자인 구현하기

나동빈


  이번 시간에는 지난 번에 만들었던 학습 모델을 이용하기 위해 가장 먼저 플라스크(Flask) 웹 서버를 구축하고 웹 디자인 작업을 해주도록 하겠습니다. 그러므로 웹 디자인 프레임워크부터 다운로드를 받아주도록 하겠습니다.


  MDBootstrap의 무료 디자인 템플릿을 사용하도록 하겠습니다.


  MDBoostrap 무료 템플릿: https://mdbootstrap.com/freebies/



  저는 위와 같이 'Full Page Video Carousel' 템플릿을 선택했습니다.



  다운로드를 받으시면 'Full Page Video Carousel'이 존재합니다.


  

  위에 존재하는 모든 폴더 및 파일들을 우리의 프로젝트 폴더로 옮겨줍시다.



  이제 index.html 파일을 웹 브라우저로 실행해 보시면 예쁜 웹 사이트가 등장하는 것을 알 수 있습니다.


  

  

  이후에 자신이 원하는 웹 서비스에 맞게 디자인을 자유롭게 꾸며주시면 됩니다. 저는 웹 사이트의 불필요한 부분을 쳐내고 필요한 부분만 넣었습니다.


※ 필요한 부분만 남겨서 간단히 웹 디자인 하기 ※


<!DOCTYPE html>

<html lang="en">


<head>

  <meta charset="utf-8">

  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

  <meta http-equiv="x-ua-compatible" content="ie=edge">

  <title>VEGITA</title>

  <!-- Font Awesome -->

  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">

  <!-- Bootstrap core CSS -->

  <link href="css/bootstrap.min.css" rel="stylesheet">

  <!-- Material Design Bootstrap -->

  <link href="css/mdb.min.css" rel="stylesheet">

  <!-- Your custom styles (optional) -->

  <link href="css/style.min.css" rel="stylesheet">

  <style type="text/css">


    html,

    body,

    header,

    .carousel {

      height: 100%;

    }


    @media (min-width: 800px) and (max-width: 850px) {

            .navbar:not(.top-nav-collapse) {

                background: #1C2331!important;

            }

        }

  </style>

</head>


<body>


  <nav class="navbar fixed-top navbar-expand-lg navbar-dark scrolling-navbar">

    <div class="container">

      <a class="navbar-brand" href="https://mdbootstrap.com/material-design-for-bootstrap/" target="_blank">

        <strong>VEGITA</strong>

      </a>

      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent"

        aria-expanded="false" aria-label="Toggle navigation">

        <span class="navbar-toggler-icon"></span>

      </button>

      <div class="collapse navbar-collapse" id="navbarSupportedContent">

        <ul class="navbar-nav mr-auto">

          <li class="nav-item active">

            <a class="nav-link" href="#">HOME

              <span class="sr-only">(current)</span>

            </a>

          </li>

        </ul>


        <ul class="navbar-nav nav-flex-icons">

          <li class="nav-item">

            <a href="#" class="nav-link border border-light rounded"

              target="_blank">

              <i class="fa fa-github mr-2"></i>GITHUB

            </a>

          </li>

        </ul>

      </div>

    </div>

  </nav>


  <div id="carousel-example-1z" class="carousel slide carousel-fade" data-ride="carousel">

    <ol class="carousel-indicators">

      <li data-target="#carousel-example-1z" data-slide-to="0" class="active"></li>

      <li data-target="#carousel-example-1z" data-slide-to="1"></li>

      <li data-target="#carousel-example-1z" data-slide-to="2"></li>

    </ol>

    <div class="carousel-inner" role="listbox">

      <div class="carousel-item active">

        <div class="view">

          <video class="video-intro" autoplay loop>

            <source src="https://mdbootstrap.com/img/video/city.mp4" type="video/mp4" >

          </video>

          <div class="mask rgba-black-light d-flex justify-content-center align-items-center">

            <div class="text-center white-text mx-5 wow fadeIn">

              <h1 class="mb-4">

                <strong>배추 가격 예측 AI 로봇</strong>

              </h1>

              <p>

                <strong>빠르고 정확하게 향후 배추 가격을 예측합니다.</strong>

              </p>

              <p class="mb-4 d-none d-md-block">

                <strong>기상청 전국 기온 및 강수량 데이터와 전국 월별 배추 가격 빅 데이터를 분석하여 시계열 수치 예측을 수행합니다</strong>

              </p>

              <a target="_blank" href="#" class="btn btn-outline-white btn-lg">START

                <i class="fa fa-graduation-cap ml-2"></i>

              </a>

            </div>

          </div>

        </div>

      </div>

      <div class="carousel-item">

        <div class="view">

          <video class="video-intro" autoplay loop>

              <source src="https://mdbootstrap.com/img/video/forest.mp4" type="video/mp4">

          </video>

          <div class="mask rgba-black-light d-flex justify-content-center align-items-center">

            <div class="text-center white-text mx-5 wow fadeIn">

              <h1 class="mb-4">

                <strong>배추 가격 예측 AI 로봇</strong>

              </h1>

              <p>

                <strong>빠르고 정확하게 향후 배추 가격을 예측합니다.</strong>

              </p>

              <p class="mb-4 d-none d-md-block">

                <strong>기상청 전국 기온 및 강수량 데이터와 전국 월별 배추 가격 빅 데이터를 분석하여 시계열 수치 예측을 수행합니다</strong>

              </p>

              <a target="_blank" href="#" class="btn btn-outline-white btn-lg">START

                <i class="fa fa-graduation-cap ml-2"></i>

              </a>

            </div>

          </div>

        </div>

      </div>

      <div class="carousel-item">

        <div class="view">

          <video class="video-intro" autoplay loop>

              <source src="https://mdbootstrap.com/img/video/Tropical.mp4" type="video/mp4">

          </video>

          <div class="mask rgba-black-light d-flex justify-content-center align-items-center">

            <div class="text-center white-text mx-5 wow fadeIn">

              <h1 class="mb-4">

                <strong>배추 가격 예측 AI 로봇</strong>

              </h1>

              <p>

                <strong>빠르고 정확하게 향후 배추 가격을 예측합니다.</strong>

              </p>

              <p class="mb-4 d-none d-md-block">

                <strong>기상청 전국 기온 및 강수량 데이터와 전국 월별 배추 가격 빅 데이터를 분석하여 시계열 수치 예측을 수행합니다</strong>

              </p>

              <a target="_blank" href="#" class="btn btn-outline-white btn-lg">START

                <i class="fa fa-graduation-cap ml-2"></i>

              </a>

            </div>

          </div>

        </div>

      </div>

    </div>

    <a class="carousel-control-prev" href="#carousel-example-1z" role="button" data-slide="prev">

      <span class="carousel-control-prev-icon" aria-hidden="true"></span>

      <span class="sr-only">Previous</span>

    </a>

    <a class="carousel-control-next" href="#carousel-example-1z" role="button" data-slide="next">

      <span class="carousel-control-next-icon" aria-hidden="true"></span>

      <span class="sr-only">Next</span>

    </a>


  </div>


  <main>

    <div class="container">

      <section class="mt-5 wow fadeIn">

        <div class="row">

          <div class="col-md-6 mb-4">

            <img src="https://mdbootstrap.com/img/Marketing/mdb-press-pack/mdb-main.jpg" class="img-fluid z-depth-1-half" alt="">

          </div>

          <div class="col-md-6 mb-4">

            <h3 class="h3 mb-3">배추 가격 예측 결과</h3>

            <p>머신 러닝 선형 회귀(Linear Regression) 모델을 확장하여 시계열에 따른 배추 가격을 예측하고 학습 결과를 확인했습니다. 미래의 배추 가격을 효과적으로 예측할 수 있습니다.</p>

            <hr>

            <p>2,900개 이상의 데이터를 활용하여 1.8% 미만의 데이터 오차율을 보이는 배추 가격 예측 모델을 개발했습니다.

            </p>

            <a target="_blank" href="#" class="btn btn-grey btn-md">Download

              <i class="fa fa-download ml-1"></i>

            </a>

          </div>

        </div>

      </section>


      <hr class="my-5">


      <section>

        <h3 class="h3 text-center mb-5">배추 가격 예측하기</h3>

        <div class="row wow fadeIn">

          <div class="col-lg-6 col-md-12 px-4">

            평균 기온:

            <br>

            최저 기온:

            <br>

            최고 기온:

            <br>

            강수량:

          </div>

          <div class="col-lg-6 col-md-12">

            결과:

          </div>

        </div>

      </section>


    </div>

  </main>


  <footer class="page-footer text-center font-small mt-4 wow fadeIn">

    <div class="footer-copyright py-3">

      © 2018 Copyright:

      <a href="#" target="_blank"> 나동빈 </a>

    </div>

  </footer>


  <!-- SCRIPTS -->

  <!-- JQuery -->

  <script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>

  <!-- Bootstrap tooltips -->

  <script type="text/javascript" src="js/popper.min.js"></script>

  <!-- Bootstrap core JavaScript -->

  <script type="text/javascript" src="js/bootstrap.min.js"></script>

  <!-- MDB core JavaScript -->

  <script type="text/javascript" src="js/mdb.min.js"></script>

  <!-- Initializations -->

  <script type="text/javascript">

    // Animations initialization

    new WOW().init();

  </script>

</body>


</html>



※ 플라스크 웹 서버 구현하기 ※


  이제 다른 사용자들이 우리가 만든 웹 사이트를 볼 수 있도록 하기 위해서 플라스크(Flask) 웹 서버를 만들어 봅시다. 플라스크는 파이썬 기반의 웹 서버 프레임워크입니다. 따라서 server.py 소스코드를 생성해 줍시다.



※ 플라스크 웹 서버 기초 소스코드 ※


# -*- coding: utf-8 -*-

from flask import Flask, render_template, request


app = Flask(__name__)


@app.route("/", methods=['GET', 'POST'])

def index():

        return render_template('index.html')


if __name__ == '__main__':

   app.run(debug = True)


  기본적으로 플라스크(Flask)는 static 폴더와 templates 폴더 안에 웹 문서 파일을 넣도록 되어 있습니다. 따라서 templates 폴더 안에 index.html 파일을 넣고, 기타 디자인 파일은 static 폴더 안에 넣어줍시다. 이후에 다음과 같이 서버를 실행해 봅시다.




  이후에 플라스크의 기본 포트인 5000번 포트로 접속했을 때 위와 같이 디자인이 깨지는 것을 알 수 있습니다. 이것은 플라스크 내부의 웹 문서의 CSS 파일 및 JS 파일의 링크를 바르게 설정하면 해결됩니다. 바로 static 폴더의 상대 경로를 이용하는 방식입니다.


※ CSS 파일 불러오는 소스코드 ※


  <!-- Bootstrap core CSS -->

  <link href="{{url_for('static', filename='css/bootstrap.min.css')}}" rel="stylesheet">

  <!-- Material Design Bootstrap -->

  <link href="{{url_for('static', filename='css/mdb.min.css')}}" rel="stylesheet">

  <!-- Your custom styles (optional) -->

  <link href="{{url_for('static', filename='css/style.min.css')}}" rel="stylesheet">


※ JS 파일 불러오는 소스코드 ※

  <!-- JQuery -->

  <script type="text/javascript" src="{{url_for('static', filename='js/jquery-3.3.1.min.js')}}"></script>

  <!-- Bootstrap tooltips -->

  <script type="text/javascript" src="{{url_for('static', filename='js/popper.min.js')}}"></script>

  <!-- Bootstrap core JavaScript -->

  <script type="text/javascript" src="{{url_for('static', filename='js/bootstrap.min.js')}}"></script>

  <!-- MDB core JavaScript -->

  <script type="text/javascript" src="{{url_for('static', filename='js/mdb.min.js')}}"></script>


  이후에 다음과 같이 재접속을 하면 웹 디자인이 안정적으로 출력되는 것을 알 수 있습니다.




다음 시간에는 위와 같은 '배추 가격 예측하기' 서버 기능을 작업해보도록 하겠습니다.


728x90
반응형