prince-canuma commited on
Commit
a85ab4d
·
verified ·
1 Parent(s): f0e1cbc

Upload function_calling_examples.ipynb

Browse files
Files changed (1) hide show
  1. function_calling_examples.ipynb +819 -0
function_calling_examples.ipynb ADDED
@@ -0,0 +1,819 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cells": [
3
+ {
4
+ "cell_type": "markdown",
5
+ "metadata": {},
6
+ "source": [
7
+ "# Function Calling with FunctionGemma\n",
8
+ "\n",
9
+ "This notebook demonstrates how to use FunctionGemma for function calling with MLX-LM. We'll cover different use cases including datetime, weather, calendar, email, database queries, and more.\n",
10
+ "\n",
11
+ "## Requirements\n",
12
+ "\n",
13
+ "```bash\n",
14
+ "pip install -U mlx-lm\n",
15
+ "```"
16
+ ]
17
+ },
18
+ {
19
+ "cell_type": "markdown",
20
+ "metadata": {},
21
+ "source": [
22
+ "## Setup"
23
+ ]
24
+ },
25
+ {
26
+ "cell_type": "code",
27
+ "execution_count": null,
28
+ "metadata": {},
29
+ "outputs": [],
30
+ "source": [
31
+ "import json\n",
32
+ "import re\n",
33
+ "from datetime import datetime\n",
34
+ "from mlx_lm import load, generate"
35
+ ]
36
+ },
37
+ {
38
+ "cell_type": "code",
39
+ "execution_count": null,
40
+ "metadata": {},
41
+ "outputs": [],
42
+ "source": [
43
+ "# Load the model\n",
44
+ "model, tokenizer = load(\"mlx-community/functiongemma-270m-it-bf16\")\n",
45
+ "print(\"✅ Model loaded\")"
46
+ ]
47
+ },
48
+ {
49
+ "cell_type": "markdown",
50
+ "metadata": {},
51
+ "source": [
52
+ "## Function Definitions\n",
53
+ "\n",
54
+ "Below are mock implementations of various functions that demonstrate different use cases. In production, these would connect to real APIs and services."
55
+ ]
56
+ },
57
+ {
58
+ "cell_type": "code",
59
+ "execution_count": null,
60
+ "metadata": {},
61
+ "outputs": [],
62
+ "source": [
63
+ "# Use Case 0: System DateTime\n",
64
+ "def get_current_datetime() -> dict:\n",
65
+ " \"\"\"Get current system date and time.\"\"\"\n",
66
+ " now = datetime.now()\n",
67
+ " return {\n",
68
+ " \"datetime\": now.isoformat(),\n",
69
+ " \"date\": now.strftime(\"%Y-%m-%d\"),\n",
70
+ " \"time\": now.strftime(\"%H:%M:%S\"),\n",
71
+ " \"day_of_week\": now.strftime(\"%A\"),\n",
72
+ " \"timezone\": now.astimezone().tzname()\n",
73
+ " }\n",
74
+ "\n",
75
+ "datetime_schema = {\n",
76
+ " \"type\": \"function\",\n",
77
+ " \"function\": {\n",
78
+ " \"name\": \"get_current_datetime\",\n",
79
+ " \"description\": \"Gets the current system date and time\",\n",
80
+ " \"parameters\": {\n",
81
+ " \"type\": \"OBJECT\",\n",
82
+ " \"properties\": {},\n",
83
+ " \"required\": [],\n",
84
+ " },\n",
85
+ " }\n",
86
+ "}"
87
+ ]
88
+ },
89
+ {
90
+ "cell_type": "code",
91
+ "execution_count": null,
92
+ "metadata": {},
93
+ "outputs": [],
94
+ "source": [
95
+ "# Use Case 1: Weather\n",
96
+ "def get_current_temperature(location: str) -> dict:\n",
97
+ " \"\"\"Get current temperature for a location.\"\"\"\n",
98
+ " temps = {\n",
99
+ " \"London\": 15, \"Paris\": 18, \"Tokyo\": 22,\n",
100
+ " \"New York\": 12, \"Sydney\": 25\n",
101
+ " }\n",
102
+ " return {\n",
103
+ " \"location\": location,\n",
104
+ " \"temperature\": temps.get(location, 20),\n",
105
+ " \"unit\": \"celsius\"\n",
106
+ " }\n",
107
+ "\n",
108
+ "weather_schema = {\n",
109
+ " \"type\": \"function\",\n",
110
+ " \"function\": {\n",
111
+ " \"name\": \"get_current_temperature\",\n",
112
+ " \"description\": \"Gets the current temperature for a given location.\",\n",
113
+ " \"parameters\": {\n",
114
+ " \"type\": \"OBJECT\",\n",
115
+ " \"properties\": {\n",
116
+ " \"location\": {\n",
117
+ " \"type\": \"STRING\",\n",
118
+ " \"description\": \"The city name, e.g. San Francisco\",\n",
119
+ " },\n",
120
+ " },\n",
121
+ " \"required\": [\"location\"],\n",
122
+ " },\n",
123
+ " }\n",
124
+ "}"
125
+ ]
126
+ },
127
+ {
128
+ "cell_type": "code",
129
+ "execution_count": null,
130
+ "metadata": {},
131
+ "outputs": [],
132
+ "source": [
133
+ "# Use Case 2: Calendar\n",
134
+ "def create_calendar_event(title: str, date: str, time: str) -> dict:\n",
135
+ " \"\"\"Create a calendar event.\"\"\"\n",
136
+ " return {\n",
137
+ " \"success\": True,\n",
138
+ " \"event\": {\n",
139
+ " \"title\": title,\n",
140
+ " \"date\": date,\n",
141
+ " \"time\": time,\n",
142
+ " \"event_id\": f\"evt_{hash(title+date)}\"\n",
143
+ " }\n",
144
+ " }\n",
145
+ "\n",
146
+ "calendar_schema = {\n",
147
+ " \"type\": \"function\",\n",
148
+ " \"function\": {\n",
149
+ " \"name\": \"create_calendar_event\",\n",
150
+ " \"description\": \"Creates a new event in the calendar\",\n",
151
+ " \"parameters\": {\n",
152
+ " \"type\": \"OBJECT\",\n",
153
+ " \"properties\": {\n",
154
+ " \"title\": {\"type\": \"STRING\", \"description\": \"Event title\"},\n",
155
+ " \"date\": {\"type\": \"STRING\", \"description\": \"Event date (YYYY-MM-DD)\"},\n",
156
+ " \"time\": {\"type\": \"STRING\", \"description\": \"Event time (HH:MM)\"}\n",
157
+ " },\n",
158
+ " \"required\": [\"title\", \"date\", \"time\"],\n",
159
+ " },\n",
160
+ " }\n",
161
+ "}"
162
+ ]
163
+ },
164
+ {
165
+ "cell_type": "code",
166
+ "execution_count": null,
167
+ "metadata": {},
168
+ "outputs": [],
169
+ "source": [
170
+ "# Use Case 3: Email\n",
171
+ "def send_email(recipient: str, subject: str, body: str) -> dict:\n",
172
+ " \"\"\"Send an email.\"\"\"\n",
173
+ " return {\n",
174
+ " \"success\": True,\n",
175
+ " \"message_id\": f\"msg_{hash(recipient+subject)}\",\n",
176
+ " \"sent_to\": recipient\n",
177
+ " }\n",
178
+ "\n",
179
+ "email_schema = {\n",
180
+ " \"type\": \"function\",\n",
181
+ " \"function\": {\n",
182
+ " \"name\": \"send_email\",\n",
183
+ " \"description\": \"Sends an email to a recipient\",\n",
184
+ " \"parameters\": {\n",
185
+ " \"type\": \"OBJECT\",\n",
186
+ " \"properties\": {\n",
187
+ " \"recipient\": {\"type\": \"STRING\", \"description\": \"Email address\"},\n",
188
+ " \"subject\": {\"type\": \"STRING\", \"description\": \"Email subject\"},\n",
189
+ " \"body\": {\"type\": \"STRING\", \"description\": \"Email body\"}\n",
190
+ " },\n",
191
+ " \"required\": [\"recipient\", \"subject\", \"body\"],\n",
192
+ " },\n",
193
+ " }\n",
194
+ "}"
195
+ ]
196
+ },
197
+ {
198
+ "cell_type": "code",
199
+ "execution_count": null,
200
+ "metadata": {},
201
+ "outputs": [],
202
+ "source": [
203
+ "# Use Case 4: Database\n",
204
+ "def search_database(query: str, table: str) -> dict:\n",
205
+ " \"\"\"Search database.\"\"\"\n",
206
+ " return {\n",
207
+ " \"results\": [\n",
208
+ " {\"id\": 1, \"name\": \"Result 1\"},\n",
209
+ " {\"id\": 2, \"name\": \"Result 2\"}\n",
210
+ " ],\n",
211
+ " \"count\": 2,\n",
212
+ " \"table\": table\n",
213
+ " }\n",
214
+ "\n",
215
+ "database_schema = {\n",
216
+ " \"type\": \"function\",\n",
217
+ " \"function\": {\n",
218
+ " \"name\": \"search_database\",\n",
219
+ " \"description\": \"Searches a database table\",\n",
220
+ " \"parameters\": {\n",
221
+ " \"type\": \"OBJECT\",\n",
222
+ " \"properties\": {\n",
223
+ " \"query\": {\"type\": \"STRING\", \"description\": \"Search query\"},\n",
224
+ " \"table\": {\"type\": \"STRING\", \"description\": \"Table name\"}\n",
225
+ " },\n",
226
+ " \"required\": [\"query\", \"table\"],\n",
227
+ " },\n",
228
+ " }\n",
229
+ "}"
230
+ ]
231
+ },
232
+ {
233
+ "cell_type": "code",
234
+ "execution_count": null,
235
+ "metadata": {},
236
+ "outputs": [],
237
+ "source": [
238
+ "# Use Case 5: File System\n",
239
+ "def list_files(directory: str) -> dict:\n",
240
+ " \"\"\"List files in directory.\"\"\"\n",
241
+ " return {\n",
242
+ " \"files\": [\"file1.txt\", \"file2.py\", \"file3.md\"],\n",
243
+ " \"count\": 3,\n",
244
+ " \"directory\": directory\n",
245
+ " }\n",
246
+ "\n",
247
+ "filesystem_schema = {\n",
248
+ " \"type\": \"function\",\n",
249
+ " \"function\": {\n",
250
+ " \"name\": \"list_files\",\n",
251
+ " \"description\": \"Lists files in a directory\",\n",
252
+ " \"parameters\": {\n",
253
+ " \"type\": \"OBJECT\",\n",
254
+ " \"properties\": {\n",
255
+ " \"directory\": {\"type\": \"STRING\", \"description\": \"Directory path\"}\n",
256
+ " },\n",
257
+ " \"required\": [\"directory\"],\n",
258
+ " },\n",
259
+ " }\n",
260
+ "}"
261
+ ]
262
+ },
263
+ {
264
+ "cell_type": "code",
265
+ "execution_count": null,
266
+ "metadata": {},
267
+ "outputs": [],
268
+ "source": [
269
+ "# Use Case 6: Translation\n",
270
+ "def translate_text(text: str, target_language: str) -> dict:\n",
271
+ " \"\"\"Translate text.\"\"\"\n",
272
+ " return {\n",
273
+ " \"original\": text,\n",
274
+ " \"translated\": f\"[{target_language.upper()}] {text}\",\n",
275
+ " \"language\": target_language\n",
276
+ " }\n",
277
+ "\n",
278
+ "translation_schema = {\n",
279
+ " \"type\": \"function\",\n",
280
+ " \"function\": {\n",
281
+ " \"name\": \"translate_text\",\n",
282
+ " \"description\": \"Translates text to another language\",\n",
283
+ " \"parameters\": {\n",
284
+ " \"type\": \"OBJECT\",\n",
285
+ " \"properties\": {\n",
286
+ " \"text\": {\"type\": \"STRING\", \"description\": \"Text to translate\"},\n",
287
+ " \"target_language\": {\"type\": \"STRING\", \"description\": \"Target language (e.g., Spanish, French)\"}\n",
288
+ " },\n",
289
+ " \"required\": [\"text\", \"target_language\"],\n",
290
+ " },\n",
291
+ " }\n",
292
+ "}"
293
+ ]
294
+ },
295
+ {
296
+ "cell_type": "code",
297
+ "execution_count": null,
298
+ "metadata": {},
299
+ "outputs": [],
300
+ "source": [
301
+ "# Use Case 7: Calculator\n",
302
+ "def calculate(expression: str) -> dict:\n",
303
+ " \"\"\"Calculate expression.\"\"\"\n",
304
+ " try:\n",
305
+ " result = eval(expression)\n",
306
+ " return {\"expression\": expression, \"result\": result, \"success\": True}\n",
307
+ " except Exception as e:\n",
308
+ " return {\"expression\": expression, \"error\": str(e), \"success\": False}\n",
309
+ "\n",
310
+ "calculator_schema = {\n",
311
+ " \"type\": \"function\",\n",
312
+ " \"function\": {\n",
313
+ " \"name\": \"calculate\",\n",
314
+ " \"description\": \"Evaluates a mathematical expression\",\n",
315
+ " \"parameters\": {\n",
316
+ " \"type\": \"OBJECT\",\n",
317
+ " \"properties\": {\n",
318
+ " \"expression\": {\"type\": \"STRING\", \"description\": \"Math expression (e.g., '2+2', '10*5')\"}\n",
319
+ " },\n",
320
+ " \"required\": [\"expression\"],\n",
321
+ " },\n",
322
+ " }\n",
323
+ "}"
324
+ ]
325
+ },
326
+ {
327
+ "cell_type": "code",
328
+ "execution_count": null,
329
+ "metadata": {},
330
+ "outputs": [],
331
+ "source": [
332
+ "# Use Case 8: Timer\n",
333
+ "def set_timer(duration_minutes: int, label: str) -> dict:\n",
334
+ " \"\"\"Set a timer.\"\"\"\n",
335
+ " return {\n",
336
+ " \"timer_id\": f\"timer_{hash(label)}\",\n",
337
+ " \"duration_minutes\": duration_minutes,\n",
338
+ " \"label\": label,\n",
339
+ " \"status\": \"active\"\n",
340
+ " }\n",
341
+ "\n",
342
+ "timer_schema = {\n",
343
+ " \"type\": \"function\",\n",
344
+ " \"function\": {\n",
345
+ " \"name\": \"set_timer\",\n",
346
+ " \"description\": \"Sets a timer with specified duration\",\n",
347
+ " \"parameters\": {\n",
348
+ " \"type\": \"OBJECT\",\n",
349
+ " \"properties\": {\n",
350
+ " \"duration_minutes\": {\"type\": \"NUMBER\", \"description\": \"Duration in minutes\"},\n",
351
+ " \"label\": {\"type\": \"STRING\", \"description\": \"Timer label\"}\n",
352
+ " },\n",
353
+ " \"required\": [\"duration_minutes\", \"label\"],\n",
354
+ " },\n",
355
+ " }\n",
356
+ "}"
357
+ ]
358
+ },
359
+ {
360
+ "cell_type": "code",
361
+ "execution_count": null,
362
+ "metadata": {},
363
+ "outputs": [],
364
+ "source": [
365
+ "# Use Case 9: News\n",
366
+ "def get_news(category: str, limit: int) -> dict:\n",
367
+ " \"\"\"Get news articles.\"\"\"\n",
368
+ " return {\n",
369
+ " \"category\": category,\n",
370
+ " \"articles\": [f\"Article {i+1}\" for i in range(limit)],\n",
371
+ " \"count\": limit\n",
372
+ " }\n",
373
+ "\n",
374
+ "news_schema = {\n",
375
+ " \"type\": \"function\",\n",
376
+ " \"function\": {\n",
377
+ " \"name\": \"get_news\",\n",
378
+ " \"description\": \"Gets news articles by category\",\n",
379
+ " \"parameters\": {\n",
380
+ " \"type\": \"OBJECT\",\n",
381
+ " \"properties\": {\n",
382
+ " \"category\": {\"type\": \"STRING\", \"description\": \"News category (e.g., technology, sports)\"},\n",
383
+ " \"limit\": {\"type\": \"NUMBER\", \"description\": \"Number of articles\"}\n",
384
+ " },\n",
385
+ " \"required\": [\"category\", \"limit\"],\n",
386
+ " },\n",
387
+ " }\n",
388
+ "}"
389
+ ]
390
+ },
391
+ {
392
+ "cell_type": "code",
393
+ "execution_count": null,
394
+ "metadata": {},
395
+ "outputs": [],
396
+ "source": [
397
+ "# Use Case 10: Reminder\n",
398
+ "def create_reminder(task: str, reminder_time: str) -> dict:\n",
399
+ " \"\"\"Create a reminder.\"\"\"\n",
400
+ " return {\n",
401
+ " \"reminder_id\": f\"rem_{hash(task)}\",\n",
402
+ " \"task\": task,\n",
403
+ " \"reminder_time\": reminder_time,\n",
404
+ " \"status\": \"scheduled\"\n",
405
+ " }\n",
406
+ "\n",
407
+ "reminder_schema = {\n",
408
+ " \"type\": \"function\",\n",
409
+ " \"function\": {\n",
410
+ " \"name\": \"create_reminder\",\n",
411
+ " \"description\": \"Creates a reminder for a task\",\n",
412
+ " \"parameters\": {\n",
413
+ " \"type\": \"OBJECT\",\n",
414
+ " \"properties\": {\n",
415
+ " \"task\": {\"type\": \"STRING\", \"description\": \"Task description\"},\n",
416
+ " \"reminder_time\": {\"type\": \"STRING\", \"description\": \"Time for reminder (e.g., '2pm tomorrow')\"}\n",
417
+ " },\n",
418
+ " \"required\": [\"task\", \"reminder_time\"],\n",
419
+ " },\n",
420
+ " }\n",
421
+ "}"
422
+ ]
423
+ },
424
+ {
425
+ "cell_type": "markdown",
426
+ "metadata": {},
427
+ "source": [
428
+ "## Function & Schema Registry"
429
+ ]
430
+ },
431
+ {
432
+ "cell_type": "code",
433
+ "execution_count": null,
434
+ "metadata": {},
435
+ "outputs": [],
436
+ "source": [
437
+ "ALL_FUNCTIONS = {\n",
438
+ " \"get_current_datetime\": get_current_datetime,\n",
439
+ " \"get_current_temperature\": get_current_temperature,\n",
440
+ " \"create_calendar_event\": create_calendar_event,\n",
441
+ " \"send_email\": send_email,\n",
442
+ " \"search_database\": search_database,\n",
443
+ " \"list_files\": list_files,\n",
444
+ " \"translate_text\": translate_text,\n",
445
+ " \"calculate\": calculate,\n",
446
+ " \"set_timer\": set_timer,\n",
447
+ " \"get_news\": get_news,\n",
448
+ " \"create_reminder\": create_reminder\n",
449
+ "}\n",
450
+ "\n",
451
+ "ALL_SCHEMAS = {\n",
452
+ " \"datetime\": datetime_schema,\n",
453
+ " \"weather\": weather_schema,\n",
454
+ " \"calendar\": calendar_schema,\n",
455
+ " \"email\": email_schema,\n",
456
+ " \"database\": database_schema,\n",
457
+ " \"filesystem\": filesystem_schema,\n",
458
+ " \"translation\": translation_schema,\n",
459
+ " \"calculator\": calculator_schema,\n",
460
+ " \"timer\": timer_schema,\n",
461
+ " \"news\": news_schema,\n",
462
+ " \"reminder\": reminder_schema\n",
463
+ "}"
464
+ ]
465
+ },
466
+ {
467
+ "cell_type": "markdown",
468
+ "metadata": {},
469
+ "source": [
470
+ "## Response Parser\n",
471
+ "\n",
472
+ "FunctionGemma uses a specific format for function calls:\n",
473
+ "```\n",
474
+ "<start_function_call>call:function_name{key:value,key:value}<end_function_call>\n",
475
+ "```\n",
476
+ "\n",
477
+ "String values may be wrapped in `<escape>` tags."
478
+ ]
479
+ },
480
+ {
481
+ "cell_type": "code",
482
+ "execution_count": null,
483
+ "metadata": {},
484
+ "outputs": [],
485
+ "source": [
486
+ "def parse_function_call(response: str):\n",
487
+ " \"\"\"Parse FunctionGemma's response format.\"\"\"\n",
488
+ " if \"<start_function_call>\" not in response:\n",
489
+ " return None, None\n",
490
+ "\n",
491
+ " start = response.find(\"<start_function_call>\") + len(\"<start_function_call>\")\n",
492
+ " end = response.find(\"<end_function_call>\")\n",
493
+ "\n",
494
+ " if end == -1:\n",
495
+ " call_str = response[start:].strip()\n",
496
+ " else:\n",
497
+ " call_str = response[start:end].strip()\n",
498
+ "\n",
499
+ " # Parse: call:function_name{key:value,key:value}\n",
500
+ " match = re.match(r'call:([\\w_]+)\\{([^}]*)\\}?', call_str, re.DOTALL)\n",
501
+ " if not match:\n",
502
+ " return None, None\n",
503
+ "\n",
504
+ " func_name = match.group(1)\n",
505
+ " args_str = match.group(2).strip()\n",
506
+ "\n",
507
+ " # Handle empty parameters\n",
508
+ " if not args_str:\n",
509
+ " return func_name, {}\n",
510
+ "\n",
511
+ " # Process escape tags\n",
512
+ " temp = args_str\n",
513
+ " while '<escape>' in temp:\n",
514
+ " start_idx = temp.find('<escape>')\n",
515
+ " end_idx = temp.find('<escape>', start_idx + 8)\n",
516
+ " if end_idx != -1:\n",
517
+ " escaped_content = temp[start_idx+8:end_idx]\n",
518
+ " temp = temp[:start_idx] + escaped_content + temp[end_idx+8:]\n",
519
+ " else:\n",
520
+ " temp = temp.replace('<escape>', '')\n",
521
+ " break\n",
522
+ "\n",
523
+ " # Parse key:value pairs\n",
524
+ " args = {}\n",
525
+ " for pair in temp.split(','):\n",
526
+ " if ':' in pair:\n",
527
+ " key, value = pair.split(':', 1)\n",
528
+ " key = key.strip()\n",
529
+ " value = value.strip()\n",
530
+ "\n",
531
+ " # Type conversion\n",
532
+ " try:\n",
533
+ " if '.' in value:\n",
534
+ " args[key] = float(value)\n",
535
+ " else:\n",
536
+ " args[key] = int(value)\n",
537
+ " except ValueError:\n",
538
+ " args[key] = value.strip('\"\\'')\n",
539
+ "\n",
540
+ " return func_name, args"
541
+ ]
542
+ },
543
+ {
544
+ "cell_type": "markdown",
545
+ "metadata": {},
546
+ "source": [
547
+ "## Test Runner"
548
+ ]
549
+ },
550
+ {
551
+ "cell_type": "code",
552
+ "execution_count": null,
553
+ "metadata": {},
554
+ "outputs": [],
555
+ "source": [
556
+ "def run_function_call(query: str, schema: dict, verbose: bool = True) -> dict:\n",
557
+ " \"\"\"\n",
558
+ " Run a function call with FunctionGemma.\n",
559
+ "\n",
560
+ " Args:\n",
561
+ " query: Natural language query from the user\n",
562
+ " schema: Function schema to make available\n",
563
+ " verbose: Whether to print detailed output\n",
564
+ "\n",
565
+ " Returns:\n",
566
+ " dict with 'success', 'function', 'args', and 'result' keys\n",
567
+ " \"\"\"\n",
568
+ " current_dt = get_current_datetime()\n",
569
+ "\n",
570
+ " # IMPORTANT: Developer role activates function calling\n",
571
+ " messages = [\n",
572
+ " {\n",
573
+ " \"role\": \"developer\",\n",
574
+ " \"content\": f\"\"\"You are a model that can do function calling with the following functions.\n",
575
+ "\n",
576
+ "Current system information:\n",
577
+ "- Date: {current_dt['date']} ({current_dt['day_of_week']})\n",
578
+ "- Time: {current_dt['time']}\n",
579
+ "- Timezone: {current_dt['timezone']}\"\"\"\n",
580
+ " },\n",
581
+ " {\n",
582
+ " \"role\": \"user\",\n",
583
+ " \"content\": query\n",
584
+ " }\n",
585
+ " ]\n",
586
+ "\n",
587
+ " # Apply chat template with tools\n",
588
+ " prompt = tokenizer.apply_chat_template(\n",
589
+ " messages,\n",
590
+ " tools=[schema],\n",
591
+ " add_generation_prompt=True,\n",
592
+ " tokenize=False\n",
593
+ " )\n",
594
+ "\n",
595
+ " # Generate response\n",
596
+ " response = generate(model, tokenizer, prompt=prompt, max_tokens=1024, verbose=False)\n",
597
+ "\n",
598
+ " if verbose:\n",
599
+ " print(f\"Query: {query}\")\n",
600
+ " print(f\"Response: {response}\")\n",
601
+ "\n",
602
+ " # Parse and execute\n",
603
+ " func_name, func_args = parse_function_call(response)\n",
604
+ "\n",
605
+ " if func_name and func_args is not None:\n",
606
+ " if verbose:\n",
607
+ " print(f\"\\n✅ Function: {func_name}()\")\n",
608
+ " print(f\" Arguments: {json.dumps(func_args, indent=2)}\")\n",
609
+ "\n",
610
+ " if func_name in ALL_FUNCTIONS:\n",
611
+ " result = ALL_FUNCTIONS[func_name](**func_args)\n",
612
+ " if verbose:\n",
613
+ " print(f\" Result: {json.dumps(result, indent=2)}\")\n",
614
+ " return {\"success\": True, \"function\": func_name, \"args\": func_args, \"result\": result}\n",
615
+ "\n",
616
+ " if verbose:\n",
617
+ " print(\"\\n❌ No function call detected\")\n",
618
+ " return {\"success\": False, \"function\": None, \"args\": None, \"result\": None}"
619
+ ]
620
+ },
621
+ {
622
+ "cell_type": "markdown",
623
+ "metadata": {},
624
+ "source": [
625
+ "## Examples\n",
626
+ "\n",
627
+ "Let's test each use case:"
628
+ ]
629
+ },
630
+ {
631
+ "cell_type": "code",
632
+ "execution_count": null,
633
+ "metadata": {},
634
+ "outputs": [],
635
+ "source": [
636
+ "# DateTime\n",
637
+ "run_function_call(\"What is the current date and time?\", datetime_schema)"
638
+ ]
639
+ },
640
+ {
641
+ "cell_type": "code",
642
+ "execution_count": null,
643
+ "metadata": {},
644
+ "outputs": [],
645
+ "source": [
646
+ "# Weather\n",
647
+ "run_function_call(\"What's the temperature in London?\", weather_schema)"
648
+ ]
649
+ },
650
+ {
651
+ "cell_type": "code",
652
+ "execution_count": null,
653
+ "metadata": {},
654
+ "outputs": [],
655
+ "source": [
656
+ "# Calendar\n",
657
+ "run_function_call(\"Create a meeting event for tomorrow at 2pm called Team Sync\", calendar_schema)"
658
+ ]
659
+ },
660
+ {
661
+ "cell_type": "code",
662
+ "execution_count": null,
663
+ "metadata": {},
664
+ "outputs": [],
665
+ "source": [
666
+ "# Email\n",
667
+ "run_function_call(\n",
668
+ " \"Send an email to john@example.com with subject 'Meeting' and body 'See you tomorrow'\",\n",
669
+ " email_schema\n",
670
+ ")"
671
+ ]
672
+ },
673
+ {
674
+ "cell_type": "code",
675
+ "execution_count": null,
676
+ "metadata": {},
677
+ "outputs": [],
678
+ "source": [
679
+ "# Database\n",
680
+ "run_function_call(\"Search the users table for active accounts\", database_schema)"
681
+ ]
682
+ },
683
+ {
684
+ "cell_type": "code",
685
+ "execution_count": null,
686
+ "metadata": {},
687
+ "outputs": [],
688
+ "source": [
689
+ "# File System\n",
690
+ "run_function_call(\"List files in the /home/user directory\", filesystem_schema)"
691
+ ]
692
+ },
693
+ {
694
+ "cell_type": "code",
695
+ "execution_count": null,
696
+ "metadata": {},
697
+ "outputs": [],
698
+ "source": [
699
+ "# Translation\n",
700
+ "run_function_call(\"Translate 'Hello World' to Spanish\", translation_schema)"
701
+ ]
702
+ },
703
+ {
704
+ "cell_type": "code",
705
+ "execution_count": null,
706
+ "metadata": {},
707
+ "outputs": [],
708
+ "source": [
709
+ "# Calculator\n",
710
+ "run_function_call(\"Calculate 25 * 4 + 10\", calculator_schema)"
711
+ ]
712
+ },
713
+ {
714
+ "cell_type": "code",
715
+ "execution_count": null,
716
+ "metadata": {},
717
+ "outputs": [],
718
+ "source": [
719
+ "# Timer\n",
720
+ "run_function_call(\"Set a 5 minute timer for coffee\", timer_schema)"
721
+ ]
722
+ },
723
+ {
724
+ "cell_type": "code",
725
+ "execution_count": null,
726
+ "metadata": {},
727
+ "outputs": [],
728
+ "source": [
729
+ "# News\n",
730
+ "run_function_call(\"Get 3 technology news articles\", news_schema)"
731
+ ]
732
+ },
733
+ {
734
+ "cell_type": "code",
735
+ "execution_count": null,
736
+ "metadata": {},
737
+ "outputs": [],
738
+ "source": [
739
+ "# Reminder\n",
740
+ "run_function_call(\"Remind me to call mom at 6pm today\", reminder_schema)"
741
+ ]
742
+ },
743
+ {
744
+ "cell_type": "markdown",
745
+ "metadata": {},
746
+ "source": [
747
+ "## Run All Tests"
748
+ ]
749
+ },
750
+ {
751
+ "cell_type": "code",
752
+ "execution_count": null,
753
+ "metadata": {},
754
+ "outputs": [],
755
+ "source": [
756
+ "test_cases = [\n",
757
+ " (\"datetime\", datetime_schema, \"What is the current date and time?\"),\n",
758
+ " (\"weather\", weather_schema, \"What's the temperature in London?\"),\n",
759
+ " (\"calendar\", calendar_schema, \"Create a meeting event for tomorrow at 2pm called Team Sync\"),\n",
760
+ " (\"email\", email_schema, \"Send an email to john@example.com with subject 'Meeting' and body 'See you tomorrow'\"),\n",
761
+ " (\"database\", database_schema, \"Search the users table for active accounts\"),\n",
762
+ " (\"filesystem\", filesystem_schema, \"List files in the /home/user directory\"),\n",
763
+ " (\"translation\", translation_schema, \"Translate 'Hello World' to Spanish\"),\n",
764
+ " (\"calculator\", calculator_schema, \"Calculate 25 * 4 + 10\"),\n",
765
+ " (\"timer\", timer_schema, \"Set a 5 minute timer for coffee\"),\n",
766
+ " (\"news\", news_schema, \"Get 3 technology news articles\"),\n",
767
+ " (\"reminder\", reminder_schema, \"Remind me to call mom at 6pm today\")\n",
768
+ "]\n",
769
+ "\n",
770
+ "successful = 0\n",
771
+ "for name, schema, query in test_cases:\n",
772
+ " print(f\"\\n{'='*60}\")\n",
773
+ " print(f\"USE CASE: {name.upper()}\")\n",
774
+ " print(f\"{'='*60}\")\n",
775
+ " result = run_function_call(query, schema)\n",
776
+ " if result[\"success\"]:\n",
777
+ " successful += 1\n",
778
+ "\n",
779
+ "print(f\"\\n\\n{'='*60}\")\n",
780
+ "print(f\"SUMMARY: {successful}/{len(test_cases)} tests passed ({successful/len(test_cases)*100:.1f}%)\")\n",
781
+ "print(f\"{'='*60}\")"
782
+ ]
783
+ },
784
+ {
785
+ "cell_type": "markdown",
786
+ "metadata": {},
787
+ "source": [
788
+ "## Key Takeaways\n",
789
+ "\n",
790
+ "1. **Developer Role**: Use `role: \"developer\"` to activate function calling mode\n",
791
+ "2. **Schema Format**: Follow the OBJECT/STRING/NUMBER type format in schemas\n",
792
+ "3. **Response Format**: FunctionGemma uses `<start_function_call>call:name{args}<end_function_call>`\n",
793
+ "4. **Escaped Strings**: String values may be wrapped in `<escape>` tags\n",
794
+ "5. **Context**: Providing current datetime helps with time-aware queries"
795
+ ]
796
+ }
797
+ ],
798
+ "metadata": {
799
+ "kernelspec": {
800
+ "display_name": "mlx",
801
+ "language": "python",
802
+ "name": "python3"
803
+ },
804
+ "language_info": {
805
+ "codemirror_mode": {
806
+ "name": "ipython",
807
+ "version": 3
808
+ },
809
+ "file_extension": ".py",
810
+ "mimetype": "text/x-python",
811
+ "name": "python",
812
+ "nbconvert_exporter": "python",
813
+ "pygments_lexer": "ipython3",
814
+ "version": "3.12.12"
815
+ }
816
+ },
817
+ "nbformat": 4,
818
+ "nbformat_minor": 4
819
+ }