This commit is contained in:
h z
2026-02-12 15:45:48 +00:00
commit 343a4b8d67
34 changed files with 2321 additions and 0 deletions

0
storage/__init__.py Normal file
View File

109
storage/database.py Normal file
View File

@@ -0,0 +1,109 @@
from sqlalchemy import Column, Integer, String, DateTime, Text
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from datetime import datetime
import json
from models.debate import DebateSession
from exceptions import ServiceNotConfiguredError
from services.config_service import ConfigService
Base = declarative_base()
class DebateSessionDB(Base):
__tablename__ = "debate_sessions"
id = Column(Integer, primary_key=True, index=True)
session_id = Column(String(255), unique=True, index=True, nullable=False)
topic = Column(Text, nullable=False)
participants = Column(Text, nullable=False) # JSON string
constraints = Column(Text, nullable=False) # JSON string
rounds = Column(Text, nullable=False) # JSON string
status = Column(String(50), nullable=False)
created_at = Column(DateTime, nullable=False)
completed_at = Column(DateTime, nullable=True)
summary = Column(Text, nullable=True)
evidence_library = Column(Text, nullable=True) # JSON string
# ---------------------------------------------------------------------------
# Lazy engine / session factory
# ---------------------------------------------------------------------------
_engine = None
_SessionLocal = None
def _get_engine():
from sqlalchemy import create_engine
global _engine
if _engine is None:
db_url = ConfigService.get_database_url()
if not db_url:
raise ServiceNotConfiguredError("数据库未配置")
_engine = create_engine(db_url)
return _engine
def _get_session_factory():
global _SessionLocal
if _SessionLocal is None:
_SessionLocal = sessionmaker(
autocommit=False, autoflush=False, bind=_get_engine()
)
return _SessionLocal
def init_db():
"""Create all tables if DB is configured; silently skip otherwise."""
if not ConfigService.is_db_configured():
print("WARNING: Database not configured, skipping table creation.")
return
try:
from db_models import Base as ApiBase
engine = _get_engine()
Base.metadata.create_all(bind=engine)
ApiBase.metadata.create_all(bind=engine)
except Exception as e:
global _engine, _SessionLocal
print(f"WARNING: Database connection failed, skipping table creation: {e}")
if _engine is not None:
_engine.dispose()
_engine = None
_SessionLocal = None
def debate_session_from_db(db_session) -> DebateSession:
"""Convert database session to Pydantic model."""
evidence_library = []
if db_session.evidence_library:
evidence_library = json.loads(db_session.evidence_library)
return DebateSession(
session_id=db_session.session_id,
topic=db_session.topic,
participants=json.loads(db_session.participants),
constraints=json.loads(db_session.constraints),
rounds=json.loads(db_session.rounds),
status=db_session.status,
created_at=db_session.created_at,
completed_at=db_session.completed_at,
summary=db_session.summary,
evidence_library=evidence_library
)
def debate_session_to_db(session: DebateSession) -> DebateSessionDB:
"""Convert Pydantic model to database model."""
return DebateSessionDB(
session_id=session.session_id,
topic=session.topic,
participants=json.dumps([p.dict() for p in session.participants]),
constraints=json.dumps(session.constraints.dict()),
rounds=json.dumps([r.dict() for r in session.rounds], default=str),
status=session.status,
created_at=session.created_at,
completed_at=session.completed_at,
summary=session.summary,
evidence_library=json.dumps([e.dict() for e in session.evidence_library], default=str) if session.evidence_library else None
)

View File

@@ -0,0 +1,67 @@
from sqlalchemy.orm import Session
from datetime import datetime
import json
from typing import Optional
from models.debate import DebateSession
from storage.database import DebateSessionDB, debate_session_from_db, debate_session_to_db
class SessionManager:
"""
Manages debate sessions in storage
"""
def __init__(self):
pass
async def save_session(self, db: Session, session: DebateSession):
"""
Save a debate session to the database
"""
db_session = debate_session_to_db(session)
db.add(db_session)
db.commit()
db.refresh(db_session)
async def get_session(self, db: Session, session_id: str) -> Optional[DebateSession]:
"""
Retrieve a debate session from the database
"""
db_session = db.query(DebateSessionDB).filter(DebateSessionDB.session_id == session_id).first()
if not db_session:
return None
return debate_session_from_db(db_session)
async def update_session(self, db: Session, session: DebateSession):
"""
Update an existing debate session in the database
"""
db_session = db.query(DebateSessionDB).filter(DebateSessionDB.session_id == session.session_id).first()
if db_session:
db_session.topic = session.topic
db_session.participants = json.dumps([p.dict() for p in session.participants])
db_session.constraints = json.dumps(session.constraints.dict())
db_session.rounds = json.dumps([r.dict() for r in session.rounds], default=str)
db_session.status = session.status
db_session.completed_at = session.completed_at
db_session.summary = session.summary
db_session.evidence_library = json.dumps([e.dict() for e in session.evidence_library], default=str) if session.evidence_library else None
db.commit()
db.refresh(db_session)
async def list_sessions(self, db: Session):
"""
List all debate sessions
"""
db_sessions = db.query(DebateSessionDB).all()
return [
{
"session_id": db_session.session_id,
"topic": db_session.topic,
"status": db_session.status,
"created_at": db_session.created_at.isoformat() if db_session.created_at else None
}
for db_session in db_sessions
]