Akwbw commited on
Commit
ad7ea0d
Β·
verified Β·
1 Parent(s): af920d1

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +244 -0
app.py ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import os
3
+ import zipfile
4
+ 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",
23
+ "Authorization": f"Bearer {API_KEY}"
24
+ }
25
+ payload = {
26
+ "model": AI_MODEL,
27
+ "messages": [
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:
163
+ project_root = root
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:
216
+ if file.endswith(".apk") and "release" in file:
217
+ unsigned_apk = os.path.join(root, 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")