DeepImagix commited on
Commit
1bb7c2f
Β·
verified Β·
1 Parent(s): 4d30276

Upload studio_generate.py

Browse files
Files changed (1) hide show
  1. studio_generate.py +29 -20
studio_generate.py CHANGED
@@ -54,70 +54,79 @@ POLAR_ORG_ID = os.environ.get("POLAR_ORG_ID", "")
54
  FIREBASE_KEY_PATH = os.environ.get("FIREBASE_KEY_PATH", "serviceAccountKey.json")
55
  ADMIN_UIDS = set(os.environ.get("STUDIO_ADMIN_UIDS", "").split(","))
56
 
57
- # ── MONGODB (reuse main.py's connection if available, else create our own) ────
58
- # IMPORTANT: We use pymongo (sync) β€” NOT motor (async). Motor creates a separate
59
- # connection that fails on Render. Instead we reuse main.py's existing working
60
- # MongoClient via sys.modules, or create our own with the same SSL settings.
61
  import sys as _sys
62
 
 
 
63
  def _get_db():
64
- """Get the neuraprompt database. Reuses main.py's connection if available."""
 
 
 
 
 
 
65
  main_mod = _sys.modules.get("main")
66
  if main_mod and hasattr(main_mod, "neuraprompt_db"):
67
- return main_mod.neuraprompt_db
 
 
68
  # Fallback: create our own pymongo client (same SSL settings as main.py)
 
69
  _client = MongoClient(
70
  MONGO_URL, ssl=True,
71
  tlsAllowInvalidCertificates=False,
72
  tlsCAFile="/etc/ssl/certs/ca-certificates.crt",
73
  server_api=ServerApi("1"),
74
  )
75
- return _client["neuraprompt"]
 
76
 
77
- db = _get_db()
78
- print(f"[Studio v2] MongoDB: {'reusing main.py connection' if _sys.modules.get('main') and hasattr(_sys.modules.get('main'), 'neuraprompt_db') else 'own connection'}")
79
 
80
  # ── ASYNC DB HELPER (pymongo is sync, so we wrap calls in asyncio.to_thread) ──
81
  async def _db_find_one(collection, query, projection=None):
82
  """Async wrapper for db.collection.find_one()"""
83
  return await asyncio.to_thread(
84
- lambda: db[collection].find_one(query, projection) if projection else db[collection].find_one(query)
85
  )
86
 
87
  async def _db_update_one(collection, query, update, upsert=False):
88
- return await asyncio.to_thread(lambda: db[collection].update_one(query, update, upsert=upsert))
89
 
90
  async def _db_insert_one(collection, doc):
91
- return await asyncio.to_thread(lambda: db[collection].insert_one(doc))
92
 
93
  async def _db_count_documents(collection, query):
94
- return await asyncio.to_thread(lambda: db[collection].count_documents(query))
95
 
96
  async def _db_find(collection, query, projection=None, sort=None, limit=None):
97
  def _do():
98
- cursor = db[collection].find(query, projection) if projection else db[collection].find(query)
99
  if sort: cursor = cursor.sort(*sort) if isinstance(sort, tuple) else cursor.sort(sort)
100
  if limit: cursor = cursor.limit(limit)
101
  return list(cursor)
102
  return await asyncio.to_thread(_do)
103
 
104
  async def _db_delete_one(collection, query):
105
- return await asyncio.to_thread(lambda: db[collection].delete_one(query))
106
 
107
  async def _db_delete_many(collection, query):
108
- return await asyncio.to_thread(lambda: db[collection].delete_many(query))
109
 
110
  async def _db_insert_many(collection, docs):
111
- return await asyncio.to_thread(lambda: db[collection].insert_many(docs))
112
 
113
  async def _db_distinct(collection, field, query=None):
114
- return await asyncio.to_thread(lambda: db[collection].distinct(field, query or {}))
115
 
116
  async def _db_aggregate(collection, pipeline):
117
- return await asyncio.to_thread(lambda: list(db[collection].aggregate(pipeline)))
118
 
119
  async def _db_create_index(collection, keys, **kwargs):
120
- return await asyncio.to_thread(lambda: db[collection].create_index(keys, **kwargs))
121
 
122
 
123
  # ── CREDIT SYSTEM ─────────────────────────────────────────────────────────────
 
54
  FIREBASE_KEY_PATH = os.environ.get("FIREBASE_KEY_PATH", "serviceAccountKey.json")
55
  ADMIN_UIDS = set(os.environ.get("STUDIO_ADMIN_UIDS", "").split(","))
56
 
57
+ # ── MONGODB (lazy β€” waits until main.py is loaded, then reuses its connection) ─
 
 
 
58
  import sys as _sys
59
 
60
+ _db_instance = None
61
+
62
  def _get_db():
63
+ """Get the neuraprompt database. LAZY: reuses main.py's connection.
64
+ Called on first DB operation, not at import time β€” this ensures main.py
65
+ has finished initializing its MongoClient before we try to reuse it."""
66
+ global _db_instance
67
+ if _db_instance is not None:
68
+ return _db_instance
69
+ # Try to reuse main.py's connection (it's already connected to Atlas)
70
  main_mod = _sys.modules.get("main")
71
  if main_mod and hasattr(main_mod, "neuraprompt_db"):
72
+ _db_instance = main_mod.neuraprompt_db
73
+ print("[Studio v2] MongoDB: reusing main.py connection")
74
+ return _db_instance
75
  # Fallback: create our own pymongo client (same SSL settings as main.py)
76
+ print("[Studio v2] MongoDB: main.py not available, creating own connection")
77
  _client = MongoClient(
78
  MONGO_URL, ssl=True,
79
  tlsAllowInvalidCertificates=False,
80
  tlsCAFile="/etc/ssl/certs/ca-certificates.crt",
81
  server_api=ServerApi("1"),
82
  )
83
+ _db_instance = _client["neuraprompt"]
84
+ return _db_instance
85
 
86
+ # NOTE: db is NOT set at import time β€” it's resolved lazily on first use.
87
+ # All _db_* helpers call _get_db() internally.
88
 
89
  # ── ASYNC DB HELPER (pymongo is sync, so we wrap calls in asyncio.to_thread) ──
90
  async def _db_find_one(collection, query, projection=None):
91
  """Async wrapper for db.collection.find_one()"""
92
  return await asyncio.to_thread(
93
+ lambda: _get_db()[collection].find_one(query, projection) if projection else db[collection].find_one(query)
94
  )
95
 
96
  async def _db_update_one(collection, query, update, upsert=False):
97
+ return await asyncio.to_thread(lambda: _get_db()[collection].update_one(query, update, upsert=upsert))
98
 
99
  async def _db_insert_one(collection, doc):
100
+ return await asyncio.to_thread(lambda: _get_db()[collection].insert_one(doc))
101
 
102
  async def _db_count_documents(collection, query):
103
+ return await asyncio.to_thread(lambda: _get_db()[collection].count_documents(query))
104
 
105
  async def _db_find(collection, query, projection=None, sort=None, limit=None):
106
  def _do():
107
+ cursor = _get_db()[collection].find(query, projection) if projection else db[collection].find(query)
108
  if sort: cursor = cursor.sort(*sort) if isinstance(sort, tuple) else cursor.sort(sort)
109
  if limit: cursor = cursor.limit(limit)
110
  return list(cursor)
111
  return await asyncio.to_thread(_do)
112
 
113
  async def _db_delete_one(collection, query):
114
+ return await asyncio.to_thread(lambda: _get_db()[collection].delete_one(query))
115
 
116
  async def _db_delete_many(collection, query):
117
+ return await asyncio.to_thread(lambda: _get_db()[collection].delete_many(query))
118
 
119
  async def _db_insert_many(collection, docs):
120
+ return await asyncio.to_thread(lambda: _get_db()[collection].insert_many(docs))
121
 
122
  async def _db_distinct(collection, field, query=None):
123
+ return await asyncio.to_thread(lambda: _get_db()[collection].distinct(field, query or {}))
124
 
125
  async def _db_aggregate(collection, pipeline):
126
+ return await asyncio.to_thread(lambda: list(_get_db()[collection].aggregate(pipeline)))
127
 
128
  async def _db_create_index(collection, keys, **kwargs):
129
+ return await asyncio.to_thread(lambda: _get_db()[collection].create_index(keys, **kwargs))
130
 
131
 
132
  # ── CREDIT SYSTEM ─────────────────────────────────────────────────────────────