├── .gitignore
├── LICENSE
├── README.md
├── config.ini
├── images
└── usage-preview.png
├── main.py
├── models
├── js.txt
├── py.txt
└── ts.txt
├── modules
├── autodoc.py
├── divider.py
├── file.py
├── prompt.py
├── result.py
└── settings.py
├── requirements.txt
└── results
├── js
└── example_commented.js
├── python
├── autodoc_commented.py
├── divider_commented.py
├── file_commented.py
├── prompt_commented.py
├── result_commented.py
└── settings_commented.py
└── ts
├── example_2_commented.ts
└── example_commented.ts
/.gitignore:
--------------------------------------------------------------------------------
1 | *__pycache__
2 | /venv
3 |
4 | /.vscode
5 | /token.txt
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 awekrx
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AutoDoc-ChatGPT
2 |
3 | AutoDoc-ChatGPT is a Python script that leverages the power of ChatGPT model to automatically generate documentation for any programming language.
4 |
5 | With AutoDoc-ChatGPT, you can easily generate comprehensive documentation for your codebase. Simply provide the path to file you wish to document, and AutoDoc-ChatGPT will generate a detailed description of its functionality, parameters, and return values in natural language.
6 |
7 | ## Getting Started
8 |
9 | ### Installing
10 |
11 | Clone this repository to your local machine:
12 |
13 | ```bash
14 | git clone https://github.com/awekrx/AutoDoc-ChatGPT.git
15 | ```
16 |
17 | Then install the required packages:
18 |
19 | ```bash
20 | pip install -r requirements.txt
21 | ```
22 |
23 | ## Supported programming languages
24 |
25 | - [X]
Python
26 | - [X]
JavaScript
27 | - [X]
TypeScript
28 | - [ ]
Go
29 | - [ ]
C#
30 | - [ ]
C++
31 | - [ ]
PHP
32 | - [ ]
Ruby
33 | - [ ]
Rust
34 | - [ ]
Java
35 | - [ ]
Kotlin
36 |
37 | And others...
38 |
39 | > `disclaimer`: TypeScript and JavScript has some bugs and is under testing
40 | >
41 | > `disclaimer_2.0`: There is a known error commenting files with 2 or more classes that have methods with the same name.
42 | >
43 |
44 | ## Usage
45 |
46 | ### Edit config
47 |
48 | Open `config.ini` and add `email` and `password` there if you are not using OAuth authorization.
49 | Otherwise open [ChatGPT](https://chat.openai.com) and get the `__Secure-next-auth.session-token` cookie and write it to the `session-token`.
50 |
51 | ### Start
52 |
53 | ```bash
54 | py main.py -file "path to the file"
55 | ```
56 |
57 | The path to the file can be either relative or absolute.
58 |
59 | After execution, the file `yourfilename_commented.language` is created in the folder with the desired file.
60 |
61 | OR
62 |
63 | ```bash
64 | py main.py -file "path to the file"
65 | ```
66 |
67 | __Not recommended, little tested.__
68 | You can specify a file with a comment option to create such comments.
69 |
70 | ### Usage example
71 |
72 | 
73 |
74 | ## Alternative usage
75 |
76 | You can also use this as a function in python.
77 |
78 | ```python
79 | from modules.autodoc import AutoDoc
80 | import configparser
81 |
82 | config = configparser.ConfigParser()
83 | config.read("config.ini")
84 |
85 | auth = {
86 | "email": config["ChatGPT"]["email"],
87 | "password": config["ChatGPT"]["password"],
88 | "session_token": config["ChatGPT"]["session_token"]
89 | }
90 |
91 | result = AutoDoc(
92 | auth,
93 | "Code for commenting",
94 | "language code",
95 | "example comment model (optional)"
96 | ).start()
97 | print(result)
98 | # out: Code with comments
99 | ```
100 |
101 | ## Disclaimer
102 |
103 | Doesn't always create correct comments. It doesn't always mean what you want. Use as a draft of comments that may need to be edited.
104 |
105 | ## License
106 |
107 | This project is licensed under the MIT License.
108 |
109 | ## Acknowledgments
110 |
111 | Thanks a lot to the development of AI and separately to [СhatGPT](https://chat.openai.com) for generating the Readme.
112 |
113 | And also [acheong08](https://github.com/acheong08) for creating [ChatGPT](https://github.com/acheong08/ChatGPT).
114 |
--------------------------------------------------------------------------------
/config.ini:
--------------------------------------------------------------------------------
1 | [ChatGPT]
2 | email=
3 | password=
4 | session_token=
--------------------------------------------------------------------------------
/images/usage-preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/awekrx/AutoDoc-ChatGPT/2ae010d1f67fd55b3d3ba8f72e5761174d9a81e3/images/usage-preview.png
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | import os
2 | import argparse
3 | from modules.autodoc import AutoDoc
4 | from modules.file import File
5 | from modules.settings import *
6 | import configparser
7 |
8 | config = configparser.ConfigParser()
9 | config.read("config.ini")
10 |
11 | auth = {
12 | "email": config["ChatGPT"]["email"],
13 | "password": config["ChatGPT"]["password"],
14 | "session_token": config["ChatGPT"]["session_token"],
15 | }
16 |
17 |
18 | parser = argparse.ArgumentParser(
19 | description="AutoDoc is a console application for generating code documentation using ChatGPT. Currently supports 1 language: Python. You can use an example file for any language using -example."
20 | )
21 |
22 |
23 | parser.add_argument("-file", type=str, help="Path to the code file.", required=True)
24 |
25 | args = parser.parse_args()
26 |
27 |
28 | if not os.path.exists(args.file):
29 | exit(f"[{RED}Error{RESET}] Code file does not exist")
30 |
31 |
32 | file = File(args.file)
33 |
34 | autodoc = AutoDoc(
35 | auth,
36 | file.content(),
37 | file.language(),
38 | )
39 |
40 | result = autodoc.start()
41 | file.create_commented_file(result)
42 |
--------------------------------------------------------------------------------
/models/js.txt:
--------------------------------------------------------------------------------
1 | Write JSDoc documentations all classes, constructors, functions() for code (Comments need to be written only for the code that I threw it off | Do not add any notes from yourself | Variays: let, const. Functional parts of the code: if, else, for, and so on, you do not need to comment | Comments for everything that is not a class or function initialization are not needed, that is, for variables that are behind the class or use of functions, you do not need to comment):
2 |
3 | What not to comment:
4 | const test = 1
5 | read()
6 | if(x > 2)
7 | and etc
8 |
9 | CODE
10 |
11 | Write your answer in the format:
12 | |class/constructor/function Name|
13 | Comment: ...
14 |
15 | Example:
16 | From code:
17 | class Prototype {
18 | primitive: any;
19 | component: object;
20 | circularReference: ComponentWithBackReference;
21 | dots: [
22 | Dot,
23 | Dot,
24 | Dot?,
25 | Dot?,
26 | Dot?,
27 | Dot?,
28 | Dot?,
29 | Dot?,
30 | Dot?,
31 | Dot?,
32 | ];
33 |
34 | constructor(){
35 |
36 | }
37 |
38 | clone(): this {
39 | const clone = Object.create(this);
40 |
41 | clone.component = Object.create(this.component);
42 | clone.circularReference = {
43 | ...this.circularReference,
44 | prototype: { ...this },
45 | };
46 |
47 | return clone;
48 | }
49 | }
50 |
51 | Rectangle implements Shape {
52 | constructor(protected readonly width: number, protected readonly height: number) { }
53 |
54 | getArea(): number {
55 | return this.widththis.height;
56 | }
57 |
58 | toString(): string {
59 | return `Rectangle[width=${this.width}, height=${this.height}]`;
60 | }
61 | }
62 |
63 | Created comments:
64 | |class Prototype|
65 | Comment:
66 | This class represents a prototype object that can be cloned.
67 | @class
68 |
69 |
70 | |primitive|
71 | Comment:
72 | A property that can hold any primitive value.
73 | @type {any}
74 |
75 |
76 | |component|
77 | Comment:
78 | A property that holds an object.
79 | @type {object}
80 |
81 |
82 | |circularReference|
83 | Comment:
84 | A property that holds a reference to another object of type ComponentWithBackReference.
85 | @type {ComponentWithBackReference}
86 |
87 |
88 | |dots|
89 | Comment:
90 | A property that holds the dots of the prototype.
91 | @type {[Dot, Dot, Dot?, Dot?, Dot?, Dot?, Dot?, Dot?, Dot?, Dot?]}
92 |
93 |
94 | |constructor|
95 | Comment:
96 | Creates a new Prototype instance.
97 | @constructor
98 |
99 |
100 | |clone|
101 | Comment:
102 | Returns the clone of the object.
103 | @returns {this}
104 |
105 |
106 | |class Rectangle|
107 | Comment:
108 | This class represents a rectangle shape and implements the Shape interface.
109 | @implements {Shape}
110 | @class
111 |
112 |
113 | |constructor|
114 | Comment:
115 | Creates a new Rectangle instance with the given width and height.
116 | @constructor
117 | @param {number} width - The width of the rectangle.
118 | @param {number} height - The height of the rectangle.
119 |
120 |
121 | |getArea|
122 | Comment:
123 | Calculates and returns the area of the rectangle.
124 | @returns {number} - The area of the rectangle.
125 |
126 |
127 | |toString|
128 | Comment:
129 | Returns a string representation of the rectangle.
130 | @returns {string} - The string representation of the rectangle.
--------------------------------------------------------------------------------
/models/py.txt:
--------------------------------------------------------------------------------
1 | Write Google Style documentations all classes and functions (If there are no functions, then variables do not need to be commented) for code:
2 |
3 | CODE
4 |
5 | Write your answer in the format:
6 | |class/def Name|
7 | Description: ...
8 | Arguments: ...
9 | Returns: ...
10 |
11 | Example:
12 | |class Splitter|
13 | Description: This class takes a code string and a language string and splits the code into sections based on language-specific separators.
14 |
15 | Arguments:
16 |
17 | code (str): A string of code to be split
18 | language (str): A string representing the language of the code (e.g. "py" for Python)
19 | |def __init__|
20 | Description: Initializes a Splitter instance with the given code and language.
21 |
22 | Arguments:
23 |
24 | code (str): A string of code to be split
25 | language (str): A string representing the language of the code (e.g. "py" for Python)
26 | |def split|
27 | Description: Splits the code into sections based on language-specific separators.
28 |
29 | Arguments: None
30 |
31 | Returns:
32 |
33 | list[str]: A list of strings representing the sections of the code.
34 | |def py|
35 | Description: A method that splits Python code into sections based on class and function definitions.
36 |
37 | Arguments: None
38 |
39 | Returns:
40 |
41 | list: A list of strings representing the sections of the Python code.
--------------------------------------------------------------------------------
/models/ts.txt:
--------------------------------------------------------------------------------
1 | Write JSDoc documentations all classes, constructors, interfaces, types, functions(public/private/protected) and variables(public/private/protected) for code (Comments need to be written only for the code that I threw it off | Do not add any notes from yourself | Variays: let, const. Functional parts of the code: if, else, for, and so on, you do not need to comment | public/private/protected variables if they are inside the constructor, then they do not need to be commented):
2 |
3 | CODE
4 |
5 | Write your answer in the format:
6 | |class/constructor/function/variable/type/interface Name|
7 | Comment: ...
8 |
9 | Example:
10 | From code:
11 | class Prototype {
12 | public primitive: any;
13 | public component: object;
14 | public circularReference: ComponentWithBackReference;
15 | public dots: [
16 | Dot,
17 | Dot,
18 | Dot?,
19 | Dot?,
20 | Dot?,
21 | Dot?,
22 | Dot?,
23 | Dot?,
24 | Dot?,
25 | Dot?,
26 | ];
27 |
28 | constructor(){
29 |
30 | }
31 |
32 | public clone(): this {
33 | const clone = Object.create(this);
34 |
35 | clone.component = Object.create(this.component);
36 | clone.circularReference = {
37 | ...this.circularReference,
38 | prototype: { ...this },
39 | };
40 |
41 | return clone;
42 | }
43 | }
44 |
45 | interface Shape {
46 | getArea: () => number;
47 | }
48 |
49 | class Rectangle implements Shape {
50 | public constructor(protected readonly width: number, protected readonly height: number) { }
51 |
52 | public getArea(): number {
53 | return this.widththis.height;
54 | }
55 |
56 | public toString(): string {
57 | return `Rectangle[width=${this.width}, height=${this.height}]`;
58 | }
59 | }
60 |
61 | Created comments:
62 | |class Prototype|
63 | Comment:
64 | This class represents a prototype object that can be cloned.
65 | @class
66 |
67 |
68 | |public primitive|
69 | Comment:
70 | A public property that can hold any primitive value.
71 | @type {any}
72 |
73 |
74 | |public component|
75 | Comment:
76 | A public property that holds an object.
77 | @type {object}
78 |
79 |
80 | |public circularReference|
81 | Comment:
82 | A public property that holds a reference to another object of type ComponentWithBackReference.
83 | @type {ComponentWithBackReference}
84 |
85 |
86 | |public dots|
87 | Comment:
88 | A public property that holds the dots of the prototype.
89 | @type {[Dot, Dot, Dot?, Dot?, Dot?, Dot?, Dot?, Dot?, Dot?, Dot?]}
90 |
91 |
92 | |constructor|
93 | Comment:
94 | Creates a new Prototype instance.
95 | @constructor
96 |
97 |
98 | |public clone|
99 | Comment:
100 | Returns the clone of the object.
101 | @returns {this}
102 |
103 |
104 | |interface Shape|
105 | Comment:
106 | This interface represents a shape.
107 | @interface
108 |
109 |
110 | |class Rectangle|
111 | Comment:
112 | This class represents a rectangle shape and implements the Shape interface.
113 | @implements {Shape}
114 | @class
115 |
116 |
117 | |constructor|
118 | Comment:
119 | Creates a new Rectangle instance with the given width and height.
120 | @constructor
121 | @param {number} width - The width of the rectangle.
122 | @param {number} height - The height of the rectangle.
123 |
124 |
125 | |public getArea|
126 | Comment:
127 | Calculates and returns the area of the rectangle.
128 | @returns {number} - The area of the rectangle.
129 |
130 |
131 | |public toString|
132 | Comment:
133 | Returns a string representation of the rectangle.
134 | @returns {string} - The string representation of the rectangle.
--------------------------------------------------------------------------------
/modules/autodoc.py:
--------------------------------------------------------------------------------
1 | import os
2 | from time import sleep
3 |
4 | from colorama import init as colorama_init
5 |
6 | from revChatGPT.V1 import Chatbot
7 | from modules.prompt import Prompt
8 | from modules.divider import Divider
9 | from modules.settings import *
10 | from modules.result import Result
11 |
12 | from rich.console import Console
13 |
14 | console = Console()
15 |
16 | colorama_init()
17 |
18 |
19 | class AutoDoc:
20 | def __init__(self, config: str, code: str, language: str):
21 | self.__config = config
22 |
23 | self.__code = code
24 | if not isinstance(self.__code, str):
25 | exit(f"[{RED}Error{RESET}] Code is must be a string")
26 | elif len(self.__code) == 0:
27 | exit(f"[{RED}Error{RESET}] Code is empty")
28 |
29 | self.__language = language
30 | if not self.__language in Settings.supported_languages:
31 | exit(f"[{RED}Error{RESET}] .{self.__language} language not supported")
32 |
33 | def __ask(self, code) -> str:
34 | response = None
35 | conversation = None
36 | try:
37 | for data in self.__chatbot.ask(
38 | Prompt(self.__language, code).create(),
39 | conversation_id=self.__conversation,
40 | parent_id=None,
41 | ):
42 | response = data["message"]
43 | conversation = data["conversation_id"]
44 | if not self.__conversation:
45 | self.__conversation = conversation
46 | return response
47 | except:
48 | raise ValueError("ChatGPT error")
49 |
50 | def start(self):
51 | with console.status("[bold green] Please wait...") as status:
52 | print(f"[{BLUE}1{RESET}] {BOLD}Dividing text{RESET}")
53 | self.__divided = Divider(self.__code, self.__language).divide()
54 |
55 | if len(self.__divided) == 0:
56 | exit(
57 | f"[{RED}END{RESET}] {BOLD}There is nothing to comment in the code{RESET}"
58 | )
59 |
60 | print(
61 | f"[{BLUE}2{RESET}] {BOLD}Text is divided into {len(self.__divided)} parts{RESET}"
62 | )
63 |
64 | print(f"[{BLUE}3{RESET}] {BOLD}Connecting to ChatGPT{RESET}")
65 | if self.__config["session_token"]:
66 | self.__chatbot = Chatbot(
67 | config={
68 | "session_token": self.__config["session_token"],
69 | }
70 | )
71 | elif self.__config["email"] and self.__config["password"]:
72 | self.__chatbot = Chatbot(
73 | config={
74 | "email": self.__config["email"],
75 | "password": self.__config["password"],
76 | }
77 | )
78 | else:
79 | raise ValueError("No login details")
80 |
81 | self.__conversation = None
82 |
83 | self.__count = 1
84 | self.__comments = []
85 | for entity in self.__divided:
86 | print(
87 | f"[{BLUE}4.{self.__count}{RESET}] {BOLD}Chatbot generating comments ({self.__count}/{len(self.__divided)}){RESET}"
88 | )
89 | response = self.__ask(entity)
90 | self.__comments.append(response)
91 | sleep(1)
92 | self.__count += 1
93 |
94 | print(f"[{BLUE}5{RESET}] {BOLD}Merge file and comments{RESET}")
95 | self.__commented_code = self.__code
96 | for comment in self.__comments:
97 | self.__commented_code = Result(
98 | self.__commented_code, comment, self.__language
99 | ).get()
100 |
101 | print(f"[{BLUE}6{RESET}] {BOLD}Ready. Thanks for using!{RESET}"),
102 | return self.__commented_code
103 |
--------------------------------------------------------------------------------
/modules/divider.py:
--------------------------------------------------------------------------------
1 | import re
2 | from modules.settings import Settings
3 |
4 |
5 | class Divider:
6 | def __init__(self, text: str, language: str):
7 | self.__text = text
8 | self.__language = language
9 | self.__splitted_content = []
10 |
11 | def divide(
12 | self,
13 | ) -> list[str]:
14 | starts = re.finditer(Settings.divide_start[self.__language], self.__text)
15 | ends = re.finditer(Settings.divide_end[self.__language], self.__text)
16 |
17 | while True:
18 | start = None
19 | end = None
20 | try:
21 | start = next(starts).start()
22 | end = next(ends).start()
23 | if end < start:
24 | end = next(ends).start()
25 | self.__splitted_content.append(self.__text[start:end])
26 | except:
27 | if start != None:
28 | self.__splitted_content.append(self.__text[start:])
29 | break
30 |
31 | return self.__splitted_content
32 |
--------------------------------------------------------------------------------
/modules/file.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 |
4 | class File:
5 | def __init__(self, path: str):
6 | self.__path = os.path.normpath(os.path.abspath(path))
7 | self.__dirname = os.path.dirname(self.__path)
8 | self.__basename = os.path.basename(self.__path).split(".")[0]
9 | self.__language = os.path.basename(self.__path).split(".")[1]
10 |
11 | def content(self) -> str:
12 | self.__text = open(self.__path, "r").read()
13 | return self.__text
14 |
15 | def language(self) -> str:
16 | return self.__language
17 |
18 | def create_commented_file(self, content: str) -> None:
19 | path = os.path.join(
20 | self.__dirname,
21 | self.__basename + f"_commented.{self.__language}",
22 | )
23 | open(path, "w").write(content)
24 |
--------------------------------------------------------------------------------
/modules/prompt.py:
--------------------------------------------------------------------------------
1 | class Prompt:
2 | def __init__(self, language: str, text: str):
3 | self.__text = text
4 | self.__language = language
5 |
6 | def create(self) -> str:
7 | return (
8 | open(f"./models/{self.__language}.txt", "r")
9 | .read()
10 | .replace("CODE", self.__text)
11 | )
12 |
--------------------------------------------------------------------------------
/modules/result.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 |
4 | class Result:
5 | def __init__(self, code: str, text_comment: str, language: str):
6 | self.__code = code
7 | self.__text_comment = text_comment
8 | self.__language = language
9 |
10 | def get(self) -> str:
11 | if self.__language == "py":
12 | return self.__py()
13 | elif self.__language == "ts" or self.__language == "js":
14 | return self.__ts()
15 |
16 | def __py(self) -> str:
17 | regexpes = re.finditer(r"\|(.+?)\|", self.__text_comment)
18 | indexes = []
19 |
20 | while True:
21 | try:
22 | match = next(regexpes)
23 | start = match.start()
24 | end = match.end()
25 | indexes.append((start, end))
26 | except:
27 | break
28 |
29 | names = []
30 | comments = []
31 | for i in range(len(indexes)):
32 | names.append(self.__text_comment[indexes[i][0] + 1 : indexes[i][1] - 1])
33 | if i < len(indexes) - 1:
34 | comments.append(
35 | self.__text_comment[indexes[i][1] + 1 : indexes[i + 1][0]].replace(
36 | "Description: ", ""
37 | )
38 | )
39 | else:
40 | comments.append(
41 | self.__text_comment[indexes[i][1] :].replace("Description: ", "")
42 | )
43 |
44 | for i in range(len(names)):
45 | index = self.__code.index(names[i])
46 | split_start = self.__code[index:]
47 | doubledot = index + split_start.index(":\n") + 1
48 | tabs = re.search(r":\n(.*?)[a-zA-Z]", split_start).span()
49 | tabs_count = tabs[1] - tabs[0]
50 | tab = (tabs_count - 3) * " "
51 | replace_text = self.__code[index:doubledot]
52 | new_replace_text = comments[i].replace("\n", f"\n{tab}")
53 | self.__code = self.__code.replace(
54 | replace_text,
55 | f'{replace_text}\n{tab}"""\n{tab}{new_replace_text}\n{tab}"""',
56 | )
57 | return self.__code
58 |
59 | def __ts(self) -> str:
60 | regexpes = re.finditer(r"\|(.+?)\|\n", self.__text_comment)
61 | indexes = []
62 |
63 | while True:
64 | try:
65 | match = next(regexpes)
66 | start = match.start()
67 | end = match.end() - 1
68 | indexes.append((start, end))
69 | except:
70 | break
71 |
72 | names: list[str] = []
73 | comments: list[str] = []
74 | for i in range(len(indexes)):
75 | names.append(self.__text_comment[indexes[i][0] + 1 : indexes[i][1] - 1])
76 | if i < len(indexes) - 1:
77 | comments.append(
78 | re.sub(
79 | r"Comment:\n|Comment: \n",
80 | "",
81 | self.__text_comment[indexes[i][1] + 1 : indexes[i + 1][0]],
82 | )
83 | )
84 | else:
85 | comments.append(
86 | self.__text_comment[indexes[i][1] :].replace("Comment:\n", "")
87 | )
88 |
89 | for i in range(len(names)):
90 | comments[i] = " * " + comments[i].replace("\n", "\n * ")
91 | comments[i] = re.sub(r"\n\s\*\s\n\s\*\s", "", comments[i])
92 | index = self.__code.find(names[i])
93 |
94 | for j in range(index, 0, -1):
95 | if self.__code[j] == "\n":
96 | from_new_string = self.__code[j + 1 :]
97 | tabs_end = re.search(r"[a-zA-Z]", from_new_string).start()
98 | tabs = from_new_string[:tabs_end]
99 | comments[i] = re.sub(r"\n", f"\n{tabs}", comments[i])
100 | splitted_code = list(self.__code)
101 | splitted_code[j] = f"\n{tabs}/**\n{tabs}{comments[i]}\n{tabs} */\n"
102 | self.__code = "".join(splitted_code)
103 | break
104 | else:
105 | self.__code = f"\n/**\n{comments[i]}\n */\n" + self.__code
106 | return self.__code
107 |
--------------------------------------------------------------------------------
/modules/settings.py:
--------------------------------------------------------------------------------
1 | from colorama import Fore, Style
2 |
3 | RESET = Style.RESET_ALL
4 | GREEN = Fore.GREEN
5 | BLUE = Fore.BLUE
6 | RED = Fore.RED
7 | YELLOW = Fore.YELLOW
8 | BOLD = "\033[1m"
9 |
10 |
11 | class Settings:
12 | supported_languages = ["py", "ts", "js"]
13 | divide_start = {
14 | "py": r"(? 0:
66 | self.__language = "example"
67 |
68 | def __ask(self, code) -> str:
69 | """
70 | Sends a prompt to the chatbot API and returns the response.
71 |
72 | Arguments:
73 |
74 | code (str): A string containing the code prompt to send to the chatbot API.
75 |
76 | Returns:
77 |
78 | str: A string containing the response from the chatbot API.
79 |
80 |
81 | """
82 | response = None
83 | conversation = None
84 | try:
85 | for data in self.__chatbot.ask(
86 | Prompt(self.__language, code).create(),
87 | conversation_id=self.__conversation,
88 | parent_id=None,
89 | ):
90 | response = data["message"]
91 | conversation = data["conversation_id"]
92 | if not self.__conversation:
93 | self.__conversation = conversation
94 | return response
95 | except:
96 | raise ValueError("ChatGPT error")
97 |
98 | def start(self):
99 | """
100 |
101 | Generates comments for the code using the chatbot API.
102 |
103 | Arguments: None
104 |
105 | Returns:
106 |
107 | str: A string containing the original code with comments generated by the chatbot API.
108 | """
109 | with console.status("[bold green] Please wait...") as status:
110 | print(f"[{BLUE}1{RESET}] {BOLD}Dividing text{RESET}")
111 | self.__divided = Divider(self.__code, self.__language).divide()
112 | print(
113 | f"[{BLUE}2{RESET}] {BOLD}Text is divided into {len(self.__divided)} parts{RESET}"
114 | )
115 |
116 | print(f"[{BLUE}3{RESET}] {BOLD}Connecting to ChatGPT{RESET}")
117 | self.__chatbot = Chatbot({"session_token": self.__token})
118 | self.__conversation = None
119 |
120 | self.__count = 1
121 | self.__comments = []
122 | for entity in self.__divided:
123 | print(
124 | f"[{BLUE}4.{self.__count}{RESET}] {BOLD}Chatbot generating comments ({self.__count}/{len(self.__divided)}){RESET}"
125 | )
126 | response = self.__ask(entity)
127 | self.__comments.append(response)
128 | sleep(1)
129 | self.__count += 1
130 |
131 | print(f"[{BLUE}5{RESET}] {BOLD}Merge file and comments{RESET}")
132 | self.__commented_code = self.__code
133 | for comment in self.__comments:
134 | self.__commented_code = Result(
135 | self.__commented_code, comment, self.__language
136 | ).get()
137 |
138 | print(f"[{BLUE}6{RESET}] {BOLD}Ready. Thanks for using!{RESET}"),
139 | return self.__commented_code
140 |
--------------------------------------------------------------------------------
/results/python/divider_commented.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 |
4 | class Divider:
5 | """
6 | A class that takes a text string and a language string, and splits the text into sections based on language-specific separators.
7 |
8 | Arguments:
9 |
10 | text (str): A string of text to be split
11 | language (str): A string representing the language of the text (e.g. "py" for Python)
12 |
13 |
14 | """
15 | def __init__(self, text: str, language: str):
16 | """
17 | Initializes a Divider instance with the given text and language.
18 |
19 | Arguments:
20 |
21 | text (str): A string of text to be split
22 | language (str): A string representing the language of the text (e.g. "py" for Python)
23 |
24 |
25 | """
26 | self.__text = text
27 | self.__language = language
28 | self.__splitted_content = []
29 |
30 | def divide(
31 | self,
32 | ) -> list[str]:
33 | """
34 | Splits the text into sections based on language-specific separators.
35 |
36 | Arguments: None
37 |
38 | Returns:
39 |
40 | list[str]: A list of strings representing the sections of the text.
41 |
42 |
43 | """
44 | if self.__language == "py":
45 | return self.__py()
46 |
47 | def __py(self) -> list[str]:
48 | """
49 |
50 | A method that splits Python code into sections based on class and function definitions.
51 |
52 | Arguments: None
53 |
54 | Returns:
55 |
56 | list[str]: A list of strings representing the sections of the Python code.
57 | """
58 | starts = re.finditer(r"(? str:
32 | """
33 | Retrieves the content of the file.
34 |
35 | Arguments: None
36 |
37 | Returns:
38 |
39 | str: A string representing the content of the file.
40 |
41 |
42 | """
43 | self.__text = open(self.__path, "r").read()
44 | return self.__text
45 |
46 | def language(self) -> str:
47 | """
48 | Retrieves the language of the file.
49 |
50 | Arguments: None
51 |
52 | Returns:
53 |
54 | str: A string representing the language of the file.
55 |
56 |
57 | """
58 | return self.__language
59 |
60 | def create_commented_file(self, content: str) -> None:
61 | """
62 |
63 | Creates a new file with the commented content.
64 |
65 | Arguments:
66 |
67 | content (str): A string representing the commented content to be written into the new file.
68 |
69 | Returns: None
70 | """
71 | path = os.path.join(
72 | self.__dirname,
73 | self.__basename + f"_commented.{self.__language}",
74 | )
75 | open(path, "w").write(content)
76 |
--------------------------------------------------------------------------------
/results/python/prompt_commented.py:
--------------------------------------------------------------------------------
1 | class Prompt:
2 | """
3 | A class for generating prompts for coding exercises in a specified language.
4 |
5 | Arguments:
6 |
7 | language (str): A string representing the language of the prompt (e.g. "python")
8 | text (str): A string representing the code to be used in the prompt.
9 | example_text (str): Optional. A string representing an example usage of the code in the prompt.
10 |
11 |
12 | """
13 | def __init__(self, language: str, text: str, example_text: str = ""):
14 | """
15 | Initializes a Prompt instance with the given language, code, and example text.
16 |
17 | Arguments:
18 |
19 | language (str): A string representing the language of the prompt (e.g. "python")
20 | text (str): A string representing the code to be used in the prompt.
21 | example_text (str): Optional. A string representing an example usage of the code in the prompt.
22 |
23 |
24 | """
25 | self.__text = text
26 | self.__language = language
27 | self.__example_text = example_text
28 |
29 | def create(self) -> str:
30 | """
31 |
32 | Generates a prompt using the given language, code, and example text.
33 |
34 | Arguments: None
35 |
36 | Returns:
37 |
38 | str: A string representing the prompt, with placeholders for the code and example text filled in.
39 | """
40 | if self.__example_text:
41 | return (
42 | open(f"./models/{self.__language}.txt", "r")
43 | .read()
44 | .replace("CODE", self.__text)
45 | .replace("EXAMPLE", self.__example_text)
46 | )
47 | else:
48 | return (
49 | open(f"./models/{self.__language}.txt", "r")
50 | .read()
51 | .replace("CODE", self.__text)
52 | )
53 |
--------------------------------------------------------------------------------
/results/python/result_commented.py:
--------------------------------------------------------------------------------
1 | import re
2 |
3 |
4 | class Result:
5 | """
6 | This class represents a code result with its associated text comment and language.
7 |
8 | Arguments:
9 |
10 | code (str): A string of code.
11 | text_comment (str): A string of text comment associated with the code.
12 | language (str): A string representing the language of the code (e.g. "py" for Python).
13 |
14 |
15 | """
16 | def __init__(self, code: str, text_comment: str, language: str):
17 | """
18 | Initializes a Result instance with the given code, text comment, and language.
19 |
20 | Arguments:
21 |
22 | code (str): A string of code.
23 | text_comment (str): A string of text comment associated with the code.
24 | language (str): A string representing the language of the code (e.g. "py" for Python).
25 |
26 |
27 | """
28 | self.__code = code
29 | self.__text_comment = text_comment
30 | self.__language = language
31 |
32 | def get(self) -> str:
33 | """
34 | Returns a modified version of the code with the text comments included as docstrings for the appropriate class and function definitions in the code.
35 |
36 | Arguments: None
37 |
38 | Returns:
39 |
40 | str: A string representing the modified version of the code.
41 |
42 |
43 | """
44 | if self.__language == "py":
45 | return self.__py()
46 |
47 | def __py(self) -> str:
48 | """
49 | A private method that splits Python code into sections based on the "
50 | """
51 | regexpes = re.finditer(r"\|(.+?)\|", self.__text_comment)
52 | indexes = []
53 |
54 | while True:
55 | try:
56 | match = next(regexpes)
57 | start = match.start()
58 | end = match.end()
59 | indexes.append((start, end))
60 | except:
61 | break
62 |
63 | names = []
64 | comments = []
65 | for i in range(len(indexes)):
66 | """
67 | " and "..." separators in the text comment associated with the code.
68 |
69 | Arguments: None
70 |
71 | Returns:
72 |
73 | str: A string representing the modified version of the Python code.
74 | """
75 | names.append(self.__text_comment[indexes[i][0] + 1 : indexes[i][1] - 1])
76 | if i < len(indexes) - 1:
77 | comments.append(
78 | self.__text_comment[indexes[i][1] + 1 : indexes[i + 1][0]].replace(
79 | "Description: ", ""
80 | )
81 | )
82 | else:
83 | comments.append(
84 | self.__text_comment[indexes[i][1] :].replace("Description: ", "")
85 | )
86 |
87 | for i in range(len(names)):
88 | index = self.__code.index(names[i])
89 | split_start = self.__code[index:]
90 | doubledot = index + split_start.index(":\n") + 1
91 | tabs = re.search(r":\n(.*?)[a-zA-Z]", split_start).span()
92 | tabs_count = tabs[1] - tabs[0]
93 | tab = (tabs_count - 3) * " "
94 | replace_text = self.__code[index:doubledot]
95 | new_replace_text = comments[i].replace("\n", f"\n{tab}")
96 | self.__code = self.__code.replace(
97 | replace_text,
98 | f'{replace_text}\n{tab}"""\n{tab}{new_replace_text}\n{tab}"""',
99 | )
100 | return self.__code
101 |
--------------------------------------------------------------------------------
/results/python/settings_commented.py:
--------------------------------------------------------------------------------
1 | from colorama import Fore, Style
2 |
3 | RESET = Style.RESET_ALL
4 | GREEN = Fore.GREEN
5 | BLUE = Fore.BLUE
6 | RED = Fore.RED
7 | YELLOW = Fore.YELLOW
8 | BOLD = "\033[1m"
9 |
10 |
11 | class Settings:
12 | """
13 |
14 | This class stores the settings for a program.
15 |
16 | Variables:
17 | - supported_languages (list): A list of supported languages.
18 |
19 | Example Usage:
20 | ```python
21 | settings = Settings()
22 | print(settings.supported_languages) # Output: ["py"]
23 | ```
24 |
25 | Note: There are no functions defined in this class.
26 | """
27 | supported_languages = ["py"]
28 |
--------------------------------------------------------------------------------
/results/ts/example_2_commented.ts:
--------------------------------------------------------------------------------
1 | import * as http from "http";
2 |
3 |
4 | /**
5 | *
6 | * This type represents the HTTP methods that can be used for making requests.
7 | * @typedef {'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATСH'} protocols
8 | */
9 | type protocols = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATСH'
10 |
11 |
12 |
13 | /**
14 | * This class represents a server and creates an instance of http.Server.
15 | * @class
16 | *
17 | */
18 | export default class Server {
19 | /**
20 | * A private property that holds an instance of http.Server.
21 | * @type {http.Server}
22 | *
23 | */
24 | private server: http.Server;
25 | /**
26 | * A private property that holds the port number.
27 | * @type {string|number}
28 | *
29 | */
30 | private port!: string | number;
31 | /**
32 | * Creates a new Server instance with the given serverResponse and serverError functions.
33 | * @constructor
34 | * @param {function} serverResponse - The function that will handle server response.
35 | * @param {function} serverError - The function that will handle server error.
36 | *
37 | */
38 | constructor(serverResponse: (data: string, req: http.IncomingMessage, res: http.ServerResponse) => void, serverError: (req: http.IncomingMessage, res: http.ServerResponse) => void) {
39 | this.server = http
40 | .createServer((req: http.IncomingMessage, res: http.ServerResponse) => {
41 | if (req.method == "GET") {
42 | if (req.url) {
43 | let body = '';
44 | req.on('data', chunk => {
45 | body += chunk.toString();
46 | });
47 | req.on('end', () => {
48 | res.setHeader('Content-Type', 'application/json');
49 | try {
50 | serverResponse(body, req, res);
51 | } catch (error) {
52 | serverError(req, res)
53 | }
54 | });
55 | }
56 | }
57 | })
58 | }
59 |
60 | /**
61 | *
62 | * Starts the server on the specified port.
63 | * @param {string|number} port - The port number on which the server will listen.
64 | * @returns {void}
65 | */
66 | public listen(port: string | number,) {
67 | this.port = port;
68 | this.server.listen(this.port);
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/results/ts/example_commented.ts:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * This class represents a Pizza and has a constructor that initializes its name and toppings.
4 | * @class
5 | *
6 | */
7 | class Pizza {
8 | constructor(
9 | /**
10 | * A public property that holds the name of the pizza.
11 | * @type {string}
12 | *
13 | */
14 | public name: string,
15 | /**
16 | *
17 | * A public property that holds an array of strings representing the pizza toppings.
18 | * @type {string[]}
19 | */
20 | public toppings: string[]
21 | ) { };
22 | }
23 | /**
24 | * This class provides a static method to create a Pizza object.
25 | * @class
26 | *
27 | */
28 | class PizzaMaker {
29 | /**
30 | * Creates a new Pizza object with the given name and toppings.
31 | * @static
32 | * @param {Pizza} event - The Pizza object to create.
33 | * @returns {Pizza} - The newly created Pizza object.
34 | *
35 | */
36 | static create(event: Pizza) {
37 | return new Pizza(
38 | event.name,
39 | event.toppings
40 | );
41 | }
42 | }
43 | /**
44 | *
45 | * Creates a new Pizza object using the PizzaMaker class.
46 | * @const
47 | * @type {Pizza}
48 | */
49 | const pizza = PizzaMaker.create({
50 | name: 'Inferno',
51 | toppings: ['cheese', 'peppers']
52 | });
--------------------------------------------------------------------------------