diff --git a/backend/db/dbsetup.py b/backend/db/dbsetup.py index af16e2a..0007e9a 100644 --- a/backend/db/dbsetup.py +++ b/backend/db/dbsetup.py @@ -193,6 +193,13 @@ class DatabaseManager: Returns: sqlite3.Connection: SQLite 연결 객체 """ + # 연결이 닫혀있으면 재생성 + if self.sqlite_conn is not None: + try: + self.sqlite_conn.execute("SELECT 1") + except Exception: + self.sqlite_conn = None + if self.sqlite_conn is None: # 파일 존재 여부 확인 is_new_db = not self.sqlite_db_path.exists() diff --git a/backend/gui/pos_sales_gui.py b/backend/gui/pos_sales_gui.py index 99786d5..c1f007d 100644 --- a/backend/gui/pos_sales_gui.py +++ b/backend/gui/pos_sales_gui.py @@ -181,8 +181,7 @@ class SalesQueryThread(QThread): finally: if mssql_conn: mssql_conn.close() - if sqlite_conn: - sqlite_conn.close() + # sqlite_conn은 싱글톤이므로 닫지 않음 (닫으면 다른 곳에서 I/O 에러 발생) class QRGeneratorThread(QThread): @@ -600,9 +599,7 @@ class UserMileageDialog(QDialog): except Exception as e: QMessageBox.critical(self, '오류', f'회원 정보 조회 실패:\n{str(e)}') - finally: - if conn: - conn.close() + # conn은 싱글톤이므로 닫지 않음 class POSSalesGUI(QMainWindow): diff --git a/backend/services/clawdbot_client.py b/backend/services/clawdbot_client.py index 327b7a3..3031026 100644 --- a/backend/services/clawdbot_client.py +++ b/backend/services/clawdbot_client.py @@ -45,7 +45,7 @@ def _load_gateway_config(): async def _ask_gateway(message, session_id='pharmacy-upsell', - system_prompt=None, timeout=60): + system_prompt=None, timeout=60, model=None): """ Clawdbot Gateway WebSocket API 호출 @@ -112,7 +112,29 @@ async def _ask_gateway(message, session_id='pharmacy-upsell', return None break # 연결 성공 - # 4. agent 요청 + # 4. 모델 오버라이드 (sessions.patch) + if model: + patch_id = str(uuid.uuid4()) + patch_frame = { + 'type': 'req', + 'id': patch_id, + 'method': 'sessions.patch', + 'params': { + 'key': session_id, + 'model': model, + } + } + await ws.send(json.dumps(patch_frame)) + # patch 응답 대기 + while True: + msg = await asyncio.wait_for(ws.recv(), timeout=10) + data = json.loads(msg) + if data.get('id') == patch_id: + if not data.get('ok'): + logger.warning(f"[Clawdbot] sessions.patch 실패: {data.get('error', {}).get('message', 'unknown')}") + break + + # 5. agent 요청 agent_id = str(uuid.uuid4()) agent_params = { 'message': message, @@ -174,7 +196,7 @@ async def _ask_gateway(message, session_id='pharmacy-upsell', def ask_clawdbot(message, session_id='pharmacy-upsell', - system_prompt=None, timeout=60): + system_prompt=None, timeout=60, model=None): """ 동기 래퍼: Flask에서 직접 호출 가능 @@ -183,6 +205,7 @@ def ask_clawdbot(message, session_id='pharmacy-upsell', session_id: 세션 ID (대화 구분용) system_prompt: 추가 시스템 프롬프트 timeout: 타임아웃 (초) + model: 모델 오버라이드 (예: 'anthropic/claude-sonnet-4-5') Returns: str: AI 응답 텍스트 (실패 시 None) @@ -190,7 +213,7 @@ def ask_clawdbot(message, session_id='pharmacy-upsell', try: loop = asyncio.new_event_loop() result = loop.run_until_complete( - _ask_gateway(message, session_id, system_prompt, timeout) + _ask_gateway(message, session_id, system_prompt, timeout, model=model) ) loop.close() return result @@ -201,6 +224,8 @@ def ask_clawdbot(message, session_id='pharmacy-upsell', # 업셀링 전용 ────────────────────────────────────── +UPSELL_MODEL = 'anthropic/claude-sonnet-4-5' # 업셀링은 Sonnet (빠르고 충분) + UPSELL_SYSTEM_PROMPT = """당신은 동네 약국(청춘약국)의 친절한 약사입니다. 고객의 구매 이력을 보고, 자연스럽고 따뜻한 톤으로 약 하나를 추천합니다. 강압적이거나 광고 같은 느낌이 아닌, 진심으로 건강을 걱정하는 약사의 말투로 작성해주세요. @@ -238,7 +263,8 @@ def generate_upsell(user_name, current_items, recent_products): prompt, session_id=f'upsell-{user_name}', system_prompt=UPSELL_SYSTEM_PROMPT, - timeout=30 + timeout=30, + model=UPSELL_MODEL ) if not response_text: @@ -285,7 +311,8 @@ def generate_upsell_real(user_name, current_items, recent_products, available_pr prompt, session_id=f'upsell-real-{user_name}', system_prompt=UPSELL_REAL_SYSTEM_PROMPT, - timeout=30 + timeout=30, + model=UPSELL_MODEL ) if not response_text: diff --git a/backend/utils/qr_token_generator.py b/backend/utils/qr_token_generator.py index 12ee72b..8d8423b 100644 --- a/backend/utils/qr_token_generator.py +++ b/backend/utils/qr_token_generator.py @@ -115,8 +115,8 @@ def save_token_to_db(transaction_id, token_hash, total_amount, claimable_points, - token_hash가 이미 존재하면 실패 (UNIQUE 제약) """ try: - db_manager = DatabaseManager() - conn = db_manager.get_sqlite_connection() + from db.dbsetup import db_manager as _db_manager + conn = _db_manager.get_sqlite_connection() cursor = conn.cursor() # 중복 체크 (transaction_id)