A lightweight LoRA fine-tune of
google/functiongemma-270m-it that converts natural language sports event requests into structured
create_sports_event function calls with proper ISO 8601 timestamps and timezone handling.
1from transformers import AutoTokenizer, AutoModelForCausalLM
2from peft import PeftModel
3import torch
4import json
5from datetime import datetime, timedelta
6from zoneinfo import ZoneInfo
7
8BASE_MODEL = "google/functiongemma-270m-it"
9ADAPTER_REPO = "sarvkk/funcgemma-event-parser-v2"
10
11device = "cuda" if torch.cuda.is_available() else "cpu"
12
13# Load base + LoRA adapter
14base_model = AutoModelForCausalLM.from_pretrained(
15 BASE_MODEL,
16 device_map={"": device},
17 dtype=torch.bfloat16,
18 attn_implementation="eager",
19 low_cpu_mem_usage=True,
20)
21model = PeftModel.from_pretrained(base_model, ADAPTER_REPO, device_map={"": device})
22tokenizer = AutoTokenizer.from_pretrained(ADAPTER_REPO)
23model.eval()
24
25# Function schema
26FUNCTION_SCHEMA = {
27 "name": "create_sports_event",
28 "description": "Create a new sports event from natural language description",
29 "parameters": {
30 "type": "object",
31 "properties": {
32 "sport": {"type": "string", "description": "Type of sport"},
33 "venue_name": {"type": "string", "description": "Name of the venue"},
34 "start_time": {"type": "string", "description": "ISO 8601 with timezone"},
35 "max_participants": {"type": "integer", "default": 2},
36 "event_type": {
37 "type": "string",
38 "enum": ["Casual", "Light Training", "Looking to Improve", "Competitive Game"],
39 },
40 },
41 "required": ["sport", "venue_name", "start_time"],
42 },
43}
44
45# Build prompt with date context
46now = datetime.now()
47today_str = now.strftime("%Y-%m-%d")
48today_day = now.strftime("%A")
49current_time = now.strftime("%H:%M")
50tomorrow_str = (now + timedelta(days=1)).strftime("%Y-%m-%d")
51user_timezone = "America/New_York"
52tz = ZoneInfo(user_timezone)
53offset = now.replace(hour=12, tzinfo=tz).strftime("%z")
54tz_offset = f"{offset[:3]}:{offset[3:]}"
55
56user_query = "Soccer this Friday 4pm @ Central Park"
57
58prompt = f"""<start_of_turn>user
59Current date and time: {today_str} ({today_day}) at {current_time}
60User timezone: {user_timezone} (UTC{tz_offset})
61
62User request: {user_query}
63
64Available functions:
65{json.dumps([FUNCTION_SCHEMA], indent=2)}
66
67Important:
68- Calculate dates relative to {today_str}
69- "tomorrow" = {tomorrow_str}
70- "Friday" = the next upcoming Friday from {today_str}
71- All times should be in ISO 8601 format with timezone offset
72- Example: "{tomorrow_str}T16:00:00{tz_offset}"
73<end_of_turn>
74<start_of_turn>model
75"""
76
77inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
78with torch.no_grad():
79 outputs = model.generate(
80 **inputs,
81 max_new_tokens=300,
82 do_sample=False,
83 pad_token_id=tokenizer.eos_token_id,
84 )
85
86result = tokenizer.decode(outputs[0], skip_special_tokens=True)
87start = result.find("<function_call>") + len("<function_call>")
88end = result.find("</function_call>")
89if end == -1:
90 end = len(result)
91parsed = json.loads(result[start:end].strip())
92print(json.dumps(parsed, indent=2))
1{
2 "name": "create_sports_event",
3 "arguments": {
4 "sport": "Soccer",
5 "venue_name": "Central Park",
6 "start_time": "2026-02-13T16:00:00-05:00",
7 "max_participants": 22,
8 "event_type": "Casual"
9 }
10}
Each example includes the current date context in the prompt so the model learns to resolve relative dates ("tomorrow", "this Friday", "next Monday") dynamically.
6 held-out queries with unseen venue names across 5 timezones, testing relative date resolution and diverse sports.
Compared against a
Gemma-2 2B LoRA adapter trained on the same task, on a Tesla T4 GPU: