Text Generation
Transformers
English
chain-of-thought
reasoning
instruct
pretrained-from-scratch
decoder-only
transformer
qwen-tokenizer
rope
rmsnorm
swiglu
gqa
engram
Eval Results (legacy)
Instructions to use wop/Cosmos-T2-Accelerate-beta with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use wop/Cosmos-T2-Accelerate-beta with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="wop/Cosmos-T2-Accelerate-beta")# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("wop/Cosmos-T2-Accelerate-beta", dtype="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use wop/Cosmos-T2-Accelerate-beta with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "wop/Cosmos-T2-Accelerate-beta" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "wop/Cosmos-T2-Accelerate-beta", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/wop/Cosmos-T2-Accelerate-beta
- SGLang
How to use wop/Cosmos-T2-Accelerate-beta with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "wop/Cosmos-T2-Accelerate-beta" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "wop/Cosmos-T2-Accelerate-beta", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "wop/Cosmos-T2-Accelerate-beta" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "wop/Cosmos-T2-Accelerate-beta", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use wop/Cosmos-T2-Accelerate-beta with Docker Model Runner:
docker model run hf.co/wop/Cosmos-T2-Accelerate-beta
| """Cosmos T2-Accelerate-beta — Gradio Chat Demo | |
| Standalone inference app generated by the Cosmos T2-Accelerate-beta universal training notebook. | |
| It matches the notebook architecture: RoPE, RMSNorm, SwiGLU, GQA, and a configurable Engram memory path. | |
| """ | |
| import contextlib | |
| import math | |
| import re | |
| import threading | |
| from pathlib import Path | |
| import gradio as gr | |
| import torch | |
| import torch.nn as nn | |
| import torch.nn.functional as F | |
| from huggingface_hub import hf_hub_download | |
| from transformers import AutoTokenizer | |
| MODEL_REPO_ID = "wop/Cosmos-T2-Accelerate-beta" | |
| CHECKPOINT_NAME = "Cosmos-T2-Accelerate-beta.pt" | |
| TOKENIZER_NAME = "Qwen/Qwen2.5-0.5B" | |
| MODEL_NAME = "Cosmos T2-Accelerate-beta" | |
| DEFAULT_SYSTEM_PROMPT = "Enable thinking features: INTUITION" | |
| MAX_CTX_HARD = 1028 | |
| MAX_NEW_HARD = 1028 | |
| USE_KV_CACHE = True | |
| DEVICE = "cuda" if torch.cuda.is_available() else "cpu" | |
| DTYPE = torch.float16 if DEVICE == "cuda" else torch.float32 | |
| # --------------------------------------------------------------------------- | |
| # Architecture | |
| # --------------------------------------------------------------------------- | |
| class RMSNorm(nn.Module): | |
| def __init__(self, dim, eps=1e-6): | |
| super().__init__() | |
| self.weight = nn.Parameter(torch.ones(dim)) | |
| self.eps = eps | |
| def forward(self, x): | |
| rms = x.pow(2).mean(dim=-1, keepdim=True) | |
| x = x * torch.rsqrt(rms + self.eps) | |
| return x * self.weight | |
| def rotate_half(x): | |
| x1 = x[..., ::2] | |
| x2 = x[..., 1::2] | |
| return torch.stack((-x2, x1), dim=-1).flatten(-2) | |
| def apply_rope(q, k, cos, sin): | |
| return (q * cos) + (rotate_half(q) * sin), (k * cos) + (rotate_half(k) * sin) | |
| class GQAAttention(nn.Module): | |
| def __init__(self, d_model, n_heads, n_kv_heads, rope_base=10000, dropout=0.0): | |
| super().__init__() | |
| assert d_model % n_heads == 0 | |
| assert n_heads % n_kv_heads == 0 | |
| self.n_heads = n_heads | |
| self.n_kv_heads = n_kv_heads | |
| self.head_dim = d_model // n_heads | |
| self.dropout = dropout | |
| self.q_proj = nn.Linear(d_model, n_heads * self.head_dim, bias=False) | |
| self.k_proj = nn.Linear(d_model, n_kv_heads * self.head_dim, bias=False) | |
| self.v_proj = nn.Linear(d_model, n_kv_heads * self.head_dim, bias=False) | |
| self.o_proj = nn.Linear(d_model, d_model, bias=False) | |
| def forward(self, x, rope_cos, rope_sin, past_kv=None, use_cache=False): | |
| batch, seq_len, _ = x.shape | |
| q = self.q_proj(x).view(batch, seq_len, self.n_heads, self.head_dim).transpose(1, 2) | |
| k = self.k_proj(x).view(batch, seq_len, self.n_kv_heads, self.head_dim).transpose(1, 2) | |
| v = self.v_proj(x).view(batch, seq_len, self.n_kv_heads, self.head_dim).transpose(1, 2) | |
| q, k = apply_rope(q, k, rope_cos, rope_sin) | |
| if past_kv is not None: | |
| past_k, past_v = past_kv | |
| k = torch.cat([past_k, k], dim=2) | |
| v = torch.cat([past_v, v], dim=2) | |
| present_kv = (k, v) if use_cache else None | |
| if self.n_kv_heads != self.n_heads: | |
| repeat = self.n_heads // self.n_kv_heads | |
| k = k.repeat_interleave(repeat, dim=1) | |
| v = v.repeat_interleave(repeat, dim=1) | |
| out = F.scaled_dot_product_attention( | |
| q, k, v, is_causal=(past_kv is None), dropout_p=self.dropout if self.training else 0.0 | |
| ) | |
| out = out.transpose(1, 2).contiguous().view(batch, seq_len, -1) | |
| out = self.o_proj(out) | |
| return (out, present_kv) if use_cache else out | |
| class SwiGLUMLP(nn.Module): | |
| def __init__(self, d_model, hidden_dim, dropout=0.0): | |
| super().__init__() | |
| self.gate = nn.Linear(d_model, hidden_dim, bias=False) | |
| self.up = nn.Linear(d_model, hidden_dim, bias=False) | |
| self.down = nn.Linear(hidden_dim, d_model, bias=False) | |
| self.dropout = nn.Dropout(dropout) | |
| def forward(self, x): | |
| return self.down(self.dropout(F.silu(self.gate(x)) * self.up(x))) | |
| class EngramMemory(nn.Module): | |
| def __init__(self, d_model, bucket_count, memory_dim, order, pad_id=0, dropout=0.0): | |
| super().__init__() | |
| self.bucket_count = bucket_count | |
| self.order = order | |
| self.pad_id = pad_id | |
| self.bucket = nn.Embedding(bucket_count, memory_dim) | |
| self.query = nn.Linear(d_model, memory_dim, bias=False) | |
| self.project = nn.Linear(memory_dim, d_model, bias=False) | |
| self.gate = nn.Linear(d_model, d_model, bias=True) | |
| self.dropout = nn.Dropout(dropout) | |
| primes = [1, 1315423911, 2654435761, 97531, 433494437] | |
| self.register_buffer("primes", torch.tensor(primes[:order], dtype=torch.long), persistent=False) | |
| def hash_tokens(self, idx): | |
| batch, seq_len = idx.shape | |
| pad = torch.full((batch, self.order - 1), self.pad_id, device=idx.device, dtype=idx.dtype) | |
| history = torch.cat([pad, idx], dim=1) | |
| hashed = torch.zeros((batch, seq_len), device=idx.device, dtype=torch.long) | |
| for offset in range(self.order): | |
| slice_ = history[:, offset: offset + seq_len].long() | |
| hashed = (hashed * 1315423911 + slice_ * self.primes[offset]) % self.bucket_count | |
| return hashed | |
| def forward(self, x, idx): | |
| hashed = self.hash_tokens(idx) | |
| if hashed.size(1) != x.size(1): | |
| hashed = hashed[:, -x.size(1):] | |
| query = torch.tanh(self.query(x)) | |
| memory = self.bucket(hashed) * query | |
| memory = self.project(memory) | |
| gate = torch.sigmoid(self.gate(x)) | |
| return self.dropout(gate * memory) | |
| class Block(nn.Module): | |
| def __init__(self, d_model, n_heads, n_kv_heads, d_ff, rope_base, dropout=0.0, | |
| use_engram=False, engram_bucket_count=64, engram_dim=16, engram_order=3, pad_id=0): | |
| super().__init__() | |
| self.norm1 = RMSNorm(d_model) | |
| self.attn = GQAAttention(d_model, n_heads, n_kv_heads, rope_base=rope_base, dropout=dropout) | |
| self.norm2 = RMSNorm(d_model) | |
| self.engram = EngramMemory(d_model, engram_bucket_count, engram_dim, engram_order, | |
| pad_id=pad_id, dropout=dropout) if use_engram else None | |
| self.norm3 = RMSNorm(d_model) | |
| self.mlp = SwiGLUMLP(d_model, d_ff, dropout=dropout) | |
| def forward(self, x, idx, rope_cos, rope_sin): | |
| x = x + self.attn(self.norm1(x), rope_cos, rope_sin) | |
| if self.engram is not None: | |
| x = x + self.engram(self.norm2(x), idx) | |
| return x + self.mlp(self.norm3(x)) | |
| def forward_cached(self, x, idx_context, rope_cos, rope_sin, past_kv=None): | |
| attn_out, present_kv = self.attn(self.norm1(x), rope_cos, rope_sin, past_kv=past_kv, use_cache=True) | |
| x = x + attn_out | |
| if self.engram is not None: | |
| x = x + self.engram(self.norm2(x), idx_context) | |
| x = x + self.mlp(self.norm3(x)) | |
| return x, present_kv | |
| class CosmosT2_Accelerate_LLM(nn.Module): | |
| def __init__(self, vocab_size, d_model=32, n_layers=6, n_heads=2, n_kv_heads=1, | |
| d_ff=256, max_len=1028, rope_base=10000, dropout=0.05, use_engram=True, | |
| engram_every=2, engram_bucket_count=64, engram_dim=16, engram_order=3, pad_id=0): | |
| super().__init__() | |
| self.vocab_size = vocab_size | |
| self.d_model = d_model | |
| self.n_layers = n_layers | |
| self.n_heads = n_heads | |
| self.n_kv_heads = n_kv_heads | |
| self.head_dim = d_model // n_heads | |
| self.max_len = max_len | |
| self.rope_base = rope_base | |
| self.pad_id = pad_id | |
| self.tok_emb = nn.Embedding(vocab_size, d_model) | |
| self.blocks = nn.ModuleList() | |
| for layer_index in range(n_layers): | |
| block_uses_engram = use_engram and ((layer_index + 1) % engram_every == 0) | |
| self.blocks.append(Block( | |
| d_model=d_model, n_heads=n_heads, n_kv_heads=n_kv_heads, d_ff=d_ff, | |
| rope_base=rope_base, dropout=dropout, use_engram=block_uses_engram, | |
| engram_bucket_count=engram_bucket_count, engram_dim=engram_dim, | |
| engram_order=engram_order, pad_id=pad_id, | |
| )) | |
| self.norm_f = RMSNorm(d_model) | |
| self.apply(self._init_weights) | |
| def _init_weights(self, module): | |
| if isinstance(module, nn.Linear): | |
| nn.init.normal_(module.weight, mean=0.0, std=0.02) | |
| if module.bias is not None: | |
| nn.init.zeros_(module.bias) | |
| elif isinstance(module, nn.Embedding): | |
| nn.init.normal_(module.weight, mean=0.0, std=0.02) | |
| def build_rope(self, seq_len, device, dtype, start_pos=0): | |
| inv_freq = 1.0 / (self.rope_base ** ( | |
| torch.arange(0, self.head_dim, 2, device=device, dtype=torch.float32) / self.head_dim | |
| )) | |
| positions = torch.arange(start_pos, start_pos + seq_len, device=device, dtype=torch.float32) | |
| freqs = torch.outer(positions, inv_freq) | |
| cos = freqs.cos().repeat_interleave(2, dim=-1).to(dtype)[None, None, :, :] | |
| sin = freqs.sin().repeat_interleave(2, dim=-1).to(dtype)[None, None, :, :] | |
| return cos, sin | |
| def forward(self, idx, targets=None): | |
| if idx.size(1) > self.max_len: | |
| idx = idx[:, -self.max_len:] | |
| seq_len = idx.size(1) | |
| rope_cos, rope_sin = self.build_rope(seq_len, idx.device, self.tok_emb.weight.dtype) | |
| x = self.tok_emb(idx) | |
| for block in self.blocks: | |
| x = block(x, idx, rope_cos, rope_sin) | |
| x = self.norm_f(x) | |
| logits = F.linear(x, self.tok_emb.weight) | |
| loss = None | |
| if targets is not None: | |
| loss = F.cross_entropy(logits.reshape(-1, logits.size(-1)), targets.reshape(-1)) | |
| return logits, loss | |
| def trim_kv_cache(self, past_kv, max_tokens): | |
| if past_kv is None: | |
| return None | |
| max_tokens = max(0, int(max_tokens)) | |
| trimmed = [] | |
| for k, v in past_kv: | |
| if max_tokens == 0: | |
| k = k[:, :, :0, :].contiguous() | |
| v = v[:, :, :0, :].contiguous() | |
| elif k.size(2) > max_tokens: | |
| k = k[:, :, -max_tokens:, :].contiguous() | |
| v = v[:, :, -max_tokens:, :].contiguous() | |
| trimmed.append((k, v)) | |
| return trimmed | |
| def forward_cached(self, idx, past_kv=None, cache_pos=0, max_ctx=None, idx_context=None): | |
| self.eval() | |
| max_ctx = self.max_len if max_ctx is None else int(max_ctx) | |
| if past_kv is None: | |
| idx = idx[:, -max_ctx:] | |
| idx_context = idx | |
| cache_pos = 0 | |
| else: | |
| keep_past = max(0, max_ctx - idx.size(1)) | |
| past_kv = self.trim_kv_cache(past_kv, keep_past) | |
| idx_context = idx if idx_context is None else idx_context[:, -max_ctx:] | |
| seq_len = idx.size(1) | |
| rope_cos, rope_sin = self.build_rope( | |
| seq_len, | |
| idx.device, | |
| self.tok_emb.weight.dtype, | |
| start_pos=cache_pos, | |
| ) | |
| x = self.tok_emb(idx) | |
| present_kv = [] | |
| for layer_index, block in enumerate(self.blocks): | |
| layer_past = None if past_kv is None else past_kv[layer_index] | |
| x, layer_present = block.forward_cached(x, idx_context, rope_cos, rope_sin, past_kv=layer_past) | |
| present_kv.append(layer_present) | |
| x = self.norm_f(x) | |
| logits = F.linear(x, self.tok_emb.weight) | |
| return logits, present_kv, cache_pos + seq_len | |
| def sample_next(self, logits, temperature=0.8, top_k=50): | |
| if logits.dim() == 3: | |
| logits = logits[:, -1, :] | |
| if temperature <= 1e-6: | |
| return torch.argmax(logits, dim=-1, keepdim=True) | |
| logits = logits / temperature | |
| if top_k and top_k > 0: | |
| values, _ = torch.topk(logits, min(top_k, logits.size(-1))) | |
| logits = logits.masked_fill(logits < values[:, [-1]], float("-inf")) | |
| probs = F.softmax(logits, dim=-1) | |
| return torch.multinomial(probs, num_samples=1) | |
| def prefill_cache(self, idx, max_ctx=None): | |
| logits, past_kv, cache_pos = self.forward_cached(idx, past_kv=None, cache_pos=0, max_ctx=max_ctx) | |
| return logits[:, -1, :], past_kv, cache_pos | |
| def decode_cached(self, idx, past_kv, cache_pos, idx_context, max_ctx=None): | |
| logits, past_kv, cache_pos = self.forward_cached( | |
| idx, | |
| past_kv=past_kv, | |
| cache_pos=cache_pos, | |
| max_ctx=max_ctx, | |
| idx_context=idx_context, | |
| ) | |
| return logits[:, -1, :], past_kv, cache_pos | |
| def generate_step(self, idx, temperature=0.8, top_k=50, max_ctx=None): | |
| max_ctx = self.max_len if max_ctx is None else max_ctx | |
| logits, _, _ = self.prefill_cache(idx[:, -max_ctx:], max_ctx=max_ctx) | |
| return self.sample_next(logits, temperature=temperature, top_k=top_k) | |
| def generate(self, idx, max_new_tokens=128, temperature=0.8, top_k=50, max_ctx=None, stop_ids=None): | |
| """Autoregressive generation with KV cache. Stops on stop_ids (defaults to STOP_IDS).""" | |
| self.eval() | |
| if stop_ids is None: | |
| stop_ids = globals().get("STOP_IDS") | |
| max_ctx = self.max_len if max_ctx is None else int(max_ctx) | |
| idx = idx[:, -max_ctx:] | |
| logits, past_kv, cache_pos = self.prefill_cache(idx, max_ctx=max_ctx) | |
| for step in range(max_new_tokens): | |
| nxt = self.sample_next(logits, temperature=temperature, top_k=top_k) | |
| if stop_ids and nxt.numel() == 1 and int(nxt.item()) in stop_ids: | |
| break | |
| idx = torch.cat([idx, nxt], dim=1) | |
| if step + 1 < max_new_tokens: | |
| logits, past_kv, cache_pos = self.decode_cached( | |
| nxt, past_kv, cache_pos, idx[:, -max_ctx:], max_ctx=max_ctx) | |
| return idx | |
| # --------------------------------------------------------------------------- | |
| # Checkpoint loader | |
| # --------------------------------------------------------------------------- | |
| def load_checkpoint(tokenizer): | |
| ckpt_path = Path(CHECKPOINT_NAME) | |
| if not ckpt_path.exists(): | |
| print(f"Downloading {CHECKPOINT_NAME} from {MODEL_REPO_ID}") | |
| ckpt_path = Path(hf_hub_download(repo_id=MODEL_REPO_ID, filename=CHECKPOINT_NAME)) | |
| ckpt = torch.load(ckpt_path, map_location="cpu", weights_only=False) | |
| cfg = ckpt.get("config", {}) | |
| resolved = { | |
| "vocab_size": cfg.get("vocab_size", len(tokenizer)), | |
| "d_model": cfg.get("d_model", 32), | |
| "n_layers": cfg.get("n_layers", 6), | |
| "n_heads": cfg.get("n_heads", 2), | |
| "n_kv_heads": cfg.get("n_kv_heads", 1), | |
| "d_ff": cfg.get("d_ff", 256), | |
| "max_len": cfg.get("max_len", 1028), | |
| "rope_base": cfg.get("rope_base", 10000), | |
| "dropout": 0.0, | |
| "use_engram": cfg.get("use_engram", True), | |
| "engram_every": cfg.get("engram_every", 2), | |
| "engram_bucket_count": cfg.get("engram_bucket_count", 64), | |
| "engram_dim": cfg.get("engram_dim", 16), | |
| "engram_order": cfg.get("engram_order", 3), | |
| "pad_id": tokenizer.pad_token_id, | |
| } | |
| print(f"Model config: {resolved}") | |
| model = CosmosT2_Accelerate_LLM(**resolved) | |
| state = ckpt.get("model_state", ckpt) | |
| state = {k.replace("module.", "", 1): v for k, v in state.items()} | |
| missing, unexpected = model.load_state_dict(state, strict=False) | |
| if missing: print(f"Missing keys: {missing}") | |
| if unexpected: print(f"Unexpected keys: {unexpected}") | |
| model = model.to(DEVICE).to(DTYPE).eval() | |
| return model | |
| print(f"Device: {DEVICE} | dtype: {DTYPE}") | |
| tokenizer = AutoTokenizer.from_pretrained(TOKENIZER_NAME) | |
| if tokenizer.pad_token is None: | |
| tokenizer.pad_token = tokenizer.eos_token | |
| print(f"Tokenizer: {TOKENIZER_NAME}") | |
| model = load_checkpoint(tokenizer) | |
| n_params = sum(p.numel() for p in model.parameters()) | |
| _n_layers = model.n_layers if hasattr(model, "n_layers") else "?" | |
| print(f"Loaded {n_params / 1e6:.2f}M parameters") | |
| EOS_ID = tokenizer.eos_token_id | |
| def _resolve_stop_ids(tok): | |
| ids = set() | |
| for t in ("<|im_end|>", "<|endoftext|>"): | |
| i = tok.convert_tokens_to_ids(t) | |
| if isinstance(i, int) and i >= 0 and i != tok.unk_token_id: | |
| ids.add(i) | |
| if tok.eos_token_id is not None: | |
| ids.add(tok.eos_token_id) | |
| return ids | |
| STOP_IDS = _resolve_stop_ids(tokenizer) | |
| # --------------------------------------------------------------------------- | |
| # Text → HTML rendering (preserves <think> blocks) | |
| # --------------------------------------------------------------------------- | |
| def render_message_html(text: str, is_streaming: bool = False) -> str: | |
| """ | |
| Convert raw model output to HTML. | |
| - <think>...</think> → collapsible details block | |
| - Incomplete <think> → open/pulsing block while streaming | |
| - Remaining text → escaped, newlines → <br> | |
| """ | |
| # Split on think tags | |
| # Patterns: complete <think>...</think> or dangling <think>... | |
| parts = [] | |
| cursor = 0 | |
| pattern = re.compile(r'<think>(.*?)</think>', re.DOTALL) | |
| for m in pattern.finditer(text): | |
| # text before this think block | |
| before = text[cursor:m.start()] | |
| if before: | |
| parts.append(('text', before)) | |
| parts.append(('think_done', m.group(1))) | |
| cursor = m.end() | |
| tail = text[cursor:] | |
| # check for an open, unclosed <think> | |
| open_match = re.search(r'<think>(.*)', tail, re.DOTALL) | |
| if open_match: | |
| before_open = tail[:open_match.start()] | |
| if before_open: | |
| parts.append(('text', before_open)) | |
| parts.append(('think_open', open_match.group(1))) | |
| else: | |
| if tail: | |
| parts.append(('text', tail)) | |
| html_parts = [] | |
| for kind, content in parts: | |
| if kind == 'text': | |
| escaped = content.replace('&', '&').replace('<', '<').replace('>', '>') | |
| escaped = escaped.replace('\n', '<br>') | |
| html_parts.append(f'<span class="msg-text">{escaped}</span>') | |
| elif kind == 'think_done': | |
| inner = content.strip().replace('&', '&').replace('<', '<').replace('>', '>') | |
| inner = inner.replace('\n', '<br>') | |
| html_parts.append( | |
| f'<details class="think-block">' | |
| f'<summary>💭 Thinking</summary>' | |
| f'<div class="think-content">{inner}</div>' | |
| f'</details>' | |
| ) | |
| elif kind == 'think_open': | |
| inner = content.strip().replace('&', '&').replace('<', '<').replace('>', '>') | |
| inner = inner.replace('\n', '<br>') | |
| pulse = ' think-streaming' if is_streaming else '' | |
| html_parts.append( | |
| f'<details class="think-block{pulse}" open>' | |
| f'<summary>💭 Thinking{"…" if is_streaming else ""}</summary>' | |
| f'<div class="think-content">{inner}</div>' | |
| f'</details>' | |
| ) | |
| return ''.join(html_parts) | |
| def build_prompt(history, user_msg, system_msg): | |
| messages = [] | |
| if system_msg and system_msg.strip(): | |
| messages.append({"role": "system", "content": system_msg.strip()}) | |
| for item in history: | |
| if isinstance(item, dict) and "role" in item and "content" in item: | |
| # history stores raw text, not html | |
| messages.append({"role": item["role"], "content": item["content"]}) | |
| messages.append({"role": "user", "content": user_msg}) | |
| return tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True) | |
| # --------------------------------------------------------------------------- | |
| # Per-session stop flag | |
| # --------------------------------------------------------------------------- | |
| _stop_flags: dict[str, threading.Event] = {} | |
| def get_stop_event(session_id: str) -> threading.Event: | |
| if session_id not in _stop_flags: | |
| _stop_flags[session_id] = threading.Event() | |
| return _stop_flags[session_id] | |
| # --------------------------------------------------------------------------- | |
| # CSS | |
| # --------------------------------------------------------------------------- | |
| CUSTOM_CSS = """ | |
| html, body { overflow-x: hidden; max-width: 100vw; } | |
| .gradio-container { | |
| max-width: 980px !important; | |
| width: 100% !important; | |
| margin: auto; | |
| padding: 12px !important; | |
| box-sizing: border-box; | |
| } | |
| /* ---- header ---- */ | |
| #header-card { | |
| background: linear-gradient(135deg, #0d1117 0%, #161b22 100%); | |
| border: 1px solid #30363d; | |
| border-radius: 14px; | |
| padding: 20px 24px; | |
| margin-bottom: 12px; | |
| text-align: center; | |
| } | |
| #header-card h2 { color: #58a6ff; margin: 4px 0 8px; font-weight: 700; font-size: 1.3em; } | |
| #header-card p { color: #8b949e; margin: 3px 0; font-size: 0.88em; } | |
| .badge { | |
| display: inline-block; | |
| background: #21262d; | |
| color: #c9d1d9; | |
| padding: 2px 9px; | |
| border-radius: 999px; | |
| font-size: 0.76em; | |
| margin: 2px 3px; | |
| border: 1px solid #30363d; | |
| } | |
| .warn { | |
| background: #2a1f0a; | |
| border: 1px solid #6b4d11; | |
| color: #f0c674; | |
| padding: 8px 12px; | |
| border-radius: 8px; | |
| font-size: 0.84em; | |
| margin-top: 8px; | |
| text-align: left; | |
| } | |
| /* ---- chatbox ---- */ | |
| #chatbox { | |
| border: 1px solid #30363d; | |
| border-radius: 12px; | |
| background: #0d1117; | |
| padding: 16px; | |
| min-height: 420px; | |
| max-height: 60vh; | |
| overflow-y: auto; | |
| overflow-x: hidden; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 14px; | |
| /* no forced scroll — user controls it */ | |
| scroll-behavior: smooth; | |
| } | |
| /* ---- messages ---- */ | |
| .msg-row { display: flex; gap: 10px; align-items: flex-start; max-width: 100%; } | |
| .msg-row.user { flex-direction: row-reverse; } | |
| .msg-row.asst { flex-direction: row; } | |
| .msg-avatar { | |
| width: 30px; height: 30px; border-radius: 50%; | |
| display: flex; align-items: center; justify-content: center; | |
| font-size: 0.85em; flex-shrink: 0; margin-top: 2px; | |
| } | |
| .msg-row.user .msg-avatar { background: #1f6feb; color: #fff; } | |
| .msg-row.asst .msg-avatar { background: #21262d; color: #58a6ff; border: 1px solid #30363d; } | |
| .msg-bubble { | |
| max-width: 78%; | |
| padding: 10px 14px; | |
| border-radius: 14px; | |
| font-size: 0.93em; | |
| line-height: 1.6; | |
| word-break: break-word; | |
| overflow-wrap: break-word; | |
| } | |
| .msg-row.user .msg-bubble { | |
| background: #1f6feb; | |
| color: #fff; | |
| border-bottom-right-radius: 4px; | |
| } | |
| .msg-row.asst .msg-bubble { | |
| background: #161b22; | |
| color: #c9d1d9; | |
| border: 1px solid #30363d; | |
| border-bottom-left-radius: 4px; | |
| } | |
| /* ---- think blocks ---- */ | |
| .think-block { | |
| margin: 6px 0; | |
| border: 1px solid #30363d; | |
| border-radius: 8px; | |
| overflow: hidden; | |
| background: #0d1117; | |
| } | |
| .think-block summary { | |
| cursor: pointer; | |
| padding: 5px 10px; | |
| font-size: 0.82em; | |
| color: #8b949e; | |
| background: #161b22; | |
| user-select: none; | |
| list-style: none; | |
| } | |
| .think-block summary::-webkit-details-marker { display: none; } | |
| .think-block summary::before { content: "▶ "; font-size: 0.7em; } | |
| .think-block[open] summary::before { content: "▼ "; } | |
| .think-content { | |
| padding: 8px 12px; | |
| font-size: 0.82em; | |
| color: #6e7681; | |
| font-family: monospace; | |
| white-space: pre-wrap; | |
| line-height: 1.5; | |
| max-height: 280px; | |
| overflow-y: auto; | |
| } | |
| @keyframes pulse-border { | |
| 0% { border-color: #388bfd44; } | |
| 50% { border-color: #388bfd; } | |
| 100% { border-color: #388bfd44; } | |
| } | |
| .think-streaming { | |
| animation: pulse-border 1.4s ease-in-out infinite; | |
| } | |
| /* ---- token counter ---- */ | |
| #token-counter { | |
| font-size: 0.76em; | |
| color: #6e7681; | |
| text-align: right; | |
| padding: 2px 4px; | |
| } | |
| /* ---- input row ---- */ | |
| #input-row { | |
| display: flex; | |
| gap: 8px; | |
| align-items: flex-end; | |
| margin-top: 8px; | |
| } | |
| #user-input textarea { | |
| background: #0d1117 !important; | |
| border: 1px solid #30363d !important; | |
| border-radius: 10px !important; | |
| color: #c9d1d9 !important; | |
| resize: none; | |
| font-size: 0.93em; | |
| } | |
| #user-input textarea:focus { | |
| border-color: #388bfd !important; | |
| outline: none !important; | |
| } | |
| #send-btn, #stop-btn, #clear-btn { | |
| min-width: 72px !important; | |
| height: 42px !important; | |
| border-radius: 10px !important; | |
| font-size: 0.88em !important; | |
| font-weight: 600 !important; | |
| } | |
| #send-btn { background: #1f6feb !important; color: #fff !important; } | |
| #send-btn:hover { background: #388bfd !important; } | |
| #stop-btn { background: #da3633 !important; color: #fff !important; } | |
| #stop-btn:hover { background: #f85149 !important; } | |
| #clear-btn { background: #21262d !important; color: #c9d1d9 !important; border: 1px solid #30363d !important; } | |
| #clear-btn:hover { background: #30363d !important; } | |
| /* ---- params accordion ---- */ | |
| #params-accordion { margin-top: 10px; } | |
| footer { visibility: hidden; } | |
| @media (max-width: 640px) { | |
| .gradio-container { padding: 6px !important; } | |
| .msg-bubble { max-width: 90%; font-size: 0.88em; } | |
| #chatbox { min-height: 320px; max-height: 55vh; } | |
| } | |
| """ | |
| # --------------------------------------------------------------------------- | |
| # Gradio UI | |
| # --------------------------------------------------------------------------- | |
| _n_layers_str = str(_n_layers) | |
| HEADER_HTML = f""" | |
| <div id="header-card"> | |
| <h2>{MODEL_NAME}</h2> | |
| <p> | |
| <span class="badge">{n_params / 1e6:.2f}M params</span> | |
| <span class="badge">{_n_layers_str} layers</span> | |
| <span class="badge">RoPE + RMSNorm + SwiGLU + GQA</span> | |
| <span class="badge">Engram on</span> | |
| <span class="badge">{DEVICE.upper()}</span> | |
| </p> | |
| <p> | |
| Trained on <a href="https://huggingface.co/datasets/wop/XXXXXL-chain-of-thought" target="_blank" style="color:#58a6ff">wop/XXXXXL-chain-of-thought</a> | |
| · | |
| <a href="https://huggingface.co/wop/Cosmos-T2-Accelerate-beta" target="_blank" style="color:#58a6ff">Model repo</a> | |
| </p> | |
| <div class="warn">⚠️ Research/demo model — small, may hallucinate freely. Keep temperature low for stable outputs.</div> | |
| </div> | |
| """ | |
| with gr.Blocks( | |
| theme=gr.themes.Base(), | |
| css=CUSTOM_CSS, | |
| title=f"{MODEL_NAME} Demo", | |
| ) as demo: | |
| # ---- state ---- | |
| # history: list of {"role": "user"|"assistant", "content": <raw text>} | |
| history_state = gr.State([]) | |
| session_id = gr.State("") # unique per browser tab | |
| # ---- layout ---- | |
| gr.HTML(HEADER_HTML) | |
| chatbox = gr.HTML( | |
| value='<div id="chatbox"><div style="color:#6e7681;text-align:center;margin:auto">Send a message to start…</div></div>', | |
| elem_id="chatbox-wrapper", | |
| ) | |
| token_counter = gr.Markdown("", elem_id="token-counter") | |
| with gr.Row(elem_id="input-row"): | |
| user_input = gr.Textbox( | |
| placeholder="Ask Cosmos T2-Accelerate-beta anything… (Shift+Enter for newline)", | |
| lines=1, max_lines=6, | |
| show_label=False, | |
| elem_id="user-input", | |
| scale=8, | |
| ) | |
| send_btn = gr.Button("Send", elem_id="send-btn", variant="primary", scale=1) | |
| stop_btn = gr.Button("Stop", elem_id="stop-btn", variant="stop", scale=1) | |
| clear_btn = gr.Button("Clear", elem_id="clear-btn", scale=1) | |
| with gr.Accordion("⚙️ Generation parameters", open=False, elem_id="params-accordion"): | |
| with gr.Row(): | |
| system_box = gr.Textbox(value=DEFAULT_SYSTEM_PROMPT, label="System prompt", lines=2, scale=3) | |
| temperature = gr.Slider(0.0, 2.0, value=0.1, step=0.05, label="Temperature", scale=1) | |
| top_k = gr.Slider(1, 200, value=1, step=1, label="Top-K", scale=1) | |
| with gr.Row(): | |
| ctx_size = gr.Slider(64, MAX_CTX_HARD, value=MAX_CTX_HARD, step=64, label="Context window") | |
| max_new = gr.Slider(16, MAX_NEW_HARD, value=128, step=16, label="Max new tokens") | |
| # ---- rendering helper ---- | |
| def history_to_html(history): | |
| if not history: | |
| return '<div id="chatbox"><div style="color:#6e7681;text-align:center;margin:auto">Send a message to start…</div></div>' | |
| rows = [] | |
| for msg in history: | |
| role = msg["role"] | |
| raw = msg["content"] | |
| if role == "user": | |
| escaped = raw.replace('&', '&').replace('<', '<').replace('>', '>').replace('\n', '<br>') | |
| bubble = f'<div class="msg-bubble">{escaped}</div>' | |
| avatar = '<div class="msg-avatar">👤</div>' | |
| rows.append(f'<div class="msg-row user">{avatar}{bubble}</div>') | |
| else: | |
| html = render_message_html(raw, is_streaming=False) | |
| bubble = f'<div class="msg-bubble">{html}</div>' | |
| avatar = '<div class="msg-avatar">✦</div>' | |
| rows.append(f'<div class="msg-row asst">{avatar}{bubble}</div>') | |
| inner = "\n".join(rows) | |
| # scroll-to-bottom js trick: invisible anchor at end | |
| return f'<div id="chatbox">{inner}<div id="chat-end"></div></div><script>document.getElementById("chat-end")?.scrollIntoView({{behavior:"smooth",block:"end"}});</script>' | |
| # ---- send / stream ---- | |
| def do_send(message, history, sys_msg, temp, tk, ctx, mn, sid): | |
| if not message or not message.strip(): | |
| yield history, history_to_html(history), "", "" | |
| return | |
| # Assign session id if blank | |
| if not sid: | |
| import uuid | |
| sid = str(uuid.uuid4()) | |
| stop_evt = get_stop_event(sid) | |
| stop_evt.clear() | |
| # Append user message | |
| history = list(history) + [{"role": "user", "content": message.strip()}] | |
| # Show user message immediately, assistant bubble loading | |
| loading_html = history_to_html(history + [{"role": "assistant", "content": "▌"}]) | |
| yield history, loading_html, "", sid | |
| # Build prompt | |
| prompt = build_prompt(history[:-1], message.strip(), sys_msg) | |
| input_ids = tokenizer(prompt, return_tensors="pt", add_special_tokens=False).input_ids.to(DEVICE) | |
| ctx = int(min(max(int(ctx), 8), MAX_CTX_HARD)) | |
| if input_ids.shape[1] > ctx - 16: | |
| input_ids = input_ids[:, -(ctx - 16):] | |
| mn = int(min(max(int(mn), 1), MAX_NEW_HARD)) | |
| temp = float(max(min(temp, 2.0), 0.0)) | |
| tk = int(max(tk, 1)) | |
| cur_ids = input_ids | |
| generated = [] | |
| partial = "" | |
| n_tokens = 0 | |
| kv_cache = None | |
| cache_pos = 0 | |
| next_logits = None | |
| if USE_KV_CACHE: | |
| next_logits, kv_cache, cache_pos = model.prefill_cache(cur_ids, max_ctx=ctx) | |
| for step in range(mn): | |
| if stop_evt.is_set(): | |
| break | |
| if USE_KV_CACHE: | |
| nxt = model.sample_next(next_logits, temperature=temp, top_k=tk) | |
| else: | |
| nxt = model.generate_step(cur_ids, temperature=temp, top_k=tk, max_ctx=ctx) | |
| cur_ids = torch.cat([cur_ids, nxt], dim=1) | |
| token_id = int(nxt.item()) | |
| if token_id in STOP_IDS: | |
| break | |
| generated.append(token_id) | |
| n_tokens += 1 | |
| if USE_KV_CACHE and step + 1 < mn: | |
| next_logits, kv_cache, cache_pos = model.decode_cached( | |
| nxt, | |
| kv_cache, | |
| cache_pos, | |
| cur_ids[:, -ctx:], | |
| max_ctx=ctx, | |
| ) | |
| new_text = tokenizer.decode(generated, skip_special_tokens=False) | |
| if new_text != partial: | |
| partial = new_text | |
| stream_history = history + [{"role": "assistant", "content": partial}] | |
| # Build streaming html (open think block pulses) | |
| rows = [] | |
| for msg in stream_history[:-1]: | |
| role2 = msg["role"] | |
| raw2 = msg["content"] | |
| if role2 == "user": | |
| esc = raw2.replace('&','&').replace('<','<').replace('>','>').replace('\n','<br>') | |
| rows.append(f'<div class="msg-row user"><div class="msg-avatar">👤</div><div class="msg-bubble">{esc}</div></div>') | |
| else: | |
| h = render_message_html(raw2, is_streaming=False) | |
| rows.append(f'<div class="msg-row asst"><div class="msg-avatar">✦</div><div class="msg-bubble">{h}</div></div>') | |
| # Last (streaming) assistant message | |
| h_stream = render_message_html(partial, is_streaming=True) | |
| rows.append(f'<div class="msg-row asst"><div class="msg-avatar">✦</div><div class="msg-bubble">{h_stream}</div></div>') | |
| inner = "\n".join(rows) | |
| chat_html = f'<div id="chatbox">{inner}<div id="chat-end"></div></div><script>document.getElementById("chat-end")?.scrollIntoView({{behavior:"instant",block:"end"}});</script>' | |
| counter = f"`{n_tokens}` tokens generated" | |
| yield history, chat_html, counter, sid | |
| # Finalise | |
| final_text = tokenizer.decode(generated, skip_special_tokens=False) | |
| history = history + [{"role": "assistant", "content": final_text}] | |
| stopped = " *(stopped)*" if stop_evt.is_set() else "" | |
| counter = f"`{n_tokens}` tokens generated{stopped}" | |
| yield history, history_to_html(history), counter, sid | |
| def do_stop(sid): | |
| if sid: | |
| get_stop_event(sid).set() | |
| def do_clear(): | |
| empty_html = '<div id="chatbox"><div style="color:#6e7681;text-align:center;margin:auto">Send a message to start…</div></div>' | |
| return [], empty_html, "", "" | |
| # ---- wire up ---- | |
| gen_inputs = [user_input, history_state, system_box, temperature, top_k, ctx_size, max_new, session_id] | |
| gen_outputs = [history_state, chatbox, token_counter, session_id] | |
| send_event = send_btn.click( | |
| fn=do_send, | |
| inputs=gen_inputs, | |
| outputs=gen_outputs, | |
| show_progress=False, | |
| ) | |
| # Also trigger on Enter (without shift) | |
| user_input.submit( | |
| fn=do_send, | |
| inputs=gen_inputs, | |
| outputs=gen_outputs, | |
| show_progress=False, | |
| ) | |
| # Clear input box after sending | |
| send_btn.click(fn=lambda: "", outputs=[user_input]) | |
| user_input.submit(fn=lambda: "", outputs=[user_input]) | |
| stop_btn.click(fn=do_stop, inputs=[session_id], cancels=[send_event]) | |
| clear_btn.click(fn=do_clear, outputs=[history_state, chatbox, token_counter, user_input]) | |
| if __name__ == "__main__": | |
| demo.queue(max_size=16, default_concurrency_limit=1).launch(server_name="0.0.0.0", server_port=7860) | |