@@ -308,38 +308,27 @@ def get_codegen_challenges(self, challenge_id: str = None) -> List[Dict]:
308308 print (f"Error getting codegen challenges: { str (e )} " )
309309 return []
310310
311- def get_codegen_challenge_responses (self , challenge_id : str = None , miner_hotkey : str = None ) -> List [CodegenResponse ]:
311+ def get_codegen_challenge_responses (self , challenge_id : str = None , miner_hotkey : str = None , min_score : float = 0 , min_response_count : int = 0 , sort_by_score : bool = False , max_miners : int = 5 , hours : int = 24 ) -> List [Dict ]:
312312 """Retrieve codegen responses from the database (AWS Postgres RDS).
313- Returns a list of CodegenResponse objects matching the original output format .
313+ Returns a list of dictionaries containing miner information and their responses .
314314 Only includes responses where evaluated is TRUE and score is not NULL.
315+
316+ Additional parameters:
317+ - min_score: Minimum average score for miners to be included
318+ - min_response_count: Minimum number of responses required per miner
319+ - sort_by_score: Whether to sort miners by average score
320+ - max_miners: Maximum number of miners to return
321+ - hours: Number of hours to look back (-1 for all time)
315322 """
316323 try :
317324 with self .conn :
318325 with self .conn .cursor () as cursor :
319- if challenge_id :
320- cursor .execute ("""
326+ # Base query with optimized structure
327+ base_query = """
328+ WITH RECURSIVE time_bucket AS (
321329 SELECT
322- r.challenge_id,
323330 r.miner_hotkey,
324- r.node_id,
325- r.processing_time,
326- r.received_at,
327- r.completed_at,
328- r.evaluated,
329- r.score,
330- r.evaluated_at,
331- cr.response_patch
332- FROM responses r
333- JOIN codegen_responses cr
334- ON r.challenge_id = cr.challenge_id
335- AND r.miner_hotkey = cr.miner_hotkey
336- WHERE r.challenge_id = %s AND r.evaluated = TRUE AND r.score IS NOT NULL
337- """ , (challenge_id ,))
338- elif miner_hotkey :
339- cursor .execute ("""
340- SELECT
341331 r.challenge_id,
342- r.miner_hotkey,
343332 r.node_id,
344333 r.processing_time,
345334 r.received_at,
@@ -352,43 +341,89 @@ def get_codegen_challenge_responses(self, challenge_id: str = None, miner_hotkey
352341 JOIN codegen_responses cr
353342 ON r.challenge_id = cr.challenge_id
354343 AND r.miner_hotkey = cr.miner_hotkey
355- WHERE r.miner_hotkey = %s AND r.evaluated = TRUE AND r.score IS NOT NULL
356- """ , (miner_hotkey ,))
344+ WHERE r.evaluated = TRUE
345+ AND r.score IS NOT NULL
346+ """
347+
348+ # Add time filter if hours is not -1
349+ if hours != - 1 :
350+ base_query += " AND r.completed_at >= NOW() - INTERVAL '%s hours'"
351+ params = [hours ]
357352 else :
358- cursor .execute ("""
353+ params = []
354+
355+ # Add challenge_id or miner_hotkey filter if provided
356+ if challenge_id :
357+ base_query += " AND r.challenge_id = %s"
358+ params .append (challenge_id )
359+ elif miner_hotkey :
360+ base_query += " AND r.miner_hotkey = %s"
361+ params .append (miner_hotkey )
362+
363+ base_query += """
364+ ),
365+ miner_stats AS (
359366 SELECT
360- r.challenge_id,
361- r.miner_hotkey,
362- r.node_id,
363- r.processing_time,
364- r.received_at,
365- r.completed_at,
366- r.evaluated,
367- r.score,
368- r.evaluated_at,
369- cr.response_patch
370- FROM responses r
371- JOIN codegen_responses cr
372- ON r.challenge_id = cr.challenge_id
373- AND r.miner_hotkey = cr.miner_hotkey
374- WHERE r.evaluated = TRUE AND r.score IS NOT NULL
375- """ )
367+ miner_hotkey,
368+ COUNT(*) as response_count,
369+ AVG(score) as average_score
370+ FROM time_bucket
371+ GROUP BY miner_hotkey
372+ HAVING COUNT(*) >= %s AND AVG(score) >= %s
373+ ),
374+ miner_responses AS (
375+ SELECT
376+ t.miner_hotkey,
377+ json_agg(
378+ json_build_object(
379+ 'challenge_id', t.challenge_id,
380+ 'miner_hotkey', t.miner_hotkey,
381+ 'node_id', t.node_id,
382+ 'processing_time', t.processing_time,
383+ 'received_at', t.received_at,
384+ 'completed_at', t.completed_at,
385+ 'evaluated', t.evaluated,
386+ 'score', t.score,
387+ 'evaluated_at', t.evaluated_at,
388+ 'response_patch', t.response_patch
389+ )
390+ ORDER BY t.completed_at DESC
391+ ) as responses
392+ FROM time_bucket t
393+ JOIN miner_stats ms ON t.miner_hotkey = ms.miner_hotkey
394+ GROUP BY t.miner_hotkey
395+ )
396+ SELECT
397+ mr.miner_hotkey,
398+ ms.response_count,
399+ ms.average_score,
400+ mr.responses
401+ FROM miner_responses mr
402+ JOIN miner_stats ms ON mr.miner_hotkey = ms.miner_hotkey
403+ """
404+
405+ # Add final sorting
406+ if sort_by_score :
407+ base_query += " ORDER BY ms.average_score DESC, mr.miner_hotkey"
408+ else :
409+ base_query += " ORDER BY mr.miner_hotkey"
410+
411+ # Add final limit
412+ base_query += " LIMIT %s"
413+ params .extend ([min_response_count , min_score , max_miners ])
414+
415+ cursor .execute (base_query , params )
376416 rows = cursor .fetchall ()
377417 if not rows :
378418 return []
419+
379420 return [
380- CodegenResponse (
381- challenge_id = row [0 ],
382- miner_hotkey = row [1 ],
383- node_id = row [2 ],
384- processing_time = row [3 ],
385- received_at = row [4 ],
386- completed_at = row [5 ],
387- evaluated = row [6 ],
388- score = row [7 ],
389- evaluated_at = row [8 ],
390- response_patch = row [9 ]
391- )
421+ {
422+ "miner_hotkey" : row [0 ],
423+ "response_count" : row [1 ],
424+ "average_score" : row [2 ],
425+ "responses" : [CodegenResponse (** response ) for response in row [3 ]]
426+ }
392427 for row in rows
393428 ]
394429 except Exception as e :
0 commit comments