22from fastapi .responses import StreamingResponse
33from dotenv import load_dotenv
44from app .services .github_service import GitHubService
5- from app .services .o3_mini_openrouter_service import OpenRouterO3Service
5+ from app .services .o1_mini_openai_service import OpenAIO1Service
66from app .prompts import (
77 SYSTEM_FIRST_PROMPT ,
88 SYSTEM_SECOND_PROMPT ,
2525
2626# Initialize services
2727# claude_service = ClaudeService()
28- o3_service = OpenRouterO3Service ()
28+ o1_service = OpenAIO1Service ()
2929
3030
3131# cache github data to avoid double API calls from cost and generate
@@ -52,163 +52,6 @@ class ApiRequest(BaseModel):
5252 github_pat : str | None = None
5353
5454
55- # OLD NON STREAMING VERSION
56- @router .post ("" )
57- # @limiter.limit("1/minute;5/day") # TEMP: disable rate limit for growth??
58- async def generate (request : Request , body : ApiRequest ):
59- try :
60- # Check instructions length
61- if len (body .instructions ) > 1000 :
62- return {"error" : "Instructions exceed maximum length of 1000 characters" }
63-
64- if body .repo in [
65- "fastapi" ,
66- "streamlit" ,
67- "flask" ,
68- "api-analytics" ,
69- "monkeytype" ,
70- ]:
71- return {"error" : "Example repos cannot be regenerated" }
72-
73- # Get cached github data with PAT if provided
74- github_data = get_cached_github_data (body .username , body .repo , body .github_pat )
75-
76- # Get default branch first
77- default_branch = github_data ["default_branch" ]
78- file_tree = github_data ["file_tree" ]
79- readme = github_data ["readme" ]
80-
81- # Check combined token count
82- combined_content = f"{ file_tree } \n { readme } "
83- # token_count = claude_service.count_tokens(combined_content)
84- token_count = o3_service .count_tokens (combined_content )
85-
86- # CLAUDE: Modified token limit check
87- # if 50000 < token_count < 190000 and not body.api_key:
88- # return {
89- # "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.",
90- # "token_count": token_count,
91- # "requires_api_key": True,
92- # }
93- # elif token_count > 200000:
94- # return {
95- # "error": f"Repository is too large (>200k tokens) for analysis. Claude 3.5 Sonnet's max context length is 200k tokens. Current size: {token_count} tokens."
96- # }
97-
98- # O3: Modified token limit check
99- if 50000 < token_count < 195000 and not body .api_key :
100- return {
101- "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 OpenRouter API key." ,
102- "token_count" : token_count ,
103- "requires_api_key" : True ,
104- }
105- elif token_count > 195000 :
106- return {
107- "error" : f"Repository is too large (>195k tokens) for analysis. OpenAI o3-mini's max context length is 200k tokens. Current size: { token_count } tokens."
108- }
109-
110- # Prepare system prompts with instructions if provided
111- first_system_prompt = SYSTEM_FIRST_PROMPT
112- third_system_prompt = SYSTEM_THIRD_PROMPT
113- if body .instructions :
114- first_system_prompt = (
115- first_system_prompt + "\n " + ADDITIONAL_SYSTEM_INSTRUCTIONS_PROMPT
116- )
117- third_system_prompt = (
118- third_system_prompt + "\n " + ADDITIONAL_SYSTEM_INSTRUCTIONS_PROMPT
119- )
120-
121- # get the explanation for sysdesign from claude
122- # explanation = claude_service.call_claude_api(
123- # system_prompt=first_system_prompt,
124- # data={
125- # "file_tree": file_tree,
126- # "readme": readme,
127- # "instructions": body.instructions,
128- # },
129- # api_key=body.api_key,
130- # )
131-
132- # get the explanation for sysdesign from o3
133- explanation = o3_service .call_o3_api (
134- system_prompt = first_system_prompt ,
135- data = {
136- "file_tree" : file_tree ,
137- "readme" : readme ,
138- "instructions" : body .instructions ,
139- },
140- api_key = body .api_key ,
141- reasoning_effort = "medium" ,
142- )
143-
144- # Check for BAD_INSTRUCTIONS response
145- if "BAD_INSTRUCTIONS" in explanation :
146- return {"error" : "Invalid or unclear instructions provided" }
147-
148- # full_second_response = claude_service.call_claude_api(
149- # system_prompt=SYSTEM_SECOND_PROMPT,
150- # data={"explanation": explanation, "file_tree": file_tree},
151- # api_key=body.api_key,
152- # )
153-
154- full_second_response = o3_service .call_o3_api (
155- system_prompt = SYSTEM_SECOND_PROMPT ,
156- data = {"explanation" : explanation , "file_tree" : file_tree },
157- api_key = body .api_key ,
158- )
159-
160- # Extract component mapping from the response
161- start_tag = "<component_mapping>"
162- end_tag = "</component_mapping>"
163- component_mapping_text = full_second_response [
164- full_second_response .find (start_tag ) : full_second_response .find (end_tag )
165- ]
166-
167- # get mermaid.js code from claude
168- # mermaid_code = claude_service.call_claude_api(
169- # system_prompt=third_system_prompt,
170- # data={
171- # "explanation": explanation,
172- # "component_mapping": component_mapping_text,
173- # "instructions": body.instructions,
174- # },
175- # api_key=body.api_key,
176- # )
177-
178- # get mermaid.js code from o3
179- mermaid_code = o3_service .call_o3_api (
180- system_prompt = third_system_prompt ,
181- data = {
182- "explanation" : explanation ,
183- "component_mapping" : component_mapping_text ,
184- "instructions" : body .instructions ,
185- },
186- api_key = body .api_key ,
187- reasoning_effort = "medium" ,
188- )
189-
190- # check for and remove code block tags
191- mermaid_code = mermaid_code .replace ("```mermaid" , "" ).replace ("```" , "" )
192-
193- # Check for BAD_INSTRUCTIONS response
194- if "BAD_INSTRUCTIONS" in mermaid_code :
195- return {"error" : "Invalid or unclear instructions provided" }
196-
197- # Process click events to include full GitHub URLs
198- processed_diagram = process_click_events (
199- mermaid_code , body .username , body .repo , default_branch
200- )
201-
202- return {"diagram" : processed_diagram , "explanation" : explanation }
203- except RateLimitError as e :
204- raise HTTPException (
205- status_code = 429 ,
206- detail = "Service is currently experiencing high demand. Please try again in a few minutes." ,
207- )
208- except Exception as e :
209- return {"error" : str (e )}
210-
211-
21255@router .post ("/cost" )
21356# @limiter.limit("5/minute") # TEMP: disable rate limit for growth??
21457async def get_generation_cost (request : Request , body : ApiRequest ):
@@ -222,8 +65,8 @@ async def get_generation_cost(request: Request, body: ApiRequest):
22265 # file_tree_tokens = claude_service.count_tokens(file_tree)
22366 # readme_tokens = claude_service.count_tokens(readme)
22467
225- file_tree_tokens = o3_service .count_tokens (file_tree )
226- readme_tokens = o3_service .count_tokens (readme )
68+ file_tree_tokens = o1_service .count_tokens (file_tree )
69+ readme_tokens = o1_service .count_tokens (readme )
22770
22871 # CLAUDE: Calculate approximate cost
22972 # Input cost: $3 per 1M tokens ($0.000003 per token)
@@ -232,7 +75,7 @@ async def get_generation_cost(request: Request, body: ApiRequest):
23275 # output_cost = 3500 * 0.000015
23376 # estimated_cost = input_cost + output_cost
23477
235- # O3: Calculate approximate cost
78+ # O3: Calculate approximate cost temp: o1-mini, same price as o3-mini
23679 # Input cost: $1.1 per 1M tokens ($0.0000011 per token)
23780 # Output cost: $4.4 per 1M tokens ($0.0000044 per token)
23881 input_cost = ((file_tree_tokens * 2 + readme_tokens ) + 3000 ) * 0.0000011
@@ -306,13 +149,13 @@ async def event_generator():
306149
307150 # Token count check
308151 combined_content = f"{ file_tree } \n { readme } "
309- token_count = o3_service .count_tokens (combined_content )
152+ token_count = o1_service .count_tokens (combined_content )
310153
311154 if 50000 < token_count < 195000 and not body .api_key :
312- yield f"data: { json .dumps ({'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 OpenRouter API key.' })} \n \n "
155+ yield f"data: { json .dumps ({'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 OpenAI API key.' })} \n \n "
313156 return
314157 elif token_count > 195000 :
315- yield f"data: { json .dumps ({'error' : f'Repository is too large (>195k tokens) for analysis. OpenAI o3 -mini\' s max context length is 200k tokens. Current size: { token_count } tokens.' })} \n \n "
158+ yield f"data: { json .dumps ({'error' : f'Repository is too large (>195k tokens) for analysis. OpenAI o1 -mini\' s max context length is 200k tokens. Current size: { token_count } tokens.' })} \n \n "
316159 return
317160
318161 # Prepare prompts
@@ -331,19 +174,18 @@ async def event_generator():
331174 )
332175
333176 # Phase 1: Get explanation
334- yield f"data: { json .dumps ({'status' : 'explanation_sent' , 'message' : 'Sending explanation request to o3 -mini...' })} \n \n "
177+ yield f"data: { json .dumps ({'status' : 'explanation_sent' , 'message' : 'Sending explanation request to o1 -mini...' })} \n \n "
335178 await asyncio .sleep (0.1 )
336179 yield f"data: { json .dumps ({'status' : 'explanation' , 'message' : 'Analyzing repository structure...' })} \n \n "
337180 explanation = ""
338- async for chunk in o3_service . call_o3_api_stream (
181+ async for chunk in o1_service . call_o1_api_stream (
339182 system_prompt = first_system_prompt ,
340183 data = {
341184 "file_tree" : file_tree ,
342185 "readme" : readme ,
343186 "instructions" : body .instructions ,
344187 },
345188 api_key = body .api_key ,
346- reasoning_effort = "medium" ,
347189 ):
348190 explanation += chunk
349191 yield f"data: { json .dumps ({'status' : 'explanation_chunk' , 'chunk' : chunk })} \n \n "
@@ -353,15 +195,14 @@ async def event_generator():
353195 return
354196
355197 # Phase 2: Get component mapping
356- yield f"data: { json .dumps ({'status' : 'mapping_sent' , 'message' : 'Sending component mapping request to o3 -mini...' })} \n \n "
198+ yield f"data: { json .dumps ({'status' : 'mapping_sent' , 'message' : 'Sending component mapping request to o1 -mini...' })} \n \n "
357199 await asyncio .sleep (0.1 )
358200 yield f"data: { json .dumps ({'status' : 'mapping' , 'message' : 'Creating component mapping...' })} \n \n "
359201 full_second_response = ""
360- async for chunk in o3_service . call_o3_api_stream (
202+ async for chunk in o1_service . call_o1_api_stream (
361203 system_prompt = SYSTEM_SECOND_PROMPT ,
362204 data = {"explanation" : explanation , "file_tree" : file_tree },
363205 api_key = body .api_key ,
364- reasoning_effort = "medium" ,
365206 ):
366207 full_second_response += chunk
367208 yield f"data: { json .dumps ({'status' : 'mapping_chunk' , 'chunk' : chunk })} \n \n "
@@ -377,19 +218,18 @@ async def event_generator():
377218 ]
378219
379220 # Phase 3: Generate Mermaid diagram
380- yield f"data: { json .dumps ({'status' : 'diagram_sent' , 'message' : 'Sending diagram generation request to o3 -mini...' })} \n \n "
221+ yield f"data: { json .dumps ({'status' : 'diagram_sent' , 'message' : 'Sending diagram generation request to o1 -mini...' })} \n \n "
381222 await asyncio .sleep (0.1 )
382223 yield f"data: { json .dumps ({'status' : 'diagram' , 'message' : 'Generating diagram...' })} \n \n "
383224 mermaid_code = ""
384- async for chunk in o3_service . call_o3_api_stream (
225+ async for chunk in o1_service . call_o1_api_stream (
385226 system_prompt = third_system_prompt ,
386227 data = {
387228 "explanation" : explanation ,
388229 "component_mapping" : component_mapping_text ,
389230 "instructions" : body .instructions ,
390231 },
391232 api_key = body .api_key ,
392- reasoning_effort = "medium" ,
393233 ):
394234 mermaid_code += chunk
395235 yield f"data: { json .dumps ({'status' : 'diagram_chunk' , 'chunk' : chunk })} \n \n "
0 commit comments