Instructions to use ornith-ai/Ornith-1.0-9B with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use ornith-ai/Ornith-1.0-9B with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="ornith-ai/Ornith-1.0-9B") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] pipe(text=messages)# Load model directly from transformers import AutoProcessor, AutoModelForMultimodalLM processor = AutoProcessor.from_pretrained("ornith-ai/Ornith-1.0-9B") model = AutoModelForMultimodalLM.from_pretrained("ornith-ai/Ornith-1.0-9B", device_map="auto") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] inputs = processor.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=40) print(processor.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Inference
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use ornith-ai/Ornith-1.0-9B with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "ornith-ai/Ornith-1.0-9B" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "ornith-ai/Ornith-1.0-9B", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/ornith-ai/Ornith-1.0-9B
- SGLang
How to use ornith-ai/Ornith-1.0-9B 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 "ornith-ai/Ornith-1.0-9B" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "ornith-ai/Ornith-1.0-9B", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'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 "ornith-ai/Ornith-1.0-9B" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "ornith-ai/Ornith-1.0-9B", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use ornith-ai/Ornith-1.0-9B with Docker Model Runner:
docker model run hf.co/ornith-ai/Ornith-1.0-9B
Add evaluation results
Ornith 9B Coding Test Feedback
Overall this is a solid showing for a 9B model. The code is clean and easy to read, and it plans well when asked to plan before writing. The simple problems (flatten, sort, to-do app, CSV merge) were handled well. But correctness slips as the tasks get harder, and a few answers contain real bugs.
What it did well:
Clear, readable code with good comments and docstrings.
Good at outlining a plan first when the prompt asked for one.
Solid explanations for most problems (the Fibonacci "why it's slow" write-up was mostly right).
Bugs and mistakes I found:
find_duplicates: if a number appears 3+ times, it gets added to the result more than once. So it returns repeats instead of a clean list of duplicates.
Fibonacci: the trade off table says memoization uses "O(1)" extra memory. That's wrong, it stores one entry per number, so it's O(n). The call count numbers were also off (fib(40) is about 200 million calls, not 1 billion).
remove_evens: the fix itself works, but one example in the explanation is wrong, it claims [4, 6] returns [6], when that input would actually crash.
Secure REST API: the user database is set up two different ways, so logging in as "admin" would crash with a KeyError. It also uses a deprecated date function and a plain-text password check.
To do app: typing a command like done with no ID crashes, even though it claimed to handle bad input.
Bottom line: good for drafts and simple tasks, but the code needs review before trusting it, especially on anything security related, where it made the most serious mistakes.
Here are the untouched prompts and answers:
Test 1 β Flatten a nested list
Prompt: Write a Python function called flatten(lst) that takes a nested list of arbitrary depth and returns a flat list. Include edge cases: empty lists, single elements, and mixed nesting depths.
Response:
def flatten(lst):
"""Recursively flatten a nested list of arbitrary depth."""
result = []
for item in lst:
if isinstance(item, list):
result.extend(flatten(item))
else:
result.append(item)
return result
How it works:
- Goes through each element. If it's a list, it recurses and adds all its contents.
- Otherwise it adds the value directly.
Edge cases handled:
flatten([])β[](empty input)flatten([1])β[1](single element)flatten([[1, [2]], 3, [[4]]])β[1, 2, 3, 4](mixed depths)
Test 2 β Find duplicates in O(n)
Prompt: Write a function find_duplicates(arr) that returns all elements appearing more than once in an array. It must run in O(n) time. Show the time complexity analysis after the code.
Response:
def find_duplicates(arr):
seen = set()
duplicates = []
for num in arr:
if num in seen:
duplicates.append(num)
else:
seen.add(num)
return duplicates
Time complexity analysis:
| Step | Work done | Complexity |
|---|---|---|
Initialize seen and duplicates |
constant | O(1) |
Loop through arr (n elements) |
each set lookup/insert is amortized O(1) | O(n) |
| Append when a duplicate is found | amortized O(1) per hit | absorbed by loop |
Total: O(n) β single pass, no sorting.
Space: O(k), where k = number of distinct elements (worst case O(n)).
Test 3 β Debug remove_evens
Prompt: This Python code is supposed to remove all even numbers from a list in-place, but it's buggy. Find and fix every bug, then explain what each bug was and why it caused the problem.
def remove_evens(lst):
for i in range(len(lst)):
if lst[i] % 2 == 0:
lst.pop(i)
return lst
print(remove_evens([1, 2, 3, 4, 5, 6]))
Response:
def remove_evens(lst):
i = len(lst) - 1
while i >= 0:
if lst[i] % 2 == 0:
del lst[i]
i -= 1
return lst
print(remove_evens([1, 2, 3, 4, 5, 6]))
Bugs and why they matter:
- Bug 1 β
range(len(lst))is fixed at the start. The loop length is set once, before any removals. As you pop items the list shrinks, butikeeps climbing, so it eventually reads past the end of the shorter list β IndexError. - Bug 2 β Removing from the front skips items. Popping shifts everything left, so the next
ilands on the item that was one spot further along. That makes it skip some evens.
Fix: loop backwards (while i >= 0). Removing from the end never disturbs the spots you haven't reached yet, so both bugs go away.
Test 4 β Speed up recursive Fibonacci
Prompt: This recursive Fibonacci function works but is extremely slow for large inputs. First explain exactly why it's slow (be specific about the math), then give two different fixes β one using memoization and one using iteration β and compare their trade-offs.
def fib(n):
if n <= 1:
return n
return fib(n-1) + fib(n-2)
Response:
Why it's slow: the recursion tree roughly doubles at each level, since fib(n) calls fib(n-1) and fib(n-2). The recurrence is the same as Fibonacci itself, which solves to O(ΟβΏ), where Ο β 1.618 (the golden ratio). That exponential growth is why it bogs down around n=30β40.
Fix 1 β Memoization (top-down):
from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
if n <= 1:
return n
return fib(n - 1) + fib(n - 2)
Fix 2 β Iteration (bottom-up):
def fib_iter(n):
if n <= 1:
return n
a, b = 0, 1
for _ in range(2, n + 1):
a, b = b, a + b
return b
Trade-offs:
| Aspect | Memoization | Iteration |
|---|---|---|
| Time | O(n) | O(n) |
| Extra space | cache entries (O(n)) | O(1) β two variables |
| Stack depth | O(n) β still recursive | O(1) β no recursion |
| Readability | clean, keeps original shape | very compact |
Bottom line: both are O(n). Iteration is safer at large n (no risk of hitting the recursion limit). Memoization keeps the recursive style, which is handy if you want to preserve that structure.
Test 5 β Command-line to-do app
Prompt: Build a simple command-line to-do list app in Python that supports adding tasks, listing tasks, marking complete, and deleting. Tasks must persist between runs using a JSON file. Outline the plan first, then implement it.
Response:
Plan:
| Concern | Approach |
|---|---|
| Data | List of dicts: {"id", "text", "done"} saved as a JSON array. Short unique ID per task. |
| Persistence | load_tasks() reads the file (empty list if missing); save_tasks() writes via a temp file then rename. |
| Input | Main loop reads one line: add, list, done <id>, delete <id>. |
| Edge cases | Strips whitespace, rejects blank tasks, reports invalid IDs, catches file errors. |
Implementation:
import json, uuid, os, tempfile
DATA_FILE = "todos.json"
def load_tasks():
"""Load tasks from JSON file; create empty list if missing."""
if not os.path.exists(DATA_FILE):
return []
with open(DATA_FILE) as f:
try:
return json.load(f) or []
except json.JSONDecodeError:
return []
def save_tasks(tasks):
"""Write tasks to JSON file atomically."""
fd, tmp = tempfile.mkstemp(suffix=".json", dir=os.path.dirname(DATA_FILE))
with os.fdopen(fd, "w") as f:
json.dump(tasks, f)
if os.path.exists(tmp):
os.replace(tmp, DATA_FILE)
def add_task(text: str):
"""Add a new task. Returns the new task dict or None on failure."""
text = text.strip()
if not text:
print("Task text cannot be empty.")
return None
tasks = load_tasks()
task = {"id": uuid.uuid4().hex[:8], "text": text, "done": False}
tasks.append(task)
save_tasks(tasks)
print(f"Added: #{task['id']} {text}")
return task
def list_tasks():
"""Print all tasks."""
tasks = load_tasks()
if not tasks:
print("No tasks yet.")
return
for t in tasks:
status = "[done]" if t["done"] else "[ ]"
print(f"{status} #{t['id']} {t['text']}")
def mark_done(task_id: str):
"""Mark a task as complete. Returns True on success."""
tasks = load_tasks()
for i, t in enumerate(tasks):
if t["id"] == task_id:
tasks[i]["done"] = True
save_tasks(tasks)
print(f"Task #{task_id} marked done.")
return True
print(f"Task #{task_id} not found.")
return False
def delete_task(task_id: str):
"""Delete a task by id. Returns True on success."""
tasks = load_tasks()
before = len(tasks)
tasks = [t for t in tasks if t["id"] != task_id]
if len(tasks) == before:
print(f"Task #{task_id} not found.")
return False
save_tasks(tasks)
print(f"Deleted task #{task_id}.")
return True
def run():
"""Main CLI loop."""
print("To-Do List (commands: add, list, done <id>, delete <id>)")
while True:
cmd = input("\n> ").strip()
if not cmd:
continue
parts = cmd.split(None, 1)
action = parts[0].lower()
if action == "add":
add_task(parts[1] if len(parts) > 1 else "")
elif action == "list":
list_tasks()
elif action in ("done", "complete"):
mark_done(parts[1])
elif action in ("delete", "del"):
delete_task(parts[1])
else:
print(f"Unknown command '{action}'. Type 'list' to see options.")
if __name__ == "__main__":
run()
Test 6 β Clean and merge 500 CSV files
Prompt: I have 500 CSV files with columns date, product_id, quantity, price. Some have missing values, some have duplicate rows, and some list price as a string with a dollar sign (e.g. "$4.99"). Write a Python script that cleans and merges them into one clean CSV. Explain the approach first.
Response:
Approach:
- Find all
.csvfiles in the folder. - Read each one with pandas and stack them into one DataFrame.
- Clean price β strip spaces, remove
$, convert to a number; turn errors into NaN. - Handle missing values (e.g. default quantity to 0).
- Remove duplicate rows after cleaning, since
"$4.99"and4.99only become identical once parsed. - Write the result to a single clean CSV.
Script:
import glob
import pandas as pd
# ββ Configuration ββββββββββββββββββββββββββββββββββββββββββββββ
INPUT_DIR = "data/" # folder containing the 500 CSVs
OUTPUT_FILE = "merged_clean.csv"
QUANTITY_DEFAULT = 0 # what to fill quantity with when NaN
PRICE_DROP_IF_NAN = False # True β drop rows where price is still NaN after cleaning
def clean_and_merge():
csv_files = sorted(glob.glob(INPUT_DIR + "*.csv"))
if not csv_files:
raise FileNotFoundError(f"No CSV files found in {INPUT_DIR}")
frames = [pd.read_csv(path, on_bad_lines="skip") for path in csv_files]
df = pd.concat(frames, ignore_index=True)
# Parse price
if "price" in df.columns:
df["price"] = df["price"].astype(str).str.strip().str.replace("$", "")
df["price"] = pd.to_numeric(df["price"], errors="coerce")
# Fill missing values
if "quantity" in df.columns:
df["quantity"] = df["quantity"].fillna(QUANTITY_DEFAULT)
# Drop rows with unresolvable price NaN (optional)
if PRICE_DROP_IF_NAN and "price" in df.columns:
before = len(df)
df = df.dropna(subset=["price"])
print(f"Dropped {before - len(df)} rows with missing price.")
# Drop exact duplicates
before = len(df)
df = df.drop_duplicates()
after = len(df)
if before != after:
print(f"Removed {before - after} duplicate rows.")
df.to_csv(OUTPUT_FILE, index=False)
print(f"Wrote {len(df)} clean records to {OUTPUT_FILE}")
if __name__ == "__main__":
clean_and_merge()
Test 7 β Production-quality sort function
Prompt: Write a function that sorts a list. Make it production-quality.
Response:
from typing import Callable, List, TypeVar, Optional
T = TypeVar("T")
def sort_list(
items: List[T],
*,
reverse: bool = False,
key: Optional[Callable[[T], object]] = None,
) -> List[T]:
"""Return a new sorted list derived from *items*.
Uses Python's built-in ``sorted`` (Timsort), which is O(n log n) and
stable. This wrapper adds explicit typing, defaults, and a clear API.
Parameters
items: The list to sort. An empty list returns [].
reverse: If True, sort in descending order (default False).
key: Optional callable that extracts a comparison key.
Returns
A new sorted list. The original list is not modified.
Examples
>>> sort_list([3, 1, 4, 1, 5])
[1, 1, 3, 4, 5]
>>> sort_list(["banana", "apple", "Cherry"], key=str.lower)
['apple', 'banana', 'Cherry']
"""
if not isinstance(items, list):
raise TypeError(
f"sort_list() expects a list argument, got {type(items).__name__}"
)
return sorted(items, reverse=reverse, key=key)
Test 8 β Secure REST API endpoint
Prompt: I need a REST API endpoint in Python. Make it secure.
Response:
# main.py
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import jwt, JWTError
from passlib.context import CryptContext
from datetime import datetime, timedelta
from typing import Optional
app = FastAPI()
# ββ Config (set via env vars) βββββββββββββββββββββββββββββββ
SECRET_KEY = "change-me-in-production" # replace with a real secret
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/login", auto_error=False)
# ββ Mock user DB (replace with real DB in production) ββββββ
USERS_DB: dict[str, dict] = {
"admin": {"password": "$2b$12$LJ3mQ...hashed...", "role": "admin"},
}
USERS_DB["demo"] = {"password_hash": "demo_password", "role": "user"}
def verify_password(plain: str, hashed: str) -> bool:
"""Replace this with bcrypt.checkpw() when using real hashes."""
return plain == hashed # demo only
# ββ Helpers ββββββββββββββββββββββββββββββββββββββββββββββββ
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
to_encode = data.copy()
expire = datetime.utcnow() + (expires_delta or timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
def authenticate_user(username: str, password: str) -> Optional[dict]:
user = USERS_DB.get(username)
if not user or not verify_password(password, user["password_hash"]):
return None
return user
# ββ Endpoints ββββββββββββββββββββββββββββββββββββββββββββββ
@app.post("/auth/login")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
"""Login. Returns JWT if credentials are valid."""
user = authenticate_user(form_data.username, form_data.password)
if not user:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid credentials")
token = create_access_token({"sub": user["role"]})
return {"access_token": token, "token_type": "bearer"}
@app.get("/protected")
async def protected_endpoint(token: str = Depends(oauth2_scheme)):
"""Protected endpoint. Rejects invalid/expired tokens."""
if not token:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Missing token")
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
except JWTError:
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid or expired token")
role = payload.get("sub")
if role is None:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Missing role claim")
return {"message": "Welcome", "role": role}
@app.post("/api/data")
async def create_data(item: dict):
"""Simple POST with basic validation."""
if not item or "name" not in item:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Missing 'name' field")
return {"status": "ok", **item}
if __name__ == "__main__":
import uvicorn
uvicorn.run("main:app", host="127.0.0.1", port=8000)
Security checklist the model listed:
| Concern | Mitigation |
|---|---|
| Transport | Use HTTPS in production |
| Auth | JWT with expiry, bcrypt password hashing (replace demo code) |
| Input | FastAPI schema validation on POST endpoints |
| Secrets | Env vars / .env β never hardcode |
| Binding | Listen on 127.0.0.1 by default; reverse proxy for public exposure |
| Logging | Add structured logging to track failed logins |
Test 9 β Diagnose a silent web scraper
Prompt: A user's Python web scraper runs without errors but returns empty results. Walk through exactly how you'd diagnose and fix it, step by step, as if executing commands. Show your reasoning at each step.
Response: The model laid out a systematic approach, from code to network to page structure:
- Read the code (
cat scraper.py) β the most common silent failures are wrong selectors or broken parsing. - Force it to talk β print the status code, response length, and first 500 characters so a 4xx/5xx hiding as "empty" becomes visible.
- Check the actual HTML β if a 200 returns real HTML, the selector probably no longer matches the page (the site changed its structure).
- Inspect the network layer (
curl -v) β a 403/429 from missing headers or rate-limiting is a classic silent failure. - Check for JavaScript-rendered content β if the data loads via JS, plain
requestsonly sees an empty shell, so you'd need Selenium/Playwright.
Quick reference the model gave:
| Diagnosis | Fix |
|---|---|
| Wrong selector | Inspect current HTML in DevTools, update CSS/XPath |
| 403/429 status | Add User-Agent, retry with delays, use a session |
| JS-rendered content | Swap requests for Playwright/Selenium |
| SSL error | Fix the cert chain (avoid verify=False except as a temporary test) |
| Empty HTML body | Check if the site is down, redirected, or changed format |
Most likely causes, in order: selector drift, missing headers, then JS-only content.
Test 10 β Refactor a 300-line script into a package
Prompt: Refactor a 300-line Python script (it fetches from an API, cleans data, writes to a database, and logs) into a proper package with modules, tests, and a setup.py. Write the full plan first β directory structure, what goes in each file, and what order to tackle it in.
Response:
Directory structure:
mypackage/
βββ setup.py # Package metadata, install config, entry points
βββ requirements.txt # Runtime dependencies
βββ README.md # Project overview and usage
βββ src/
β βββ __init__.py # Exports public API + version
β βββ fetcher.py # API data fetching (requests, retry logic)
β βββ cleaner.py # Data cleaning / transformation
β βββ writer.py # Database insertion via SQLAlchemy
β βββ logger.py # Central logging config
β βββ pipeline.py # Orchestrates the full flow; entry point
βββ tests/
β βββ __init__.py
β βββ conftest.py # Shared fixtures (mock API, DB setup)
β βββ test_fetcher.py
β βββ test_cleaner.py
β βββ test_writer.py
β βββ test_pipeline.py
βββ docs/
βββ api.md
What goes where:
| File | Purpose |
|---|---|
setup.py |
name, version, dependencies, a console-script entry point |
src/__init__.py |
Exports the main classes; exposes a version constant |
fetcher.py |
HTTP calls, auth headers, pagination, retries with backoff |
cleaner.py |
Raw records β cleaned data; nulls, type casting, dedupe |
writer.py |
SQLAlchemy engine/session; batch inserts |
logger.py |
Configures logging once: file + console handlers |
pipeline.py |
Glues the stages together with error handling |
tests/conftest.py |
Fixtures shared across test files |
Order to build it:
- Read the original script (understand data shapes and error paths).
- Scaffold the folders and empty
__init__.pyfiles. - Write
logger.pyfirst β everything depends on it. - Write
fetcher.pyβ isolated I/O, easy to mock. - Write
cleaner.pyβ pure transformation, easy to test. - Write
writer.pyβ the database layer. - Write
pipeline.pyβ ties the three together. - Write
src/__init__.pyβ exports the public API. - Write
setup.pyandrequirements.txtlast. - Write the tests, starting with
conftest.py, in dependency order.