Akwbw commited on
Commit
a49ab03
Β·
verified Β·
1 Parent(s): f2cf842

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +146 -146
app.py CHANGED
@@ -5,18 +5,18 @@ import subprocess
5
  import shutil
6
  import requests
7
  import re
 
8
 
9
  # --- CONFIGURATION ---
10
  API_ENDPOINT = "https://gen.pollinations.ai/v1/chat/completions"
11
- API_KEY = "sk_qDYtDvntvqzjmp23XKVzr9lBXYwYndaR" # Apki di hui key
12
  AI_MODEL = "claude"
13
 
14
- # Page Config
15
- st.set_page_config(page_title="AI Android Builder", layout="centered")
16
- st.title("πŸ€– AI-Powered Android APK Generator")
17
- st.markdown("Pollinations AI (Claude) check karega, build karega, aur error aya to khud fix karega.")
18
 
19
- # --- HELPER: AI API CALL ---
20
  def ask_claude(system_prompt, user_message):
21
  headers = {
22
  "Content-Type": "application/json",
@@ -28,135 +28,113 @@ def ask_claude(system_prompt, user_message):
28
  {"role": "system", "content": system_prompt},
29
  {"role": "user", "content": user_message}
30
  ],
31
- "temperature": 0.2 # Low temperature for precise code
32
  }
33
 
34
  try:
35
- response = requests.post(API_ENDPOINT, json=payload, headers=headers, timeout=60)
36
  if response.status_code == 200:
37
- return response.json()['choices'][0]['message']['content']
38
  else:
39
- return f"Error: {response.text}"
40
  except Exception as e:
41
- return f"Connection Error: {str(e)}"
42
 
43
  # --- HELPER: KEYSTORE ---
44
  def generate_keystore():
45
  keystore_path = "debug.keystore"
46
  if not os.path.exists(keystore_path):
47
- cmd = [
48
  "keytool", "-genkey", "-v", "-keystore", keystore_path,
49
  "-storepass", "android", "-alias", "androiddebugkey",
50
  "-keypass", "android", "-keyalg", "RSA", "-keysize", "2048",
51
  "-validity", "10000", "-dname", "CN=AndroidDebug,O=Android,C=US"
52
- ]
53
- subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
54
  return keystore_path
55
 
56
- # --- AI LOGIC: PRE-CHECK ---
57
- def check_project_health(project_root):
58
- # Sirf critical files parho taake AI confuse na ho
59
- manifest_path = None
60
- gradle_path = None
61
 
 
62
  for root, dirs, files in os.walk(project_root):
 
 
63
  if "AndroidManifest.xml" in files:
64
- manifest_path = os.path.join(root, "AndroidManifest.xml")
65
- if "build.gradle" in files and "app" in root: # App level gradle
66
- gradle_path = os.path.join(root, "build.gradle")
67
 
68
- if not manifest_path or not gradle_path:
69
- return "❌ Critical files (Manifest/Gradle) missing. Cannot proceed."
70
-
71
- with open(manifest_path, 'r', encoding='utf-8', errors='ignore') as f:
72
- manifest_content = f.read()
73
- with open(gradle_path, 'r', encoding='utf-8', errors='ignore') as f:
74
- gradle_content = f.read()
75
-
76
- prompt = f"""
77
- You are an Android Build Expert. Check these files for critical syntax errors that would stop a build.
78
- Do NOT change functionality. Just check if structure is valid.
79
-
80
- Manifest:
81
- {manifest_content[:2000]}
82
 
83
- Gradle:
84
- {gradle_content[:2000]}
 
85
 
86
- Reply ONLY with "SAFE" if it looks okay, or "ISSUE: [Explanation]" if bad.
87
- """
88
- return ask_claude("Analyze code structure.", prompt)
89
-
90
- # --- AI LOGIC: AUTO FIX ---
91
- def attempt_ai_repair(error_log, project_root):
92
- # 1. Error log mein se file ka path dhoondo
93
- # Format usually: /app/src/main/java/com/example/App.java:15: error: ...
94
- match = re.search(r'(/[\w/-]+\.(java|kt|xml|gradle)):(\d+):', error_log)
95
 
96
- if not match:
97
- return False, "AI could not identify the broken file in logs."
 
98
 
99
- broken_file_path = match.group(1)
100
-
101
- # Path correction (Absolute vs Relative)
102
- if not os.path.exists(broken_file_path):
103
- # Try to find it relative to project root
104
- found = False
105
- file_name = os.path.basename(broken_file_path)
106
- for root, dirs, files in os.walk(project_root):
107
- if file_name in files:
108
- broken_file_path = os.path.join(root, file_name)
109
- found = True
110
- break
111
- if not found:
112
- return False, f"File {file_name} not found."
113
-
114
- # 2. Read Broken Code
115
- with open(broken_file_path, 'r', encoding='utf-8', errors='ignore') as f:
116
- broken_code = f.read()
117
 
118
- # 3. Ask AI to fix
119
- st.info(f"πŸ€– AI is fixing: **{os.path.basename(broken_file_path)}**")
120
-
121
- system_prompt = "You are an expert Android Developer. Fix the code error. Maintain original functionality. Output ONLY the full corrected code block without markdown wrappers."
122
- user_msg = f"""
123
- The build failed with this error:
124
- {error_log[:1000]}
125
-
126
- Here is the broken file content:
127
- {broken_code}
128
-
129
- Return the FULL CORRECTED file content.
130
- """
131
-
132
- fixed_code = ask_claude(system_prompt, user_msg)
133
-
134
- # Clean AI output (remove ```java etc)
135
- fixed_code = fixed_code.replace("```java", "").replace("```kotlin", "").replace("```xml", "").replace("```", "").strip()
136
-
137
- # 4. Overwrite file
138
- try:
139
- with open(broken_file_path, 'w', encoding='utf-8') as f:
140
- f.write(fixed_code)
141
- return True, f"Fixed {os.path.basename(broken_file_path)}"
142
- except Exception as e:
143
- return False, str(e)
 
 
 
 
 
144
 
145
  # --- MAIN UI ---
146
  uploaded_file = st.file_uploader("Project ZIP Upload", type=["zip"])
147
 
148
  if uploaded_file:
149
- if st.button("πŸš€ AI Check & Build"):
150
- status_box = st.status("Initializing...", expanded=True)
151
 
152
  # 1. EXTRACT
153
- status_box.write("πŸ“‚ Extracting files...")
154
  if os.path.exists("project_extract"): shutil.rmtree("project_extract")
155
  os.makedirs("project_extract", exist_ok=True)
156
  with open("uploaded.zip", "wb") as f: f.write(uploaded_file.getbuffer())
157
  with zipfile.ZipFile("uploaded.zip", "r") as z: z.extractall("project_extract")
158
 
159
- # Root Find
160
  project_root = None
161
  for root, dirs, files in os.walk("project_extract"):
162
  if "gradlew" in files:
@@ -164,52 +142,31 @@ if uploaded_file:
164
  break
165
 
166
  if not project_root:
167
- status_box.update(label="❌ Invalid Project", state="error")
168
- st.error("Gradlew not found.")
169
  st.stop()
170
-
171
  subprocess.run(["chmod", "+x", os.path.join(project_root, "gradlew")])
172
 
173
- # 2. AI PRE-CHECK
174
- status_box.write("🧠 Claude is analyzing project structure...")
175
- ai_verdict = check_project_health(project_root)
176
 
177
- if "SAFE" in ai_verdict or "manifest" in ai_verdict.lower(): # Loose check
178
- status_box.write("βœ… AI Check Passed.")
179
  else:
180
- status_box.write(f"⚠️ AI Warning: {ai_verdict}")
181
- # Hum rukenge nahi, try karenge, shayad build ho jaye
182
 
183
- # 3. BUILD PROCESS LOOP
184
- build_success = False
185
- attempts = 0
186
- max_attempts = 2 # 1 Normal + 1 AI Repair
187
 
188
- while attempts < max_attempts:
189
- status_box.write(f"πŸ”¨ Building APK (Attempt {attempts+1})...")
190
-
191
- cmd = ["./gradlew", "assembleRelease", "--no-daemon", "--stacktrace"]
192
- result = subprocess.run(cmd, cwd=project_root, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
193
-
194
- if result.returncode == 0:
195
- build_success = True
196
- break
197
- else:
198
- attempts += 1
199
- if attempts < max_attempts:
200
- status_box.write("❌ Build Failed. Activating AI Repair Agent...")
201
- success, msg = attempt_ai_repair(result.stderr, project_root)
202
- if success:
203
- status_box.write(f"βœ… {msg}. Retrying build...")
204
- else:
205
- status_box.write(f"⚠️ AI Repair Failed: {msg}")
206
- break
207
 
208
- # 4. RESULT HANDLING
209
- if build_success:
210
- status_box.write("βœ… Build Successful! Signing APK...")
211
 
212
- # Search APK
213
  unsigned_apk = None
214
  for root, dirs, files in os.walk(project_root):
215
  for file in files:
@@ -218,27 +175,70 @@ if uploaded_file:
218
  break
219
 
220
  if unsigned_apk:
221
- # SIGNING
222
  keystore = generate_keystore()
223
- signed_name = "AI_Generated_App.apk"
224
- subprocess.run(["zipalign", "-v", "-p", "4", unsigned_apk, "aligned.apk"], stdout=subprocess.DEVNULL)
225
 
 
 
 
226
  subprocess.run([
227
  "apksigner", "sign", "--ks", keystore, "--ks-pass", "pass:android",
228
  "--out", signed_name, "aligned.apk"
229
  ])
230
 
231
- status_box.update(label="πŸŽ‰ Process Complete!", state="complete")
232
-
233
  with open(signed_name, "rb") as f:
234
- st.download_button("⬇️ Download AI Verified APK", f, file_name=signed_name, mime="application/vnd.android.package-archive")
235
  else:
236
- status_box.update(label="❌ File Missing", state="error")
237
- st.error("APK generated but file not found.")
238
  else:
239
- status_box.update(label="❌ Fatal Error", state="error")
240
- st.error("Build Failed even after AI Repair.")
241
- st.text_area("Last Error Log", result.stderr[-2000:], height=300)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
242
 
243
- # Cleanup
244
  if os.path.exists("uploaded.zip"): os.remove("uploaded.zip")
 
5
  import shutil
6
  import requests
7
  import re
8
+ import glob
9
 
10
  # --- CONFIGURATION ---
11
  API_ENDPOINT = "https://gen.pollinations.ai/v1/chat/completions"
12
+ API_KEY = "sk_qDYtDvntvqzjmp23XKVzr9lBXYwYndaR"
13
  AI_MODEL = "claude"
14
 
15
+ st.set_page_config(page_title="Strict AI Android Builder", layout="centered")
16
+ st.title("πŸ•΅οΈβ€β™‚οΈ Strict AI Auto-Builder")
17
+ st.markdown("Ye system har file ki **Jasoosi** karega aur build se pehle hi errors fix kar dega.")
 
18
 
19
+ # --- HELPER: AI API ---
20
  def ask_claude(system_prompt, user_message):
21
  headers = {
22
  "Content-Type": "application/json",
 
28
  {"role": "system", "content": system_prompt},
29
  {"role": "user", "content": user_message}
30
  ],
31
+ "temperature": 0.1 # Strictly logic, no creativity
32
  }
33
 
34
  try:
35
+ response = requests.post(API_ENDPOINT, json=payload, headers=headers, timeout=90) # Increased timeout
36
  if response.status_code == 200:
37
+ return True, response.json()['choices'][0]['message']['content']
38
  else:
39
+ return False, f"API Error {response.status_code}"
40
  except Exception as e:
41
+ return False, f"Connection Error: {str(e)}"
42
 
43
  # --- HELPER: KEYSTORE ---
44
  def generate_keystore():
45
  keystore_path = "debug.keystore"
46
  if not os.path.exists(keystore_path):
47
+ subprocess.run([
48
  "keytool", "-genkey", "-v", "-keystore", keystore_path,
49
  "-storepass", "android", "-alias", "androiddebugkey",
50
  "-keypass", "android", "-keyalg", "RSA", "-keysize", "2048",
51
  "-validity", "10000", "-dname", "CN=AndroidDebug,O=Android,C=US"
52
+ ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
 
53
  return keystore_path
54
 
55
+ # --- CORE LOGIC: THE JASOOS (STRICT SCANNER) ---
56
+ def strict_scan_and_fix(project_root, status_box):
57
+ # Hum in specific files ko target karenge jo 99% errors ki wajah banti hain
58
+ critical_files = []
 
59
 
60
+ # 1. Gradle Files dhoondo
61
  for root, dirs, files in os.walk(project_root):
62
+ if "build.gradle" in files:
63
+ critical_files.append(os.path.join(root, "build.gradle"))
64
  if "AndroidManifest.xml" in files:
65
+ critical_files.append(os.path.join(root, "AndroidManifest.xml"))
 
 
66
 
67
+ # 2. Main Java/Kotlin Files (Top 2 largest files utha lo - assuming wahi main logic hai)
68
+ source_files = []
69
+ for root, dirs, files in os.walk(project_root):
70
+ for file in files:
71
+ if file.endswith(".java") or file.endswith(".kt"):
72
+ source_files.append(os.path.join(root, file))
 
 
 
 
 
 
 
 
73
 
74
+ # Sort by size (descending) and take top 2
75
+ source_files.sort(key=lambda x: os.path.getsize(x), reverse=True)
76
+ critical_files.extend(source_files[:2])
77
 
78
+ total_files = len(critical_files)
79
+ fixed_count = 0
 
 
 
 
 
 
 
80
 
81
+ for i, file_path in enumerate(critical_files):
82
+ file_name = os.path.basename(file_path)
83
+ status_box.write(f"🧐 Auditing: **{file_name}** ({i+1}/{total_files})")
84
 
85
+ with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
86
+ content = f.read()
87
+
88
+ # --- PROMPT: STRICT ENVIRONMENT MATCHING ---
89
+ system_prompt = """
90
+ You are a Senior Android Architect auditing code for a CI/CD server.
91
+ Server Specs: Linux, Java 17, Android SDK 33.
 
 
 
 
 
 
 
 
 
 
 
92
 
93
+ Rules:
94
+ 1. Fix any deprecated Gradle plugins (use valid versions for Java 17).
95
+ 2. Ensure compileSdkVersion is 33 or 34.
96
+ 3. Fix Manifest package name errors.
97
+ 4. In Java/Kotlin, fix syntax errors strictly.
98
+ 5. DO NOT remove main logic, only fix structure/syntax.
99
+
100
+ Output:
101
+ If the code is 100% PERFECT, reply exactly: "NO_CHANGES_NEEDED"
102
+ If there is ANY issue, reply with the FULL CORRECTED CODE only. No markdown.
103
+ """
104
+
105
+ user_msg = f"Check this file content:\n\n{content}"
106
+
107
+ success, response = ask_claude(system_prompt, user_msg)
108
+
109
+ if success:
110
+ if "NO_CHANGES_NEEDED" not in response:
111
+ # AI ne changes kiye hain
112
+ cleaned_code = response.replace("```gradle", "").replace("```java", "").replace("```xml", "").replace("```kotlin", "").replace("```", "").strip()
113
+
114
+ # Safety check: Code empty to nahi?
115
+ if len(cleaned_code) > 10:
116
+ with open(file_path, 'w', encoding='utf-8') as f:
117
+ f.write(cleaned_code)
118
+ fixed_count += 1
119
+ status_box.write(f"πŸ› οΈ **Fixed Issues in {file_name}**")
120
+ else:
121
+ status_box.write(f"⚠️ AI Skip ({file_name}): API Error")
122
+
123
+ return fixed_count
124
 
125
  # --- MAIN UI ---
126
  uploaded_file = st.file_uploader("Project ZIP Upload", type=["zip"])
127
 
128
  if uploaded_file:
129
+ if st.button("πŸš€ Strict Build (Guarantee Mode)"):
130
+ status_box = st.status("Initializing Detective Mode...", expanded=True)
131
 
132
  # 1. EXTRACT
 
133
  if os.path.exists("project_extract"): shutil.rmtree("project_extract")
134
  os.makedirs("project_extract", exist_ok=True)
135
  with open("uploaded.zip", "wb") as f: f.write(uploaded_file.getbuffer())
136
  with zipfile.ZipFile("uploaded.zip", "r") as z: z.extractall("project_extract")
137
 
 
138
  project_root = None
139
  for root, dirs, files in os.walk("project_extract"):
140
  if "gradlew" in files:
 
142
  break
143
 
144
  if not project_root:
145
+ status_box.update(label="❌ Invalid Zip", state="error")
 
146
  st.stop()
147
+
148
  subprocess.run(["chmod", "+x", os.path.join(project_root, "gradlew")])
149
 
150
+ # 2. STRICT AI AUDIT (The Jasoos Step)
151
+ status_box.write("πŸ•΅οΈβ€β™‚οΈ Starting Deep Scan (Scanning all critical files)...")
152
+ fixes = strict_scan_and_fix(project_root, status_box)
153
 
154
+ if fixes > 0:
155
+ status_box.write(f"βœ… AI ne build se pehle **{fixes} files** fix kar di hain.")
156
  else:
157
+ status_box.write("βœ… Code looks perfect. Proceeding...")
 
158
 
159
+ # 3. BUILD
160
+ status_box.write("πŸ”¨ Building APK...")
 
 
161
 
162
+ # Force Clean Build
163
+ cmd = ["./gradlew", "clean", "assembleRelease", "--no-daemon", "--stacktrace"]
164
+ result = subprocess.run(cmd, cwd=project_root, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
 
166
+ if result.returncode == 0:
167
+ status_box.write("βœ… Build Successful! Signing now...")
 
168
 
169
+ # Find & Sign
170
  unsigned_apk = None
171
  for root, dirs, files in os.walk(project_root):
172
  for file in files:
 
175
  break
176
 
177
  if unsigned_apk:
 
178
  keystore = generate_keystore()
179
+ signed_name = "Pro_Signed_App.apk"
 
180
 
181
+ # Zipalign
182
+ subprocess.run(["zipalign", "-v", "-p", "4", unsigned_apk, "aligned.apk"], stdout=subprocess.DEVNULL)
183
+ # Sign
184
  subprocess.run([
185
  "apksigner", "sign", "--ks", keystore, "--ks-pass", "pass:android",
186
  "--out", signed_name, "aligned.apk"
187
  ])
188
 
189
+ status_box.update(label="πŸŽ‰ App Ready!", state="complete")
 
190
  with open(signed_name, "rb") as f:
191
+ st.download_button("⬇️ Download Final APK", f, file_name=signed_name, mime="application/vnd.android.package-archive")
192
  else:
193
+ status_box.error("APK file gum ho gayi.")
 
194
  else:
195
+ # 4. EMERGENCY REPAIR (Agar Jasoos se bhi kuch bach gaya ho)
196
+ status_box.write("⚠️ Build Error! Activating Emergency Repair...")
197
+
198
+ # Simple Repair Logic for last attempt
199
+ error_log = result.stderr
200
+ match = re.search(r'(/[\w/-]+\.(java|kt|xml|gradle)):(\d+):', error_log)
201
+ if match:
202
+ broken_file = match.group(1)
203
+ # Relative path fix
204
+ if not os.path.exists(broken_file):
205
+ for root, dirs, files in os.walk(project_root):
206
+ if os.path.basename(broken_file) in files:
207
+ broken_file = os.path.join(root, os.path.basename(broken_file))
208
+ break
209
+
210
+ if os.path.exists(broken_file):
211
+ status_box.write(f"πŸš‘ Fixing leftover error in: {os.path.basename(broken_file)}")
212
+ with open(broken_file, 'r') as f: content = f.read()
213
+
214
+ # Ask AI one last time
215
+ s_prompt = "Fix this specific build error in the code. Output ONLY code."
216
+ u_msg = f"Error: {error_log[-500:]}\nCode: {content}"
217
+ success, fixed = ask_claude(s_prompt, u_msg)
218
+
219
+ if success:
220
+ clean = fixed.replace("```java", "").replace("```", "").strip()
221
+ with open(broken_file, 'w') as f: f.write(clean)
222
+
223
+ # Last Retry
224
+ status_box.write("πŸ”„ Final Retry...")
225
+ subprocess.run(cmd, cwd=project_root, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
226
+
227
+ # Check again
228
+ final_apk = None
229
+ for root, dirs, files in os.walk(project_root):
230
+ for file in files:
231
+ if file.endswith(".apk") and "release" in file:
232
+ final_apk = os.path.join(root, file)
233
+ break
234
+ if final_apk:
235
+ status_box.update(label="πŸŽ‰ Saved by AI!", state="complete")
236
+ with open(final_apk, "rb") as f:
237
+ st.download_button("⬇️ Download Rescued APK", f, file_name="rescued_app.apk")
238
+ st.stop()
239
+
240
+ status_box.update(label="❌ Total Failure", state="error")
241
+ st.error("AI couldn't fix it automatically.")
242
+ st.text_area("Logs", result.stderr[-2000:], height=300)
243
 
 
244
  if os.path.exists("uploaded.zip"): os.remove("uploaded.zip")