diff --git a/server/agent/llm/clients/deepseek.py b/server/agent/llm/clients/deepseek.py index cef875aa..f4922561 100644 --- a/server/agent/llm/clients/deepseek.py +++ b/server/agent/llm/clients/deepseek.py @@ -1,5 +1,3 @@ - - from typing import Any, List, Optional from langchain_openai import ChatOpenAI from langchain_core.utils.function_calling import convert_to_openai_tool @@ -35,7 +33,7 @@ def __init__( max_tokens=max_tokens, openai_api_key=api_key, stream_usage=True, - openai_api_base="https://api.deepseek.com" + openai_api_base="https://api.deepseek.com", ) def get_client(self): @@ -45,4 +43,4 @@ def get_tools(self, tools: List[Any]): return [convert_to_openai_tool(tool) for tool in tools] def parse_content(self, content: List[MessageContent]): - return [c.model_dump() for c in content] \ No newline at end of file + return [c.model_dump() for c in content] diff --git a/server/insight/router.py b/server/insight/router.py index 82f94b57..a34be271 100644 --- a/server/insight/router.py +++ b/server/insight/router.py @@ -1,6 +1,6 @@ import json from fastapi import APIRouter -from insight.service.activity import get_activity_data +from insight.service.activity import get_active_dates_and_times, get_activity_data from insight.service.issue import get_issue_data from insight.service.pr import get_code_frequency, get_pr_data @@ -63,3 +63,16 @@ def get_activity_insight(repo_name: str): except Exception as e: return json.dumps({"success": False, "message": str(e)}) + + +@router.get("/active_dates_and_times") +def get_active_dates_and_times_insight(repo_name: str): + try: + result = get_active_dates_and_times(repo_name) + return { + "success": True, + "data": result, + } + + except Exception as e: + return json.dumps({"success": False, "message": str(e)}) diff --git a/server/insight/service/activity.py b/server/insight/service/activity.py index 386156ef..66160571 100644 --- a/server/insight/service/activity.py +++ b/server/insight/service/activity.py @@ -1,4 +1,5 @@ import requests +import re from typing import List, Dict @@ -25,3 +26,69 @@ def get_activity_data(repo_name: str) -> List[Dict[str, int]]: except Exception as e: print(e) return [] + + +def get_active_dates_and_times(repo_name: str): + url = f"https://oss.open-digger.cn/github/{repo_name}/active_dates_and_times.json" + try: + resp = requests.get(url) + resp.raise_for_status() + data = resp.json() + + pattern_year = re.compile(r"^\d{4}$") # e.g. "2024" + pattern_quarter = re.compile(r"^\d{4}Q[1-4]$") # e.g. "2024Q3" + pattern_month = re.compile(r"^\d{4}-\d{2}$") # e.g. "2024-08" + + years = [] + quarters = [] + months = [] + + for k in data.keys(): + if pattern_year.match(k): + years.append(k) + elif pattern_quarter.match(k): + quarters.append(k) + elif pattern_month.match(k): + months.append(k) + + def safe_get_latest(lst): + return sorted(lst)[-1] if lst else None + + latest_year_key = safe_get_latest(years) + latest_quarter_key = safe_get_latest(quarters) + latest_month_key = safe_get_latest(months) + + def convert_168_to_day_hour_value(arr_168): + if not arr_168: + return [] + + day_map = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] + result = [] + for i, value in enumerate(arr_168): + day_index = i // 24 + hour = i % 24 + result.append({"day": day_map[day_index], "hour": hour, "value": value}) + return result + + year_data = ( + convert_168_to_day_hour_value(data[latest_year_key]) + if latest_year_key + else [] + ) + quarter_data = ( + convert_168_to_day_hour_value(data[latest_quarter_key]) + if latest_quarter_key + else [] + ) + month_data = ( + convert_168_to_day_hour_value(data[latest_month_key]) + if latest_month_key + else [] + ) + + result = {"year": year_data, "quarter": quarter_data, "month": month_data} + + return result + except Exception as e: + print(e) + return [] diff --git a/server/tests/insight/test_activity.py b/server/tests/insight/test_activity.py index bc184797..ef7fd8e7 100644 --- a/server/tests/insight/test_activity.py +++ b/server/tests/insight/test_activity.py @@ -1,6 +1,6 @@ import unittest -from unittest.mock import patch, MagicMock -from insight.service.activity import get_activity_data +from unittest.mock import Mock, patch, MagicMock +from insight.service.activity import get_activity_data, get_active_dates_and_times class TestGetActivityData(unittest.TestCase): @@ -42,3 +42,39 @@ def test_get_activity_data_invalid_json(self, mock_get): repo_name = "petercat-ai/petercat" result = get_activity_data(repo_name) self.assertEqual(result, []) + + +class TestGetActiveDatesAndTimes(unittest.TestCase): + + @patch("insight.service.activity.requests.get") + def test_get_active_dates_and_times(self, mock_get): + fake_json = { + "2024": [0] * 168, + "2025": [1] * 168, + "2025Q1": [2] * 168, + "2025-01": [3] * 168, + } + + mock_resp = Mock() + mock_resp.json.return_value = fake_json + mock_resp.status_code = 200 + mock_get.return_value = mock_resp + + result = get_active_dates_and_times("petercat-ai/petercat") + + self.assertIn("year", result) + self.assertIn("quarter", result) + self.assertIn("month", result) + + self.assertEqual(len(result["year"]), 168) + self.assertEqual(len(result["quarter"]), 168) + self.assertEqual(len(result["month"]), 168) + + self.assertEqual(result["year"][0], {"day": "Mon", "hour": 0, "value": 1}) + self.assertEqual(result["year"][167], {"day": "Sun", "hour": 23, "value": 1}) + + self.assertEqual(result["quarter"][0], {"day": "Mon", "hour": 0, "value": 2}) + self.assertEqual(result["quarter"][167], {"day": "Sun", "hour": 23, "value": 2}) + + self.assertEqual(result["month"][0], {"day": "Mon", "hour": 0, "value": 3}) + self.assertEqual(result["month"][167], {"day": "Sun", "hour": 23, "value": 3})