import streamlit as st import os import zipfile import subprocess import shutil import requests import re import time # --- CONFIGURATION --- API_ENDPOINT = "https://gen.pollinations.ai/v1/chat/completions" API_KEY = "sk_qDYtDvntvqzjmp23XKVzr9lBXYwYndaR" AI_MODEL = "claude" MAX_RETRIES = 10 # AI 10 baar koshish karega haar manne se pehle st.set_page_config(page_title="AI Terminator Builder", layout="centered") st.title("๐Ÿค– AI Terminator Builder") st.markdown("This AI will **Hunt & Fix** errors recursively until the APK is built.") # --- HELPER: AI API --- def ask_claude(system_prompt, user_message): headers = { "Content-Type": "application/json", "Authorization": f"Bearer {API_KEY}" } payload = { "model": AI_MODEL, "messages": [ {"role": "system", "content": system_prompt}, {"role": "user", "content": user_message} ], "temperature": 0.1 # High precision } try: response = requests.post(API_ENDPOINT, json=payload, headers=headers, timeout=60) if response.status_code == 200: return True, response.json()['choices'][0]['message']['content'] return False, f"API Error: {response.text}" except Exception as e: return False, f"Connection Error: {str(e)}" # --- HELPER: KEYSTORE --- def generate_keystore(): keystore_path = "debug.keystore" if not os.path.exists(keystore_path): subprocess.run([ "keytool", "-genkey", "-v", "-keystore", keystore_path, "-storepass", "android", "-alias", "androiddebugkey", "-keypass", "android", "-keyalg", "RSA", "-keysize", "2048", "-validity", "10000", "-dname", "CN=AndroidDebug,O=Android,C=US" ], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) return keystore_path # --- STEP 1: FORCE UPGRADE (Base Setup) --- def initial_modernization(project_root, status_box): status_box.write("๐Ÿ› ๏ธ AI is modernizing project engine first...") # 1. Gradle Wrapper Upgrade to 8.0 wrapper_props = os.path.join(project_root, "gradle", "wrapper", "gradle-wrapper.properties") os.makedirs(os.path.dirname(wrapper_props), exist_ok=True) new_props = """distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists """ with open(wrapper_props, "w") as f: f.write(new_props) # 2. Root Build.gradle Fix root_gradle = None for root, dirs, files in os.walk(project_root): if "build.gradle" in files and "app" not in root: root_gradle = os.path.join(root, "build.gradle") break if root_gradle: with open(root_gradle, 'r') as f: content = f.read() # AI se kaho dependencies update kare p = "Update 'classpath' dependencies to be compatible with Gradle 8. Use 'com.android.tools.build:gradle:8.0.0'. Output full code." ok, fix = ask_claude(p, content) if ok: clean = fix.replace("```gradle","").replace("```","").strip() with open(root_gradle, 'w') as f: f.write(clean) status_box.write("โœ… AI updated root build.gradle configuration.") # --- STEP 2: THE FIXER LOOP --- def analyze_and_fix_errors(project_root, error_log, status_box): # Regex to find file paths in error logs (Java, Kotlin, XML, Gradle) # Pattern looks for: /path/to/file.ext:line_number: error match = re.search(r'(/[\w/-]+\.(java|kt|xml|gradle))', error_log) target_file = None if match: extracted_path = match.group(1) # Verify path exists (Handle relative/absolute mismatch) if os.path.exists(extracted_path): target_file = extracted_path else: # Try to find by filename filename = os.path.basename(extracted_path) for root, dirs, files in os.walk(project_root): if filename in files: target_file = os.path.join(root, filename) break # Agar Logs se file nahi mili, to fallback 'build.gradle' (App Level) par jao if not target_file: for root, dirs, files in os.walk(project_root): if "build.gradle" in files and "app" in root: target_file = os.path.join(root, "build.gradle") break if target_file: file_name = os.path.basename(target_file) status_box.write(f"๐Ÿง AI identified issue in: **{file_name}**") with open(target_file, 'r', errors='ignore') as f: current_code = f.read() system_prompt = """ You are an elite Android debugger. Analyze the Error Log and the File Content. Fix the code to resolve the build error. Ensure Java 17 / Gradle 8 compatibility. RETURN ONLY THE CORRECTED CODE. NO EXPLANATION. """ user_message = f""" ERROR LOG: {error_log[-2000:]} FILE CONTENT ({file_name}): {current_code} """ success, ai_fix = ask_claude(system_prompt, user_message) if success: # Clean response cleaned_code = ai_fix.replace("```java", "").replace("```kotlin", "").replace("```xml", "").replace("```gradle", "").replace("```", "").strip() with open(target_file, 'w', encoding='utf-8') as f: f.write(cleaned_code) status_box.write(f"๐Ÿค– **AI Message:** I have corrected `{file_name}` to fix the reported error.") return True else: status_box.error("AI API Failed to respond.") return False else: status_box.warning("Could not identify specific broken file from logs. Trying generic fix...") return False # --- MAIN UI --- uploaded_file = st.file_uploader("Project ZIP Upload", type=["zip"]) if uploaded_file: if st.button("๐Ÿš€ Start Terminator Build"): status_box = st.status("Initializing System...", expanded=True) # 1. EXTRACT if os.path.exists("project_extract"): shutil.rmtree("project_extract") os.makedirs("project_extract", exist_ok=True) with open("uploaded.zip", "wb") as f: f.write(uploaded_file.getbuffer()) with zipfile.ZipFile("uploaded.zip", "r") as z: z.extractall("project_extract") project_root = None for root, dirs, files in os.walk("project_extract"): if "gradlew" in files: project_root = root break if not project_root: st.error("Gradlew not found.") st.stop() subprocess.run(["chmod", "+x", os.path.join(project_root, "gradlew")]) # 2. PRE-BUILD MODERNIZATION initial_modernization(project_root, status_box) # 3. THE LOOP (MAX RETRIES) build_success = False cmd = ["./gradlew", "assembleRelease", "--no-daemon", "--stacktrace"] for attempt in range(1, MAX_RETRIES + 1): status_box.write(f"๐Ÿ”„ **Build Attempt {attempt}/{MAX_RETRIES}** is running...") result = subprocess.run(cmd, cwd=project_root, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) if result.returncode == 0: build_success = True break # Loop khatam, kaam ho gaya else: status_box.write(f"โŒ Build Failed (Attempt {attempt}). AI is analyzing logs...") # AI FIXING LOGIC fixed = analyze_and_fix_errors(project_root, result.stderr, status_box) if not fixed: # Agar AI file nahi dhoond paya, to shayad "clean" ki zaroorat hai subprocess.run(["./gradlew", "clean"], cwd=project_root) status_box.write("๐Ÿงน AI cleaned the project cache.") # Thora saans lene do system ko time.sleep(1) # 4. FINAL OUTCOME if build_success: status_box.update(label="โœ… Build Successful! Signing APK...", state="complete") target_apk = None for root, dirs, files in os.walk(project_root): for file in files: if file.endswith(".apk") and "release" in file: target_apk = os.path.join(root, file) break if target_apk: keystore = generate_keystore() signed = "AI_Terminator_App.apk" subprocess.run(["zipalign", "-v", "-p", "4", target_apk, "aligned.apk"], stdout=subprocess.DEVNULL) subprocess.run(["apksigner", "sign", "--ks", keystore, "--ks-pass", "pass:android", "--out", signed, "aligned.apk"]) with open(signed, "rb") as f: st.download_button("โฌ‡๏ธ Download Final APK", f, file_name=signed) else: status_box.update(label="โŒ Mission Failed", state="error") st.error(f"AI tried {MAX_RETRIES} times but could not fix all errors.") st.text_area("Last Error Log", result.stderr[-2000:], height=300) if os.path.exists("uploaded.zip"): os.remove("uploaded.zip")