Skip to content

Commit ccc946e

Browse files
committed
Merge remote-tracking branch 'origin/main' into fix/projects-metadata
2 parents 010ff37 + 307993f commit ccc946e

File tree

4 files changed

+75
-35
lines changed

4 files changed

+75
-35
lines changed

services/apps/git_integration/src/crowdgit/services/maintainer/bedrock.py

Lines changed: 53 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
import asyncio
12
import json
3+
import random
24
from typing import Generic, TypeVar
35

46
import aioboto3
57
from botocore.config import Config
8+
from botocore.exceptions import ClientError
69
from pydantic import BaseModel, ValidationError
710

811
from crowdgit.logger import logger
@@ -20,6 +23,10 @@ class BedrockResponse(BaseModel, Generic[T]):
2023
cost: float
2124

2225

26+
MAX_THROTTLE_RETRIES = 5
27+
THROTTLE_BASE_DELAY = 10 # seconds
28+
29+
2330
async def invoke_bedrock(
2431
instruction, pydantic_model: type[T], replacements=None, max_tokens=65000, temperature=0
2532
) -> BedrockResponse[T]:
@@ -71,41 +78,54 @@ async def invoke_bedrock(
7178
}
7279
)
7380

81+
modelId = "us.anthropic.claude-sonnet-4-20250514-v1:0"
82+
accept = "application/json"
83+
contentType = "application/json"
84+
85+
for attempt in range(1, MAX_THROTTLE_RETRIES + 1):
86+
try:
87+
response = await bedrock_client.invoke_model(
88+
body=body, modelId=modelId, accept=accept, contentType=contentType
89+
)
90+
break
91+
except ClientError as e:
92+
if (
93+
e.response["Error"]["Code"] == "ThrottlingException"
94+
and attempt < MAX_THROTTLE_RETRIES
95+
):
96+
delay = THROTTLE_BASE_DELAY * (2 ** (attempt - 1)) + random.uniform(0, 2)
97+
logger.warning(
98+
f"Bedrock ThrottlingException (attempt {attempt}/{MAX_THROTTLE_RETRIES}), "
99+
f"retrying in {delay:.1f}s: {e}"
100+
)
101+
await asyncio.sleep(delay)
102+
else:
103+
raise
104+
74105
try:
75-
modelId = "us.anthropic.claude-sonnet-4-20250514-v1:0"
76-
accept = "application/json"
77-
contentType = "application/json"
78-
response = await bedrock_client.invoke_model(
79-
body=body, modelId=modelId, accept=accept, contentType=contentType
80-
)
106+
body_bytes = await response["body"].read()
107+
response_body = json.loads(body_bytes.decode("utf-8"))
108+
raw_text = response_body["content"][0]["text"].replace('"""', "").strip()
109+
110+
# Expect pure JSON - no markdown handling
111+
output = json.loads(raw_text)
81112

113+
# Calculate cost
114+
input_tokens = response_body["usage"]["input_tokens"]
115+
output_tokens = response_body["usage"]["output_tokens"]
116+
input_cost = (input_tokens / 1000) * 0.003
117+
output_cost = (output_tokens / 1000) * 0.015
118+
total_cost = input_cost + output_cost
119+
120+
# Validate output with the provided model if it exists
82121
try:
83-
body_bytes = await response["body"].read()
84-
response_body = json.loads(body_bytes.decode("utf-8"))
85-
raw_text = response_body["content"][0]["text"].replace('"""', "").strip()
86-
87-
# Expect pure JSON - no markdown handling
88-
output = json.loads(raw_text)
89-
90-
# Calculate cost
91-
input_tokens = response_body["usage"]["input_tokens"]
92-
output_tokens = response_body["usage"]["output_tokens"]
93-
input_cost = (input_tokens / 1000) * 0.003
94-
output_cost = (output_tokens / 1000) * 0.015
95-
total_cost = input_cost + output_cost
96-
97-
# Validate output with the provided model if it exists
98-
try:
99-
validated_output = pydantic_model.model_validate(output, strict=True)
100-
except ValidationError as ve:
101-
logger.error(f"Output validation failed: {ve}")
102-
raise ve
103-
104-
return BedrockResponse[T](output=validated_output, cost=total_cost)
105-
except Exception as e:
106-
logger.error("Failed to parse the response as JSON. Raw response:")
107-
logger.error(response_body["content"][0]["text"])
108-
raise e
122+
validated_output = pydantic_model.model_validate(output, strict=True)
123+
except ValidationError as ve:
124+
logger.error(f"Output validation failed: {ve}")
125+
raise ve
126+
127+
return BedrockResponse[T](output=validated_output, cost=total_cost)
109128
except Exception as e:
110-
logger.error(f"Amazon Bedrock API error: {e}")
129+
logger.error("Failed to parse the response as JSON. Raw response:")
130+
logger.error(response_body["content"][0]["text"])
111131
raise e

services/libs/tinybird/datasources/project_insights_copy_ds.datasource

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ DESCRIPTION >
1616
- `organizationDependencyPercentage` column is the combined contribution percentage of dependent organizations.
1717
- `achievements` column is an array of tuples (leaderboardType, rank, totalCount) representing project achievements.
1818
- `healthScore` column is the overall health score for the project (0-100).
19+
- `contributorHealthScore` column is the health score percentage for the contributors category (0-100).
20+
- `popularityHealthScore` column is the health score percentage for the popularity category (0-100).
21+
- `developmentHealthScore` column is the health score percentage for the development category (0-100).
22+
- `securityHealthScore` column is the health score percentage for the security category (0-100).
1923
- `firstCommit` column is the timestamp of the first commit in the project.
2024
- `starsLast365Days` column is the count of stars in the last 365 days.
2125
- `forksLast365Days` column is the count of forks in the last 365 days.
@@ -43,6 +47,10 @@ SCHEMA >
4347
`organizationDependencyPercentage` Float64,
4448
`achievements` Array(Tuple(String, UInt64, UInt64)),
4549
`healthScore` Nullable(Float64),
50+
`contributorHealthScore` Nullable(Float64),
51+
`popularityHealthScore` Nullable(Float64),
52+
`developmentHealthScore` Nullable(Float64),
53+
`securityHealthScore` Nullable(Float64),
4654
`firstCommit` Nullable(DateTime64(3)),
4755
`starsLast365Days` UInt64,
4856
`forksLast365Days` UInt64,

services/libs/tinybird/pipes/project_insights.pipe

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
DESCRIPTION >
22
- `project_insights.pipe` serves project insights data for a specific project.
3-
- Returns comprehensive metrics including project metadata (name, logoUrl, isLF), health score, contributor count, software value, contributor and organization dependency metrics, leaderboard achievements, and activity metrics for both current and previous 365-day periods.
3+
- Returns comprehensive metrics including project metadata (name, logoUrl, isLF), health score with category breakdowns (contributors, popularity, development, security), contributor count, software value, contributor and organization dependency metrics, leaderboard achievements, and activity metrics for both current and previous 365-day periods.
44
- Parameters:
55
- `slug`: Optional string for a single project slug (e.g., 'kubernetes')
66
- `slugs`: Optional array of project slugs for multi-project query (e.g., ['kubernetes', 'tensorflow'])
@@ -27,6 +27,10 @@ SQL >
2727
organizationDependencyPercentage,
2828
achievements,
2929
healthScore,
30+
contributorHealthScore,
31+
popularityHealthScore,
32+
developmentHealthScore,
33+
securityHealthScore,
3034
firstCommit,
3135
starsLast365Days,
3236
forksLast365Days,

services/libs/tinybird/pipes/project_insights_copy.pipe

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,11 @@ SQL >
3939
contributorDependencyCount,
4040
contributorDependencyPercentage,
4141
organizationDependencyCount,
42-
organizationDependencyPercentage
42+
organizationDependencyPercentage,
43+
contributorPercentage,
44+
popularityPercentage,
45+
developmentPercentage,
46+
securityPercentage
4347
FROM health_score_copy_ds
4448

4549
NODE project_insights_copy_achievements
@@ -106,6 +110,10 @@ SQL >
106110
COALESCE(dep.organizationDependencyPercentage, 0) AS organizationDependencyPercentage,
107111
COALESCE(ach.achievements, []) AS achievements,
108112
base.healthScore AS healthScore,
113+
dep.contributorPercentage AS contributorHealthScore,
114+
dep.popularityPercentage AS popularityHealthScore,
115+
dep.developmentPercentage AS developmentHealthScore,
116+
dep.securityPercentage AS securityHealthScore,
109117
base.firstCommit AS firstCommit,
110118
l365.starsLast365Days AS starsLast365Days,
111119
l365.forksLast365Days AS forksLast365Days,

0 commit comments

Comments
 (0)