33from app .services .github_service import GitHubService
44from app .services .claude_service import ClaudeService
55from app .core .limiter import limiter
6- import os
7- from app .prompts import SYSTEM_FIRST_PROMPT , SYSTEM_SECOND_PROMPT , SYSTEM_THIRD_PROMPT , ADDITIONAL_SYSTEM_INSTRUCTIONS_PROMPT
6+ from app .prompts import (
7+ SYSTEM_FIRST_PROMPT ,
8+ SYSTEM_SECOND_PROMPT ,
9+ SYSTEM_THIRD_PROMPT ,
10+ ADDITIONAL_SYSTEM_INSTRUCTIONS_PROMPT ,
11+ )
812from anthropic ._exceptions import RateLimitError
913from pydantic import BaseModel
1014from functools import lru_cache
@@ -29,11 +33,7 @@ def get_cached_github_data(username: str, repo: str):
2933 file_tree = github_service .get_github_file_paths_as_list (username , repo )
3034 readme = github_service .get_github_readme (username , repo )
3135
32- return {
33- "default_branch" : default_branch ,
34- "file_tree" : file_tree ,
35- "readme" : readme
36- }
36+ return {"default_branch" : default_branch , "file_tree" : file_tree , "readme" : readme }
3737
3838
3939class ApiRequest (BaseModel ):
@@ -51,7 +51,13 @@ async def generate(request: Request, body: ApiRequest):
5151 if len (body .instructions ) > 1000 :
5252 return {"error" : "Instructions exceed maximum length of 1000 characters" }
5353
54- if body .repo in ["fastapi" , "streamlit" , "flask" , "api-analytics" , "monkeytype" ]:
54+ if body .repo in [
55+ "fastapi" ,
56+ "streamlit" ,
57+ "flask" ,
58+ "api-analytics" ,
59+ "monkeytype" ,
60+ ]:
5561 return {"error" : "Example repos cannot be regenerated" }
5662
5763 # Get cached github data
@@ -71,7 +77,7 @@ async def generate(request: Request, body: ApiRequest):
7177 return {
7278 "error" : f"File tree and README combined exceeds token limit (50,000). Current size: { token_count } tokens. This GitHub repository is too large for my wallet, but you can continue by providing your own Anthropic API key." ,
7379 "token_count" : token_count ,
74- "requires_api_key" : True
80+ "requires_api_key" : True ,
7581 }
7682 elif token_count > 200000 :
7783 return {
@@ -82,20 +88,22 @@ async def generate(request: Request, body: ApiRequest):
8288 first_system_prompt = SYSTEM_FIRST_PROMPT
8389 third_system_prompt = SYSTEM_THIRD_PROMPT
8490 if body .instructions :
85- first_system_prompt = first_system_prompt + \
86- "\n " + ADDITIONAL_SYSTEM_INSTRUCTIONS_PROMPT
87- third_system_prompt = third_system_prompt + \
88- "\n " + ADDITIONAL_SYSTEM_INSTRUCTIONS_PROMPT
91+ first_system_prompt = (
92+ first_system_prompt + "\n " + ADDITIONAL_SYSTEM_INSTRUCTIONS_PROMPT
93+ )
94+ third_system_prompt = (
95+ third_system_prompt + "\n " + ADDITIONAL_SYSTEM_INSTRUCTIONS_PROMPT
96+ )
8997
9098 # get the explanation for sysdesign from claude
9199 explanation = claude_service .call_claude_api (
92100 system_prompt = first_system_prompt ,
93101 data = {
94102 "file_tree" : file_tree ,
95103 "readme" : readme ,
96- "instructions" : body .instructions
104+ "instructions" : body .instructions ,
97105 },
98- api_key = body .api_key
106+ api_key = body .api_key ,
99107 )
100108
101109 # Check for BAD_INSTRUCTIONS response
@@ -104,18 +112,14 @@ async def generate(request: Request, body: ApiRequest):
104112
105113 full_second_response = claude_service .call_claude_api (
106114 system_prompt = SYSTEM_SECOND_PROMPT ,
107- data = {
108- "explanation" : explanation ,
109- "file_tree" : file_tree
110- }
115+ data = {"explanation" : explanation , "file_tree" : file_tree },
111116 )
112117
113118 # Extract component mapping from the response
114119 start_tag = "<component_mapping>"
115120 end_tag = "</component_mapping>"
116121 component_mapping_text = full_second_response [
117- full_second_response .find (start_tag ):
118- full_second_response .find (end_tag )
122+ full_second_response .find (start_tag ) : full_second_response .find (end_tag )
119123 ]
120124
121125 # get mermaid.js code from claude
@@ -124,8 +128,8 @@ async def generate(request: Request, body: ApiRequest):
124128 data = {
125129 "explanation" : explanation ,
126130 "component_mapping" : component_mapping_text ,
127- "instructions" : body .instructions
128- }
131+ "instructions" : body .instructions ,
132+ },
129133 )
130134
131135 # Check for BAD_INSTRUCTIONS response
@@ -134,18 +138,14 @@ async def generate(request: Request, body: ApiRequest):
134138
135139 # Process click events to include full GitHub URLs
136140 processed_diagram = process_click_events (
137- mermaid_code ,
138- body .username ,
139- body .repo ,
140- default_branch
141+ mermaid_code , body .username , body .repo , default_branch
141142 )
142143
143- return {"diagram" : processed_diagram ,
144- "explanation" : explanation }
144+ return {"diagram" : processed_diagram , "explanation" : explanation }
145145 except RateLimitError as e :
146146 raise HTTPException (
147147 status_code = 429 ,
148- detail = "Service is currently experiencing high demand. Please try again in a few minutes."
148+ detail = "Service is currently experiencing high demand. Please try again in a few minutes." ,
149149 )
150150 except Exception as e :
151151 return {"error" : str (e )}
@@ -184,12 +184,13 @@ def process_click_events(diagram: str, username: str, repo: str, branch: str) ->
184184 Process click events in Mermaid diagram to include full GitHub URLs.
185185 Detects if path is file or directory and uses appropriate URL format.
186186 """
187+
187188 def replace_path (match ):
188189 # Extract the path from the click event
189- path = match .group (2 ).strip ('" \' ' )
190+ path = match .group (2 ).strip (" \" '" )
190191
191192 # Determine if path is likely a file (has extension) or directory
192- is_file = '.' in path .split ('/' )[- 1 ]
193+ is_file = "." in path .split ("/" )[- 1 ]
193194
194195 # Construct GitHub URL
195196 base_url = f"https://github.com/{ username } /{ repo } "
0 commit comments