ThongCoding commited on
Commit
c989e45
·
1 Parent(s): e3d6cc3
Dockerfile CHANGED
@@ -4,10 +4,10 @@ RUN apt-get update && apt-get install -y \
4
  build-essential cmake wget git \
5
  && rm -rf /var/lib/apt/lists/*
6
 
7
- WORKDIR /code
8
- COPY . /code
9
 
10
  RUN pip install --no-cache-dir -r requirements.txt
11
- RUN chmod -R 777 /code
12
 
13
  CMD ["python", "app.py"]
 
4
  build-essential cmake wget git \
5
  && rm -rf /var/lib/apt/lists/*
6
 
7
+ WORKDIR /app
8
+ COPY . /app
9
 
10
  RUN pip install --no-cache-dir -r requirements.txt
11
+ RUN chmod -R 777 /app
12
 
13
  CMD ["python", "app.py"]
app.py CHANGED
@@ -1,30 +1,81 @@
 
1
  from fastapi import FastAPI
2
  from fastapi.middleware.cors import CORSMiddleware
3
  from pydantic import BaseModel
4
- from model import generate_structure
 
5
  import uvicorn
6
 
 
 
 
 
7
  app = FastAPI()
8
 
9
- # Allow all CORS (for testing or frontend use)
10
  app.add_middleware(
11
  CORSMiddleware,
12
- allow_origins=["*"],
13
- allow_credentials=True,
14
  allow_methods=["*"],
15
  allow_headers=["*"],
16
  )
17
 
 
18
  class PromptRequest(BaseModel):
19
- prompt: str
 
 
20
 
21
- @app.post("/prompt")
22
- async def prompt_route(data: PromptRequest):
23
  try:
24
- response = generate_structure(data.prompt)
25
- return {"response": response}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  except Exception as e:
27
  return {"error": str(e)}
28
 
29
- if __name__ == "__main__":
30
  uvicorn.run(app, host="0.0.0.0", port=7860)
 
1
+ import curl_cffi
2
  from fastapi import FastAPI
3
  from fastapi.middleware.cors import CORSMiddleware
4
  from pydantic import BaseModel
5
+ import os
6
+
7
  import uvicorn
8
 
9
+ # Load Gemini API key from secret
10
+ GEM_API_KEY = os.getenv('GEMINI_API_KEY')
11
+
12
+ # Init app
13
  app = FastAPI()
14
 
15
+ # CORS (allow frontend)
16
  app.add_middleware(
17
  CORSMiddleware,
18
+ allow_origins=["*"], # Optional: restrict in prod
 
19
  allow_methods=["*"],
20
  allow_headers=["*"],
21
  )
22
 
23
+ # Request model
24
  class PromptRequest(BaseModel):
25
+ structure_name: str
26
+ structure_desc: str
27
+ blocks_allowed: list[str] # Enforce lowercase block names client-side
28
 
29
+ @app.post("/generate_structure")
30
+ async def generate_with_gemini(req: PromptRequest):
31
  try:
32
+ # Compose the extremely strict prompt
33
+ prompt = f"""You are a Minecraft-style structure planner. You have the curiosity to build almost anything you could think of. {req.structure_name}
34
+
35
+ {req.structure_desc}
36
+
37
+ Only output a JSON object describing a 3D structure using this format:
38
+
39
+ {{
40
+ "width": <int>,
41
+ "height": <int>,
42
+ "depth": <int>,
43
+ "layers": [
44
+ [
45
+ ["stone", "stone", "stone"],
46
+ ["stone", "air", "stone"],
47
+ ["stone", "stone", "stone"]
48
+ ],
49
+ ...
50
+ ]
51
+ }}
52
+
53
+ Only use lowercase Minecraft block IDs (e.g. "stone", "air", "glass", "planks").
54
+ You could only build this structure using {" ".join(req.blocks_allowed)}
55
+ Do not include any natural language or explanation.
56
+ Output strictly valid JSON only."""
57
+
58
+ # Call Gemini API using curl_cffi
59
+ session = curl_cffi.Session(impersonate="chrome110") # Optional impersonation
60
+ response = session.post(
61
+ url="https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent",
62
+ headers={
63
+ "x-goog-api-key": GEM_API_KEY,
64
+ "Content-Type": "application/json"
65
+ },
66
+ json={
67
+ "contents": [{
68
+ "parts": [{
69
+ "text": prompt
70
+ }]
71
+ }]
72
+ }
73
+ )
74
+
75
+ return {"response": response.text}
76
+
77
  except Exception as e:
78
  return {"error": str(e)}
79
 
80
+ if __name__ == "__main__":
81
  uvicorn.run(app, host="0.0.0.0", port=7860)
cache/text.txt DELETED
File without changes
data/example_output.json DELETED
@@ -1,17 +0,0 @@
1
- {
2
- "width": 3,
3
- "height": 2,
4
- "depth": 3,
5
- "layers": [
6
- [
7
- ["stone", "stone", "stone"],
8
- ["stone", "air", "stone"],
9
- ["stone", "stone", "stone"]
10
- ],
11
- [
12
- ["stone", "glass", "stone"],
13
- ["glass", "air", "glass"],
14
- ["stone", "glass", "stone"]
15
- ]
16
- ]
17
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
model.py DELETED
@@ -1,41 +0,0 @@
1
- import os
2
- import shutil
3
- import requests
4
- from llama_cpp import Llama
5
-
6
- MODEL_URL = "https://huggingface.co/MaziyarPanahi/Llama-3.2-1B-Instruct-GGUF/resolve/main/Llama-3.2-1B-Instruct.Q4_K_M.gguf"
7
- MODEL_FILENAME = "Llama-3.2-1B-Instruct.Q4_K_M.gguf"
8
- MODEL_PATH = f"./models/{MODEL_FILENAME}"
9
-
10
- def download_model():
11
- os.makedirs("./models", exist_ok=True)
12
- print("📦 Downloading GGUF model directly from URL...")
13
- response = requests.get(MODEL_URL, stream=True)
14
- if response.status_code == 200:
15
- with open(MODEL_PATH, 'wb') as f:
16
- shutil.copyfileobj(response.raw, f)
17
- print(f"✅ Model downloaded to {MODEL_PATH}")
18
- else:
19
- raise RuntimeError(f"❌ Failed to download model. Status code: {response.status_code}")
20
-
21
- # Only download if not already present
22
- if not os.path.exists(MODEL_PATH):
23
- download_model()
24
-
25
- # Load model with llama-cpp-python
26
- llm = Llama(
27
- model_path=MODEL_PATH,
28
- n_ctx=512,
29
- n_batch=512,
30
- n_threads=6,
31
- chat_format="llama-3",
32
- verbose=False
33
- )
34
-
35
- def generate_structure(prompt: str) -> str:
36
- messages = [
37
- {"role": "system", "content": "You are a Minecraft-style structure planner. You always respond with strictly valid JSON describing a 3D structure."},
38
- {"role": "user", "content": prompt}
39
- ]
40
- output = llm.create_chat_completion(messages=messages)
41
- return output["choices"][0]["message"]["content"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
prompt.py DELETED
@@ -1,24 +0,0 @@
1
- def get_strict_prompt() -> str:
2
- return """
3
- You are a Minecraft-style structure planner.
4
-
5
- Only output a JSON object describing a 3D structure using this format:
6
-
7
- {
8
- "width": <int>,
9
- "height": <int>,
10
- "depth": <int>,
11
- "layers": [
12
- [
13
- ["stone", "stone", "stone"],
14
- ["stone", "air", "stone"],
15
- ["stone", "stone", "stone"]
16
- ],
17
- ...
18
- ]
19
- }
20
-
21
- Only use lowercase Minecraft block IDs (e.g. "stone", "air", "glass", "planks").
22
- Max size: 7×7×7. Do not include any natural language or explanation.
23
- Output strictly valid JSON only.
24
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
requirements.txt CHANGED
@@ -1,5 +1,4 @@
1
  fastapi
2
  uvicorn
3
- llama-cpp-python==0.2.74 # prebuilt versions now available from PyPI
4
  python-dotenv
5
- huggingface_hub
 
1
  fastapi
2
  uvicorn
3
+ curl_cffi
4
  python-dotenv
 
structure_prompt_config.json DELETED
@@ -1,3 +0,0 @@
1
- {
2
- "template": "You are a Minecraft-style structure planner. You have the curiosity to build almost anything you could think of. {structure_name}\n\nOnly output a JSON object describing a 3D structure using this format:\n\n{{\n \"width\": <int>,\n \"height\": <int>,\n \"depth\": <int>,\n \"layers\": [\n [\n [\"stone\", \"stone\", \"stone\"],\n [\"stone\", \"air\", \"stone\"],\n [\"stone\", \"stone\", \"stone\"]\n ],\n ...\n ]\n}}\n\nOnly use lowercase Minecraft block IDs (e.g. \"stone\", \"air\", \"glass\", \"planks\").\nYou could only build this structure using {blocks_allowed}\nDo not include any natural language or explanation.\nOutput strictly valid JSON only."
3
- }
 
 
 
 
structures.json DELETED
@@ -1,74 +0,0 @@
1
- [
2
- {
3
- "name": "castle_tower",
4
- "description": "A medieval tower with battlements and defensive height.",
5
- "required_blocks": ["stone_bricks", "cobblestone", "mossy_stone_bricks", "oak_planks", "torch"],
6
- "tags": ["medieval", "defense"]
7
- },
8
- {
9
- "name": "underground_bunker",
10
- "description": "A secure underground base with reinforced walls and redstone lighting.",
11
- "required_blocks": ["obsidian", "iron_block", "redstone_lamp", "lever", "smooth_stone"],
12
- "tags": ["underground", "modern"]
13
- },
14
- {
15
- "name": "treehouse",
16
- "description": "A cozy elevated structure built into a tree canopy.",
17
- "required_blocks": ["oak_logs", "oak_planks", "leaves", "ladder", "glass_pane"],
18
- "tags": ["nature", "elevated"]
19
- },
20
- {
21
- "name": "desert_hut",
22
- "description": "A simple shelter for desert biomes.",
23
- "required_blocks": ["sandstone", "smooth_sandstone", "cut_sandstone", "oak_door", "torch"],
24
- "tags": ["desert", "village"]
25
- },
26
- {
27
- "name": "ice_temple",
28
- "description": "A mystical temple made from packed ice and glowing blocks.",
29
- "required_blocks": ["packed_ice", "blue_ice", "snow_block", "sea_lantern", "light_blue_stained_glass"],
30
- "tags": ["frozen", "temple"]
31
- },
32
- {
33
- "name": "sky_platform",
34
- "description": "A suspended platform in the sky, usable as base foundation.",
35
- "required_blocks": ["stone_slab", "glass", "iron_block", "torch", "scaffolding"],
36
- "tags": ["sky", "platform"]
37
- },
38
- {
39
- "name": "nether_watchtower",
40
- "description": "A watchtower adapted for survival in the Nether.",
41
- "required_blocks": ["nether_bricks", "red_nether_bricks", "soul_torch", "basalt", "iron_bars"],
42
- "tags": ["nether", "fortification"]
43
- },
44
- {
45
- "name": "floating_island",
46
- "description": "A small magical floating island with vegetation.",
47
- "required_blocks": ["grass_block", "dirt", "leaves", "oak_logs", "glowstone"],
48
- "tags": ["floating", "fantasy"]
49
- },
50
- {
51
- "name": "library_room",
52
- "description": "An interior room filled with books and study space.",
53
- "required_blocks": ["bookshelf", "oak_planks", "lantern", "glass_pane", "carpet"],
54
- "tags": ["indoor", "library"]
55
- },
56
- {
57
- "name": "farm_stable",
58
- "description": "A small stable and feeding zone for animals.",
59
- "required_blocks": ["hay_block", "fence", "oak_planks", "coarse_dirt", "torch"],
60
- "tags": ["farm", "animals"]
61
- },
62
- {
63
- "name": "swamp_shack",
64
- "description": "A mossy shack on stilts above swampy water.",
65
- "required_blocks": ["mossy_cobblestone", "spruce_planks", "vines", "lily_pad", "oak_trapdoor"],
66
- "tags": ["swamp", "shack"]
67
- },
68
- {
69
- "name": "mine_entrance",
70
- "description": "A small cave entrance with support beams and torches.",
71
- "required_blocks": ["stone", "oak_logs", "rails", "torch", "gravel"],
72
- "tags": ["mining", "cave"]
73
- }
74
- ]