Androidwithai / app.py
Akwbw's picture
Update app.py
09becbc verified
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")