File size: 6,052 Bytes
b7082b3
 
 
 
 
563534f
122833b
b7082b3
563534f
b7082b3
 
 
 
563534f
b7082b3
 
 
 
 
 
 
 
 
 
 
 
 
 
122833b
 
 
 
b7082b3
 
122833b
 
 
 
b7082b3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122833b
b7082b3
 
 
 
122833b
b7082b3
122833b
b7082b3
 
 
 
 
 
 
 
 
122833b
 
b7082b3
122833b
 
 
b7082b3
122833b
b7082b3
122833b
 
 
 
 
 
 
b7082b3
 
 
 
563534f
b7082b3
122833b
 
b7082b3
 
 
 
 
 
 
 
563534f
b7082b3
563534f
 
b7082b3
 
122833b
b7082b3
 
 
 
563534f
b7082b3
563534f
 
122833b
 
 
 
 
 
b7082b3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
563534f
 
b7082b3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import os
import re
import json
import tempfile
import zipfile
import gradio as gr
import spaces
from huggingface_hub import hf_hub_download

# ---- LLM: llama.cpp via llama_cpp_agent ----
from llama_cpp import Llama
from llama_cpp_agent import LlamaCppAgent, MessagesFormatterType
from llama_cpp_agent.providers import LlamaCppPythonProvider

# ----------------------
# Model configuration
# ----------------------
DEFAULT_REPO_ID = "tHottie/NeuralDaredevil-8B-abliterated-Q4_K_M-GGUF"
DEFAULT_FILENAME = "neuraldaredevil-8b-abliterated-q4_k_m-imat.gguf"
MODELS_DIR = "models"
os.makedirs(MODELS_DIR, exist_ok=True)

def ensure_model(repo_id: str, filename: str) -> str:
    local_path = os.path.join(MODELS_DIR, filename)
    if not os.path.exists(local_path):
        hf_hub_download(repo_id=repo_id, filename=filename, local_dir=MODELS_DIR)
    return local_path

# GPU context ensures model loads only when a GPU session is active
@spaces.GPU(duration=120)
def package_with_llm(ai_text, repo_id, filename, temperature, top_p, top_k, repeat_penalty, max_tokens, force_heuristic):
    model_path = ensure_model(repo_id, filename)
    llm = Llama(
        model_path=model_path,
        n_ctx=8192,
        n_gpu_layers=81,
        n_batch=1024,
        flash_attn=True,
    )
    provider = LlamaCppPythonProvider(llm)
    agent = LlamaCppAgent(
        provider,
        system_prompt=(
            "You are an expert code-packager and software project compiler. "
            "Given an AI-generated project description containing code blocks and hints "
            "about filenames or structure, extract each file with its most likely filename "
            "and exact code content. Return ONLY a strict JSON array named manifest, "
            "where each element is an object with keys 'filename' and 'content'. "
            "Do not add commentary outside JSON. "
            "Ensure filenames include directories if implied (e.g., 'src/main.py'). "
            "Preserve code exactly as provided inside code fences."
        ),
        predefined_messages_formatter_type=MessagesFormatterType.GEMMA_2,
        debug_output=False
    )

    prompt = f"""
Read the following AI project description and return ONLY JSON.
Output schema (strict):
[{{"filename": "server.js", "content": "// code..."}}]

AI project description:
{ai_text}
"""

    settings = provider.get_provider_default_settings()
    settings.temperature = float(temperature)
    settings.top_p = float(top_p)
    settings.top_k = int(top_k)
    settings.repeat_penalty = float(repeat_penalty)
    settings.max_tokens = int(max_tokens)
    settings.stream = False

    out = agent.get_chat_response(prompt, llm_sampling_settings=settings, print_output=False)

    # Parse JSON output robustly
    try:
        start, end = out.find('['), out.rfind(']')
        if start != -1 and end > start:
            manifest = json.loads(out[start:end+1])
        else:
            raise ValueError("No JSON found")
    except Exception:
        manifest = [{"filename": "project.txt", "content": out}]

    # Heuristic fallback if model fails
    if force_heuristic or (len(manifest) == 1 and manifest[0]["filename"] == "project.txt"):
        manifest = naive_regex_merge(ai_text)

    return create_zip_from_manifest(manifest)

def naive_regex_merge(text):
    blocks = []
    code_pattern = re.compile(r"```([a-zA-Z0-9]*)\n(.*?)```", re.DOTALL)
    lines = text.splitlines()
    candidates = []
    for line in lines:
        m = re.search(r"([A-Za-z0-9_\-./]+?\.[A-Za-z0-9]+)", line)
        if m:
            candidates.append(m.group(1))
    for idx, m in enumerate(code_pattern.finditer(text)):
        lang = m.group(1) or "txt"
        code = m.group(2)
        filename = candidates[idx] if idx < len(candidates) else f"file_{idx+1}.{lang}"
        blocks.append({"filename": filename, "content": code})
    return blocks

def create_zip_from_manifest(manifest):
    temp_dir = tempfile.mkdtemp()
    zip_path = os.path.join(temp_dir, "project.zip")
    with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as z:
        for item in manifest:
            fname = item.get("filename", "project.txt").lstrip("/")
            content = item.get("content", "")
            fpath = os.path.join(temp_dir, fname)
            os.makedirs(os.path.dirname(fpath), exist_ok=True)
            with open(fpath, "w", encoding="utf-8") as f:
                f.write(content)
            z.write(fpath, arcname=fname)
    return zip_path

# --------------------------
# Gradio Interface
# --------------------------
with gr.Blocks(title="AI Project Packager (GGUF, ZeroGPU)") as demo:
    gr.Markdown("# AI Project Packager (GGUF, ZeroGPU)")
    gr.Markdown("Uses ephemeral GPU power to infer filenames & package AI-generated code projects.")

    with gr.Row():
        ai_text = gr.Textbox(lines=24, label="Paste AI response here")

    with gr.Accordion("LLM Settings", open=False):
        repo_id = gr.Textbox(value=DEFAULT_REPO_ID, label="Model repo_id")
        filename = gr.Textbox(value=DEFAULT_FILENAME, label="Model filename (*.gguf)")
        with gr.Row():
            temperature = gr.Slider(0.0, 2.0, value=0.2, step=0.05, label="Temperature")
            top_p = gr.Slider(0.1, 1.0, value=0.9, step=0.05, label="Top-p")
            top_k = gr.Slider(0, 100, value=40, step=1, label="Top-k")
        with gr.Row():
            repeat_penalty = gr.Slider(0.8, 2.0, value=1.1, step=0.05, label="Repeat penalty")
            max_tokens = gr.Slider(256, 4096, value=2048, step=32, label="Max tokens")
        force_heuristic = gr.Checkbox(value=False, label="Force heuristic filename/code merge if JSON parse fails")

    out_zip = gr.File(label="Download packaged ZIP")

    run_btn = gr.Button("Package Project", variant="primary")
    run_btn.click(
        fn=package_with_llm,
        inputs=[ai_text, repo_id, filename, temperature, top_p, top_k, repeat_penalty, max_tokens, force_heuristic],
        outputs=[out_zip]
    )

if __name__ == "__main__":
    demo.launch()