npm-resolver / app.py
ArpitBaliyan's picture
Update app.py
fb0cc1d verified
import gradio as gr
import json
import torch
# Detect device
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
print(f"Running on device: {DEVICE}")
# Load model โ€” unsloth only works on GPU; fall back to plain transformers on CPU
if DEVICE == "cuda":
from unsloth import FastLanguageModel
print("Loading trained model via unsloth...")
model, tokenizer = FastLanguageModel.from_pretrained(
model_name="ArpitBaliyan/npm-resolver-rl-model",
max_seq_length=2048,
load_in_4bit=True,
)
FastLanguageModel.for_inference(model)
else:
from transformers import AutoModelForCausalLM, AutoTokenizer
print("No GPU found โ€” loading model via transformers (CPU mode, slow)...")
MODEL_NAME = "ArpitBaliyan/npm-resolver-rl-model"
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, use_fast=False)
model = AutoModelForCausalLM.from_pretrained(MODEL_NAME, torch_dtype=torch.float32)
model.eval()
def resolve_npm_conflict(pkg_json_str, error_log_str):
system_prompt = """You are an expert Node.js dependency resolver.
You must output a SINGLE JSON object with keys: "package_to_update" and "new_version".
Do not output markdown or explanations. Just raw JSON.
CRITICAL RULE: You MUST include the caret symbol (^) in the new_version (e.g., "^18.0.0")."""
user_prompt = f"PACKAGE.JSON:\n{pkg_json_str}\n\nERRORS:\n{error_log_str}"
messages = [
{"role": "system", "content": system_prompt},
{"role": "user", "content": user_prompt}
]
inputs = tokenizer.apply_chat_template(
messages, tokenize=True, add_generation_prompt=True, return_tensors="pt"
).to(DEVICE)
outputs = model.generate(input_ids=inputs, max_new_tokens=64, pad_token_id=tokenizer.eos_token_id)
generated_tokens = outputs[0][inputs.shape[1]:]
ai_response = tokenizer.decode(generated_tokens, skip_special_tokens=True).strip()
try:
# Clean the response in case the AI added markdown backticks
clean_json = ai_response.replace("```json", "").replace("```", "").strip()
action = json.loads(clean_json)
pkg = action.get("package_to_update")
ver = action.get("new_version")
current_data = json.loads(pkg_json_str)
# Check if "dependencies" key exists, otherwise use root
deps = current_data.get("dependencies", current_data)
if ver == "DELETE":
deps.pop(pkg, None)
else:
deps[pkg] = ver
# If we had to go into a sub-key, put it back
if "dependencies" in current_data:
current_data["dependencies"] = deps
else:
current_data = deps
return clean_json, json.dumps(current_data, indent=2)
except Exception as e:
return ai_response, f"Error applying fix: {str(e)}"
# UI Layout
with gr.Blocks(theme=gr.themes.Soft()) as demo:
gr.Markdown("# ๐Ÿš€ AutoResolve RL: AI Dependency Fixer")
with gr.Row():
with gr.Column():
in_pkg = gr.Code(label="Current package.json", language="json", lines=10)
in_err = gr.Textbox(label="NPM Error Log", lines=4)
btn = gr.Button("๐Ÿ”ฎ Resolve Dependencies", variant="primary")
with gr.Column():
out_action = gr.Code(label="AI Action", language="json")
out_pkg = gr.Code(label="Fixed package.json", language="json")
# Examples for the judges to click
gr.Examples(
examples=[
['{"dependencies": {"react": "^17.0.0", "react-router-dom": "6.0.0"}}', "Conflict: react-router-dom@6.0.0 requires react@^18.0.0"],
],
inputs=[in_pkg, in_err]
)
btn.click(resolve_npm_conflict, inputs=[in_pkg, in_err], outputs=[out_action, out_pkg])
demo.launch()