pip install markdown openai anthropic
Step 2: Update docstring_generator.py
This utility will generate enhanced Markdown and HTML documentation from Python code, including AI-generated explanations and examples.
File to update: app/utils/docstring_generator.py
import os
import requests
from .code_parser import extract_functions_and_classes, extract_function_signature, extract_class_metadata
from dotenv import load_dotenv
from .query_handler import explain_code
load_dotenv()
DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY")
def generate_docstring(code_snippet, context=None):
"""
Generate a docstring for a given code snippet using DeepSeek.
"""
prompt = f"""
Generate a docstring for the following Python code. Follow PEP-257 standards and include:
- A one-line summary.
- A detailed description (if necessary).
- Args (for functions).
- Returns (for functions).
- Raises (if applicable).
Code:
{code_snippet}
Context:
{context if context else "No additional context provided."}
"""
headers = {
"Authorization": f"Bearer {DEEPSEEK_API_KEY}",
"Content-Type": "application/json"
}
data = {
"model": "deepseek-chat", # Specify the model
"prompt": prompt,
"max_tokens": 200,
"temperature": 0.7
}
response = requests.post(
"https://api.deepseek.com/beta/completions",
headers=headers,
json=data
)
if response.status_code == 200:
return response.json()["choices"][0]["text"].strip()
else:
# Print the response details for debugging
print(f"API Response: {response.status_code}, {response.text}")
raise Exception(f"Failed to generate docstring: {response.status_code}")
def improve_docstring(existing_docstring, context=None):
"""
Improve an existing docstring using DeepSeek.
"""
prompt = f"""
Improve the following docstring for clarity, readability, and completeness. Convert passive voice to active voice where applicable.
Docstring:
{existing_docstring}
Context:
{context if context else "No additional context provided."}
"""
headers = {
"Authorization": f"Bearer {DEEPSEEK_API_KEY}",
"Content-Type": "application/json"
}
data = {
"model": "deepseek-chat", # Specify the model
"prompt": prompt,
"max_tokens": 200,
"temperature": 0.7
}
response = requests.post(
"https://api.deepseek.com/beta/completions", # Use the beta endpoint
headers=headers,
json=data
)
if response.status_code == 200:
return response.json()["choices"][0]["text"].strip()
else:
# Print the response details for debugging
print(f"API Response: {response.status_code}, {response.text}")
raise Exception(f"Failed to improve docstring: {response.status_code}")
def generate_markdown_docs(code):
"""
Generate enhanced Markdown documentation from Python code using AI.
"""
functions, classes = extract_functions_and_classes(code)
docs = "# API Documentation\n\n"
# Add function documentation
docs += "## Functions\n\n"
for func in functions:
signature = extract_function_signature(func)
docs += f"### `{signature['name']}`\n"
docs += f"**Arguments:** `{', '.join(signature['args'])}`\n\n"
docs += f"**Returns:** `{signature['returns']}`\n\n"
# Generate AI explanation for the function
explanation = explain_code(func, f"What does the function `{signature['name']}` do?")
docs += f"**Explanation:** {explanation}\n\n"
# Generate AI example usage for the function
example = explain_code(func, f"Provide an example usage for the function `{signature['name']}`.")
docs += f"**Example Usage:**\n```python\n{example}\n```\n\n"
# Add class documentation
docs += "## Classes\n\n"
for cls in classes:
metadata = extract_class_metadata(cls)
docs += f"### `{metadata['name']}`\n"
docs += f"**Methods:** `{', '.join(metadata['methods'])}`\n\n"
docs += f"**Docstring:** {metadata['docstring']}\n\n"
# Generate AI explanation for the class
explanation = explain_code(cls, f"What does the class `{metadata['name']}` do?")
docs += f"**Explanation:** {explanation}\n\n"
# Generate AI example usage for the class
example = explain_code(cls, f"Provide an example usage for the class `{metadata['name']}`.")
docs += f"**Example Usage:**\n```python\n{example}\n```\n\n"
return docs
def generate_html_docs(markdown_docs):
"""
Convert Markdown documentation to HTML.
"""
import markdown
return markdown.markdown(markdown_docs)
def save_docs(docs, filename):
"""
Save documentation to a file in the /docs folder.
If the /docs folder doesn't exist, create it.
"""
# Ensure the /docs folder exists
os.makedirs("docs", exist_ok=True)
# Save the file in the /docs folder
with open(f"docs/{filename}", "w") as f:
f.write(docs)
def push_to_github(docs, repo_name, branch="gh-pages"):
"""
Push documentation to GitHub Pages.
"""
import subprocess
# Save docs to a temporary file in the /docs folder
save_docs(docs, "index.html")
# Push the /docs folder to GitHub Pages
subprocess.run(["git", "add", "docs/"])
subprocess.run(["git", "commit", "-m", "Update documentation"])
subprocess.run(["git", "push", "origin", branch])
def detect_outdated_docs(code, docs):
"""
Detect outdated documentation by comparing code and docs.
"""
current_docs = generate_markdown_docs(code)
if current_docs != docs:
return "Documentation is outdated. Please regenerate."
return "Documentation is up-to-date."
def tag_documentation_version(version):
"""
Tag the current documentation with a version number.
"""
import subprocess
subprocess.run(["git", "tag", f"v{version}"])
subprocess.run(["git", "push", "origin", f"v{version}"])
Understand new imports and functions:
- Imports:
extract_functions_and_classes
, extract_function_signature
, and extract_class_metadata
from code_parser
: These functions analyze the code to extract functions, retrieve function signatures, and gather class metadata.
explain_code
from query_handler
: This function leverages an AI model to explain code functionality, aiding in generating clear documentation.
generate_markdown_docs
, generate_html_docs
, save_docs
, and push_to_github
from query_handler
: These functions handle documentation generation, conversion to HTML, saving to the local file system, and pushing to GitHub for hosting.
- Functions:
extract_functions_and_classes
: This function scans the code and identifies functions and classes for documentation purposes.
extract_function_signature
: This function retrieves the function name, arguments, and return type.
extract_class_metadata
: This function gathers class-level details, such as methods and docstrings.
explain_code
: This function sends code snippets to an AI model to generate explanations and examples.
generate_markdown_docs
: This function generates structured Markdown documentation from the extracted functions and classes.
generate_html_docs
: This function converts Markdown documentation into HTML format.
save_docs
: This function saves the documentation to a file in the /docs
folder.
push_to_github
: This function pushes the documentation to a specified GitHub repository and branch.
Step 3: Update routes.py
file
Update the routes.py
file to include the new /generate-docs
route and integrate it with the chatbot interface.
File to Update: app/routes.py
from flask import Blueprint, jsonify, request, render_template
from .utils.docstring_generator import generate_docstring, improve_docstring, generate_markdown_docs, generate_html_docs, save_docs
from app.utils.github_api import fetch_repo_contents, filter_python_files, download_file_contents
from app.utils.code_parser import extract_functions_and_classes, extract_function_signature, extract_class_metadata
from .utils.query_handler import explain_code
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
import os
main_bp = Blueprint('main', __name__)
# Rate limiting for API endpoints
limiter = Limiter(key_func=get_remote_address)
@main_bp.route('/')
def home():
return render_template("index.html")
@main_bp.route('/generate-docstring', methods=['POST'])
def generate_docstring_route():
"""
Generate a docstring for a given code snippet.
"""
data = request.json
code_snippet = data.get("code")
context = data.get("context", "")
try:
docstring = generate_docstring(code_snippet, context)
return jsonify({"docstring": docstring})
except Exception as e:
return jsonify({"error": str(e)}), 500
@main_bp.route("/fetch-repo", methods=["POST"])
def fetch_repo():
"""
Fetch and display Python files from a GitHub repository.
"""
data = request.json
owner = data.get("owner")
repo = data.get("repo")
try:
contents = fetch_repo_contents(owner, repo)
python_files = filter_python_files(contents)
return jsonify({"python_files": python_files})
except Exception as e:
return jsonify({"error": str(e)}), 500
@main_bp.route("/parse-file", methods=["POST"])
def parse_file():
"""
Parse a Python file and extract metadata.
"""
data = request.json
download_url = data.get("download_url")
try:
code = download_file_contents(download_url)
functions, classes = extract_functions_and_classes(code)
function_metadata = [extract_function_signature(func) for func in functions]
class_metadata = [extract_class_metadata(cls) for cls in classes]
return jsonify({
"functions": function_metadata,
"classes": class_metadata
})
except Exception as e:
return jsonify({"error": str(e)}), 500
@main_bp.route("/improve-docstring", methods=["POST"])
def improve_docstring_route():
"""
Improve an existing docstring.
"""
data = request.json
existing_docstring = data.get("docstring")
context = data.get("context", "")
try:
improved_docstring = improve_docstring(existing_docstring, context)
return jsonify({"improved_docstring": improved_docstring})
except Exception as e:
return jsonify({"error": str(e)}), 500
@main_bp.route("/explain-code", methods=["POST"])
@limiter.limit("10 per minute")
def explain_code_route():
"""
Explain code functionality based on a natural language query.
"""
data = request.json
code_snippet = data.get("code")
query = data.get("query")
try:
explanation = explain_code(code_snippet, query)
return jsonify({"explanation": explanation})
except Exception as e:
return jsonify({"error": str(e)}), 500
@main_bp.route("/chatbot", methods=["POST"])
@limiter.limit("10 per minute") # Rate limit to prevent abuse
def chatbot_route():
"""
Chatbot endpoint for interactive code understanding.
"""
data = request.json
user_input = data.get("input")
code_snippet = data.get("code", "")
try:
# Use the same explain_code utility for chatbot responses
response = explain_code(code_snippet, user_input)
return jsonify({"response": response})
except Exception as e:
return jsonify({"error": str(e)}), 500
@main_bp.route("/generate-docs", methods=["POST"])
def generate_docs_route():
"""
Generate Markdown and HTML documentation from a code snippet.
"""
data = request.json
code_snippet = data.get("code")
try:
# Generate Markdown documentation
markdown_docs = generate_markdown_docs(code_snippet)
save_docs(markdown_docs, "docs.md") # Save Markdown to /docs/docs.md
# Generate HTML documentation
html_docs = generate_html_docs(markdown_docs)
save_docs(html_docs, "index.html") # Save HTML to /docs/index.html
return jsonify({
"message": "Documentation generated successfully!",
"markdown_docs": markdown_docs,
"html_docs": html_docs
})
except Exception as e:
return jsonify({"error": str(e)}), 500
The /generate-docs
route in this Flask application allows users to generate documentation from a provided code snippet. Here’s how it works:
- Receive Input: The route listens for a POST request and expects a JSON payload with a
code
field that contains the code snippet to document.
- Generate Markdown Documentation: The
generate_markdown_docs
function processes the code snippet and produces Markdown-formatted documentation. The code saves this output as docs.md
in the /docs
directory using the save_docs
function.
- Convert to HTML: The route then calls the
generate_html_docs
function to convert the Markdown documentation into HTML format. It saves the resulting file as index.html
in the same /docs
directory.
- Return the Response: If successful, the route responds with a JSON object that includes a success message and the generated Markdown and HTML documentation. If an error occurs, the route catches the exception and returns a JSON object with the error message and a
500
status code.
This route streamlines the process of generating and saving both Markdown and HTML documentation for code snippets.
Step 4: Create and push the gh-pages
Branch
- Create the
gh-pages
Branch:
- Run the following commands in your terminal to create and switch to the
gh-pages
branch:
git checkout -b gh-pages
- Push the branch to GitHub:
- Push the
gh-pages
branch to your GitHub repository:
git push origin gh-pages
Step 5: Enable GitHub Pages for your repository
- Go to Your Repository:
- Open Repository Settings:
- Click on the Settings tab in your repository.
- Enable GitHub Pages:
- Scroll down to the Pages section in the left sidebar.
- Under Source, select the
gh-pages
branch and the /docs
folder.
- Click Save.
- Verify GitHub Pages URL:
- Once enabled, GitHub will provide you with a URL for your hosted documentation (e.g.,
https://henrymbuguak.github.io/ai-doc-assistant/
).
Step 6: Integrate documentation generation with Chatbot
- Update the Chatbot Interface:
- Modify the chatbot interface to call the
/generate-docs
route after displaying the DeepSeek response.
- Here’s the updated HTML and JavaScript code for the chatbot interface:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Doc Assistant</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
padding: 20px;
}
.response-box {
margin-top: 20px;
padding: 15px;
border: 1px solid #ddd;
border-radius: 5px;
background-color: #f9f9f9;
}
.loading-spinner {
display: none; /* Hidden by default */
margin-top: 10px;
}
</style>
</head>
<body>
<div class="container">
<h1 class="text-center">Welcome to the AI-Powered Documentation Assistant!</h1>
<p class="text-center">Use the chatbot below to ask questions about your code.</p>
<!-- Chatbot Form -->
<div class="row justify-content-center">
<div class="col-md-8">
<!-- Code Input Field -->
<div class="mb-3">
<label for="codeInput" class="form-label">Paste your Python code here:</label>
<textarea class="form-control" id="codeInput" rows="5" placeholder="Example: def add(a, b): return a + b"></textarea>
<small class="form-text text-muted">Enter the Python code you want to ask questions about.</small>
</div>
<!-- Query Input Field -->
<div class="mb-3">
<label for="userQuery" class="form-label">Ask a question about the code:</label>
<input type="text" class="form-control" id="userQuery" placeholder="Example: What does this function do?">
<small class="form-text text-muted">Type your question in natural language.</small>
</div>
<!-- Ask Button -->
<button class="btn btn-primary" onclick="sendQuery()">Ask</button>
<!-- Loading Spinner -->
<div class="loading-spinner text-center">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-2">Your query is being processed. Please wait a few seconds...</p>
</div>
<!-- Response Box -->
<div class="response-box mt-3" id="responseBox">
<strong>Response:</strong>
<p id="response"></p>
</div>
</div>
</div>
</div>
<!-- Bootstrap JS and dependencies -->
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.min.js"></script>
<script>
async function sendQuery() {
const code = document.getElementById("codeInput").value;
const query = document.getElementById("userQuery").value;
const responseElement = document.getElementById("response");
const responseBox = document.getElementById("responseBox");
const loadingSpinner = document.querySelector(".loading-spinner");
// Show loading spinner and hide response box
loadingSpinner.style.display = "block";
responseBox.style.display = "none";
try {
// Step 1: Send the query to the chatbot endpoint
const chatbotResponse = await fetch("/chatbot", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ input: query, code: code })
});
const chatbotData = await chatbotResponse.json();
// Hide loading spinner and show response
loadingSpinner.style.display = "none";
responseBox.style.display = "block";
if (chatbotData.response) {
responseElement.innerText = chatbotData.response;
} else {
responseElement.innerText = "Error: " + (chatbotData.error || "No response received.");
}
// Step 2: Automatically generate documentation after displaying the chatbot response
await generateDocumentation(code);
} catch (error) {
// Handle network or other errors
loadingSpinner.style.display = "none";
responseBox.style.display = "block";
responseElement.innerText = "Error: " + error.message;
}
}
// Function to generate documentation
async function generateDocumentation(code) {
try {
// Call the /generate-docs endpoint
const docsResponse = await fetch("/generate-docs", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ code: code })
});
const docsData = await docsResponse.json();
// Display documentation generation success message
const responseElement = document.getElementById("response");
responseElement.innerText += "\n\nDocumentation generated successfully! Check the /docs folder.";
} catch (error) {
console.error("Error generating documentation:", error);
const responseElement = document.getElementById("response");
responseElement.innerText += "\n\nFailed to generate documentation. Please try again.";
}
}
</script>
</body>
</html>
The /generate-docs
functionality in the provided code automates the creation of both Markdown and HTML documentation from a Python code snippet. Here’s how the process works:
- User Input Handling: When the user pastes a Python code snippet and submits a query, the
sendQuery()
function sends a request to the /chatbot
endpoint. After receiving a response from the chatbot, the function automatically triggers the documentation generation process.
- Generating Documentation: The
generateDocumentation()
function sends a POST request to the /generate-docs
endpoint. It passes the user’s code as JSON data in the request body.
- Receiving and Handling the Response: The server processes the code, generates Markdown documentation, converts it to HTML, and saves both files (
docs.md
and index.html
) in the /docs
folder. If the operation succeeds, the response informs the user that the documentation was successfully generated.
- Error Handling: If the documentation generation fails, the function logs the error to the console and notifies the user of the failure.
This approach ensures that the system efficiently handles the code analysis and automatically creates documentation to enhance code understanding and maintainability.
Step 7: Run Flask and test the Chatbot interface
- Run Flask:
- Start the Flask app by running the following command in your terminal:
python run.py
- Access the Chatbot interface:
- Open your browser and navigate to
http://127.0.0.1:5000
.
- You should see the chatbot interface.
- Test the Chatbot:
- Paste your Python code into the Code Input Field.
- Ask a question about the code in the Query Input Field.
- Click the Ask button to see the chatbot’s response.
- After the chatbot responds, it will automatically generate documentation and display a success message.
Step 8: Push the generated documentation to GitHub Pages
- Commit and push the documentation:
- Verify your documentation on GitHub Pages:
- Open your browser and navigate to the GitHub Pages URL provided in the Settings tab (e.g.,
https://henrymbuguak.github.io/ai-doc-assistant/
).
- Ensure the documentation is displayed correctly and matches the generated
index.html
file.
Lesson 10: Compare DeepSeek with OpenAI GPT and Claude
When building an AI-powered documentation assistant, it’s important to evaluate different AI tools to determine which one best suits your needs. DeepSeek, OpenAI GPT, and Claude are all powerful AI models, but they differ in terms of performance, cost, and ease of integration. By comparing these tools, you can make an informed decision about which one to use for generating documentation.
- DeepSeek: A cost-effective and efficient AI model designed for code understanding and documentation generation.
- OpenAI GPT: A widely-used AI model known for its versatility and high-quality text generation.
- Claude: An AI model from Anthropic, optimized for natural language tasks and documentation.
Comparing these tools allows you to:
- Evaluate the quality of generated documentation.
- Understand the cost implications of using each tool.
- Choose the best tool for your specific use case.
Step 1: Obtain API Keys for OpenAI and Anthropic
- Get OpenAI API Key:
- Get Anthropic API Key:
Facebook Comments