faizee07 commited on
Commit
e923fbd
·
verified ·
1 Parent(s): 9651c0a

Upload 4 files

Browse files
Files changed (4) hide show
  1. Dockerfile +25 -0
  2. app.py +133 -0
  3. index.html +73 -0
  4. style.css +98 -0
Dockerfile ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use an official Python runtime as a parent image
2
+ FROM python:3.9-slim
3
+
4
+ # Set the working directory in the container
5
+ WORKDIR /code
6
+
7
+ # Copy the dependencies file to the working directory
8
+ COPY requirements.txt .
9
+
10
+ # Install any needed packages specified in requirements.txt
11
+ # We also need git to be installed in the container
12
+ RUN apt-get update && apt-get install -y git && \
13
+ pip install --no-cache-dir -r requirements.txt
14
+
15
+ # Copy the rest of the application code to the working directory
16
+ COPY . .
17
+
18
+ # Make port 7860 available to the world outside this container
19
+ EXPOSE 7860
20
+
21
+ # Define environment variable
22
+ ENV PORT=7860
23
+
24
+ # Run app.py when the container launches
25
+ CMD ["python", "app.py"]
app.py ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import shutil
3
+ import tempfile
4
+ from flask import Flask, request, jsonify, render_template
5
+ import git
6
+ import json
7
+
8
+ app = Flask(__name__)
9
+
10
+ def analyze_repo(repo_path):
11
+ """
12
+ Analyzes the cloned repository to gather information.
13
+ This is a simplified analysis function. A real-world agent
14
+ would be much more sophisticated.
15
+ """
16
+ project_name = os.path.basename(repo_path)
17
+ language = "Not Detected"
18
+ dependencies = []
19
+ install_command = "No install command found."
20
+ run_command = "No run command found."
21
+
22
+ # --- Technology and Dependency Analysis ---
23
+ if os.path.exists(os.path.join(repo_path, 'requirements.txt')):
24
+ language = "Python"
25
+ with open(os.path.join(repo_path, 'requirements.txt'), 'r') as f:
26
+ dependencies = [line.strip() for line in f.readlines() if line.strip()]
27
+ install_command = "pip install -r requirements.txt"
28
+ # Try to find a common run command
29
+ if os.path.exists(os.path.join(repo_path, 'app.py')) or os.path.exists(os.path.join(repo_path, 'main.py')):
30
+ run_command = "python app.py # or python main.py"
31
+
32
+
33
+ elif os.path.exists(os.path.join(repo_path, 'package.json')):
34
+ language = "JavaScript (Node.js)"
35
+ with open(os.path.join(repo_path, 'package.json'), 'r') as f:
36
+ package_data = json.load(f)
37
+ dependencies = list(package_data.get('dependencies', {}).keys())
38
+ install_command = "npm install"
39
+ if package_data.get('scripts', {}).get('start'):
40
+ run_command = "npm start"
41
+ else:
42
+ run_command = "node index.js # or appropriate script"
43
+
44
+ # Simple logic to infer project purpose from file names
45
+ purpose = f"A {language} project."
46
+ if 'test' in str(os.listdir(repo_path)).lower():
47
+ purpose += " It appears to have testing capabilities."
48
+ if 'dockerfile' in str(os.listdir(repo_path)).lower():
49
+ purpose += " It can be containerized using Docker."
50
+
51
+ return {
52
+ "project_name": project_name,
53
+ "language": language,
54
+ "dependencies": dependencies,
55
+ "install_command": install_command,
56
+ "run_command": run_command,
57
+ "purpose": purpose
58
+ }
59
+
60
+ def generate_readme_content(analysis):
61
+ """Generates the README.md content from the analysis results."""
62
+
63
+ readme = f"# {analysis['project_name']}\n\n"
64
+ readme += f"## 🤖 About This Project\n\n{analysis['purpose']}\n\n"
65
+ readme += f"This project is primarily written in **{analysis['language']}**.\n\n"
66
+
67
+ readme += "## 🚀 Getting Started\n\n"
68
+ readme += "### Prerequisites\n\n"
69
+ readme += f"Make sure you have {analysis['language']} and the necessary build tools installed on your system.\n\n"
70
+
71
+ readme += "### Installation\n\n"
72
+ readme += "1. Clone the repository:\n"
73
+ readme += " ```sh\n git clone <repository_url>\n ```\n"
74
+ readme += "2. Navigate to the project directory:\n"
75
+ readme += f" ```sh\n cd {analysis['project_name']}\n ```\n"
76
+ readme += "3. Install the dependencies:\n"
77
+ readme += f" ```sh\n {analysis['install_command']}\n ```\n\n"
78
+
79
+ if analysis['dependencies']:
80
+ readme += "Key dependencies include:\n"
81
+ for dep in analysis['dependencies'][:5]: # Show first 5 dependencies
82
+ readme += f"- `{dep}`\n"
83
+ readme += "\n"
84
+
85
+ readme += "### Usage\n\n"
86
+ readme += "To run the project, execute the following command:\n"
87
+ readme += f"```sh\n{analysis['run_command']}\n```\n\n"
88
+
89
+ readme += "---\n"
90
+ readme += "*This README was automatically generated by an AI agent.*"
91
+
92
+ return readme
93
+
94
+ @app.route('/')
95
+ def index():
96
+ return render_template('index.html')
97
+
98
+ @app.route('/generate', methods=['POST'])
99
+ def generate():
100
+ data = request.get_json()
101
+ repo_url = data.get('url')
102
+
103
+ if not repo_url:
104
+ return jsonify({"error": "GitHub repository URL is required."}), 400
105
+
106
+ temp_dir = tempfile.mkdtemp()
107
+
108
+ try:
109
+ # --- Agent Tool 1: Git Clone ---
110
+ print(f"Cloning repository: {repo_url} into {temp_dir}")
111
+ git.Repo.clone_from(repo_url, temp_dir)
112
+
113
+ # --- Agent Tool 2: File Analysis ---
114
+ print("Analyzing repository structure...")
115
+ analysis_result = analyze_repo(temp_dir)
116
+
117
+ # --- Agent Step 3: Write README ---
118
+ print("Generating README content...")
119
+ readme_content = generate_readme_content(analysis_result)
120
+
121
+ return jsonify({"readme": readme_content})
122
+
123
+ except git.exc.GitCommandError as e:
124
+ return jsonify({"error": f"Failed to clone repository. Is the URL correct and public? Error: {e}"}), 500
125
+ except Exception as e:
126
+ return jsonify({"error": f"An unexpected error occurred: {str(e)}"}), 500
127
+ finally:
128
+ # --- Cleanup ---
129
+ print(f"Cleaning up temporary directory: {temp_dir}")
130
+ shutil.rmtree(temp_dir)
131
+
132
+ if __name__ == '__main__':
133
+ app.run(host='0.0.0.0', port=int(os.environ.get("PORT", 7860)))
index.html ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>GitHub README Generator</title>
7
+ <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
8
+ </head>
9
+ <body>
10
+ <div class="container">
11
+ <h1>GitHub README Generator 💻</h1>
12
+ <p>Enter a public GitHub repository URL and let the AI agent generate a professional README.md for you.</p>
13
+
14
+ <form id="repo-form">
15
+ <div class="input-group">
16
+ <input type="url" id="repo-url" placeholder="e.g., https://github.com/user/project" required>
17
+ <button type="submit">Generate</button>
18
+ </div>
19
+ </form>
20
+
21
+ <div class="loader" id="loader"></div>
22
+
23
+ <div id="result-container" style="display: none;">
24
+ <h2>Generated README.md:</h2>
25
+ <pre id="result"></pre>
26
+ </div>
27
+ </div>
28
+
29
+ <script>
30
+ document.getElementById('repo-form').addEventListener('submit', async function(event) {
31
+ event.preventDefault();
32
+
33
+ const url = document.getElementById('repo-url').value;
34
+ const loader = document.getElementById('loader');
35
+ const resultContainer = document.getElementById('result-container');
36
+ const resultDiv = document.getElementById('result');
37
+
38
+ // Show loader and hide previous result
39
+ loader.style.display = 'block';
40
+ resultContainer.style.display = 'none';
41
+ resultDiv.textContent = '';
42
+
43
+ try {
44
+ const response = await fetch('/generate', {
45
+ method: 'POST',
46
+ headers: {
47
+ 'Content-Type': 'application/json'
48
+ },
49
+ body: JSON.stringify({ url: url })
50
+ });
51
+
52
+ const data = await response.json();
53
+
54
+ if (response.ok) {
55
+ resultDiv.textContent = data.readme;
56
+ resultContainer.style.display = 'block';
57
+ } else {
58
+ resultDiv.textContent = 'Error: ' + data.error;
59
+ resultContainer.style.display = 'block';
60
+ }
61
+
62
+ } catch (error) {
63
+ resultDiv.textContent = 'An unexpected error occurred: ' + error.toString();
64
+ resultContainer.style.display = 'block';
65
+ } finally {
66
+ // Hide loader
67
+ loader.style.display = 'none';
68
+ }
69
+ });
70
+ </script>
71
+ </body>
72
+ </html>
73
+
style.css ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');
2
+
3
+ body {
4
+ font-family: 'Inter', sans-serif;
5
+ background-color: #f0f2f5;
6
+ color: #1c1e21;
7
+ margin: 0;
8
+ display: flex;
9
+ justify-content: center;
10
+ align-items: center;
11
+ min-height: 100vh;
12
+ }
13
+
14
+ .container {
15
+ background-color: #ffffff;
16
+ padding: 40px 50px;
17
+ border-radius: 12px;
18
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
19
+ width: 100%;
20
+ max-width: 700px;
21
+ text-align: center;
22
+ }
23
+
24
+ h1 {
25
+ font-size: 2.5em;
26
+ color: #1877f2;
27
+ margin-bottom: 10px;
28
+ }
29
+
30
+ p {
31
+ color: #606770;
32
+ font-size: 1.1em;
33
+ margin-bottom: 30px;
34
+ }
35
+
36
+ .input-group {
37
+ display: flex;
38
+ margin-bottom: 20px;
39
+ }
40
+
41
+ #repo-url {
42
+ flex-grow: 1;
43
+ padding: 15px;
44
+ border: 1px solid #dddfe2;
45
+ border-radius: 6px 0 0 6px;
46
+ font-size: 1em;
47
+ outline: none;
48
+ }
49
+
50
+ #repo-url:focus {
51
+ border-color: #1877f2;
52
+ box-shadow: 0 0 0 2px rgba(24, 119, 242, 0.2);
53
+ }
54
+
55
+ button {
56
+ padding: 15px 25px;
57
+ border: none;
58
+ background-color: #1877f2;
59
+ color: white;
60
+ font-size: 1em;
61
+ font-weight: 600;
62
+ border-radius: 0 6px 6px 0;
63
+ cursor: pointer;
64
+ transition: background-color 0.3s;
65
+ }
66
+
67
+ button:hover {
68
+ background-color: #166fe5;
69
+ }
70
+
71
+ .loader {
72
+ border: 4px solid #f3f3f3;
73
+ border-top: 4px solid #1877f2;
74
+ border-radius: 50%;
75
+ width: 40px;
76
+ height: 40px;
77
+ animation: spin 1s linear infinite;
78
+ margin: 30px auto;
79
+ display: none; /* Hidden by default */
80
+ }
81
+
82
+ @keyframes spin {
83
+ 0% { transform: rotate(0deg); }
84
+ 100% { transform: rotate(360deg); }
85
+ }
86
+
87
+ #result {
88
+ margin-top: 30px;
89
+ padding: 20px;
90
+ background-color: #f7f7f7;
91
+ border: 1px solid #dddfe2;
92
+ border-radius: 6px;
93
+ text-align: left;
94
+ white-space: pre-wrap; /* Allows text to wrap */
95
+ font-family: 'Courier New', Courier, monospace;
96
+ max-height: 400px;
97
+ overflow-y: auto;
98
+ }