알토르 7

toddcanwell·2025년 9월 20일
post-thumbnail

웹사이트의 구현 방식

MPA
서버에서 모든 페이지(리소스)를 랜더링해서 html로 응답
페이지가 이동할때마다 리소스를 서버에서 다시 받아오는 방식 : 실제 페이지 이동시 깜빡거리는 현상
server에서 템플릿엔진을 사용해서 html을 렌더링하여 html을 응답해준다.

SPA
페이지 이동시 마치 모바일 앱처럼 부드럽게 이동하는 현상, 컨텐츠만 바뀌게된다.
필요한 데이터들은 API로 가져와서 화면의 일부만 갱신한다.

보통 백엔드 서버는 api만 제공만하고 , 응답을 Json 형태로 해주기에 http 통신만 가능하다면 웹외에도 모바일 애플리케이션 등 다양한 클라이언트에서도 사용가능해서 유용하다.

ejs
템플릿 엔진중 하나로 서버에서 데이터를 HTML에 끼워 넣어 완성된 페이지를 만들어 주는 도구.

cors
CORS: 브라우저 정책. API 서버가 허용 헤더를 줘야 브라우저가 통과시킴

Promise
Promise: 비동기 결과를 안전하게 순서 있게 다루기 위한 도구(then/catch, async/await)


DBMS
DBMS (Database ManageMent System) : 데이터베이스 관리시스템 : 데이터를 저장/조회/수정/삭제 할수있는 인터페이스 제공해주는 소프트웨어
테이블 행/열 구조인 관계형 : mysql, PostgreSQL, Oracle
문서,키-값,그래프 구조인 비관계형 : MongoDB, Redis , Cassandra

WorkBench
workbench : DBMB를 조작하기 편한 GUI
ex) MySQL Workbench, MongoDB Compass

소스코드 접속
애플리케이션에서 DBMS랑 연결할 때 사용하는 방식
코드 안에서 직접 DB CRUD 작업 가능

MongoDB
대표적인 NoSQL DBMS 으로 Json과 비슷한 document로 데이터 저장

MongoDB 서버
 └── 데이터베이스 (Database) : 테이블들이 모여있는 스키마와 비슷한 개념 
     └── 컬렉션 (Collection) : 데이터가 저장되는 테이블와 비슷한개념 
         └── 문서 (Document) : 레코드와 비슷한 개념 
         
#Document
{
	"name" : "Todd",
	"age" : 25,
	"skills" : ["JS","Python"]
}
         

MongoDB Atlas
MongoDB Atlas : MongoDB의 클라우드 서비스 : aws나 로컬저장소에 직접 db를 설치하지않고 Atlas가 서버와 DB를 대신 관리해준다.

cluster 클러스터
클러스터 : DB 시스템에서 여러대의 물리적 서버 컴퓨터(노드)를 묶어서 하나의 논리적데이터베이스 처럼 동작하게 하는 구조

물리적으로 여러컴퓨터를 이용하지만 코드에서 클러스터 uri 하나에 접속하여 하나의 mongoDB 서버처럼 이용가능하다.


1. Mongo Atlas 회원가입 및 새 클러스터 생성

2. 데이터베이스 사용자 생성


3. 네트워크 액세스 설정


4. 코드수정

.env 추가사항
OPENAI_API_KEY = my_openAi_API_KEY 

ASSISTANT_ID = my_assistant_id

MONGODB_URI = mongodb+srv://사용자아이디:사용자패스워드@cluster0.e7lzjav.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0

COLLECTION_NAME=chat_messages 

app.py MongoDB 연결 설정 및 저장함수추가

pymongo : 파이썬용 몽고디비 공식드라이버 : 파이썬에서 몽고디비에 연결/crud 수행
datetime : 타임스탬프를 기록해주는 용도

#  MongoDB 연결을 위한 모듈 추가
from pymongo import MongoClient
#  날짜/시간 처리를 위한 모듈 추가  
from datetime import datetime

#  MongoDB 연결 설정 
MONGODB_URI = os.getenv('MONGODB_URI')
DATABASE_NAME = os.getenv('DATABASE_NAME', 'portfolio_chat')
COLLECTION_NAME = os.getenv('COLLECTION_NAME', 'chat_messages')

#  MongoDB 클라이언트 생성 및 연결 테스트 
try:
    client_mongo = MongoClient(MONGODB_URI)
    # 연결 테스트
    client_mongo.admin.command('ping')
    print("MongoDB 연결 성공!")
    db = client_mongo[DATABASE_NAME]
    collection = db[COLLECTION_NAME]
except Exception as e:
    print(f"MongoDB 연결 실패: {e}")
    client_mongo = None
    db = None
    collection = None

# 완전히 새로운 함수 추가 (라인 66-91)
def save_chat_to_mongodb(user_message, ai_response, thread_id):
    """
    채팅 데이터를 MongoDB에 저장하는 함수
    """
    if collection is None:
        print("MongoDB 연결이 없어서 데이터를 저장할 수 없습니다.")
        return False
    
    try:
        # 저장할 데이터 구조
        chat_data = {
            "user_message": user_message,
            "ai_response": ai_response,
            "thread_id": thread_id,
            "timestamp": datetime.now(),
            "created_at": datetime.now().isoformat()
        }
        
        # MongoDB에 데이터 삽입
        result = collection.insert_one(chat_data)
        print(f"채팅 데이터 저장 성공! ID: {result.inserted_id}")
        return True
        
    except Exception as e:
        print(f"채팅 데이터 저장 실패: {e}")
        return False

app.py sendMessage 엔드포인트 추가 및 변경

@app.route("/sendMessage", methods=["POST"])
def send_message():
    """
    사용자 메시지를 받아서 OpenAI Assistant에 전달하고 응답을 반환하는 API 엔드포인트
    """
    global thread_id  # 전역 변수 thread_id를 사용
    
    try:
        # 클라이언트가 보낸 JSON 데이터를 파싱
        data = request.get_json()
        # JSON에서 'message' 키의 값을 가져옴 (사용자 입력 메시지)
        message = data.get('message', '')
        
        # 메시지가 비어있으면 에러를 반환
        if not message:
            return jsonify({"error": "메시지가 없습니다."}), 400
        
        # 터미널에 받은 메시지를 출력 (디버깅용)
        print(f"받은 메시지: {message}")
        
        # 스레드가 없으면 새로 생성 (첫 번째 메시지인 경우)
        if thread_id is None:
            # 새로운 대화 스레드를 생성
            thread = client.beta.threads.create()
            # 생성된 스레드의 ID를 저장
            thread_id = thread.id
            print(f"새 스레드 생성: {thread_id}")
        
        # 사용자 메시지를 스레드에 추가
        client.beta.threads.messages.create(
            thread_id=thread_id,  # 대화 스레드 ID
            role="user",          # 메시지 역할 (사용자)
            content=message       # 메시지 내용
        )
        
        # Assistant를 실행하여 응답을 생성
        run = client.beta.threads.runs.create(
            thread_id=thread_id,      # 대화 스레드 ID
            assistant_id=ASSISTANT_ID # OpenAI 대시보드에서 생성한 Assistant ID
        )
        
        # Assistant가 응답을 완료할 때까지 기다림
        while True:
            # 현재 실행 상태를 확인
            run_status = client.beta.threads.runs.retrieve(
                thread_id=thread_id,
                run_id=run.id
            )
            
            # 실행이 완료되면 루프를 종료
            if run_status.status == "completed":
                break
            # 실행이 실패하면 에러를 반환
            elif run_status.status == "failed":
                return jsonify({"error": "Assistant 실행 실패"}), 500
        
        # Assistant의 응답 메시지를 가져옴
        messages = client.beta.threads.messages.list(thread_id=thread_id)
        # 가장 최근 메시지(Assistant의 응답)를 가져옴
        assistant_message = messages.data[0]
        # 응답 내용을 추출
        ai_response = assistant_message.content[0].text.value
        
        # 참조 표시를 제거
        cleaned_response = clean_response(ai_response)
        
        # 터미널에 Assistant 응답을 출력 (디버깅용)
        print(f"Assistant 응답 (원본): {ai_response}")
        print(f"Assistant 응답 (정리됨): {cleaned_response}")
        
        # MongoDB에 채팅 데이터 저장
        save_success = save_chat_to_mongodb(message, cleaned_response, thread_id)
        if save_success:
            print("채팅 데이터가 MongoDB에 성공적으로 저장되었습니다.")
        else:
            print("채팅 데이터 저장에 실패했습니다.")
        
        # 클라이언트에게 성공 응답을 JSON 형태로 반환
        return jsonify({
            "success": True,
            "message": cleaned_response,
            "original_message": message,
            "saved_to_db": save_success
        })
        
    except Exception as e:
        # 에러가 발생하면 터미널에 에러 메시지를 출력
        print(f"에러 발생: {str(e)}")
        # 클라이언트에게 에러 응답을 반환
        return jsonify({"error": f"서버 에러: {str(e)}"}), 500

5. 로컬에서 테스트


6. EC2인스턴스 테스트 배포

ec2인스턴스 .env 파일설정

가상환경활성화후 pymongo 다운로드 -> 구니콘 실행 테스트 성공

구니콘 서비스유닛 백그라운드프로세스 다시실행

mongo Atlas 네트워크 액세스에 ec2 인스턴스 고정ip 등록

채팅창

profile
toddcanwell

0개의 댓글