初始化项目,由ModelHub XC社区提供模型

Model: Nanthasit/sakthai-context-7b-merged
Source: Original Platform
This commit is contained in:
ModelHub XC
2026-07-21 19:53:11 +08:00
commit 6ddc2e5064
10 changed files with 304272 additions and 0 deletions

View File

@@ -0,0 +1,119 @@
{
"type": "workbench_hf_jobs",
"model": "Nanthasit/sakthai-context-7b-merged",
"load_time_seconds": 137.3,
"device": "cuda:0",
"gpu": "Tesla T4",
"vram_used_gb": 5.56,
"timestamp": "2026-07-07T14:44:33Z",
"results": [
{
"name": "basic_greeting",
"passed": true,
"response_preview": "Hello!",
"response_length": 6,
"latency_seconds": 1.08,
"prompt_tokens": 31,
"completion_tokens": 3,
"checks": [
"non_empty"
]
},
{
"name": "tool_call_intent",
"passed": true,
"response_preview": "Searching for the latest AI news...",
"response_length": 35,
"latency_seconds": 0.93,
"prompt_tokens": 37,
"completion_tokens": 8,
"checks": [
"non_empty",
"substantial"
]
},
{
"name": "name_recall",
"passed": true,
"response_preview": "Your name is Beer.",
"response_length": 18,
"latency_seconds": 0.78,
"prompt_tokens": 45,
"completion_tokens": 6,
"checks": [
"non_empty",
"substantial",
"name_recall"
]
},
{
"name": "factual_qa",
"passed": true,
"response_preview": "Tokyo.",
"response_length": 6,
"latency_seconds": 0.63,
"prompt_tokens": 28,
"completion_tokens": 4,
"checks": [
"non_empty",
"correct"
]
},
{
"name": "json_output",
"passed": true,
"response_preview": "{\"frameworks\": [\"TensorFlow\", \"PyTorch\", \"Keras\"]}",
"response_length": 50,
"latency_seconds": 1.62,
"prompt_tokens": 41,
"completion_tokens": 18,
"checks": [
"non_empty",
"substantial",
"valid_json"
]
},
{
"name": "instruction_following",
"passed": true,
"response_preview": "A transformer is an electrical device that transfers electrical energy between two or more circuits through inductively coupled conductors\u2014called windings\u2014without any physical connection between the c",
"response_length": 208,
"latency_seconds": 2.94,
"prompt_tokens": 29,
"completion_tokens": 36,
"checks": [
"non_empty",
"substantial"
]
},
{
"name": "multi_step_reasoning",
"passed": true,
"response_preview": "Let's break this down step by step:\n\n1. You start with 3 apples.\n2. You give away 1 apple: 3 - 1 = 2 apples remaining.\n3. You buy 5 more apples: 2 + 5 = 7 apples.\n\nSo, you end up with 7 apples.",
"response_length": 193,
"latency_seconds": 5.21,
"prompt_tokens": 50,
"completion_tokens": 68,
"checks": [
"non_empty",
"substantial",
"correct_answer"
]
},
{
"name": "context_window",
"passed": true,
"response_preview": "The paper \"Attention Is All You Need\" was published in 2017. It introduced the transformer architecture which has since become a fundamental building block for many state-of-the-art natural language p",
"response_length": 246,
"latency_seconds": 4.45,
"prompt_tokens": 65,
"completion_tokens": 54,
"checks": [
"non_empty",
"substantial",
"correct_answer"
]
}
],
"summary": "8/8 passed"
}

View File

@@ -0,0 +1,218 @@
#!/usr/bin/env python3
"""Workbench test: 7B merged model via Inference Endpoint."""
import json, time, os, sys
import requests
MODEL = "Nanthasit/sakthai-context-7b-merged"
ENDPOINT_URL = None # Set dynamically after deployment
# Read endpoint URL from args or env
if len(sys.argv) > 1:
ENDPOINT_URL = sys.argv[1]
elif "ENDPOINT_URL" in os.environ:
ENDPOINT_URL = os.environ["ENDPOINT_URL"]
else:
print("Usage: python3 sakthai-7b-workbench-test.py <endpoint_url>")
print("Or set ENDPOINT_URL env var")
sys.exit(1)
TOKEN_PATH = "/opt/data/profiles/sakthai/home/.cache/huggingface/token"
with open(TOKEN_PATH) as f:
HF_TOKEN = f.read().strip()
HEADERS = {
"Authorization": f"Bearer {HF_TOKEN}",
"Content-Type": "application/json"
}
tests = [
{
"name": "basic_greeting",
"desc": "Say hello in one sentence",
"messages": [
{"role": "system", "content": "You are SakThai, a helpful assistant. Be concise."},
{"role": "user", "content": "Say hello in one sentence."}
],
"checks": ["non_empty", "substantial"]
},
{
"name": "tool_call_intent",
"desc": "Tool-use intent",
"messages": [
{"role": "system", "content": "You are SakThai with tools: search(query), read_file(path), run_command(command)."},
{"role": "user", "content": "Search for the latest AI news"}
],
"checks": ["non_empty", "substantial"]
},
{
"name": "name_recall",
"desc": "Remember name across 3 turns",
"messages": [
{"role": "system", "content": "You are SakThai."},
{"role": "user", "content": "My name is Beer."},
{"role": "assistant", "content": "Nice to meet you, Beer!"},
{"role": "user", "content": "What's my name?"}
],
"checks": ["non_empty", "name_recall"]
},
{
"name": "factual_qa",
"desc": "Simple factual question",
"messages": [
{"role": "system", "content": "You are SakThai. Be concise."},
{"role": "user", "content": "What is the capital of Japan?"}
],
"checks": ["non_empty", "correct"]
},
{
"name": "json_output",
"desc": "Structured JSON",
"messages": [
{"role": "system", "content": "You are SakThai. Only respond with valid JSON."},
{"role": "user", "content": 'List 3 ML frameworks: {"frameworks": ["a","b","c"]}'}
],
"checks": ["non_empty", "valid_json"]
},
{
"name": "instruction_following",
"desc": "Follow formatting instruction",
"messages": [
{"role": "system", "content": "You are SakThai. Exactly one sentence."},
{"role": "user", "content": "Explain what a transformer is."}
],
"checks": ["non_empty", "substantial"]
},
{
"name": "multi_step_reasoning",
"desc": "Multi-step reasoning",
"messages": [
{"role": "system", "content": "You are SakThai, a helpful assistant."},
{"role": "user", "content": "If you have 3 apples and give away 1, then buy 5 more, how many do you have? Show your work."}
],
"checks": ["non_empty", "substantial"]
},
{
"name": "context_window",
"desc": "Longer context understanding",
"messages": [
{"role": "system", "content": "You are SakThai. Be concise."},
{"role": "user", "content": "The transformer architecture introduced in 'Attention Is All You Need' revolutionized NLP by replacing recurrent layers with multi-head self-attention. It uses positional encodings, layer normalization, and feed-forward networks in an encoder-decoder structure. BERT, GPT, and T5 all build on this foundation. What year was the original transformer paper published?"}
],
"checks": ["non_empty", "correct_answer"]
}
]
print(f"🧪 WORKBENCH TEST — SakThai Context 7B")
print(f" Endpoint: {ENDPOINT_URL}")
print(f" Model: {MODEL}")
print(f" Time: {time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())}")
print()
results = []
for i, test in enumerate(tests):
print(f"{''*60}")
print(f"TEST {i+1}: {test['name']}{test['desc']}")
print(f" Turns: {len(test['messages'])}", flush=True)
try:
t0 = time.time()
resp = requests.post(
f"{ENDPOINT_URL}/v1/chat/completions",
headers=HEADERS,
json={
"model": "tgi",
"messages": test["messages"],
"max_tokens": 256,
"temperature": 0.1,
},
timeout=120
)
elapsed = time.time() - t0
if resp.status_code != 200:
raise Exception(f"HTTP {resp.status_code}: {resp.text[:200]}")
data = resp.json()
choice = data["choices"][0]
content = choice["message"]["content"].strip()
finish = choice.get("finish_reason", "")
usage = data.get("usage", {})
# Run quality checks
checks = []
if len(content) > 0:
checks.append("non_empty")
if len(content) > 10:
checks.append("substantial")
if "beer" in content.lower() and test["name"] == "name_recall":
checks.append("name_recall")
if "tokyo" in content.lower() and test["name"] == "factual_qa":
checks.append("correct")
if "2017" in content and test["name"] == "context_window":
checks.append("correct_answer")
if test["name"] == "json_output":
try:
json.loads(content)
checks.append("valid_json")
except:
pass
result = {
"name": test["name"],
"passed": len(checks) > 0,
"response_preview": content[:200],
"response_length": len(content),
"latency_seconds": round(elapsed, 2),
"prompt_tokens": usage.get("prompt_tokens"),
"completion_tokens": usage.get("completion_tokens"),
"finish_reason": finish,
"checks": checks
}
print(f" {'' if result['passed'] else ''} Response: {content[:150]}")
print(f"{elapsed:.2f}s | ✅ {checks} | 🔚 {finish}")
if result.get("prompt_tokens"):
print(f" 📝 {result['prompt_tokens']}{result['completion_tokens']}")
except Exception as e:
result = {
"name": test["name"],
"passed": False,
"error": str(e)[:300]
}
print(f" ❌ FAIL: {e}")
results.append(result)
sys.stdout.flush()
# Summary
print(f"\n{'='*60}")
passed = sum(1 for r in results if r.get("passed"))
total = len(results)
print(f"📊 WORKBENCH SUMMARY — 7B ({MODEL})")
print(f"\nResults: {passed}/{total} passed")
print()
for r in results:
status = "" if r.get("passed") else ""
name = r["name"].ljust(22)
lat = f"{r.get('latency_seconds', 0):.1f}s" if r.get("passed") else " - "
detail = str(r.get("checks", r.get("error", "?")[:60]))
print(f" {status} {name}{lat} {detail}")
# Save record
record = {
"test_run": f"workbench-{time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())}",
"model": MODEL,
"endpoint_url": ENDPOINT_URL,
"timestamp": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
"results": results,
"summary": f"{passed}/{total} passed"
}
output_path = "/opt/data/sakthai-7b-workbench-test-record.json"
with open(output_path, "w") as f:
json.dump(record, f, indent=2)
print(f"\n💾 Saved: {output_path}")
print("🏁 Done.")

204
eval/workbench-7b-hfjobs.py Normal file
View File

@@ -0,0 +1,204 @@
#!/usr/bin/env python3
"""HF Jobs workbench test: SakThai Context 7B merged model, 4-bit, T4 GPU."""
import json, time, os, sys
import torch
MODEL = "Nanthasit/sakthai-context-7b-merged"
HF_TOKEN = os.environ.get("HF_TOKEN", "")
os.environ["HF_TOKEN"] = HF_TOKEN
os.environ["PYTORCH_CUDA_ALLOC_CONF"] = "expandable_segments:True"
print("=" * 60)
print(f"WORKBENCH TEST — SakThai Context 7B")
print(f"Model: {MODEL}")
print(f"GPU: {torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'NONE'}")
print(f"VRAM: {torch.cuda.get_device_properties(0).total_memory / 1e9:.1f}GB" if torch.cuda.is_available() else "N/A")
print(f"Time: {time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())}")
print("=" * 60)
sys.stdout.flush()
# Load model with 4-bit quantization
print("\n📥 Loading model in 4-bit...", flush=True)
t0 = time.time()
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_compute_dtype=torch.bfloat16,
bnb_4bit_use_double_quant=True,
bnb_4bit_quant_type="nf4",
)
tokenizer = AutoTokenizer.from_pretrained(MODEL, token=HF_TOKEN)
model = AutoModelForCausalLM.from_pretrained(
MODEL,
quantization_config=bnb_config,
device_map="auto",
torch_dtype=torch.bfloat16,
token=HF_TOKEN,
trust_remote_code=True,
)
load_time = time.time() - t0
print(f"✅ Loaded in {load_time:.1f}s on {model.device}", flush=True)
print(f" VRAM: {torch.cuda.memory_allocated() / 1e9:.2f}GB used", flush=True)
# Tests
tests = [
{"name": "basic_greeting", "desc": "Say hello",
"messages": [
{"role": "system", "content": "You are SakThai, a helpful assistant. Be concise."},
{"role": "user", "content": "Say hello in one sentence."}
]},
{"name": "tool_call_intent", "desc": "Tool-use intent",
"messages": [
{"role": "system", "content": "You are SakThai with tools: search(query), read_file(path), run_command(command)."},
{"role": "user", "content": "Search for the latest AI news"}
]},
{"name": "name_recall", "desc": "Remember name across 3 turns",
"messages": [
{"role": "system", "content": "You are SakThai."},
{"role": "user", "content": "My name is Beer."},
{"role": "assistant", "content": "Nice to meet you, Beer!"},
{"role": "user", "content": "What's my name?"}
]},
{"name": "factual_qa", "desc": "Capital of Japan",
"messages": [
{"role": "system", "content": "You are SakThai. Be concise."},
{"role": "user", "content": "What is the capital of Japan?"}
]},
{"name": "json_output", "desc": "Structured JSON",
"messages": [
{"role": "system", "content": "You are SakThai. Respond only with valid JSON."},
{"role": "user", "content": 'List 3 ML frameworks: {"frameworks": ["a","b","c"]}'}
]},
{"name": "instruction_following", "desc": "One sentence only",
"messages": [
{"role": "system", "content": "You are SakThai. Exactly one sentence."},
{"role": "user", "content": "Explain what a transformer is."}
]},
{"name": "multi_step_reasoning", "desc": "Math reasoning",
"messages": [
{"role": "system", "content": "You are SakThai, a helpful assistant."},
{"role": "user", "content": "If you have 3 apples and give away 1, then buy 5 more, how many do you have? Show your work."}
]},
{"name": "context_window", "desc": "Recall from context",
"messages": [
{"role": "system", "content": "You are SakThai."},
{"role": "user", "content": "'Attention Is All You Need' introduced the transformer architecture with multi-head self-attention, positional encodings, and encoder-decoder structure. BERT, GPT, T5 build on it. What year was the paper published?"}
]},
]
results = []
for i, test in enumerate(tests):
print(f"\n{''*60}", flush=True)
print(f"TEST {i+1}: {test['name']}{test['desc']}", flush=True)
try:
prompt = tokenizer.apply_chat_template(
test["messages"], tokenize=False, add_generation_prompt=True
)
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
t1 = time.time()
with torch.no_grad():
outputs = model.generate(
**inputs,
max_new_tokens=256,
temperature=0.1,
do_sample=True,
pad_token_id=tokenizer.eos_token_id,
)
elapsed = time.time() - t1
input_len = inputs.input_ids.shape[1]
response = tokenizer.decode(outputs[0][input_len:], skip_special_tokens=True).strip()
prompt_tokens = input_len
completion_tokens = outputs.shape[1] - input_len
# Quality checks
checks = []
if len(response) > 0: checks.append("non_empty")
if len(response) > 10: checks.append("substantial")
if test["name"] == "name_recall" and "beer" in response.lower():
checks.append("name_recall")
if test["name"] == "factual_qa" and "tokyo" in response.lower():
checks.append("correct")
if test["name"] == "context_window" and "2017" in response:
checks.append("correct_answer")
if test["name"] == "json_output":
try:
json.loads(response)
checks.append("valid_json")
except:
pass
if test["name"] == "multi_step_reasoning":
if any(c in response for c in ["7", "seven"]) and ("apple" in response.lower()):
checks.append("correct_answer")
passed = len(response) > 0 # at minimum non-empty
result = {
"name": test["name"], "passed": passed,
"response_preview": response[:200],
"response_length": len(response),
"latency_seconds": round(elapsed, 2),
"prompt_tokens": prompt_tokens,
"completion_tokens": completion_tokens,
"checks": checks,
}
status = "" if passed else ""
print(f" {status} {response[:120]}", flush=True)
print(f"{elapsed:.2f}s | 📝 {prompt_tokens}{completion_tokens} | ✅ {checks}", flush=True)
except Exception as e:
result = {"name": test["name"], "passed": False, "error": str(e)[:300]}
print(f"{e}", flush=True)
results.append(result)
sys.stdout.flush()
# Summary
print(f"\n{'='*60}", flush=True)
passed = sum(1 for r in results if r.get("passed"))
total = len(results)
print(f"📊 7B WORKBENCH SUMMARY: {passed}/{total} passed", flush=True)
for r in results:
status = "" if r.get("passed") else ""
lat = f"{r.get('latency_seconds',0):.1f}s" if r.get("passed") else " - "
detail = str(r.get("checks", r.get("error","?")[:60]))
print(f" {status} {r['name']:<22}{lat} {detail}", flush=True)
# Save record
record = {
"type": "workbench_hf_jobs",
"model": MODEL,
"load_time_seconds": round(load_time, 1),
"device": str(model.device),
"gpu": torch.cuda.get_device_name(0) if torch.cuda.is_available() else "cpu",
"vram_used_gb": round(torch.cuda.memory_allocated() / 1e9, 2) if torch.cuda.is_available() else 0,
"timestamp": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
"results": results,
"summary": f"{passed}/{total} passed",
}
record_path = "/tmp/sakthai-7b-workbench-record.json"
with open(record_path, "w") as f:
json.dump(record, f, indent=2)
print(f"\n💾 Saved: {record_path}", flush=True)
# Upload record to HF repo
try:
from huggingface_hub import HfApi, login
login(token=HF_TOKEN)
api = HfApi()
api.upload_file(
path_or_fileobj=record_path,
path_in_repo=f"eval/workbench-7b-{time.strftime('%Y-%m-%d')}.json",
repo_id="Nanthasit/sakthai-context-7b-merged",
repo_type="model",
)
print(f"📤 Uploaded to HF repo", flush=True)
except Exception as e:
print(f"⚠️ Upload failed: {e}", flush=True)
print("\n🏁 Done.", flush=True)