import gradio as gr
import google.generativeai as genai
import os
class KyungAhNeChatbot:
def __init__(self):
# 허깅페이스 스페이스에서는 secrets에서 API 키 가져오기
api_key = os.getenv("GEMINI_API_KEY")
if not api_key:
raise ValueError("GEMINI_API_KEY 환경변수가 설정되지 않았습니다!")
# 제미나이 클라이언트 설정
genai.configure(api_key=api_key)
self.model = genai.GenerativeModel('gemini-2.0-flash-exp')
# 경아네 반찬가게 FAQ 데이터
self.faq_data = """
경아네 반찬가게 고객센터 FAQ:
== 기본 정보 ==
• 고객센터: 010-8082-0047
• 입금계좌: 하나은행 12345-00-1234304 주)경아네
• 최소 주문금액: 26,000원
== 주문 관련 ==
1. Q: 주문은 어떻게 하나요?
A: ① 로그인 → ② 주문하기 클릭 → ③ 전체주문 또는 일별주문 클릭 → ④ 드시고 싶은 반찬 클릭(최소 26,000원) → ⑤ 구매버튼 및 장바구니 버튼 클릭 → ⑥ 결제창에서 신용카드/제로페이/무통장 중 선택하여 결제
2. Q: 첫주문 방법이 궁금해요
A: 첫방문 감사합니다. 이용방법과 배송지역을 확인 → 회원가입 후 로그인 → 주문창에서 원하는 반찬 선택 → 장바구니 담기 → 구매버튼으로 결제
3. Q: 반찬 추가는 어떻게 하나요?
A: 첫 페이지에서 구매하고 싶은 반찬 선택 → 장바구니 담기 → 장바구니에서 수량 추가 가능
== 결제 관련 ==
4. Q: 카드결제는 어떻게 하나요?
A: 결제창에서 신용카드/제로페이/무통장 중 선택해서 결제하면 됩니다
5. Q: 포인트 사용은 어떻게 하나요?
A: 결제시 첫 페이지에서 포인트 금액을 입력하고 무통장입금으로 결제
6. Q: 선결제는 어떻게 하나요?
A: 선결제는 3가지로 나뉩니다 - 카드선결제, 제로페이, 현금결제. 선결제 후 홈페이지 게시글에 남기거나 고객센터로 문자 주시면 됩니다
7. Q: 계좌번호 확인은 어디서 하나요?
A: 무통장 거래시 입금계좌가 나옵니다. 하나은행 12345-00-1234304 주)경아네
8. Q: 결제가 안돼요
A: 신용카드 결제 안될 시 고객센터(010-8082-0047)로 연락주세요
== 배송 관련 ==
9. Q: 배송비는 얼마인가요?
A: 새벽배송 3,500원, 택배배송 4,000원
10. Q: 새벽배송인지 택배인지 어떻게 구분하나요?
A: 이용방법에서 배송지를 입력하시면 확인 가능합니다
11. Q: 배송은 어떻게 이루어지나요?
A: 전날 포장 → 배송업체 냉장센터 8시 입고 → 분류 작업 → 새벽배송(2-7시)/택배배송(다음날 하루 중)
12. Q: 반찬이 아직 안왔어요
A: 죄송합니다. 배송업체에 확인 후 연락드리겠습니다
== 취소/환불 관련 ==
13. Q: 취소는 어떻게 하나요?
A: 취소는 2일 전에만 가능합니다. 하루 전에는 반찬이 이미 제작되어 취소가 안됩니다
14. Q: 환불은 어떻게 이루어지나요?
A: 카드는 취소 후 환불까지 2-3일 소요. 카드취소는 문의 남기시면 적립금 포인트가 카드취소로 처리됩니다
15. Q: 반찬이 상한 것 같아요
A: 죄송합니다. 배송과정에서 상한 것 같습니다. 계좌환불/카드취소/적립금 중 편하신 방법으로 환불해드리겠습니다
== 메뉴/상품 관련 ==
16. Q: 정기식 구성은 어떻게 되나요?
A: 고객님이 선택하기 어려운 분을 위해 마련되었습니다. 국1개 + 반찬4개 (메인1개, 서브1개, 나물 및 반찬2개)
17. Q: 반찬 미리보기는 어떻게 되나요?
A: 반찬명을 말씀해주시면 알려드리겠습니다
18. Q: 영양성분을 알 수 있나요?
A: 가능합니다. 반찬명을 말씀해주시면 영양성분 알려드립니다
19. Q: 원산지를 알고 싶어요
A: 원산지표를 링크로 제공해드립니다
== 이벤트/혜택 관련 ==
20. Q: 이벤트는 어디서 보나요?
A: 이벤트 주문창이 별도로 있습니다
21. Q: 소개하면 혜택이 있나요?
A: 소개해주시면 감사합니다. 소개하신 분과 소개받은 분 모두에게 서비스찬 또는 포인트 적립금으로 혜택을 드립니다
22. Q: 후기 남기면 어떤 혜택이 있나요?
A: 후기를 남겨주시면 500포인트를 적립해드립니다
== 기타 ==
23. Q: 주문 누락인 것 같아요
A: 죄송합니다. 확인해보겠습니다. 아이디를 입력해주세요
모든 문의사항은 고객센터 010-8082-0047로 연락주세요.
"""
def chat_stream(self, message, history):
system_prompt = f"""
당신은 경아네 반찬가게의 친절한 상담원입니다.
{self.faq_data}
위 FAQ 정보를 참고하여 고객의 질문에 정확하고 친절하게 답변해주세요.
- FAQ에 있는 정보는 정확히 제공해주세요
- FAQ에 없는 내용은 "자세한 사항은 고객센터(010-8082-0047)로 문의해주세요"라고 안내해주세요
- 반말보다는 존댓말을 사용해주세요
- 간결하고 이해하기 쉽게 답변해주세요
- "안녕하세요 경아네입니다"로 시작하고 "감사합니다"로 마무리해주세요
"""
print(f"사용자 질문: {message}")
print(f"API 키 상태: {'설정됨' if os.getenv('GEMINI_API_KEY') else '없음'}")
try:
response = self.model.generate_content(
contents=f"{system_prompt}\n\n사용자 질문: {message}"
)
print(f"응답 받음: {response.text[:100]}...")
yield response.text
except Exception as e:
error_msg = str(e)
print(f"에러 발생: {error_msg}")
yield f"""죄송합니다. 기술적 문제가 발생했습니다.
에러 정보: {error_msg}
고객센터(010-8082-0047)로 연락해주세요."""
# 챗봇 인스턴스 생성
try:
chatbot = KyungAhNeChatbot()
# 커스텀 헤더 HTML
header_html = """
"""
# 그라디오 인터페이스 생성
with gr.Blocks(
theme=gr.themes.Base(
primary_hue="green",
secondary_hue="blue",
neutral_hue="slate",
font=gr.themes.GoogleFont("Noto Sans KR"),
).set(
body_background_fill="linear-gradient(135deg, #667eea 0%, #764ba2 100%)",
block_background_fill="rgba(255, 255, 255, 0.95)",
block_border_width="0px",
block_radius="16px",
block_shadow="0 8px 32px rgba(0, 0, 0, 0.1)",
),
css="""
/* 전체 컨테이너 스타일 */
.gradio-container {
max-width: 1000px !important;
margin: auto !important;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
/* 헤더 영역 */
.header-container {
background: rgba(255, 255, 255, 0.95);
border-radius: 20px;
padding: 30px;
margin-bottom: 20px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
/* 메인 타이틀 */
.main-title {
font-size: 2.5rem;
font-weight: 700;
background: linear-gradient(45deg, #FF6B6B, #4ECDC4);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
text-align: center;
margin-bottom: 10px;
font-family: 'Noto Sans KR', sans-serif;
}
/* 서브타이틀 */
.sub-title {
font-size: 1.1rem;
color: #666;
text-align: center;
margin-bottom: 20px;
font-family: 'Noto Sans KR', sans-serif;
}
/* 정보 카드들 */
.info-cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
margin-top: 20px;
}
.info-card {
background: linear-gradient(45deg, #FF9A9E, #FECFEF);
padding: 15px;
border-radius: 12px;
text-align: center;
color: white;
font-weight: 600;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease;
}
.info-card:hover {
transform: translateY(-5px);
}
/* 채팅 영역 */
.chatbot {
background: rgba(255, 255, 255, 0.95) !important;
border-radius: 20px !important;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.1) !important;
backdrop-filter: blur(20px) !important;
border: 1px solid rgba(255, 255, 255, 0.2) !important;
min-height: 500px !important;
}
/* 입력 영역 */
.input-container textarea {
background: rgba(255, 255, 255, 0.9) !important;
border-radius: 15px !important;
border: 2px solid #4ECDC4 !important;
padding: 12px !important;
font-family: 'Noto Sans KR', sans-serif !important;
}
/* 전송 버튼 */
button {
background: linear-gradient(45deg, #FF6B6B, #4ECDC4) !important;
border: none !important;
border-radius: 12px !important;
color: white !important;
font-weight: 600 !important;
padding: 10px 20px !important;
transition: all 0.3s ease !important;
font-family: 'Noto Sans KR', sans-serif !important;
}
button:hover {
transform: translateY(-2px) !important;
box-shadow: 0 5px 15px rgba(255, 107, 107, 0.4) !important;
}
/* 모바일 반응형 */
@media (max-width: 768px) {
.gradio-container {
padding: 10px;
}
.main-title {
font-size: 2rem;
}
.info-cards {
grid-template-columns: 1fr 1fr;
}
}
"""
) as demo:
# 헤더 표시
gr.HTML(header_html)
# 채팅 인터페이스
gr.ChatInterface(
fn=chatbot.chat_stream,
examples=[
"주문은 어떻게 하나요?",
"포인트는 어떻게 사용하나요?",
"배송비가 얼마인가요?",
"환불 방법을 알려주세요",
"정기식 구성이 어떻게 되나요?",
"후기 쓰면 혜택이 있나요?",
"반찬이 상한 것 같아요",
"원산지를 알고 싶어요"
]
)
except Exception as e:
def error_message(message, history):
yield "❌ GEMINI_API_KEY가 설정되지 않았습니다. 관리자에게 문의하세요."
demo = gr.ChatInterface(
fn=error_message,
title="🥢 설정 오류",
description="API 키 설정이 필요합니다."
)
if __name__ == "__main__":
demo.launch()