8000 Feature/#1/localization by Arcadia822 · Pull Request #7 · codedog-ai/codedog · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Feature/#1/localization #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 18 additions & 17 deletions codedog/adapters/github_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@

# used for github app
github_app_id = env.get("GITHUB_APP_ID", 0)
github_private_key = load_private_key(
env.get("GITHUB_PRIVATE_KEY_PATH", "/app/private_key.pem"))
github_private_key = load_private_key(env.get("GITHUB_PRIVATE_KEY_PATH", "/app/private_key.pem"))


issue_pattern = re.compile(r"#[0-9]+")
Expand All @@ -53,7 +52,7 @@ class GithubEvent(BaseModel):
installation: dict = {}


def handle_github_event(event: GithubEvent, local=False, **args) -> str:
def handle_github_event(event: GithubEvent, local=False, **kwargs) -> str:
# TODO: parse event related exception
_event_filter(event)

Expand All @@ -64,40 +63,42 @@ def handle_github_event(event: GithubEvent, local=False, **args) -> str:
assert repository_id
assert pull_request_number
# TODO: config
return handle_pull_request(repository_id, pull_request_number, installation_id, local, get_ttl_hash(120), **args)
return handle_pull_request(repository_id, pull_request_number, installation_id, local, get_ttl_hash(120), **kwargs)


def get_github_client(installation_id: int):
if installation_id is None or installation_id == 0:
return default_gh
jwt_token = get_jwt_token(github_private_key, github_app_id)
access_token = get_access_token_by_installation_id(
installation_id, jwt_token)
access_token = get_access_token_by_installation_id(installation_id, jwt_token)
github_client = Github(access_token)
return github_client


@lru_cache()
def handle_pull_request(repository_id: int, pull_request_number: int, installation_id: int,
local=False, ttl_hash=None, **args):
def handle_pull_request(
repository_id: int, pull_request_number: int, installation_id: int, local=False, ttl_hash=None, **kwargs
):
del ttl_hash
logger.info(
"Retrive pull request from Github",
extra={"github.repo.id": repository_id,
"github.pull.number": pull_request_number,
"github.installation_id": installation_id},
extra={
"github.repo.id": repository_id,
"github.pull.number": pull_request_number,
"github.installation_id": installation_id,
},
)
github_client = get_github_client(installation_id)
github_client = default_gh if local else get_github_client(installation_id)

pr = get_pr(github_client, repository_id, pull_request_number)

changes = pr.changes

callbacks = []
if not local:
callbacks = [_comment_callback(github_client.get_repo(
repository_id).get_pull(pull_request_number))]
callbacks = [_comment_callback(github_client.get_repo(repository_id).get_pull(pull_request_number))]

thread = threading.Thread(target=asyncio.run, args=(_review_wrapper(pr, changes, callbacks, **args),))
thread = threading.Thread(target=asyncio.run, args=(_review_wrapper(pr, changes, callbacks, **kwargs),))
thread.start()

return "Review Submitted."
Expand Down Expand Up @@ -192,8 +193,8 @@ def get_potential_issue(repo: Repository, pull: GithubPullRequest) -> Issue:
return issue


async def _review_wrapper(pr: PullRequest, changes: list[Change], callbacks: list[callable] = [], **args):
review = Review(pr=pr, changes=changes, callbacks=callbacks, **args)
async def _review_wrapper(pr: PullRequest, changes: list[Change], callbacks: list[callable] = [], **kwargs):
review = Review(pr=pr, changes=changes, callbacks=callbacks, **kwargs)
await review.execute()


Expand Down
20 changes: 10 additions & 10 deletions codedog/chains.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@
from langchain.output_parsers import OutputFixingParser, PydanticOutputParser

from codedog.model import ChangeSummary
from codedog.templates import grimoire_cn

GRIMOIRE = grimoire_cn
from codedog.templates import grimoire_cn, grimoire_en


class Chains:
def __init__(self, llm: BaseChatModel):
self._review_fallback_prompt = PromptTemplate.from_template(GRIMOIRE.PR_CHANGE_REVIEW_FALLBACK_TEMPLATE)
self._summary_prompt = PromptTemplate.from_template(GRIMOIRE.PR_SUMMARIZE_TEMPLATE)
self._feedback_prompt = PromptTemplate.from_template(GRIMOIRE.PR_SIMPLE_FEEDBACK_TEMPLATE)
def __init__(self, llm: BaseChatModel, lang: str = "cn"):
grimoire = grimoire_cn if lang == "cn" else grimoire_en

self._review_fallback_prompt = PromptTemplate.from_template(grimoire.PR_CHANGE_REVIEW_FALLBACK_TEMPLATE)
self._summary_prompt = PromptTemplate.from_template(grimoire.PR_SUMMARIZE_TEMPLATE)
self._feedback_prompt = PromptTemplate.from_template(grimoire.PR_SIMPLE_FEEDBACK_TEMPLATE)
self._raw_review_parser = PydanticOutputParser(pydantic_object=ChangeSummary)
self._review_parser = OutputFixingParser.from_llm(llm=llm, parser=self._raw_review_parser)
self._review_prompt = PromptTemplate(
template=GRIMOIRE.PR_CHANGE_REVIEW_TEMPLATE,
template=grimoire.PR_CHANGE_REVIEW_TEMPLATE,
input_variables=["text", "name"],
partial_variables={"format_instructions": self._raw_review_parser.get_format_instructions()},
)
Expand All @@ -30,9 +30,9 @@ def __init__(self, llm: BaseChatModel):
self._feedback_chain = LLMChain(llm=llm, prompt=self._feedback_prompt)

@staticmethod
def init_chains():
def init_chains(lang: str = "cn"):
llm = load_llm()
return Chains(llm=llm)
return Chains(llm=llm, lang=lang)

@property
def llm(self):
Expand Down
76 changes: 0 additions & 76 deletions codedog/report.py

This file was deleted.

99 changes: 86 additions & 13 deletions codedog/review.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,16 @@
import json
import logging
import time
import traceback

from langchain.callbacks import get_openai_callback
from langchain.schema import OutputParserException

from codedog.chains import Chains
from codedog.model import Change, ChangeSummary, PullRequest
from codedog.report import generate_change_summary, generate_feedback
from codedog.templates import grimoire_cn, template_cn
from codedog.templates import template_cn, template_en
from codedog.version import VERSION

GRIMOIRE = grimoire_cn
TEMPLATE = template_cn
logger = logging.getLogger(__name__)

# TODO: unit test
Expand All @@ -30,11 +28,13 @@ def __init__(
pr: PullRequest,
changes: list[Change],
callbacks: list | None = None,
chains: Chains = None,
lang: str = "cn",
**kwargs,
):
self._chains: Chains = chains if isinstance(chains, Chains) else Chains.init_chains()

assert lang in ("cn", "en")
self.language = lang
self._chains = Chains.init_chains(lang=lang)
self._template = template_cn if lang == "cn" else template_en
# --- data --------------------
self._pr = pr
self._changes: list[Change] = changes
Expand Down Expand Up @@ -84,7 +84,7 @@ async def execute(self) -> None:

logger.info("Success code review %s", self.json_str())
except Exception as ex:
logger.warn("Fail code review %s %s", ex, self.json_str())
logger.warn("Fail code review %s %s %s", ex, self.json_str(), traceback.format_exc().replace("\n", "\\n"))

def print_report(self) -> None:
print(self.report())
Expand Down Expand Up @@ -148,27 +148,100 @@ async def _feedback(self):
self._meter_api_call_tokens(cb.total_tokens, cb.total_cost)

def _generate_report(self) -> str:
header: str = TEMPLATE.REPORT_HEADER.format(
header: str = self._template.REPORT_HEADER.format(
repo_name=self._pr.repository_name, pr_number=self._pr.pr_id, url=self._pr.url, version=VERSION
)

telemetry: str = TEMPLATE.REPORT_TELEMETRY.format(
telemetry: str = self._template.REPORT_TELEMETRY.format(
start_time=datetime.datetime.fromtimestamp(self._telemetry["start_time"]).strftime("%Y-%m-%d %H:%M:%S"),
time_usage=int(self._telemetry["time_usage"]),
files=self._telemetry["files"],
tokens=self._telemetry["tokens"],
cost=self._telemetry.get("cost", 0),
)

summary: str = TEMPLATE.REPORT_PR_SUMMARY.format(
summary: str = self._template.REPORT_PR_SUMMARY.format(
pr_summary=self._pr_summary,
pr_changes_summary=generate_change_summary(self._changes),
pr_changes_summary=self._generate_change_summary(),
)
feedback: str = TEMPLATE.REPORT_FEEDBACK.format(feedback=generate_feedback(self._changes))
feedback: str = self._template.REPORT_FEEDBACK.format(feedback=self._generate_feedback())

report = "\n".join([header, telemetry, summary, feedback])
return report

def _generate_change_summary(self) -> str:
"""format change summary

Args:
changes (list[Change]): pr changes and reviews
Returns:
str: format markdown table string of change summary
"""
changes = self._changes
important_changes = []
housekeeping_changes = []

important_idx = 1
housekeeping_idx = 1
for change in changes:
file_name = change.file_name or ""
url = change.url or ""
summary = change.summary or ""

text = summary.replace("\n", "<br/>") if summary else ""
text_template: str = self._template.TABLE_LINE.format(file_name=file_name, url=url, text=text)

if not change.major:
text = text_template.format(idx=important_idx)
important_idx += 1
important_changes.append(text)
else:
text = text_template.format(idx=housekeeping_idx)
housekeeping_idx += 1
housekeeping_changes.append(text)

important_changes = "\n".join(important_changes) if important_changes else self._template.TABLE_LINE_NODATA
housekeeping_changes = (
"\n".join(housekeeping_changes) if housekeeping_changes else self._template.TABLE_LINE_NODATA
)
text = self._template.CHANGE_SUMMARY.format(
important_changes=important_changes, housekeeping_changes=housekeeping_changes
)
return text

def _generate_feedback(self) -> str:
"""format feedback

Args:
changes (list[Change]): pr changes and reviews
Returns:
str: format markdown table string of feedback
"""
changes = self._changes

texts = []

idx = 1
for change in changes:
file_name = change.file_name
url = change.url

feedback = change.feedback
if (
not feedback
or feedback in ("ok", "OK")
or (len(feedback) < 30 and "ok" in feedback.lower()) # 移除ok + 其他短语的回复
):
continue

text = f"{self._template.T3_TITLE_LINE.format(idx=idx, file_name=file_name, url=url)}\n\n{feedback}"

texts.append(text)
idx += 1

concat_feedback_text = "\n\n".join(texts) if texts else self._template.TABLE_LINE_NODATA
return concat_feedback_text

async def _execute_callback(self):
if not self._callbacks:
self.print_report()
Expand Down
6 changes: 2 additions & 4 deletions codedog/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,7 @@ async def gitlab(event: GitlabEvent, url: str, token: str, source: str = "") ->


@app.post("/v1/webhook/github", response_model=Response)
async def github(
event: GithubEvent,
) -> Response:
async def github(event: GithubEvent, lang: str = "en") -> Response:
"""Github webhook.

Args:
Expand All @@ -67,7 +65,7 @@ async def github(
Response: message.
"""
try:
message = handle_github_event(event)
message = handle_github_event(event, lang=lang)
except CodedogError as e:
return Response(message=e.message, code=e.code)
except Exception:
Expand Down
Loading
0