feat: add multi-chain support to blockchain explorer and improve GPU review handling
- Add multi-chain configuration with devnet, testnet, and mainnet RPC URLs - Add chain selector dropdown in explorer UI for network switching - Add chain_id parameter to all API endpoints (chain/head, blocks, transactions, search) - Add /api/chains endpoint to list supported blockchain networks - Update blockchain explorer port from 3001 to 8016 - Update devnet RPC port from 8080 to 8026 - Add GPU reviews table
This commit is contained in:
@@ -116,6 +116,19 @@ CREATE TABLE IF NOT EXISTS job_history (
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- GPU reviews table
|
||||
CREATE TABLE IF NOT EXISTS gpu_reviews (
|
||||
id VARCHAR(255) PRIMARY KEY,
|
||||
gpu_id VARCHAR(255) NOT NULL,
|
||||
user_id VARCHAR(255) DEFAULT '',
|
||||
rating INTEGER NOT NULL CHECK (rating >= 1 AND rating <= 5),
|
||||
comment TEXT DEFAULT '',
|
||||
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_gpu_reviews_gpu_id ON gpu_reviews(gpu_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_gpu_reviews_created_at ON gpu_reviews(created_at);
|
||||
|
||||
-- Comments for documentation
|
||||
COMMENT ON TABLE jobs IS 'AI compute jobs submitted to the network';
|
||||
COMMENT ON TABLE miners IS 'Registered GPU miners';
|
||||
@@ -124,3 +137,4 @@ COMMENT ON TABLE blocks IS 'Blockchain blocks for transaction ordering';
|
||||
COMMENT ON TABLE transactions IS 'On-chain transactions';
|
||||
COMMENT ON TABLE api_keys IS 'API authentication keys';
|
||||
COMMENT ON TABLE job_history IS 'Job event history for analytics';
|
||||
COMMENT ON TABLE gpu_reviews IS 'User reviews for GPU marketplace';
|
||||
|
||||
2
apps/coordinator-api/src/app.py
Normal file
2
apps/coordinator-api/src/app.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# Import the FastAPI app from main.py for compatibility
|
||||
from main import app
|
||||
5
apps/coordinator-api/src/app/app.py
Normal file
5
apps/coordinator-api/src/app/app.py
Normal file
@@ -0,0 +1,5 @@
|
||||
# Import the FastAPI app from main.py for uvicorn compatibility
|
||||
import sys
|
||||
import os
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
from main import app
|
||||
@@ -8,7 +8,7 @@ engine = create_engine(
|
||||
"sqlite:////home/oib/windsurf/aitbc/apps/coordinator-api/aitbc_coordinator.db",
|
||||
connect_args={"check_same_thread": False},
|
||||
poolclass=StaticPool,
|
||||
echo=False
|
||||
echo=True # Enable SQL logging for debugging
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -498,36 +498,94 @@ async def add_gpu_review(
|
||||
gpu_id: str, request: GPUReviewRequest, session: Annotated[Session, Depends(get_session)]
|
||||
) -> Dict[str, Any]:
|
||||
"""Add a review for a GPU."""
|
||||
gpu = _get_gpu_or_404(session, gpu_id)
|
||||
try:
|
||||
gpu = _get_gpu_or_404(session, gpu_id)
|
||||
|
||||
# Validate request data
|
||||
if not (1 <= request.rating <= 5):
|
||||
raise HTTPException(
|
||||
status_code=http_status.HTTP_400_BAD_REQUEST,
|
||||
detail="Rating must be between 1 and 5"
|
||||
)
|
||||
|
||||
# Create review object
|
||||
review = GPUReview(
|
||||
gpu_id=gpu_id,
|
||||
user_id="current_user",
|
||||
rating=request.rating,
|
||||
comment=request.comment,
|
||||
)
|
||||
|
||||
# Log transaction start
|
||||
logger.info(f"Starting review transaction for GPU {gpu_id}", extra={
|
||||
"gpu_id": gpu_id,
|
||||
"rating": request.rating,
|
||||
"user_id": "current_user"
|
||||
})
|
||||
|
||||
# Add review to session
|
||||
session.add(review)
|
||||
session.flush() # ensure the new review is visible to aggregate queries
|
||||
|
||||
# Recalculate average from DB (new review already included after flush)
|
||||
total_count_result = session.execute(
|
||||
select(func.count(GPUReview.id)).where(GPUReview.gpu_id == gpu_id)
|
||||
).one()
|
||||
total_count = total_count_result[0] if hasattr(total_count_result, '__getitem__') else total_count_result
|
||||
|
||||
avg_rating_result = session.execute(
|
||||
select(func.avg(GPUReview.rating)).where(GPUReview.gpu_id == gpu_id)
|
||||
).one()
|
||||
avg_rating = avg_rating_result[0] if hasattr(avg_rating_result, '__getitem__') else avg_rating_result
|
||||
avg_rating = avg_rating or 0.0
|
||||
|
||||
review = GPUReview(
|
||||
gpu_id=gpu_id,
|
||||
user_id="current_user",
|
||||
rating=request.rating,
|
||||
comment=request.comment,
|
||||
)
|
||||
session.add(review)
|
||||
session.flush() # ensure the new review is visible to aggregate queries
|
||||
|
||||
# Recalculate average from DB (new review already included after flush)
|
||||
total_count = session.execute(
|
||||
select(func.count(GPUReview.id)).where(GPUReview.gpu_id == gpu_id)
|
||||
).one()
|
||||
avg_rating = session.execute(
|
||||
select(func.avg(GPUReview.rating)).where(GPUReview.gpu_id == gpu_id)
|
||||
).one() or 0.0
|
||||
|
||||
gpu.average_rating = round(float(avg_rating), 2)
|
||||
gpu.total_reviews = total_count
|
||||
session.commit()
|
||||
session.refresh(review)
|
||||
|
||||
return {
|
||||
"status": "review_added",
|
||||
"gpu_id": gpu_id,
|
||||
"review_id": review.id,
|
||||
"average_rating": gpu.average_rating,
|
||||
}
|
||||
# Update GPU stats
|
||||
gpu.average_rating = round(float(avg_rating), 2)
|
||||
gpu.total_reviews = total_count
|
||||
|
||||
# Commit transaction
|
||||
session.commit()
|
||||
|
||||
# Refresh review object
|
||||
session.refresh(review)
|
||||
|
||||
# Log success
|
||||
logger.info(f"Review transaction completed successfully for GPU {gpu_id}", extra={
|
||||
"gpu_id": gpu_id,
|
||||
"review_id": review.id,
|
||||
"total_reviews": total_count,
|
||||
"average_rating": gpu.average_rating
|
||||
})
|
||||
|
||||
return {
|
||||
"status": "review_added",
|
||||
"gpu_id": gpu_id,
|
||||
"review_id": review.id,
|
||||
"average_rating": gpu.average_rating,
|
||||
}
|
||||
|
||||
except HTTPException:
|
||||
# Re-raise HTTP exceptions as-is
|
||||
raise
|
||||
except Exception as e:
|
||||
# Log error and rollback transaction
|
||||
logger.error(f"Failed to add review for GPU {gpu_id}: {str(e)}", extra={
|
||||
"gpu_id": gpu_id,
|
||||
"error": str(e),
|
||||
"error_type": type(e).__name__
|
||||
})
|
||||
|
||||
# Rollback on error
|
||||
try:
|
||||
session.rollback()
|
||||
except Exception as rollback_error:
|
||||
logger.error(f"Failed to rollback transaction: {str(rollback_error)}")
|
||||
|
||||
# Return generic error
|
||||
raise HTTPException(
|
||||
status_code=http_status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="Failed to add review"
|
||||
)
|
||||
|
||||
|
||||
@router.get("/marketplace/orders")
|
||||
|
||||
Reference in New Issue
Block a user