Spaces:
Paused
Paused
Deploy private Astheral demo with real weights on ZeroGPU
Browse files- README.md +30 -6
- app.py +91 -0
- requirements.txt +5 -0
README.md
CHANGED
|
@@ -1,13 +1,37 @@
|
|
| 1 |
---
|
| 2 |
title: Astheral
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: gradio
|
| 7 |
-
sdk_version:
|
| 8 |
-
python_version:
|
| 9 |
app_file: app.py
|
|
|
|
| 10 |
pinned: false
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
---
|
|
|
|
| 12 |
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
title: Astheral
|
| 3 |
+
emoji: ✨
|
| 4 |
+
colorFrom: indigo
|
| 5 |
+
colorTo: purple
|
| 6 |
sdk: gradio
|
| 7 |
+
sdk_version: 5.49.1
|
| 8 |
+
python_version: "3.10"
|
| 9 |
app_file: app.py
|
| 10 |
+
hf_oauth: true
|
| 11 |
pinned: false
|
| 12 |
+
license: llama3.1
|
| 13 |
+
models:
|
| 14 |
+
- SEE7/Astheral
|
| 15 |
+
short_description: Real Astheral 8.03B weights with streaming ZeroGPU inference
|
| 16 |
---
|
| 17 |
+
# Astheral
|
| 18 |
|
| 19 |
+
**Built with Llama.** This Space runs the actual merged weights from [SEE7/Astheral](https://huggingface.co/SEE7/Astheral), fine-tuned from DeepHermes 3 / Llama 3.1 8B. No mock replies, base-model substitution, or external inference API.
|
| 20 |
+
|
| 21 |
+
Model revision: `d9aa899722be4788f57107c2951c72d0ec6614ee`.
|
| 22 |
+
|
| 23 |
+
## Hosting and costs
|
| 24 |
+
|
| 25 |
+
Private owner-use deployment to avoid exposing your prepaid credits to public traffic. Configured for Hugging Face ZeroGPU, using the default GPU size. Requires ZeroGPU hardware to remain selected in Settings. No CPU inference fallback and no paid dedicated GPU is configured.
|
| 26 |
+
|
| 27 |
+
As documented by Hugging Face at deployment, PRO includes 40 GPU minutes per day with higher queue priority. Beyond that allowance, ZeroGPU can automatically consume prepaid credits at $1 per 10 GPU minutes. This application does not implement an account-wide billing cap. Monitor your billing and quota in Hugging Face settings.
|
| 28 |
+
|
| 29 |
+
ZeroGPU is shared: GPU queues and cold starts can add latency. Replies stream when generation starts. Each request reserves up to 30 GPU seconds, with generation targeting 23 seconds, 2,048 input tokens, and a default 192 output tokens. Only one generation runs at once.
|
| 30 |
+
|
| 31 |
+
## Modes
|
| 32 |
+
|
| 33 |
+
Instruct and Thinking use the model's published settings.json. Thinking uses the model's existing visible worked-solution format and may reach the output limit. The model and tokenizer are pinned to the same repository revision.
|
| 34 |
+
|
| 35 |
+
## Licensing
|
| 36 |
+
|
| 37 |
+
See the [model card and license](https://huggingface.co/SEE7/Astheral). Llama 3.1 licensing and attribution apply.
|
app.py
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
os.environ["TOKENIZERS_PARALLELISM"] = "false"
|
| 3 |
+
|
| 4 |
+
import spaces
|
| 5 |
+
import json
|
| 6 |
+
from threading import Thread
|
| 7 |
+
import gradio as gr
|
| 8 |
+
import torch
|
| 9 |
+
from huggingface_hub import hf_hub_download
|
| 10 |
+
from transformers import AutoModelForCausalLM, AutoTokenizer, TextIteratorStreamer
|
| 11 |
+
|
| 12 |
+
MODEL_ID = "SEE7/Astheral"
|
| 13 |
+
MODEL_REVISION = "d9aa899722be4788f57107c2951c72d0ec6614ee"
|
| 14 |
+
settings = json.load(open(hf_hub_download(MODEL_ID, "settings.json", revision=MODEL_REVISION)))
|
| 15 |
+
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, revision=MODEL_REVISION)
|
| 16 |
+
model = AutoModelForCausalLM.from_pretrained(
|
| 17 |
+
MODEL_ID, revision=MODEL_REVISION, torch_dtype=torch.bfloat16,
|
| 18 |
+
device_map={"": "cuda"}, low_cpu_mem_usage=True,
|
| 19 |
+
attn_implementation="sdpa", use_safetensors=True,
|
| 20 |
+
).eval()
|
| 21 |
+
|
| 22 |
+
@spaces.GPU(duration=30)
|
| 23 |
+
def respond(message, history, max_tokens, temperature, mode, request: gr.Request):
|
| 24 |
+
if not message or not message.strip():
|
| 25 |
+
raise gr.Error("Enter a message first.")
|
| 26 |
+
if len(message) > 12000:
|
| 27 |
+
raise gr.Error("Please keep your message under 12,000 characters.")
|
| 28 |
+
system = settings["system"]
|
| 29 |
+
if mode == "Thinking":
|
| 30 |
+
system += "\n" + settings["thinking"]
|
| 31 |
+
messages = [{"role": "system", "content": system}]
|
| 32 |
+
# Keep the system instruction and the most recent complete turns within 2K tokens.
|
| 33 |
+
turns = [item for item in history[-12:] if item.get("role") in ("user", "assistant") and isinstance(item.get("content"), str)]
|
| 34 |
+
latest = {"role": "user", "content": message.strip()}
|
| 35 |
+
while turns and len(tokenizer.apply_chat_template(messages + turns + [latest], tokenize=True, add_generation_prompt=True)) > 2048:
|
| 36 |
+
turns = turns[2:]
|
| 37 |
+
inputs = tokenizer.apply_chat_template(
|
| 38 |
+
messages + turns + [latest], tokenize=True, add_generation_prompt=True,
|
| 39 |
+
return_dict=True, return_tensors="pt",
|
| 40 |
+
)
|
| 41 |
+
if inputs["input_ids"].shape[1] > 2048:
|
| 42 |
+
raise gr.Error("That message is too long for this budget-friendly demo. Please shorten it.")
|
| 43 |
+
inputs = inputs.to("cuda")
|
| 44 |
+
streamer = TextIteratorStreamer(tokenizer, skip_prompt=True, skip_special_tokens=True, timeout=28)
|
| 45 |
+
generation = dict(
|
| 46 |
+
**inputs, streamer=streamer, max_new_tokens=int(max_tokens),
|
| 47 |
+
do_sample=float(temperature) > 0, max_time=23,
|
| 48 |
+
pad_token_id=128004, eos_token_id=128009,
|
| 49 |
+
)
|
| 50 |
+
if float(temperature) > 0:
|
| 51 |
+
generation.update(temperature=float(temperature), top_p=0.9)
|
| 52 |
+
errors = []
|
| 53 |
+
def generate():
|
| 54 |
+
try:
|
| 55 |
+
with torch.inference_mode():
|
| 56 |
+
model.generate(**generation)
|
| 57 |
+
except Exception as exc:
|
| 58 |
+
errors.append(exc)
|
| 59 |
+
streamer.end()
|
| 60 |
+
worker = Thread(target=generate, daemon=True)
|
| 61 |
+
worker.start()
|
| 62 |
+
response = ""
|
| 63 |
+
try:
|
| 64 |
+
for text in streamer:
|
| 65 |
+
response += text
|
| 66 |
+
yield response
|
| 67 |
+
finally:
|
| 68 |
+
worker.join(timeout=2)
|
| 69 |
+
if errors:
|
| 70 |
+
raise gr.Error("Generation failed. Please retry with a shorter prompt.") from errors[0]
|
| 71 |
+
if not response.strip():
|
| 72 |
+
raise gr.Error("No text was generated. Please try again.")
|
| 73 |
+
|
| 74 |
+
with gr.Blocks(theme=gr.themes.Soft(primary_hue="indigo"), title="Astheral · Built with Llama") as demo:
|
| 75 |
+
gr.Markdown("# Astheral\n**Built with Llama · SEE7's real 8.03B model · ZeroGPU**")
|
| 76 |
+
gr.Markdown("Chat with the published Astheral weights. Replies stream as they are generated. Shared GPU queues and cold starts can add a wait.")
|
| 77 |
+
gr.LoginButton()
|
| 78 |
+
with gr.Accordion("Response settings", open=False):
|
| 79 |
+
max_tokens = gr.Slider(32, 512, value=192, step=32, label="Maximum new tokens")
|
| 80 |
+
temperature = gr.Slider(0, 1, value=0.6, step=0.1, label="Temperature (0 = deterministic)")
|
| 81 |
+
mode = gr.Radio(["Instruct", "Thinking"], value="Instruct", label="Mode")
|
| 82 |
+
gr.Markdown("To conserve GPU quota, each reply has a 23-second generation time target. Thinking may need more tokens to finish.")
|
| 83 |
+
gr.ChatInterface(
|
| 84 |
+
fn=respond, type="messages", additional_inputs=[max_tokens, temperature, mode],
|
| 85 |
+
examples=["Explain Python generators in three sentences.", "Write a short starship announcement."],
|
| 86 |
+
cache_examples=False, concurrency_limit=1, api_name="chat",
|
| 87 |
+
)
|
| 88 |
+
gr.Markdown("ZeroGPU usage follows your Hugging Face quota. PRO currently includes 40 GPU minutes/day; usage beyond the included quota can automatically consume prepaid credits. [Check billing](https://huggingface.co/settings/billing) · [Model and license](https://huggingface.co/SEE7/Astheral)")
|
| 89 |
+
demo.queue(max_size=6, default_concurrency_limit=1)
|
| 90 |
+
if __name__ == "__main__":
|
| 91 |
+
demo.launch()
|
requirements.txt
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
spaces
|
| 2 |
+
torch==2.8.0
|
| 3 |
+
transformers==4.57.1
|
| 4 |
+
accelerate==1.11.0
|
| 5 |
+
gradio==5.49.1
|