Download chatcode/runtime.py from gamedevelop/pocketvision-chat-code: direct link, hf CLI and curl.
- Browser
- Download file 4.74 kB
-
https://huggingface.co/gamedevelop/pocketvision-chat-code/resolve/main/chatcode/runtime.py
- Command line
-
hf download hf://gamedevelop/pocketvision-chat-code/chatcode/runtime.py
-
curl -L -o runtime.py https://huggingface.co/gamedevelop/pocketvision-chat-code/resolve/main/chatcode/runtime.py
4.74 kB
| """Pinned text-only inference. Model weights are loaded only on a cloud GPU.""" | |
| from __future__ import annotations | |
| import json | |
| import os | |
| from pathlib import Path | |
| ROOT = Path(__file__).resolve().parent.parent | |
| CONFIG = json.loads(Path(__file__).with_name("config.json").read_text(encoding="utf-8")) | |
| os.environ.setdefault("HF_HOME", str(ROOT / ".cache/huggingface")) | |
| os.environ.setdefault("HF_HUB_DISABLE_XET", "1") | |
| os.environ.setdefault("TOKENIZERS_PARALLELISM", "false") | |
| os.environ.setdefault("GRADIO_ANALYTICS_ENABLED", "false") | |
| def conversation(prompt: str, history: list[dict] | None = None) -> list[dict]: | |
| if not prompt.strip(): | |
| raise ValueError("Enter a message first.") | |
| if len(prompt) > 24000: | |
| raise ValueError("Please split this message into smaller parts.") | |
| messages = [{"role": "system", "content": CONFIG["system_prompt"]}] | |
| previous = history or [] | |
| if len(previous) % 2: | |
| raise ValueError("Conversation history is incomplete. Start a new chat.") | |
| for index, item in enumerate(previous): | |
| if item.get("role") != ("user" if index % 2 == 0 else "assistant"): | |
| raise ValueError("Conversation history is invalid. Start a new chat.") | |
| if not isinstance(item.get("content"), str): | |
| raise ValueError("This chat accepts text messages only.") | |
| messages.append({"role": item["role"], "content": item["content"]}) | |
| messages.append({"role": "user", "content": prompt.strip()}) | |
| return messages | |
| def gpu_available() -> bool: | |
| import torch | |
| return bool(torch.cuda.is_available()) | |
| def load_engine(adapter: str | None = None): | |
| import torch | |
| from transformers import AutoModelForCausalLM, AutoTokenizer | |
| if not gpu_available(): | |
| raise RuntimeError("The cloud model is not connected. This computer shows the interface preview only.") | |
| tokenizer = AutoTokenizer.from_pretrained( | |
| CONFIG["base_model"], revision=CONFIG["base_revision"], trust_remote_code=False) | |
| model = AutoModelForCausalLM.from_pretrained( | |
| CONFIG["base_model"], revision=CONFIG["base_revision"], trust_remote_code=False, | |
| dtype=torch.bfloat16 if torch.cuda.is_bf16_supported() else torch.float16, | |
| device_map={"": "cuda:0"}, attn_implementation="sdpa") | |
| if adapter: | |
| from peft import PeftConfig, PeftModel | |
| adapter_config = PeftConfig.from_pretrained(adapter) | |
| if (adapter_config.base_model_name_or_path != CONFIG["base_model"] | |
| or adapter_config.revision != CONFIG["base_revision"]): | |
| raise ValueError("Adapter does not match the pinned chat-and-code model.") | |
| model = PeftModel.from_pretrained(model, adapter) | |
| return tokenizer, model.eval() | |
| def answer(tokenizer, model, prompt: str, history: list[dict] | None = None, | |
| max_new_tokens: int = CONFIG["max_new_tokens"]) -> str: | |
| if not 1 <= max_new_tokens <= 2048: | |
| raise ValueError("Response length must be between 1 and 2,048 tokens.") | |
| messages = conversation(prompt, history) | |
| while True: | |
| inputs = tokenizer.apply_chat_template( | |
| messages, tokenize=True, add_generation_prompt=True, | |
| return_dict=True, return_tensors="pt") | |
| if inputs["input_ids"].shape[1] + max_new_tokens <= 4096: | |
| break | |
| if len(messages) <= 2: | |
| raise ValueError("This message is too long. Please send a smaller code example.") | |
| del messages[1:3] | |
| return generate_messages(tokenizer, model, messages, max_new_tokens=max_new_tokens) | |
| def generate_messages(tokenizer, model, messages, max_new_tokens=768, | |
| context_limit=4096, do_sample=True): | |
| import torch | |
| if not 1 <= max_new_tokens <= 2048 or not 256 <= context_limit <= 8192: | |
| raise ValueError("Invalid response or context length.") | |
| inputs = tokenizer.apply_chat_template( | |
| messages, tokenize=True, add_generation_prompt=True, | |
| return_dict=True, return_tensors="pt") | |
| if inputs["input_ids"].shape[1] + max_new_tokens > context_limit: | |
| raise ValueError("Source packet is too long. Shorten the excerpts; no sources were silently removed.") | |
| inputs = inputs.to(model.device) | |
| sampling = {"temperature": 0.7, "top_p": 0.8, "top_k": 20} if do_sample else {} | |
| with torch.inference_mode(): | |
| output = model.generate( | |
| **inputs, max_new_tokens=max_new_tokens, do_sample=do_sample, **sampling, | |
| pad_token_id=tokenizer.pad_token_id, eos_token_id=tokenizer.eos_token_id) | |
| reply = tokenizer.decode(output[0, inputs["input_ids"].shape[1]:], skip_special_tokens=True).strip() | |
| if not reply: | |
| raise RuntimeError("The model returned an empty response. Please try again.") | |
| return reply | |