Refactor code for improved readability and consistency
- Cleaned up whitespace and formatting in various files including http.py, language.py, logger.py, safe_exec.py, and SQL migration scripts. - Consolidated import statements and removed unnecessary blank lines. - Updated logging configuration for better clarity. - Enhanced the safe execution code with improved error handling and logging. - Removed commented-out code and unnecessary variables in backfill_zero_trades.py and other scripts. - Added a pyproject.toml for Ruff and Vulture configuration. - Introduced requirements-dev.txt for development dependencies. - Removed commented-out stock entries in init.sql for cleaner migration scripts.
This commit is contained in:
@@ -2,18 +2,20 @@
|
||||
Polymarket prediction market API routing
|
||||
Provide on-demand analysis interface (read-only, no transactions involved)
|
||||
"""
|
||||
from flask import Blueprint, jsonify, request, g
|
||||
|
||||
from app.utils.auth import login_required
|
||||
from app.utils.logger import get_logger
|
||||
from app.utils.db import get_db_connection
|
||||
from app.data_sources.polymarket import PolymarketDataSource
|
||||
import re
|
||||
import json
|
||||
import re
|
||||
|
||||
from flask import Blueprint, g, jsonify, request
|
||||
|
||||
from app.data_sources.polymarket import PolymarketDataSource
|
||||
from app.utils.auth import login_required
|
||||
from app.utils.db import get_db_connection
|
||||
from app.utils.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
polymarket_bp = Blueprint('polymarket', __name__)
|
||||
polymarket_bp = Blueprint("polymarket", __name__)
|
||||
|
||||
# Initialize service
|
||||
polymarket_source = PolymarketDataSource()
|
||||
@@ -24,13 +26,13 @@ polymarket_source = PolymarketDataSource()
|
||||
def analyze_polymarket():
|
||||
"""
|
||||
Analyze Polymarket prediction market (user enters link or title)
|
||||
|
||||
|
||||
POST /api/polymarket/analyze
|
||||
Body: {
|
||||
"input": "https://polymarket.com/event/xxx" or "market title",
|
||||
"language": "zh-CN" (optional)
|
||||
}
|
||||
|
||||
|
||||
process:
|
||||
1. Parse market_id or slug from input
|
||||
2. Get market data from API
|
||||
@@ -39,40 +41,33 @@ def analyze_polymarket():
|
||||
5. Return analysis results
|
||||
"""
|
||||
try:
|
||||
from decimal import Decimal
|
||||
|
||||
from app.services.billing_service import BillingService
|
||||
from app.services.polymarket_analyzer import PolymarketAnalyzer
|
||||
from decimal import Decimal
|
||||
|
||||
user_id = getattr(g, 'user_id', None)
|
||||
|
||||
user_id = getattr(g, "user_id", None)
|
||||
if not user_id:
|
||||
return jsonify({
|
||||
"code": 0,
|
||||
"msg": "User not authenticated",
|
||||
"data": None
|
||||
}), 401
|
||||
|
||||
return jsonify({"code": 0, "msg": "User not authenticated", "data": None}), 401
|
||||
|
||||
data = request.get_json() or {}
|
||||
input_text = (data.get('input') or '').strip()
|
||||
language = data.get('language', 'zh-CN')
|
||||
|
||||
input_text = (data.get("input") or "").strip()
|
||||
language = data.get("language", "zh-CN")
|
||||
|
||||
if not input_text:
|
||||
return jsonify({
|
||||
"code": 0,
|
||||
"msg": "Input is required (Polymarket URL or market title)",
|
||||
"data": None
|
||||
}), 400
|
||||
|
||||
return jsonify({"code": 0, "msg": "Input is required (Polymarket URL or market title)", "data": None}), 400
|
||||
|
||||
# 1. Parse market_id or slug
|
||||
market_id = None
|
||||
slug = None
|
||||
|
||||
|
||||
# Try to extract from URL
|
||||
url_patterns = [
|
||||
r'polymarket\.com/event/([^/?]+)',
|
||||
r'polymarket\.com/markets/(\d+)',
|
||||
r'polymarket\.com/market/(\d+)',
|
||||
r"polymarket\.com/event/([^/?]+)",
|
||||
r"polymarket\.com/markets/(\d+)",
|
||||
r"polymarket\.com/market/(\d+)",
|
||||
]
|
||||
|
||||
|
||||
for pattern in url_patterns:
|
||||
match = re.search(pattern, input_text)
|
||||
if match:
|
||||
@@ -83,7 +78,7 @@ def analyze_polymarket():
|
||||
else:
|
||||
slug = extracted
|
||||
break
|
||||
|
||||
|
||||
# If not extracted from the URL, try searching the market
|
||||
if not market_id and not slug:
|
||||
# Try searching by title
|
||||
@@ -91,16 +86,18 @@ def analyze_polymarket():
|
||||
search_results = polymarket_source.search_markets(input_text, limit=5)
|
||||
if search_results:
|
||||
# Use first search result
|
||||
market_id = search_results[0].get('market_id')
|
||||
market_id = search_results[0].get("market_id")
|
||||
logger.info(f"Found market via search: {market_id}")
|
||||
|
||||
|
||||
if not market_id and not slug:
|
||||
return jsonify({
|
||||
"code": 0,
|
||||
"msg": "Could not parse market ID or slug from input. Please provide a valid Polymarket URL or market title.",
|
||||
"data": None
|
||||
}), 400
|
||||
|
||||
return jsonify(
|
||||
{
|
||||
"code": 0,
|
||||
"msg": "Could not parse market ID or slug from input. Please provide a valid Polymarket URL or market title.",
|
||||
"data": None,
|
||||
}
|
||||
), 400
|
||||
|
||||
# 2. Obtain market data
|
||||
if market_id:
|
||||
market = polymarket_source.get_market_details(market_id)
|
||||
@@ -109,123 +106,103 @@ def analyze_polymarket():
|
||||
search_results = polymarket_source.search_markets(slug, limit=10)
|
||||
market = None
|
||||
for result in search_results:
|
||||
if result.get('slug') == slug or slug in (result.get('question') or ''):
|
||||
if result.get("slug") == slug or slug in (result.get("question") or ""):
|
||||
market = result
|
||||
market_id = result.get('market_id')
|
||||
market_id = result.get("market_id")
|
||||
break
|
||||
|
||||
|
||||
if not market and search_results:
|
||||
# Use first search result
|
||||
market = search_results[0]
|
||||
market_id = market.get('market_id')
|
||||
|
||||
market_id = market.get("market_id")
|
||||
|
||||
if not market:
|
||||
return jsonify({
|
||||
"code": 0,
|
||||
"msg": "Market not found. Please check the URL or title.",
|
||||
"data": None
|
||||
}), 404
|
||||
|
||||
return jsonify({"code": 0, "msg": "Market not found. Please check the URL or title.", "data": None}), 404
|
||||
|
||||
if not market_id:
|
||||
market_id = market.get('market_id')
|
||||
|
||||
market_id = market.get("market_id")
|
||||
|
||||
if not market_id:
|
||||
return jsonify({
|
||||
"code": 0,
|
||||
"msg": "Invalid market data",
|
||||
"data": None
|
||||
}), 400
|
||||
|
||||
return jsonify({"code": 0, "msg": "Invalid market data", "data": None}), 400
|
||||
|
||||
# 3. Check billing
|
||||
billing = BillingService()
|
||||
cost = 0
|
||||
|
||||
|
||||
if billing.is_billing_enabled():
|
||||
cost = billing.get_feature_cost('polymarket_deep_analysis')
|
||||
|
||||
cost = billing.get_feature_cost("polymarket_deep_analysis")
|
||||
|
||||
if cost > 0:
|
||||
user_credits = billing.get_user_credits(user_id)
|
||||
if user_credits < Decimal(str(cost)):
|
||||
return jsonify({
|
||||
"code": 0,
|
||||
"msg": "Insufficient credits",
|
||||
"data": {
|
||||
"required": cost,
|
||||
"current": float(user_credits),
|
||||
"shortage": float(Decimal(str(cost)) - user_credits)
|
||||
return jsonify(
|
||||
{
|
||||
"code": 0,
|
||||
"msg": "Insufficient credits",
|
||||
"data": {
|
||||
"required": cost,
|
||||
"current": float(user_credits),
|
||||
"shortage": float(Decimal(str(cost)) - user_credits),
|
||||
},
|
||||
}
|
||||
}), 400
|
||||
|
||||
), 400
|
||||
|
||||
# Deduct points (use check_and_consume method, it will automatically get the cost from the configuration)
|
||||
success, error_msg = billing.check_and_consume(
|
||||
user_id=user_id,
|
||||
feature='polymarket_deep_analysis',
|
||||
reference_id=f"polymarket_{market_id}"
|
||||
user_id=user_id, feature="polymarket_deep_analysis", reference_id=f"polymarket_{market_id}"
|
||||
)
|
||||
|
||||
|
||||
if not success:
|
||||
# Check whether it is an error due to insufficient points
|
||||
if error_msg.startswith('insufficient_credits'):
|
||||
parts = error_msg.split(':')
|
||||
if error_msg.startswith("insufficient_credits"):
|
||||
parts = error_msg.split(":")
|
||||
if len(parts) >= 3:
|
||||
current_credits = parts[1]
|
||||
required_credits = parts[2]
|
||||
return jsonify({
|
||||
"code": 0,
|
||||
"msg": "Insufficient credits",
|
||||
"data": {
|
||||
"required": float(required_credits),
|
||||
"current": float(current_credits),
|
||||
"shortage": float(Decimal(required_credits) - Decimal(current_credits))
|
||||
return jsonify(
|
||||
{
|
||||
"code": 0,
|
||||
"msg": "Insufficient credits",
|
||||
"data": {
|
||||
"required": float(required_credits),
|
||||
"current": float(current_credits),
|
||||
"shortage": float(Decimal(required_credits) - Decimal(current_credits)),
|
||||
},
|
||||
}
|
||||
}), 400
|
||||
return jsonify({
|
||||
"code": 0,
|
||||
"msg": f"Failed to deduct credits: {error_msg}",
|
||||
"data": None
|
||||
}), 500
|
||||
|
||||
), 400
|
||||
return jsonify({"code": 0, "msg": f"Failed to deduct credits: {error_msg}", "data": None}), 500
|
||||
|
||||
# 4. Perform AI analysis (pass language and model parameters)
|
||||
analyzer = PolymarketAnalyzer()
|
||||
model = request.get_json().get('model') # Optional: Get model parameters from request
|
||||
model = request.get_json().get("model") # Optional: Get model parameters from request
|
||||
analysis_result = analyzer.analyze_market(
|
||||
market_id,
|
||||
user_id=user_id,
|
||||
use_cache=False,
|
||||
language=language,
|
||||
model=model
|
||||
market_id, user_id=user_id, use_cache=False, language=language, model=model
|
||||
)
|
||||
|
||||
if analysis_result.get('error'):
|
||||
return jsonify({
|
||||
"code": 0,
|
||||
"msg": analysis_result.get('error', 'Analysis failed'),
|
||||
"data": None
|
||||
}), 500
|
||||
|
||||
|
||||
if analysis_result.get("error"):
|
||||
return jsonify({"code": 0, "msg": analysis_result.get("error", "Analysis failed"), "data": None}), 500
|
||||
|
||||
# 5. Get remaining points
|
||||
remaining_credits = 0
|
||||
if billing.is_billing_enabled():
|
||||
remaining_credits = float(billing.get_user_credits(user_id))
|
||||
|
||||
return jsonify({
|
||||
"code": 1,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"market": market,
|
||||
"analysis": analysis_result,
|
||||
"credits_charged": cost,
|
||||
"remaining_credits": remaining_credits
|
||||
|
||||
return jsonify(
|
||||
{
|
||||
"code": 1,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"market": market,
|
||||
"analysis": analysis_result,
|
||||
"credits_charged": cost,
|
||||
"remaining_credits": remaining_credits,
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Polymarket analyze API failed: {e}", exc_info=True)
|
||||
return jsonify({
|
||||
"code": 0,
|
||||
"msg": str(e),
|
||||
"data": None
|
||||
}), 500
|
||||
return jsonify({"code": 0, "msg": str(e), "data": None}), 500
|
||||
|
||||
|
||||
@polymarket_bp.route("/history", methods=["GET"])
|
||||
@@ -233,30 +210,34 @@ def analyze_polymarket():
|
||||
def get_polymarket_history():
|
||||
"""
|
||||
Get user's Polymarket analysis history.
|
||||
|
||||
|
||||
GET /api/polymarket/history?page=1&page_size=20
|
||||
"""
|
||||
try:
|
||||
user_id = g.user_id
|
||||
page = request.args.get('page', 1, type=int)
|
||||
page_size = min(request.args.get('page_size', 20, type=int), 100)
|
||||
page = request.args.get("page", 1, type=int)
|
||||
page_size = min(request.args.get("page_size", 20, type=int), 100)
|
||||
offset = (page - 1) * page_size
|
||||
|
||||
|
||||
with get_db_connection() as db:
|
||||
cur = db.cursor()
|
||||
|
||||
|
||||
# Get total
|
||||
cur.execute("""
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT COUNT(*) AS total
|
||||
FROM qd_analysis_tasks
|
||||
WHERE user_id = %s AND market = 'Polymarket'
|
||||
""", (user_id,))
|
||||
""",
|
||||
(user_id,),
|
||||
)
|
||||
total_row = cur.fetchone()
|
||||
total = total_row['total'] if total_row else 0
|
||||
|
||||
total = total_row["total"] if total_row else 0
|
||||
|
||||
# Get history
|
||||
cur.execute("""
|
||||
SELECT
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT
|
||||
t.id,
|
||||
t.symbol AS market_id,
|
||||
t.model,
|
||||
@@ -269,60 +250,65 @@ def get_polymarket_history():
|
||||
WHERE t.user_id = %s AND t.market = 'Polymarket'
|
||||
ORDER BY t.created_at DESC
|
||||
LIMIT %s OFFSET %s
|
||||
""", (user_id, page_size, offset))
|
||||
""",
|
||||
(user_id, page_size, offset),
|
||||
)
|
||||
rows = cur.fetchall() or []
|
||||
cur.close()
|
||||
|
||||
|
||||
# Parse results
|
||||
items = []
|
||||
for row in rows:
|
||||
result_json = row.get('result_json', '{}')
|
||||
result_json = row.get("result_json", "{}")
|
||||
try:
|
||||
result_data = json.loads(result_json) if result_json else {}
|
||||
except:
|
||||
except Exception as e:
|
||||
logger.debug(f"Failed to parse result JSON for task {row.get('id')}: {e}")
|
||||
result_data = {}
|
||||
|
||||
market_data = result_data.get('market', {})
|
||||
analysis_data = result_data.get('analysis', {})
|
||||
|
||||
created_at = row.get('created_at')
|
||||
completed_at = row.get('completed_at')
|
||||
if created_at and hasattr(created_at, 'isoformat'):
|
||||
|
||||
market_data = result_data.get("market", {})
|
||||
analysis_data = result_data.get("analysis", {})
|
||||
|
||||
created_at = row.get("created_at")
|
||||
completed_at = row.get("completed_at")
|
||||
if created_at and hasattr(created_at, "isoformat"):
|
||||
created_at = created_at.isoformat()
|
||||
if completed_at and hasattr(completed_at, 'isoformat'):
|
||||
if completed_at and hasattr(completed_at, "isoformat"):
|
||||
completed_at = completed_at.isoformat()
|
||||
|
||||
items.append({
|
||||
'id': row.get('id'),
|
||||
'market_id': row.get('market_id'),
|
||||
'market_title': market_data.get('question') or market_data.get('title') or f"Market {row.get('market_id')}",
|
||||
'market_url': market_data.get('polymarket_url'),
|
||||
'ai_predicted_probability': analysis_data.get('ai_predicted_probability'),
|
||||
'market_probability': analysis_data.get('market_probability'),
|
||||
'recommendation': analysis_data.get('recommendation'),
|
||||
'opportunity_score': analysis_data.get('opportunity_score'),
|
||||
'confidence_score': analysis_data.get('confidence_score'),
|
||||
'status': row.get('status'),
|
||||
'created_at': created_at,
|
||||
'completed_at': completed_at
|
||||
})
|
||||
|
||||
return jsonify({
|
||||
"code": 1,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"items": items,
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size,
|
||||
"total_pages": (total + page_size - 1) // page_size
|
||||
|
||||
items.append(
|
||||
{
|
||||
"id": row.get("id"),
|
||||
"market_id": row.get("market_id"),
|
||||
"market_title": market_data.get("question")
|
||||
or market_data.get("title")
|
||||
or f"Market {row.get('market_id')}",
|
||||
"market_url": market_data.get("polymarket_url"),
|
||||
"ai_predicted_probability": analysis_data.get("ai_predicted_probability"),
|
||||
"market_probability": analysis_data.get("market_probability"),
|
||||
"recommendation": analysis_data.get("recommendation"),
|
||||
"opportunity_score": analysis_data.get("opportunity_score"),
|
||||
"confidence_score": analysis_data.get("confidence_score"),
|
||||
"status": row.get("status"),
|
||||
"created_at": created_at,
|
||||
"completed_at": completed_at,
|
||||
}
|
||||
)
|
||||
|
||||
return jsonify(
|
||||
{
|
||||
"code": 1,
|
||||
"msg": "success",
|
||||
"data": {
|
||||
"items": items,
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size,
|
||||
"total_pages": (total + page_size - 1) // page_size,
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Get Polymarket history failed: {e}", exc_info=True)
|
||||
return jsonify({
|
||||
"code": 0,
|
||||
"msg": str(e),
|
||||
"data": None
|
||||
}), 500
|
||||
return jsonify({"code": 0, "msg": str(e), "data": None}), 500
|
||||
|
||||
Reference in New Issue
Block a user