macOS/리눅스 사용자를 위한 GPT와 Flask로 AI 키워드 봇 개발
이번 글에서는 macOS 또는 리눅스 환경에서 OpenAI의 GPT API와 Python 웹 프레임워크 Flask를 사용하여, 여러분이 궁금해하는 키워드에 대해 AI가 똑똑하게 설명해주는 웹 애플리케이션을 만드는 방법을 소개합니다. 터미널 사용이 익숙하지 않아도 괜찮아요. 한 단계 한 단계 따라오시면, 어느새 멋진 AI 봇이 여러분 손에서 탄생할 거랍니다. 전반적인 과정은 이전 글인 Windows 기반의 내용과 같으므로 얻어지는 결과는 같으므로 이미지는 생략하고 진행과정의 설명으로 대신합니다.
오늘의 개발 목표:
- 웹 페이지에서 사용자가 특정 키워드를 입력합니다.
- Flask 백엔드가 이 키워드를 GPT API로 전송합니다.
- GPT 모델이 해당 키워드에 대한 설명을 생성합니다.
- 생성된 설명을 웹 페이지에 결과로 표시합니다.
프로젝트 명칭: MyFirstWebWithLLM
필요한 개발 도구 (환경):
- macOS 또는 Linux 운영체제
- Python (3.7 이상 권장, 대부분의 macOS/Linux에는 기본 설치되어 있거나 쉽게 설치 가능)
- Flask (Python 웹 프레임워크)
- OpenAI Python 라이브러리
- 가상 환경 (venv) – 프로젝트별 독립적인 개발 환경 구성
[1단계]: 프로젝트 디렉토리 생성 및 가상 환경 설정
먼저, 우리 프로젝트를 위한 전용 공간(디렉토리)을 만들고, 다른 Python 프로젝트와 충돌하지 않도록 격리된 가상 환경을 설정합니다.
- 프로젝트 디렉토리 생성 및 이동: 터미널(Terminal)을 실행하세요. (macOS: Launchpad에서 'Terminal' 검색, Linux: 배포판에 따라 다름, 보통 Ctrl+Alt+T) 다음 명령어를 사용하여 원하는 위치에 MyFirstWebWithLLM이라는 디렉토리를 만들고, 그 안으로 이동합니다. (예: 홈 디렉토리 아래 Projects 폴더)(~/Projects는 예시이며, 여러분이 원하는 경로로 변경해도 됩니다.)
-
mkdir -p ~/Projects/MyFirstWebWithLLM # -p 옵션은 상위 디렉토리도 필요하면 생성 cd ~/Projects/MyFirstWebWithLLM
- 가상 환경 생성: 프로젝트 디렉토리 안에서 다음 명령어를 실행하여 myenv라는 이름의 가상 환경을 만듭니다. macOS나 최신 Linux 배포판에서는 python3를 사용하는 것이 일반적입니다.(만약 python3 명령어가 없다면 python -m venv myenv를 시도해 보세요.) 실행 후, ls 명령어로 확인해보면 myenv라는 하위 디렉토리가 생성된 것을 볼 수 있습니다.
-
python3 -m venv myenv
- 가상 환경 활성화: 생성한 가상 환경을 사용하기 위해 다음 명령어로 활성화합니다.명령어를 실행하면, 터미널 프롬프트의 맨 앞에 (myenv)라는 표시가 나타납니다. 이는 현재 가상 환경 내에서 작업 중임을 의미합니다.
-
source myenv/bin/activate
[2단계]: 필수 라이브러리 설치
우리 AI 봇을 구동하기 위해 웹 개발 도구인 Flask와 GPT API와 통신할 openai 라이브러리를 설치해야 합니다.
- requirements.txt 파일 생성: 프로젝트 디렉토리(MyFirstWebWithLLM) 내에 requirements.txt라는 파일을 만들고, 필요한 라이브러리 목록을 작성합니다. 터미널에서 텍스트 편집기(예: nano, vim, code)를 사용하거나 GUI 편집기를 사용해도 됩니다. 예시 (nano 사용):편집기가 열리면 다음 두 줄을 입력하고 저장 후 닫습니다. (nano의 경우: Ctrl+O 저장, Enter, Ctrl+X 종료)
Flask openai
-
nano requirements.txt
- 라이브러리 설치: 가상 환경이 활성화된 터미널((myenv) 표시가 있는 상태)에서 다음 명령어를 실행하여 requirements.txt 파일에 명시된 라이브러리들을 설치합니다.(만약 pip 대신 pip3를 주로 사용한다면 pip3 install -r requirements.txt를 사용하세요. 가상 환경 내에서는 보통 pip이 해당 환경의 Python 버전에 맞춰져 있습니다.)
-
pip install -r requirements.txt
[3단계]: OpenAI API 키 발급 및 안전한 환경 변수 설정
GPT 모델을 사용하려면 OpenAI에서 제공하는 API 키가 필요합니다. 이 키는 매우 중요한 정보이므로 안전하게 관리해야 합니다.
- OpenAI API 키 발급:
- OpenAI API 키 페이지로 이동하여 OpenAI 계정으로 로그인하거나 새로 만듭니다.
- API 키 관리 섹션에서 "Create new secret key" 버튼을 클릭하여 새 API 키를 생성합니다.
- 매우 중요: 생성된 API 키는 해당 창에서만 전체 내용을 볼 수 있습니다. 즉시 안전한 곳(예: 암호 관리 프로그램)에 복사하여 보관하세요. 창을 닫거나 벗어나면 다시는 전체 키를 볼 수 없습니다.
- API 키 환경 변수 설정 (보안 강화): API 키를 코드에 직접 작성하는 것은 보안상 매우 위험합니다. 대신, 운영체제의 환경 변수로 설정하여 코드에서는 이 변수를 참조하도록 합니다.
- 현재 터미널 세션에 임시로 설정하기: (터미널을 닫으면 설정이 사라집니다) 터미널에 다음 명령어를 입력하세요. "여러분의_API_키_여기에_붙여넣으세요" 부분을 실제 발급받은 키로 대체합니다.
export OPENAI_API_KEY="여러분의_API_키_여기에_붙여넣으세요"
- 영구적으로 설정하기 (권장): 매번 터미널을 열 때마다 API 키를 자동으로 로드하려면, 쉘(Shell)의 설정 파일에 위 export 명령어를 추가해야 합니다.
- 사용하는 쉘의 종류를 확인합니다 (보통 Bash 또는 Zsh). 터미널에서 echo $SHELL 명령어로 확인할 수 있습니다.
- 해당 쉘의 설정 파일을 엽니다:
- Bash 쉘: nano ~/.bashrc 또는 nano ~/.bash_profile
- Zsh 쉘 (macOS 최신 버전 기본값): nano ~/.zshrc
- 파일 맨 아래에 다음 줄을 추가합니다 (API 키는 실제 키로 변경). export OPENAI_API_KEY="여러분의_API_키_여기에_붙여넣으세요"
- 파일을 저장하고 편집기를 닫습니다.
- 변경사항을 즉시 적용하려면 다음 명령어를 실행하거나 (해당 쉘 설정 파일명으로 변경), 터미널을 새로 여세요.
source ~/.zshrc # 또는 source ~/.bashrc 등
- 현재 터미널 세션에 임시로 설정하기: (터미널을 닫으면 설정이 사라집니다) 터미널에 다음 명령어를 입력하세요. "여러분의_API_키_여기에_붙여넣으세요" 부분을 실제 발급받은 키로 대체합니다.
[4단계]: 웹 페이지 구조 설계 (HTML 템플릿)
사용자가 키워드를 입력하고 AI의 답변을 확인할 수 있는 웹 페이지의 기본 구조(HTML)를 만듭니다.
- templates 디렉토리 생성: MyFirstWebWithLLM 프로젝트 디렉토리 내에 templates라는 이름의 새 디렉토리를 만듭니다. Flask는 이 디렉토리에서 HTML 템플릿 파일을 찾습니다.
-
mkdir templates
- 키워드 입력 페이지 (index.html) 생성: MyFirstWebWithLLM/templates/ 디렉토리 안에 index.html 파일을 생성하고 다음 코드를 작성하여 저장합니다.
<!doctype html> <html lang="ko"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>AI 키워드 검색봇 (macOS/Linux)</title> <style> body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; margin: 20px; background-color: #f8f9fa; color: #212529; display: flex; flex-direction: column; align-items: center; min-height: 90vh; text-align: center;} h1 { color: #007bff; margin-bottom: 30px; } form { background-color: #ffffff; padding: 30px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); width: 100%; max-width: 500px; } label { display: block; margin-bottom: 10px; font-weight: 500; font-size: 1.1em; color: #495057; } input[type="text"] { width: calc(100% - 24px); padding: 12px; margin-bottom: 25px; border: 1px solid #ced4da; border-radius: 4px; font-size: 1em; box-sizing: border-box; } button { background-color: #28a745; color: white; padding: 12px 20px; border: none; border-radius: 4px; cursor: pointer; font-size: 1.1em; width: 100%; transition: background-color 0.2s ease-in-out; } button:hover { background-color: #218838; } </style> </head> <body> <h1>AI에게 질문하기</h1> <form action="/search" method="post"> <label for="keyword">궁금한 키워드를 입력하세요:</label> <input type="text" id="keyword" name="keyword" required placeholder="예: 인공지능이란?"> <button type="submit">AI에게 질문하기!</button> </form> </body> </html>
- 결과 표시 페이지 (result.html) 생성: MyFirstWebWithLLM/templates/ 디렉토리 안에 result.html 파일을 생성하고 다음 코드를 작성하여 저장합니다.
<!doctype html> <html lang="ko"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>AI 답변: {{ keyword }}</title> <style> body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; margin: 20px; background-color: #e9ecef; color: #343a40; } .container { background-color: #ffffff; padding: 25px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); margin-bottom: 25px; max-width: 800px; margin-left: auto; margin-right: auto;} h1 { color: #007bff; border-bottom: 2px solid #dee2e6; padding-bottom: 15px; font-size: 1.8em; } .keyword-highlight { color: #dc3545; font-weight: 500; } .content-box { white-space: pre-wrap; /* AI 답변의 줄바꿈과 공백을 유지 */ line-height: 1.7; background-color: #f8f9fa; padding: 20px; border: 1px solid #dee2e6; border-radius: 4px; margin-top: 20px; font-size: 1.05em;} .back-link-container { text-align: center; margin-top: 30px; } .back-link { display: inline-block; background-color: #17a2b8; color: white; text-decoration: none; font-weight: 500; padding: 10px 20px; border-radius: 4px; transition: background-color 0.2s ease-in-out; } .back-link:hover { background-color: #138496; } </style> </head> <body> <div class="container"> <h1>AI의 답변 <br>검색어: <span class="keyword-highlight">{{ keyword }}</span></h1> <div class="content-box"> {{ content }} </div> </div> <div class="back-link-container"> <a href="/" class="back-link">다른 키워드로 다시 검색</a> </div> </body> </html>
- {{ keyword }}와 {{ content }} 부분은 나중에 Python(Flask) 코드에서 동적으로 채워질 값들입니다.
[5단계]: GPT 연동 로직 구현 (search.py)
사용자가 입력한 키워드를 받아 OpenAI의 GPT 모델에 전달하고, 그 응답을 받아오는 Python 스크립트를 작성합니다.
MyFirstWebWithLLM 프로젝트 디렉토리 내에 search.py 파일을 생성하고 다음 코드를 작성하여 저장합니다.
import os
from openai import OpenAI
def get_content_from_gpt(keyword):
"""
OpenAI GPT 모델을 사용하여 주어진 키워드에 대한 설명을 생성합니다.
API 키는 'OPENAI_API_KEY' 환경 변수에서 가져옵니다.
"""
api_key = os.environ.get("OPENAI_API_KEY") # 환경 변수에서 API 키 읽기
if not api_key:
print("중요: OpenAI API 키가 환경 변수에 설정되지 않았습니다!")
return "오류: OpenAI API 키를 설정해주세요. (환경 변수 OPENAI_API_KEY 확인 필요)"
try:
# OpenAI API 클라이언트 초기화 (최신 openai 라이브러리 스타일)
client = OpenAI(api_key=api_key)
# GPT 모델에 채팅 형식으로 요청
response = client.chat.completions.create(
model="gpt-3.5-turbo", # 또는 "gpt-4o" 등 최신 고성능 모델
messages=[
{"role": "system", "content": "당신은 사용자의 질문에 대해 명확하고, 논리적이며, 이해하기 쉽게 설명해주는 AI 전문가입니다. 모든 답변은 한국어로 제공하며, 핵심 내용을 잘 요약해주세요."},
{"role": "user", "content": f"'{keyword}'에 대해 초보자도 쉽게 이해할 수 있도록 자세히 설명해주십시오."}
],
temperature=0.65, # 답변의 창의성/일관성 조절 (0.0~2.0, 낮을수록 일관적)
max_tokens=1800 # 최대 응답 길이 (토큰 단위)
)
# AI가 생성한 답변 텍스트 반환
return response.choices[0].message.content.strip()
except Exception as e:
error_message = f"GPT API 호출 중 오류 발생: {str(e)}"
print(error_message) # 서버 로그에 오류 기록
user_friendly_error = "죄송합니다, AI로부터 답변을 가져오는 중 예기치 않은 문제가 발생했습니다. 잠시 후 다시 시도해주세요."
# API 키 인증 오류 시 좀 더 명확한 안내
if "authentication" in str(e).lower() or "api key" in str(e).lower():
user_friendly_error = "OpenAI API 키 인증에 문제가 있는 것 같습니다. API 키가 정확한지, 환경 변수 설정이 올바르게 되었는지 다시 한번 확인해주십시오!"
return user_friendly_error
if __name__ == '__main__':
# search.py 파일을 직접 실행하여 테스트할 수 있습니다.
# 테스트 전에 반드시 터미널에서 OPENAI_API_KEY 환경 변수를 설정해야 합니다!
# (예: export OPENAI_API_KEY="여러분의_API_키")
test_keyword = "도커(Docker) 컨테이너 기술의 장점은 무엇인가요?"
print(f"--- '{test_keyword}'에 대한 GPT 응답 테스트 ---")
gpt_answer = get_content_from_gpt(test_keyword)
print(gpt_answer)
print("--- GPT 응답 테스트 완료 ---")
주요 코드 설명 (search.py):
- os.environ.get("OPENAI_API_KEY"): 3단계에서 설정한 OPENAI_API_KEY 환경 변수 값을 가져옵니다.
- OpenAI(api_key=api_key): API 키를 사용하여 OpenAI 서비스에 연결할 클라이언트 객체를 생성합니다.
- client.chat.completions.create(...): GPT 모델에 채팅 기반의 요청을 보냅니다.
- model: 사용할 AI 모델을 지정합니다 (예: "gpt-3.5-turbo", "gpt-4o").
- messages: AI와의 대화 내용입니다.
- role: "system": AI의 전반적인 역할이나 행동 지침을 설정합니다.
- role: "user": AI에게 전달할 사용자의 실제 질문입니다.
- temperature, max_tokens: AI 응답의 다양성과 최대 길이를 제어하는 파라미터입니다.
- response.choices[0].message.content.strip(): AI의 응답 중에서 실제 텍스트 내용만 추출하고 불필요한 공백을 제거합니다.
- try...except 블록: API 호출 중 발생할 수 있는 오류(잘못된 API 키, 네트워크 문제 등)를 감지하고, 프로그램이 비정상적으로 종료되지 않도록 처리하며 사용자에게 친절한 오류 메시지를 반환합니다.
[6단계]: 웹 서비스의 컨트롤 타워 - Flask 앱 (app.py)
사용자의 웹 요청을 받아 처리하고, search.py의 AI 기능을 호출하여 그 결과를 웹 페이지로 다시 전달하는 Flask 애플리케이션의 핵심 로직(app.py)을 작성합니다.
MyFirstWebWithLLM 프로젝트 디렉토리 내에 app.py 파일을 생성하고 다음 코드를 작성하여 저장합니다.
import os
from flask import Flask, render_template, request, redirect, url_for
from search import get_content_from_gpt # 5단계에서 작성한 search.py의 함수 임포트
# Flask 애플리케이션 인스턴스 생성
app = Flask(__name__)
# Flask 세션 관리 등을 위한 시크릿 키 설정 (보안상 중요)
# 실제 운영 환경에서는 예측 불가능한 강력한 키를 사용해야 합니다.
app.secret_key = os.urandom(32)
# 메인 페이지 (키워드 입력 폼) 라우팅
@app.route('/')
def home_page():
"""사용자가 웹사이트 루트 URL에 접속했을 때 호출됩니다."""
print("사용자가 메인 페이지('/')에 접근했습니다.")
return render_template('index.html') # index.html 템플릿을 사용자에게 보여줌
# 키워드 검색 처리 및 결과 페이지 라우팅
@app.route('/search', methods=['POST']) # HTTP POST 요청만 처리
def handle_search_request():
"""사용자가 'index.html'에서 폼을 제출했을 때 호출됩니다."""
if request.method == 'POST':
# 폼 데이터에서 'keyword' 값을 가져옴. 값이 없으면 빈 문자열 반환 후 공백 제거.
user_keyword = request.form.get('keyword', '').strip()
if not user_keyword:
print("경고: 사용자로부터 빈 키워드가 입력되었습니다. 메인 페이지로 리다이렉트합니다.")
# 키워드가 입력되지 않았으면, 다시 메인 페이지로 보냄
return redirect(url_for('home_page'))
print(f"사용자가 검색한 키워드: '{user_keyword}' (GPT에게 전달 예정)")
# search.py의 get_content_from_gpt 함수를 호출하여 AI의 설명을 가져옴
ai_generated_content = get_content_from_gpt(user_keyword)
# 디버깅을 위해 AI 응답 일부를 서버 콘솔에 출력
# print(f"AI로부터 받은 응답 (첫 150자): {ai_generated_content[:150]}...")
# result.html 템플릿에 사용자가 입력한 키워드와 AI가 생성한 내용을 전달하여 렌더링
return render_template('result.html', keyword=user_keyword, content=ai_generated_content)
# POST 요청이 아닌 다른 방법으로 '/search' URL에 접근한 경우, 메인 페이지로 리다이렉트
return redirect(url_for('home_page'))
# 이 스크립트 파일(app.py)이 직접 실행될 때 Flask 개발 서버를 시작
if __name__ == '__main__':
print("Flask 웹 애플리케이션 서버를 시작합니다. 종료하려면 Ctrl+C를 누르세요.")
# host='0.0.0.0'은 로컬 머신 외부에서도 (같은 네트워크상에서) 접근 가능하게 함
# port=5000은 웹 서버가 사용할 포트 번호
# debug=True는 개발 중에 유용 (코드 변경 시 자동 재시작, 상세 오류 정보 제공)
# 실제 서비스 배포 시에는 debug=False로 변경하고, Gunicorn 같은 WSGI 서버 사용 권장
app.run(host='0.0.0.0', port=5000, debug=True)
주요 코드 설명 (app.py):
- app = Flask(__name__): Flask 애플리케이션 객체를 생성합니다. 이 객체가 웹 서버의 역할을 합니다.
- @app.route('/'): 웹사이트의 루트 URL(예: http://localhost:5000/)로 사용자가 접속하면 home_page 함수가 실행되도록 지정합니다.
- render_template('index.html'): templates 디렉토리에서 index.html 파일을 찾아 그 내용을 웹 브라우저에 표시합니다.
- @app.route('/search', methods=['POST']): /search URL로 HTTP POST 요청이 들어오면 (주로 HTML 폼 제출 시 사용됨) handle_search_request 함수가 실행되도록 지정합니다. index.html의 폼 태그에서 action="/search" method="post"로 설정했기 때문입니다.
- request.form.get('keyword', '').strip(): 사용자가 index.html의 폼에 입력한 keyword 값을 가져옵니다.
- get_content_from_gpt(user_keyword): search.py에 정의된 함수를 호출하여 AI에게 설명을 요청합니다.
- render_template('result.html', keyword=user_keyword, content=ai_generated_content): result.html 템플릿을 렌더링하면서, keyword와 content라는 변수명으로 각각 사용자가 입력한 키워드와 AI가 생성한 설명을 전달합니다. HTML 템플릿 내에서는 {{ keyword }}와 {{ content }} 형식으로 이 값들을 사용할 수 있습니다.
- app.run(host='0.0.0.0', port=5000, debug=True): Flask 개발 서버를 시작합니다.
- host='0.0.0.0': 로컬 머신뿐만 아니라 동일 네트워크상의 다른 기기에서도 이 서버에 접속할 수 있게 합니다 (예: 스마트폰으로 내 PC IP 주소:5000 접속).
- port=5000: 서버가 사용할 포트 번호를 지정합니다.
- debug=True: 개발 모드로 실행합니다. 코드가 변경될 때마다 서버가 자동으로 재시작되며, 오류 발생 시 웹 브라우저에 상세한 디버깅 정보를 표시해줍니다. 실제 서비스 배포 시에는 보안을 위해 False로 변경해야 합니다.
[7단계]: 애플리케이션 실행 및 AI 봇 테스트
모든 코드가 준비되었습니다! 이제 직접 만든 AI 키워드 설명 봇을 실행하고 테스트해볼 시간입니다.
- 가상 환경 활성화 확인: 터미널 프롬프트 맨 앞에 (myenv) 표시가 있는지 다시 한번 확인하세요. 만약 없다면 source myenv/bin/activate 명령어로 가상 환경을 활성화합니다.
- OpenAI API 키 환경 변수 설정 확인: macOS/Linux 3단계에서 설명한 대로 API 키가 현재 터미널 세션의 환경 변수로 올바르게 설정되어 있는지 확인합니다. (터미널을 새로 열었다면, 임시 설정은 사라졌을 수 있으므로 영구 설정을 했거나 export 명령어를 다시 실행해야 합니다.)
- Flask 애플리케이션 실행: 프로젝트 디렉토리(MyFirstWebWithLLM)로 이동된 터미널에서 다음 명령어를 입력하여 app.py를 실행합니다. (Python 3 사용 권장)(또는 시스템 설정에 따라 python app.py)
-
python3 app.py
- 웹 브라우저에서 접속 및 테스트: 터미널에 다음과 유사한 메시지가 출력되면 Flask 서버가 성공적으로 실행된 것입니다.
* Serving Flask app 'app' (lazy loading) * Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: on * Running on http://0.0.0.0:5000 (Press CTRL+C to quit) * Restarting with stat * Debugger is active! * Debugger PIN: xxx-xxx-xxx
- http://127.0.0.1:5000
- http://localhost:5000
- 웹 서버 실행을 중지하려면, 터미널 창에서 Ctrl 키와 C 키를 함께 누르세요.
'AI > 생성형AI' 카테고리의 다른 글
[Make.com업무자동화](1)Make.com를 이용 방법(Gmail, GPTs) (5) | 2025.05.19 |
---|---|
[Web기반업무자동화](1)GPT API를 이용한 업무 자동화(Windows) (2) | 2025.05.17 |
[OAuth 발급]Google 인증을 위한 필수 과정 OAuth 발급 (0) | 2025.05.16 |
[GPT업무자동화] 프롬프트 만으로 보고서 생성기 만들자 (1) | 2025.05.16 |
[OAuth 발급]Google 인증을 위한 필수 과정 OAuth 발급 (3) | 2025.05.15 |