faizee07 commited on
Commit
280cc30
·
verified ·
1 Parent(s): 3db1420

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +91 -94
app.py CHANGED
@@ -4,17 +4,26 @@ import tempfile
4
  from flask import Flask, request, jsonify, render_template_string
5
  import git
6
  import json
 
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">
14
  <head>
15
  <meta charset="UTF-8">
16
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
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; }
@@ -34,8 +43,8 @@ HTML_TEMPLATE = """
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>
@@ -67,82 +76,79 @@ HTML_TEMPLATE = """
67
  </html>
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,
124
- "install_command": install_command, "run_command": run_command, "purpose": purpose
125
- }
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
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
146
 
147
  @app.route('/')
148
  def index():
@@ -151,39 +157,30 @@ def index():
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__':
 
4
  from flask import Flask, request, jsonify, render_template_string
5
  import git
6
  import json
7
+ import google.generativeai as genai
8
 
9
+ # --- IMPORTANT: Configure your API Key ---
10
+ # For local testing, you can set this directly.
11
+ # For Hugging Face Spaces, you will set this in "Secrets".
12
+ # os.environ['GOOGLE_API_KEY'] = "YOUR_API_KEY_HERE"
13
+ try:
14
+ genai.configure(api_key=os.environ.get("GOOGLE_API_KEY"))
15
+ except AttributeError:
16
+ print("WARNING: GOOGLE_API_KEY secret not set. LLM functionality will fail.")
17
 
18
+
19
+ # The HTML template remains the same
20
  HTML_TEMPLATE = """
21
  <!DOCTYPE html>
22
  <html lang="en">
23
  <head>
24
  <meta charset="UTF-8">
25
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
26
+ <title>AI README Generator 🧠</title>
27
  <style>
28
  @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap');
29
  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; }
 
43
  </head>
44
  <body>
45
  <div class="container">
46
+ <h1>AI README Generator 🧠</h1>
47
+ <p>Enter a public GitHub repository URL and let a true AI agent analyze the code and generate a README for you.</p>
48
  <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>
49
  <div class="loader" id="loader"></div>
50
  <div id="result-container"><h2>Generated README.md:</h2><pre id="result"></pre></div>
 
76
  </html>
77
  """
78
 
79
+ def generate_readme_with_llm(repo_path):
80
  """
81
+ Analyzes the repo and uses an LLM to generate the README content.
 
82
  """
83
+ # 1. Gather context: file structure and content of key files
84
+ file_structure = ""
85
+ file_contents = ""
86
+ file_limit = 5 # Limit number of files to read to save tokens
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
 
88
+ for root, _, files in os.walk(repo_path):
89
+ # Ignore git directory
90
+ if '.git' in root:
91
+ continue
92
+
93
+ level = root.replace(repo_path, '').count(os.sep)
94
+ indent = ' ' * 4 * level
95
+ file_structure += f"{indent}{os.path.basename(root)}/\n"
96
 
97
+ sub_indent = ' ' * 4 * (level + 1)
98
+ for f in files[:file_limit]:
99
+ file_structure += f"{sub_indent}{f}\n"
100
+ # Read content of a few key files
101
+ try:
102
+ with open(os.path.join(root, f), 'r', errors='ignore') as file:
103
+ content = file.read(2000) # Read first 2000 chars
104
+ file_contents += f"\n--- Start of {f} ---\n{content}\n--- End of {f} ---\n"
105
+ except Exception:
106
+ continue # Skip files we can't read
107
+
108
+ # 2. Create a detailed prompt for the LLM
109
+ prompt = f"""
110
+ You are an expert technical writer tasked with creating a high-quality README.md for a GitHub repository.
111
+ Analyze the following repository context and generate a comprehensive and user-friendly README.
112
+
113
+ **Repository Context:**
114
+
115
+ **1. File Structure:**
116
+ ```
117
+ {file_structure}
118
+ ```
119
+
120
+ **2. Content of Key Files:**
121
+ ```
122
+ {file_contents}
123
+ ```
124
+
125
+ **Instructions:**
126
+ Based on the context provided, please generate a README.md file with the following sections:
127
+ 1. **Project Title:** An appropriate title for the project.
128
+ 2. **About the Project:** A concise but informative paragraph describing the project's purpose and the technology it uses. Infer this from the file contents.
129
+ 3. **Getting Started:** Clear, step-by-step instructions for installation and setup. Infer the package manager (pip, npm, etc.) and run commands.
130
+ 4. **Usage:** A simple example of how to run the application.
131
+
132
+ **Rules:**
133
+ - The output must be in valid Markdown format.
134
+ - Be professional and clear.
135
+ - If you cannot determine a piece of information (like a specific run command), suggest a common default and state that it might need to be verified.
136
+ - Do not invent features that are not evident from the provided context.
137
+ """
138
+
139
+ # 3. Call the LLM
140
+ print("Sending request to Gemini API...")
141
+ model = genai.GenerativeModel('gemini-1.5-flash-latest')
142
+ response = model.generate_content(prompt)
143
+
144
+ # Clean up the response - sometimes the model wraps it in ```markdown
145
+ readme_text = response.text.strip()
146
+ if readme_text.startswith("```markdown"):
147
+ readme_text = readme_text[10:]
148
+ if readme_text.endswith("```"):
149
+ readme_text = readme_text[:-3]
150
+
151
+ return readme_text
152
 
153
  @app.route('/')
154
  def index():
 
157
  @app.route('/generate', methods=['POST'])
158
  def generate():
159
  repo_url = request.get_json().get('url')
160
+ if not repo_url or not repo_url.startswith("[https://github.com/](https://github.com/)"):
161
  return jsonify({"error": "A valid GitHub repository URL is required."}), 400
162
 
163
+ if not os.environ.get("GOOGLE_API_KEY"):
164
+ return jsonify({"error": "Server is missing the GOOGLE_API_KEY. Cannot contact the LLM."}), 500
165
+
166
  temp_dir = tempfile.mkdtemp()
167
  try:
 
 
168
  git.Repo.clone_from(repo_url, temp_dir)
169
 
170
+ cloned_folders = [d for d in os.listdir(temp_dir) if os.path.isdir(os.path.join(temp_dir, d))]
 
171
  if not cloned_folders:
172
  raise Exception("Cloning seems to have failed, the directory is empty.")
173
 
 
174
  repo_root_path = os.path.join(temp_dir, cloned_folders[0])
 
 
 
 
175
 
176
+ # --- NEW: Call the LLM-powered function ---
177
+ readme_content = generate_readme_with_llm(repo_root_path)
178
 
179
  return jsonify({"readme": readme_content})
180
 
 
 
181
  except Exception as e:
182
+ return jsonify({"error": f"An error occurred: {str(e)}"}), 500
183
  finally:
 
 
184
  shutil.rmtree(temp_dir)
185
 
186
  if __name__ == '__main__':