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:
parent
4c3e1d08b2
commit
db5f6063ec
@ -193,6 +193,13 @@ class DatabaseManager:
|
|||||||
Returns:
|
Returns:
|
||||||
sqlite3.Connection: SQLite 연결 객체
|
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:
|
if self.sqlite_conn is None:
|
||||||
# 파일 존재 여부 확인
|
# 파일 존재 여부 확인
|
||||||
is_new_db = not self.sqlite_db_path.exists()
|
is_new_db = not self.sqlite_db_path.exists()
|
||||||
|
|||||||
@ -181,8 +181,7 @@ class SalesQueryThread(QThread):
|
|||||||
finally:
|
finally:
|
||||||
if mssql_conn:
|
if mssql_conn:
|
||||||
mssql_conn.close()
|
mssql_conn.close()
|
||||||
if sqlite_conn:
|
# sqlite_conn은 싱글톤이므로 닫지 않음 (닫으면 다른 곳에서 I/O 에러 발생)
|
||||||
sqlite_conn.close()
|
|
||||||
|
|
||||||
|
|
||||||
class QRGeneratorThread(QThread):
|
class QRGeneratorThread(QThread):
|
||||||
@ -600,9 +599,7 @@ class UserMileageDialog(QDialog):
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
QMessageBox.critical(self, '오류', f'회원 정보 조회 실패:\n{str(e)}')
|
QMessageBox.critical(self, '오류', f'회원 정보 조회 실패:\n{str(e)}')
|
||||||
finally:
|
# conn은 싱글톤이므로 닫지 않음
|
||||||
if conn:
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
|
|
||||||
class POSSalesGUI(QMainWindow):
|
class POSSalesGUI(QMainWindow):
|
||||||
|
|||||||
@ -45,7 +45,7 @@ def _load_gateway_config():
|
|||||||
|
|
||||||
|
|
||||||
async def _ask_gateway(message, session_id='pharmacy-upsell',
|
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 호출
|
Clawdbot Gateway WebSocket API 호출
|
||||||
|
|
||||||
@ -112,7 +112,29 @@ async def _ask_gateway(message, session_id='pharmacy-upsell',
|
|||||||
return None
|
return None
|
||||||
break # 연결 성공
|
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_id = str(uuid.uuid4())
|
||||||
agent_params = {
|
agent_params = {
|
||||||
'message': message,
|
'message': message,
|
||||||
@ -174,7 +196,7 @@ async def _ask_gateway(message, session_id='pharmacy-upsell',
|
|||||||
|
|
||||||
|
|
||||||
def ask_clawdbot(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에서 직접 호출 가능
|
동기 래퍼: Flask에서 직접 호출 가능
|
||||||
|
|
||||||
@ -183,6 +205,7 @@ def ask_clawdbot(message, session_id='pharmacy-upsell',
|
|||||||
session_id: 세션 ID (대화 구분용)
|
session_id: 세션 ID (대화 구분용)
|
||||||
system_prompt: 추가 시스템 프롬프트
|
system_prompt: 추가 시스템 프롬프트
|
||||||
timeout: 타임아웃 (초)
|
timeout: 타임아웃 (초)
|
||||||
|
model: 모델 오버라이드 (예: 'anthropic/claude-sonnet-4-5')
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: AI 응답 텍스트 (실패 시 None)
|
str: AI 응답 텍스트 (실패 시 None)
|
||||||
@ -190,7 +213,7 @@ def ask_clawdbot(message, session_id='pharmacy-upsell',
|
|||||||
try:
|
try:
|
||||||
loop = asyncio.new_event_loop()
|
loop = asyncio.new_event_loop()
|
||||||
result = loop.run_until_complete(
|
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()
|
loop.close()
|
||||||
return result
|
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 = """당신은 동네 약국(청춘약국)의 친절한 약사입니다.
|
UPSELL_SYSTEM_PROMPT = """당신은 동네 약국(청춘약국)의 친절한 약사입니다.
|
||||||
고객의 구매 이력을 보고, 자연스럽고 따뜻한 톤으로 약 하나를 추천합니다.
|
고객의 구매 이력을 보고, 자연스럽고 따뜻한 톤으로 약 하나를 추천합니다.
|
||||||
강압적이거나 광고 같은 느낌이 아닌, 진심으로 건강을 걱정하는 약사의 말투로 작성해주세요.
|
강압적이거나 광고 같은 느낌이 아닌, 진심으로 건강을 걱정하는 약사의 말투로 작성해주세요.
|
||||||
@ -238,7 +263,8 @@ def generate_upsell(user_name, current_items, recent_products):
|
|||||||
prompt,
|
prompt,
|
||||||
session_id=f'upsell-{user_name}',
|
session_id=f'upsell-{user_name}',
|
||||||
system_prompt=UPSELL_SYSTEM_PROMPT,
|
system_prompt=UPSELL_SYSTEM_PROMPT,
|
||||||
timeout=30
|
timeout=30,
|
||||||
|
model=UPSELL_MODEL
|
||||||
)
|
)
|
||||||
|
|
||||||
if not response_text:
|
if not response_text:
|
||||||
@ -285,7 +311,8 @@ def generate_upsell_real(user_name, current_items, recent_products, available_pr
|
|||||||
prompt,
|
prompt,
|
||||||
session_id=f'upsell-real-{user_name}',
|
session_id=f'upsell-real-{user_name}',
|
||||||
system_prompt=UPSELL_REAL_SYSTEM_PROMPT,
|
system_prompt=UPSELL_REAL_SYSTEM_PROMPT,
|
||||||
timeout=30
|
timeout=30,
|
||||||
|
model=UPSELL_MODEL
|
||||||
)
|
)
|
||||||
|
|
||||||
if not response_text:
|
if not response_text:
|
||||||
|
|||||||
@ -115,8 +115,8 @@ def save_token_to_db(transaction_id, token_hash, total_amount, claimable_points,
|
|||||||
- token_hash가 이미 존재하면 실패 (UNIQUE 제약)
|
- token_hash가 이미 존재하면 실패 (UNIQUE 제약)
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
db_manager = DatabaseManager()
|
from db.dbsetup import db_manager as _db_manager
|
||||||
conn = db_manager.get_sqlite_connection()
|
conn = _db_manager.get_sqlite_connection()
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
# 중복 체크 (transaction_id)
|
# 중복 체크 (transaction_id)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user