11import argparse
22import os
3- import requests
43import subprocess
54
6- from urllib . parse import urlencode
5+ from typing import List , Dict , Optional
76from collections import defaultdict
8- from datetime import datetime
9- from enum import Enum
10- from pydantic import BaseModel
11- from typing import List , Dict , Optional , Any
127
8+ from scripts .client import RunLLMClient , AutodocOutputMode
139
1410# Map of languages to their file extensions
1511language_extensions = {
@@ -27,154 +23,6 @@ def calculate_cost(total_tokens: int) -> float:
2723 return (total_tokens / 1000 ) * COST_PER_1K_TOKEN
2824
2925
30- class AutodocOutputMode (Enum ):
31- # The output will be the original source code, augmented with inline function docstrings.
32- INLINE = "inline"
33-
34- # The output willl be an OpenAPI specification, generated from the source code,
35- # which is assumed to describe a Restful API.
36- OPENAPI = "openapi"
37-
38-
39- class RepositoryResponse (BaseModel ):
40- id : int
41- owner_id : str
42- # Format: owner/repo (eg. RunLLM/commons)
43- name : str
44- created_at : datetime
45- updated_at : datetime
46-
47-
48- class RegisterAutodocRunResponse (BaseModel ):
49- run_id : int
50-
51- # These are all the supported paths we can generate documentation for.
52- file_path_to_language : Dict [str , str ]
53-
54-
55- class GenerateAutodocResponse (BaseModel ):
56- documented_content : str
57- tokens_used : int
58-
59-
60- class ExplainAutodocResponse (BaseModel ):
61- explanation : str
62- tokens_used : int
63-
64-
65- class RunLLMClient :
66- def __init__ (self , server_address : str , api_key : str ):
67- self .server_address = server_address
68- self .api_key = api_key
69-
70- def _check_for_error (self , resp : Any ) -> None :
71- if resp .status_code != 200 :
72- raise Exception (f"Request failed with status code { resp .status_code } . Response: { resp .text } " )
73-
74- def _get_default_headers (self ) -> Dict [str , str ]:
75- return {
76- 'Content-Type' : 'application/json' ,
77- "x-api-key" : self .api_key ,
78- }
79-
80- def list_repositories (self ) -> List [RepositoryResponse ]:
81- resp = requests .get (
82- self .server_address + "/api/repositories" ,
83- headers = self ._get_default_headers (),
84- )
85- self ._check_for_error (resp )
86- return [
87- RepositoryResponse (
88- ** repo_dict
89- ) for repo_dict in resp .json ()
90- ]
91-
92- def create_repository (self , name : str ) -> RepositoryResponse :
93- resp = requests .post (
94- self .server_address + "/api/repository" ,
95- headers = self ._get_default_headers (),
96- json = {"name" : name },
97- )
98- self ._check_for_error (resp )
99- return RepositoryResponse (** resp .json ())
100-
101- def create_autodoc_run (self , repo_id : int , gh_action_url : str , changed_file_paths : List [str ]) -> RegisterAutodocRunResponse :
102- resp = requests .post (
103- self .server_address + "/api/autodoc" ,
104- headers = self ._get_default_headers (),
105- json = {
106- "repo_id" : repo_id ,
107- "gh_action_url" : gh_action_url ,
108- "file_paths" : changed_file_paths ,
109- }
110- )
111- self ._check_for_error (resp )
112- return RegisterAutodocRunResponse (** resp .json ())
113-
114- def generate_inline_documentation (self , run_id : int , file_path : str , file_content : str , language : str , diff : str ) -> GenerateAutodocResponse :
115- query_params = urlencode ({'file_path' : file_path })
116- resp = requests .post (
117- self .server_address + f"/api/autodoc/{ run_id } ?{ query_params } " ,
118- headers = self ._get_default_headers (),
119- json = {
120- "output_mode" : AutodocOutputMode .INLINE .value ,
121- "file_content" : file_content ,
122- "language" : language ,
123- "changes" : diff ,
124- }
125- )
126- self ._check_for_error (resp )
127- return GenerateAutodocResponse (** resp .json ())
128-
129- def generate_openapi_spec (self , run_id : int , file_path : str , original_openapi_spec : str , language : str ) -> GenerateAutodocResponse :
130- query_params = urlencode ({'file_path' : file_path })
131- resp = requests .post (
132- self .server_address + f"/api/autodoc/{ run_id } ?{ query_params } " ,
133- headers = self ._get_default_headers (),
134- json = {
135- "output_mode" : AutodocOutputMode .OPENAPI .value ,
136- "file_content" : original_openapi_spec ,
137- "language" : language ,
138- }
139- )
140- self ._check_for_error (resp )
141- return GenerateAutodocResponse (** resp .json ())
142-
143- def generate_explanation (self , run_id : int , mode : AutodocOutputMode , diff : str ) -> ExplainAutodocResponse :
144- resp = requests .post (
145- self .server_address + f"/api/autodoc/{ run_id } /explanation" ,
146- headers = self ._get_default_headers (),
147- json = {
148- "output_mode" : mode .value ,
149- "changes" : diff ,
150- }
151- )
152- self ._check_for_error (resp )
153- return ExplainAutodocResponse (** resp .json ())
154-
155- def mark_completed (self , run_id : int , pull_request_url : str ) -> None :
156- resp = requests .put (
157- self .server_address + f"/api/autodoc/{ run_id } " ,
158- headers = self ._get_default_headers (),
159- json = {
160- "status" : "Succeeded" ,
161- "pull_request_url" : pull_request_url ,
162- }
163- )
164- self ._check_for_error (resp )
165-
166- def mark_failed (self , run_id : int , error : str ) -> None :
167- resp = requests .put (
168- self .server_address + f"/api/autodoc/{ run_id } " ,
169- headers = self ._get_default_headers (),
170- json = {
171- "status" : "Failed" ,
172- "error" : error ,
173- }
174- )
175- self ._check_for_error (resp )
176-
177-
17826def _partition_diff_by_file_name (diff_lines : List [str ]) -> Dict [str , str ]:
17927 """Partition the diff into a dictionary of file paths to their individual str diffs."""
18028 diff_by_file : Dict [str , str ] = defaultdict (str )
@@ -194,6 +42,7 @@ def _partition_diff_by_file_name(diff_lines: List[str]) -> Dict[str, str]:
19442
19543 return diff_by_file
19644
45+
19746def _get_or_create_repo_id (client : RunLLMClient ) -> int :
19847 """Get the repo ID from the RunLLM API.
19948
@@ -210,6 +59,7 @@ def _get_or_create_repo_id(client: RunLLMClient) -> int:
21059 # No repo exists for this user, so we create one.
21160 return client .create_repository (repo_name ).id
21261
62+
21363def _git_diff (cached : bool = False , file_path : Optional [str ] = None ) -> str :
21464 """Run git diff and return the output as a string."""
21565 cmd = ["git" , "diff" ]
@@ -222,12 +72,14 @@ def _git_diff(cached: bool = False, file_path: Optional[str] = None) -> str:
22272 raise Exception (f'Failed to run git diff: { result .stderr .decode ("utf-8" )} ' )
22373 return result .stdout .decode ("utf-8" )
22474
75+
22576def _git_add (file_path : str ) -> None :
22677 cmd = ["git" , "add" , file_path ]
22778 result = subprocess .run (cmd , stdout = subprocess .PIPE , stderr = subprocess .PIPE )
22879 if result .returncode != 0 :
22980 raise Exception (f'Failed to run git add: { result .stderr .decode ("utf-8" )} ' )
23081
82+
23183def update_docs (
23284 client : RunLLMClient ,
23385 gh_action_url : str ,
0 commit comments