fix: SQLite 싱글톤 연결 I/O 에러 수정 + clawdbot 모델 오버라이드

- dbsetup: get_sqlite_connection()에 SELECT 1 헬스체크 추가 (죽은 연결 자동 재생성)
- pos_sales_gui: 싱글톤 SQLite conn.close() 제거 (I/O closed file 에러 원인)
- qr_token_generator: DatabaseManager() 새 생성 → 전역 db_manager 싱글톤 사용
- clawdbot_client: model 파라미터 추가, 업셀링에 claude-sonnet-4-5 지정

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
thug0bin 2026-02-27 01:27:47 +09:00
parent 4c3e1d08b2
commit db5f6063ec
4 changed files with 44 additions and 13 deletions

View File

@ -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()

View File

@ -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):

View File

@ -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:

View File

@ -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)