1
+ import yaml
2
+ import argparse
3
+ import requests
4
+ import os
5
+ import datetime
6
+ import re
7
+
8
+
9
+ def main (vrn , d ):
10
+
11
+ print (f"Generating prompt for `{ vrn } ` API on { d } ." )
12
+
13
+ p = gen_prompt (f"temp/{ vrn } /{ d } _oasdiff.md" , get_links (vrn ), )
14
+
15
+ pr_file = f"temp/{ vrn } /{ d } _prompt.md"
16
+ with open (pr_file , 'w' , encoding = "utf-8" ) as outfile :
17
+ outfile .write (p )
18
+ print (f"Wrote prompt to { pr_file } ." )
19
+
20
+ l = f"# { d } \n \n "
21
+ l += gen_log (p )
22
+
23
+ log_file = f"./fern/apis/{ vrn } /{ d } .md"
24
+ with open (log_file , 'w' , encoding = "utf-8" ) as outfile :
25
+ outfile .write (l )
26
+ print (f"Wrote log to { log_file } ." )
27
+
28
+
29
+ def gen_log (prompt ):
30
+
31
+ auth = os .environ .get ('LLM_JWT' )
32
+ headers = {"Content-Type" : "application/json" , "Authorization" : f"Bearer { auth } " }
33
+ payload = {
34
+ "model" : "us.anthropic.claude-3-5-sonnet-20241022-v2:0" ,
35
+ "messages" : [
36
+ {
37
+ "role" : "user" ,
38
+ "content" : prompt
39
+ }
40
+ ]
41
+ }
42
+
43
+ r = requests .post ('https://openwebui.dev.devrev-eng.ai/api/chat/completions' , json = payload ,
44
+ headers = headers )
45
+ log = r .json ()['choices' ][0 ]['message' ]['content' ]
46
+ log = re .sub (r"^Here's.*\n?" , '' , log , flags = re .MULTILINE )
47
+ return log
48
+
49
+
50
+ def gen_prompt (oasdiff , links ):
51
+ with open (oasdiff , 'r' ) as infile :
52
+ oasdiff = infile .read ()
53
+
54
+ prompt = f"""
55
+ Please provide an API changelog from the following OASDiff of OpenAPI spec changes. The output should be in markdown format grouping endpoints by use case/object type. For cases where some schema is modified, please also tell what endpoints it affects. Wherever an endpoint, property, or enum value is mentioned, surround it with backticks (`). Wherever an API is mentioned, include a link to the API reference from the list of API links in markdown.
56
+
57
+ <oasdiff>
58
+ { oasdiff }
59
+ </oasdiff>
60
+
61
+ <api_links>
62
+ { links }
63
+ </api_links>
64
+ """
65
+
66
+ return prompt
67
+
68
+ def get_links (version ):
69
+
70
+ src = f"./fern/apis/{ version } /openapi-{ version } .yaml"
71
+
72
+ with open (src , 'r' ) as s :
73
+ spec = yaml .safe_load (s )
74
+ apis = {}
75
+ for endp , defn in spec ['paths' ].items ():
76
+ for val in defn .values ():
77
+ tag = val .get ('tags' )[0 ]
78
+ opId = val .get ('operationId' )
79
+ api = {'opId' : opId , 'method' : endp .split ('.' )[- 1 ]}
80
+ api ['target' ] = f"/{ version } /api-reference/{ tag } /{ opId .replace (f'{ tag } -' , '' )} "
81
+ if tag not in apis :
82
+ apis [tag ] = {endp : api }
83
+ else :
84
+ apis [tag ][endp ] = api
85
+
86
+ md = f"# { version } \n \n "
87
+ for tag , api in apis .items ():
88
+ md += f"\n ## { tag } \n \n "
89
+ for val in api .values ():
90
+ link_text = f"{ tag } > { val ['method' ]} `{ val ['opId' ]} `"
91
+ md += f"- [{ link_text } ]({ val ['target' ]} )\n "
92
+ return md
93
+
94
+ if __name__ == "__main__" :
95
+ parser = argparse .ArgumentParser (description = "Generate release notes" )
96
+ parser .add_argument ('--date' , default = datetime .date .today ())
97
+ parser .add_argument ('--beta' , default = True ,
98
+ action = argparse .BooleanOptionalAction )
99
+ parser .add_argument ('--public' , default = True ,
100
+ action = argparse .BooleanOptionalAction )
101
+ args = parser .parse_args ()
102
+ if args .beta :
103
+ main ('beta' , args .date )
104
+ if args .public :
105
+ main ('public' , args .date )
0 commit comments