Spaces:
Running on Zero
Running on Zero
File size: 7,763 Bytes
9f0d24c 87e1a71 d818713 87e1a71 d818713 efbf124 03be16f d818713 fe3ebb9 d818713 062faa6 d818713 062faa6 d818713 87e1a71 d818713 95d4934 8e183cd 95d4934 44d2ebd 87e1a71 95d4934 fe3ebb9 e7cebac 44d2ebd fe3ebb9 87e1a71 d818713 062faa6 cba6fe4 062faa6 cba6fe4 2d863fc 062faa6 d818713 210247a 95d4934 210247a d818713 95d4934 87e1a71 d818713 | 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 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 | from transformers import pipeline, AutoTokenizer
import gradio as gr
import spaces
import os
import time
from collections import defaultdict
# Hidden state for the counter
# counter_state = gr.State(0)
hf_token = os.getenv("HF_TOKEN")
model_name = "markrodrigo/Qwen-3.5-2B-Spatial-SQL-1.1" # or any model / local path
# Load tokenizer
tokenizer = AutoTokenizer.from_pretrained(
model_name,
trust_remote_code=True, # needed for many Qwen models
)
pipe = pipeline("text-generation", model=model_name, tokenizer=tokenizer, device_map="auto", token=hf_token)
usage_tracker = defaultdict(list)
MAX_REQUESTS_PER_DAY = 3
TRUSTED_USERS = {"markrodrigo"} # ← Add your username here
# The Alpaca instruction prompt format
'''ALPACA_TEMPLATE = """<|begin_of_text|><|start_header_id|>system<|end_header_id|> You are a helpful assistant. You are an expert at PostGIS and Postgresql and SQL and psql. <|eot_id|><|start_header_id|>user<|end_header_id|>
### Instruction: Write a PostGIS SQL statement for the following.
{instruction}
### Input:
{input}
### Response:
<|eot_id|><|start_header_id|>assistant<|end_header_id|>
"""'''
# Define your list of pre-set example prompts
PRESET_EXAMPLES = [
"What is the area for the polygon? : 'Polygon ((-3.7515154 40.3855551, -3.7514972 40.3856581, -3.7507005 40.3855767, -3.7507167 40.3854722, -3.7515154 40.3855551))'",
"What is the centroid for the polygon? : 'Polygon ((-3.6934636 40.4808785, -3.6933352 40.4811486, -3.6930125 40.4810598, -3.693141 40.4807897, -3.6934636 40.4808785))'",
"What is the thousand meter buffer for the following point? : 'Point(-8.7522658 41.3862664)'",
"How long is the line? : 'LINESTRING (-3.6976693 40.4263178, -3.6986082 40.4258729)'",
"How far apart is the point and line? : 'Point(-109.87549823 38.60574249)' 'LineString(-109.24324628 38.76349931, -109.4821773 38.6875815)'"
]
# Custom CSS targeting the button by its ID
custom_css = """
#special-button {
background-color: #0052FF !important; /* Your desired color */
color: white !important;
border: none !important;
font-weight: 600 !important;
padding: 12px 24px !important;
}
#special-button:hover {
background-color: #CAD3DE !important;
transform: scale(1.03);
transition: all 0.2s ease;
}
#clear-chat-btn {
width: 200px !important;
min-width: 200px !important;
max-width: 200px !important;
height: 42px !important;
background-color: #FF5733 !important; /* Main hex color */
color: #FFFFFF !important; /* White text */
border: none !important;
font-size: 14px !important;
font-weight: 600 !important;
padding: 8px 16px !important;
border-radius: 8px !important; /* Optional rounded look */
}
#clear-chat-btn:hover {
background-color: #C70039 !important; /* Hover hex color (darker) */
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(199, 0, 57, 0.3) !important;
}
"""
global_counter = 0
# def get_latest_counter():
# global global_counter
# return global_counter # Dynamically fetches the current server value
def increment_counter():
global global_counter
global_counter += 1
return global_counter
@spaces.GPU
def respond(user_message, chat_history, profile: gr.OAuthProfile | None): # , counter):
# === BLOCK ANONYMOUS USERS ===
if profile is None:
raise gr.Error("You must be logged in with a Hugging Face account to use this demo.")
username = profile.username
print("Debug username:", username) # You can keep this temporarily
now = time.time()
usage_tracker[username] = [ts for ts in usage_tracker[username] if now - ts < 86400]
# Trusted users (you) get unlimited
if username in TRUSTED_USERS:
pass
else:
if len(usage_tracker[username]) >= MAX_REQUESTS_PER_DAY:
raise gr.Error(f"Daily limit reached ({MAX_REQUESTS_PER_DAY} requests/day).")
usage_tracker[username].append(now)
# global global_counter
# global_counter += 1
# 1. Increment counter
# counter += 1
chat_history = chat_history or []
if not user_message or not user_message.strip():
return chat_history, ""
# Modern format for Gradio 5/6
chat_history.append({"role": "user", "content": user_message})
chat_history.append({"role": "assistant", "content": None})
# prompt = ALPACA_TEMPLATE.format(instruction=user_message, input="")
# 1. Build the messages
'''messages = [
{"role": "system", "content": "Write a PostGIS SQL statement for the following."},
{"role": "user", "content": "What is the thousand meter buffer for the following point? : 'Point(-3.78621945 40.4463195)'"},
]'''
messages = [
{"role": "system", "content": "Write a PostGIS SQL statement for the following."},
{"role": "user", "content": user_message},
]
# 2. Apply ChatML template
prompt = tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True, # very important → adds <|im_start|>assistant\n
enable_thinking=False, # disable <think> tags (Qwen3)
)
sequences = pipe(
prompt,
max_new_tokens=256,
return_full_text=False,
temperature=0.4,
top_k=100,
do_sample=True,
)
bot_response = sequences[0]["generated_text"].strip()
chat_history[-1]["content"] = bot_response
return chat_history, "", global_counter # , counter
with gr.Blocks(title="Text to PostGIS Postgresql via Qwen 3.5") as demo:
gr.LoginButton()
gr.Markdown("# Natural Language to Spatial SQL.\n### Convert natural language and spatial primitives to PostGIS with Qwen 3.5")
chatbot = gr.Chatbot(
label="Chat",
height=400,
# type="messages",
# show_copy_button=True,
)
with gr.Row():
with gr.Column(scale=5):
msg = gr.Textbox(
placeholder="Natural Language : WKT format",
lines=2,
container=False
)
with gr.Column(scale=1, min_width=100):
submit_btn = gr.Button("Submit", variant="primary", elem_id="special-button" ) # gr.themes.Ocean()
gr.Markdown("### Quick Examples")
gr.Examples(
examples=PRESET_EXAMPLES,
inputs=msg,
label="Click an example → then click Submit"
)
# counter_display = gr.Textbox(label="Request Counter:", value=0, interactive=False)
# submit_btn.click(fn=respond, inputs=[msg, chatbot, counter_state], outputs=[chatbot, msg, counter_state, counter_display])
# msg.submit(fn=respond, inputs=[msg, chatbot, counter_state], outputs=[chatbot, msg, counter_state, counter_display])
clear_btn = gr.Button("Clear Chat", elem_id="clear-chat-btn")
clear_btn.click(lambda: ([], ""), outputs=[chatbot, msg])
gr.Markdown("## 🚀 Space Request Tracker")
# gr.Textbox(value=str(global_counter), interactive=False)
counter_display = gr.Number(value=global_counter, label="Global Counter")
submit_btn.click(fn=respond, inputs=[msg, chatbot], outputs=[chatbot, msg, counter_display]).then(
fn=increment_counter,
inputs=[],
outputs=counter_display
)
msg.submit(fn=respond, inputs=[msg, chatbot], outputs=[chatbot, msg, counter_display])
# Display counter (optional)
# CRITICAL: This triggers every time the page loads or refreshes!
# demo.load(fn=get_latest_counter, inputs=[], outputs=counter_display)
demo.load(fn=lambda: global_counter, inputs=[], outputs=counter_display)
if __name__ == "__main__":
print("Gradio version:", gr.__version__)
demo.launch(css=custom_css) |