faizee07 commited on
Commit
38b6337
·
verified ·
1 Parent(s): 68fb9ad

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +91 -160
app.py CHANGED
@@ -7,7 +7,7 @@ import json
7
 
8
  app = Flask(__name__)
9
 
10
- # --- HTML and CSS are now embedded inside the Python file ---
11
  HTML_TEMPLATE = """
12
  <!DOCTYPE html>
13
  <html lang="en">
@@ -17,163 +17,44 @@ HTML_TEMPLATE = """
17
  <title>GitHub README Generator</title>
18
  <style>
19
  @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');
20
-
21
- body {
22
- font-family: 'Inter', sans-serif;
23
- background-color: #f0f2f5;
24
- color: #1c1e21;
25
- margin: 0;
26
- display: flex;
27
- justify-content: center;
28
- align-items: center;
29
- min-height: 100vh;
30
- padding: 20px;
31
- box-sizing: border-box;
32
- }
33
-
34
- .container {
35
- background-color: #ffffff;
36
- padding: 40px 50px;
37
- border-radius: 12px;
38
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
39
- width: 100%;
40
- max-width: 700px;
41
- text-align: center;
42
- }
43
-
44
- h1 {
45
- font-size: 2.2em;
46
- color: #1877f2;
47
- margin-bottom: 10px;
48
- }
49
-
50
- p {
51
- color: #606770;
52
- font-size: 1.1em;
53
- margin-bottom: 30px;
54
- }
55
-
56
- .input-group {
57
- display: flex;
58
- margin-bottom: 20px;
59
- }
60
-
61
- #repo-url {
62
- flex-grow: 1;
63
- padding: 15px;
64
- border: 1px solid #dddfe2;
65
- border-radius: 6px 0 0 6px;
66
- font-size: 1em;
67
- outline: none;
68
- min-width: 0; /* Fix for flexbox shrinking */
69
- }
70
-
71
- #repo-url:focus {
72
- border-color: #1877f2;
73
- box-shadow: 0 0 0 2px rgba(24, 119, 242, 0.2);
74
- }
75
-
76
- button {
77
- padding: 15px 25px;
78
- border: none;
79
- background-color: #1877f2;
80
- color: white;
81
- font-size: 1em;
82
- font-weight: 600;
83
- border-radius: 0 6px 6px 0;
84
- cursor: pointer;
85
- transition: background-color 0.3s;
86
- }
87
-
88
- button:hover {
89
- background-color: #166fe5;
90
- }
91
-
92
- .loader {
93
- border: 4px solid #f3f3f3;
94
- border-top: 4px solid #1877f2;
95
- border-radius: 50%;
96
- width: 40px;
97
- height: 40px;
98
- animation: spin 1s linear infinite;
99
- margin: 30px auto;
100
- display: none; /* Hidden by default */
101
- }
102
-
103
- @keyframes spin {
104
- 0% { transform: rotate(0deg); }
105
- 100% { transform: rotate(360deg); }
106
- }
107
-
108
- #result-container {
109
- display: none; /* Hidden by default */
110
- margin-top: 20px;
111
- }
112
-
113
- #result {
114
- margin-top: 10px;
115
- padding: 20px;
116
- background-color: #f7f7f7;
117
- border: 1px solid #dddfe2;
118
- border-radius: 6px;
119
- text-align: left;
120
- white-space: pre-wrap; /* Allows text to wrap */
121
- font-family: 'Courier New', Courier, monospace;
122
- max-height: 400px;
123
- overflow-y: auto;
124
- word-wrap: break-word;
125
- }
126
  </style>
127
  </head>
128
  <body>
129
  <div class="container">
130
  <h1>GitHub README Generator 💻</h1>
131
  <p>Enter a public GitHub repository URL and let the AI agent generate a professional README.md for you.</p>
132
-
133
- <form id="repo-form">
134
- <div class="input-group">
135
- <input type="url" id="repo-url" placeholder="e.g., https://github.com/user/project" required>
136
- <button type="submit">Generate</button>
137
- </div>
138
- </form>
139
-
140
  <div class="loader" id="loader"></div>
141
-
142
- <div id="result-container">
143
- <h2>Generated README.md:</h2>
144
- <pre id="result"></pre>
145
- </div>
146
  </div>
147
-
148
  <script>
149
  document.getElementById('repo-form').addEventListener('submit', async function(event) {
150
  event.preventDefault();
151
-
152
  const url = document.getElementById('repo-url').value;
153
  const loader = document.getElementById('loader');
154
  const resultContainer = document.getElementById('result-container');
155
  const resultDiv = document.getElementById('result');
156
-
157
  loader.style.display = 'block';
158
  resultContainer.style.display = 'none';
159
  resultDiv.textContent = '';
160
-
161
  try {
162
- const response = await fetch('/generate', {
163
- method: 'POST',
164
- headers: { 'Content-Type': 'application/json' },
165
- body: JSON.stringify({ url: url })
166
- });
167
-
168
  const data = await response.json();
169
-
170
- if (response.ok) {
171
- resultDiv.textContent = data.readme;
172
- } else {
173
- resultDiv.textContent = 'Error: ' + data.error;
174
- }
175
  resultContainer.style.display = 'block';
176
-
177
  } catch (error) {
178
  resultDiv.textContent = 'An unexpected error occurred: ' + error.toString();
179
  resultContainer.style.display = 'block';
@@ -187,34 +68,56 @@ HTML_TEMPLATE = """
187
  """
188
 
189
  def analyze_repo(repo_path):
190
- """Analyzes the cloned repository to gather information."""
 
 
 
 
191
  project_name = os.path.basename(repo_path)
192
  language = "Not Detected"
193
  dependencies = []
194
- install_command = "No install command found."
195
- run_command = "No run command found."
196
-
 
 
 
 
 
 
 
 
 
 
 
 
197
  if os.path.exists(os.path.join(repo_path, 'requirements.txt')):
198
  language = "Python"
199
  with open(os.path.join(repo_path, 'requirements.txt'), 'r') as f:
200
- dependencies = [line.strip() for line in f.readlines() if line.strip()]
201
  install_command = "pip install -r requirements.txt"
202
- if os.path.exists(os.path.join(repo_path, 'app.py')) or os.path.exists(os.path.join(repo_path, 'main.py')):
203
- run_command = "python app.py # or python main.py"
 
 
 
 
 
 
 
204
 
205
  elif os.path.exists(os.path.join(repo_path, 'package.json')):
206
  language = "JavaScript (Node.js)"
207
  with open(os.path.join(repo_path, 'package.json'), 'r') as f:
208
  package_data = json.load(f)
209
  dependencies = list(package_data.get('dependencies', {}).keys())
 
 
210
  install_command = "npm install"
211
- run_command = "npm start" if package_data.get('scripts', {}).get('start') else "node index.js"
212
-
213
- purpose = f"A {language} project."
214
- if 'test' in str(os.listdir(repo_path)).lower():
215
- purpose += " It appears to have testing capabilities."
216
- if 'dockerfile' in str(os.listdir(repo_path)).lower():
217
- purpose += " It can be containerized using Docker."
218
 
219
  return {
220
  "project_name": project_name, "language": language, "dependencies": dependencies,
@@ -223,13 +126,20 @@ def analyze_repo(repo_path):
223
 
224
  def generate_readme_content(analysis):
225
  """Generates the README.md content from the analysis results."""
226
- readme = f"# {analysis['project_name']}\n\n"
227
  readme += f"## 🤖 About This Project\n\n{analysis['purpose']}\n\n"
228
- readme += f"This project is primarily written in **{analysis['language']}**.\n\n"
229
  readme += "## 🚀 Getting Started\n\n"
230
- readme += "### Installation\n\n1. Clone the repository.\n"
231
- readme += f"2. Install dependencies:\n ```sh\n {analysis['install_command']}\n ```\n\n"
232
- readme += "### Usage\n\nTo run the project, execute:\n"
 
 
 
 
 
 
 
233
  readme += f"```sh\n{analysis['run_command']}\n```\n\n"
234
  readme += "---\n*This README was automatically generated by an AI agent.*"
235
  return readme
@@ -241,18 +151,39 @@ def index():
241
  @app.route('/generate', methods=['POST'])
242
  def generate():
243
  repo_url = request.get_json().get('url')
244
- if not repo_url:
245
- return jsonify({"error": "URL is required."}), 400
246
 
247
  temp_dir = tempfile.mkdtemp()
248
  try:
 
 
249
  git.Repo.clone_from(repo_url, temp_dir)
250
- analysis_result = analyze_repo(temp_dir)
 
 
 
 
 
 
 
 
 
 
 
 
 
251
  readme_content = generate_readme_content(analysis_result)
 
252
  return jsonify({"readme": readme_content})
 
 
 
253
  except Exception as e:
254
- return jsonify({"error": f"An error occurred: {str(e)}"}), 500
255
  finally:
 
 
256
  shutil.rmtree(temp_dir)
257
 
258
  if __name__ == '__main__':
 
7
 
8
  app = Flask(__name__)
9
 
10
+ # --- HTML Template remains embedded. No changes needed here. ---
11
  HTML_TEMPLATE = """
12
  <!DOCTYPE html>
13
  <html lang="en">
 
17
  <title>GitHub README Generator</title>
18
  <style>
19
  @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');
20
+ body { font-family: 'Inter', sans-serif; background-color: #f0f2f5; color: #1c1e21; margin: 0; display: flex; justify-content: center; align-items: center; min-height: 100vh; padding: 20px; box-sizing: border-box; }
21
+ .container { background-color: #ffffff; padding: 40px 50px; border-radius: 12px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); width: 100%; max-width: 700px; text-align: center; }
22
+ h1 { font-size: 2.2em; color: #1877f2; margin-bottom: 10px; }
23
+ p { color: #606770; font-size: 1.1em; margin-bottom: 30px; }
24
+ .input-group { display: flex; margin-bottom: 20px; }
25
+ #repo-url { flex-grow: 1; padding: 15px; border: 1px solid #dddfe2; border-radius: 6px 0 0 6px; font-size: 1em; outline: none; min-width: 0; }
26
+ #repo-url:focus { border-color: #1877f2; box-shadow: 0 0 0 2px rgba(24, 119, 242, 0.2); }
27
+ button { padding: 15px 25px; border: none; background-color: #1877f2; color: white; font-size: 1em; font-weight: 600; border-radius: 0 6px 6px 0; cursor: pointer; transition: background-color 0.3s; }
28
+ button:hover { background-color: #166fe5; }
29
+ .loader { border: 4px solid #f3f3f3; border-top: 4px solid #1877f2; border-radius: 50%; width: 40px; height: 40px; animation: spin 1s linear infinite; margin: 30px auto; display: none; }
30
+ @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
31
+ #result-container { display: none; margin-top: 20px; }
32
+ #result { margin-top: 10px; padding: 20px; background-color: #f7f7f7; border: 1px solid #dddfe2; border-radius: 6px; text-align: left; white-space: pre-wrap; font-family: 'Courier New', Courier, monospace; max-height: 400px; overflow-y: auto; word-wrap: break-word; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  </style>
34
  </head>
35
  <body>
36
  <div class="container">
37
  <h1>GitHub README Generator 💻</h1>
38
  <p>Enter a public GitHub repository URL and let the AI agent generate a professional README.md for you.</p>
39
+ <form id="repo-form"><div class="input-group"><input type="url" id="repo-url" placeholder="e.g., https://github.com/user/project" required><button type="submit">Generate</button></div></form>
 
 
 
 
 
 
 
40
  <div class="loader" id="loader"></div>
41
+ <div id="result-container"><h2>Generated README.md:</h2><pre id="result"></pre></div>
 
 
 
 
42
  </div>
 
43
  <script>
44
  document.getElementById('repo-form').addEventListener('submit', async function(event) {
45
  event.preventDefault();
 
46
  const url = document.getElementById('repo-url').value;
47
  const loader = document.getElementById('loader');
48
  const resultContainer = document.getElementById('result-container');
49
  const resultDiv = document.getElementById('result');
 
50
  loader.style.display = 'block';
51
  resultContainer.style.display = 'none';
52
  resultDiv.textContent = '';
 
53
  try {
54
+ const response = await fetch('/generate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ url: url }) });
 
 
 
 
 
55
  const data = await response.json();
56
+ if (response.ok) { resultDiv.textContent = data.readme; } else { resultDiv.textContent = 'Error: ' + data.error; }
 
 
 
 
 
57
  resultContainer.style.display = 'block';
 
58
  } catch (error) {
59
  resultDiv.textContent = 'An unexpected error occurred: ' + error.toString();
60
  resultContainer.style.display = 'block';
 
68
  """
69
 
70
  def analyze_repo(repo_path):
71
+ """
72
+ Analyzes the cloned repository to gather information.
73
+ This function now correctly receives the path to the project's root folder.
74
+ """
75
+ # FIX: The project name is the name of the folder we are analyzing.
76
  project_name = os.path.basename(repo_path)
77
  language = "Not Detected"
78
  dependencies = []
79
+ install_command = "No specific install command found."
80
+ run_command = "No specific run command found."
81
+ purpose = f"A project named '{project_name}'."
82
+
83
+ # --- Smarter Project Purpose Inference ---
84
+ # Try to find a description from an existing README
85
+ existing_readme_path = os.path.join(repo_path, 'README.md')
86
+ if os.path.exists(existing_readme_path):
87
+ with open(existing_readme_path, 'r', errors='ignore') as f:
88
+ lines = f.readlines()
89
+ # Often the first few lines after the title contain a description
90
+ if len(lines) > 2:
91
+ purpose = "".join(lines[1:3]).strip() # Grab the first two lines after title
92
+
93
+ # --- Technology and Dependency Analysis ---
94
  if os.path.exists(os.path.join(repo_path, 'requirements.txt')):
95
  language = "Python"
96
  with open(os.path.join(repo_path, 'requirements.txt'), 'r') as f:
97
+ dependencies = [line.strip() for line in f.readlines() if line.strip() and not line.startswith('#')]
98
  install_command = "pip install -r requirements.txt"
99
+ if 'flask' in str(dependencies).lower():
100
+ run_command = "flask run"
101
+ elif 'django' in str(dependencies).lower():
102
+ run_command = "python manage.py runserver"
103
+ elif os.path.exists(os.path.join(repo_path, 'app.py')):
104
+ run_command = "python app.py"
105
+ elif os.path.exists(os.path.join(repo_path, 'main.py')):
106
+ run_command = "python main.py"
107
+
108
 
109
  elif os.path.exists(os.path.join(repo_path, 'package.json')):
110
  language = "JavaScript (Node.js)"
111
  with open(os.path.join(repo_path, 'package.json'), 'r') as f:
112
  package_data = json.load(f)
113
  dependencies = list(package_data.get('dependencies', {}).keys())
114
+ if package_data.get('description'):
115
+ purpose = package_data.get('description')
116
  install_command = "npm install"
117
+ if package_data.get('scripts', {}).get('start'):
118
+ run_command = "npm start"
119
+ else:
120
+ run_command = "node index.js # (or appropriate main file)"
 
 
 
121
 
122
  return {
123
  "project_name": project_name, "language": language, "dependencies": dependencies,
 
126
 
127
  def generate_readme_content(analysis):
128
  """Generates the README.md content from the analysis results."""
129
+ readme = f"# {analysis['project_name'].replace('-', ' ').title()}\n\n"
130
  readme += f"## 🤖 About This Project\n\n{analysis['purpose']}\n\n"
131
+ readme += f"This project appears to be written in **{analysis['language']}**.\n\n"
132
  readme += "## 🚀 Getting Started\n\n"
133
+ readme += "### Installation\n\n1. **Clone the repository:**\n ```sh\n git clone <your_repository_url>\n ```\n\n"
134
+ readme += f"2. **Navigate into the directory and install dependencies:**\n ```sh\n cd {analysis['project_name']}\n {analysis['install_command']}\n ```\n\n"
135
+
136
+ if analysis['dependencies']:
137
+ readme += "### Key Dependencies\n"
138
+ for dep in analysis['dependencies'][:5]: # Show first 5 dependencies
139
+ readme += f"- `{dep}`\n"
140
+ readme += "\n"
141
+
142
+ readme += "### Usage\n\nTo run the application, execute the following command from the project root:\n"
143
  readme += f"```sh\n{analysis['run_command']}\n```\n\n"
144
  readme += "---\n*This README was automatically generated by an AI agent.*"
145
  return readme
 
151
  @app.route('/generate', methods=['POST'])
152
  def generate():
153
  repo_url = request.get_json().get('url')
154
+ if not repo_url or not repo_url.startswith("https://github.com/"):
155
+ return jsonify({"error": "A valid GitHub repository URL is required."}), 400
156
 
157
  temp_dir = tempfile.mkdtemp()
158
  try:
159
+ # --- Agent Tool 1: Git Clone ---
160
+ print(f"Cloning repository: {repo_url}")
161
  git.Repo.clone_from(repo_url, temp_dir)
162
+
163
+ # --- FIX: Find the actual project folder inside the temp directory ---
164
+ cloned_folders = os.listdir(temp_dir)
165
+ if not cloned_folders:
166
+ raise Exception("Cloning seems to have failed, the directory is empty.")
167
+
168
+ # The actual repo path is inside the temp_dir
169
+ repo_root_path = os.path.join(temp_dir, cloned_folders[0])
170
+ print(f"Analysis target found at: {repo_root_path}")
171
+
172
+ # --- Agent Tool 2: File Analysis (now on the correct path) ---
173
+ analysis_result = analyze_repo(repo_root_path)
174
+
175
+ # --- Agent Step 3: Write README ---
176
  readme_content = generate_readme_content(analysis_result)
177
+
178
  return jsonify({"readme": readme_content})
179
+
180
+ except git.exc.GitCommandError as e:
181
+ return jsonify({"error": f"Failed to clone. Is the URL correct and public? Details: {e}"}), 500
182
  except Exception as e:
183
+ return jsonify({"error": f"An unexpected error occurred: {str(e)}"}), 500
184
  finally:
185
+ # --- Cleanup ---
186
+ print(f"Cleaning up temporary directory: {temp_dir}")
187
  shutil.rmtree(temp_dir)
188
 
189
  if __name__ == '__main__':