To this point in the book, you’ve produced a text response for each prompt in Foundation Explorer. Given that the app is by nature a chat-style app, a text response was a logical choice. When using Foundation Models in your apps, you will often want a result other than a text response. For this, Apple Foundation Models supports the generating parameter when calling either the LanguageModelSession respond(to:options:) or streamResponse(to:options:) methods. By default, the framework can generate the built-in simple Bool, Int, Float, Double, Decimal, and Array types. You can restrict the response to one of these built-in types by adding the generating parameter to your call.
Open the starter project for this chapter. You’ll see a new project that lets you select meal options. You will expand this app to use Foundation Models to build a dining menu in this chapter. The app lets the user select breakfast, lunch, dinner, or dessert. You can then select a cuisine type for the menu. The next step will be to select the menu ingredients, but the app doesn’t generate them yet.
Menu Generation App
You will also see a toolbar button that will allow you to view the current transcript of the session property of this view. It starts with a default LanguageModelSession, but you’ll later tie this session into the menu generation.
While there are times when producing a built-in type is helpful, the true power of this guided generation comes when you define your data structure and provide guidance on generating it. While generating data with LLMs has always been possible with the right prompts, this has typically required careful tuning to produce a format such as JSON and meticulous text parsing. The native inclusion of this ability may be the most important feature of Foundation Models compared to general-purpose LLMs.
Imagine a scenario where you want to provide a realistic menu in a game when the player enters a restaurant. You could enter a prompt in the Foundation Explorer app from earlier chapters, such as:
Create a lunch menu for a casual dining restaurant.
The result will be a plausible menu that reads like a wall of text. For a case where the user only needs to read the result, this works fine. But if you want to put this into a data structure, you need to parse the result. Traditionally, you’d do this by producing the information in JSON. You would need to refine your prompts to create a format that you can interpret as a structure. Instead, you will let Foundation Models do this work for you.
Menu created by asking Foundation Explorer app.
Before using guided generation, you must first define the data structures to fill with the generated information. Create a new file under the Models folder named CuisineIngredients.swift and replace the code with:
This is a pretty simple structure that contains a single string array property called ingredients. Open FoodMenuView.swift. Add the following new method after generateCuisineList():
This is about as simple a list as you could create. You return four static string ingredients. Now, to call this method, find the Task modifier on the VStack that contains the view just before the navigationTitle("Menu Maker") modifier. Add the following code after the Task and before navigationTitle:
Whenever the user selects a different cuisine from the picker, this method clears the selected ingredients, then calls the new generateIngredients() method. Run the app and select a cuisine. You’ll see those four ingredients. Tap any ingredient, and you’ll see a check appear next to it. Tap an ingredient again to unselect it.
Ingredient Selection
Now that you’ve explored the user interface, you’ll adapt the app to generate a list of ingredients for the selected cuisine.
Generating Custom Data Structures
Foundation Models provides two macros that let you assist the model and guide the generated data. The first is Generable(description:), which marks structures and enumerations for guided generation and provides context to the model. You will use it along with Guide(description:) on each property in these Generable types. The framework allows nesting Generable types to support complex data hierarchies.
Foundation Models require Generable(description:) for any type that you wish to create. To see this, add the following code above the definition of CuisineIngredients:
@Generable(description: "A list of ingredients common in a specific type of cuisine.")
The parameter to the Generable macro is a textual description of the data structure’s purpose. To provide more guidance for the properties of the structure, use Guide(description:). Add the following code before the ingredients property:
@Guide(description: "A list of individual food ingredients.")
With these defined, you can now use Foundation Models to generate the ingredient list. Go back to FoodMenuView.swift and replace generateIngredients() with:
func generateIngredients() async -> [String] {
// 1
guard cuisine != "N/A" else { return [] }
isGenerating = true
defer { isGenerating = false }
// 2
let ingredientPrompt = """
Give me a list of ingredients used in \(cuisine) for \(selectedMeal).
Do not repeat ingredients. Do not provide examples of ingredients.
"""
let session = LanguageModelSession()
// 3
let response = try? await session.respond(to: ingredientPrompt, generating: CuisineIngredients.self)
// 4
if let response = response {
return response.content.ingredients
} else {
return []
}
}
Most of this should look familiar from the earlier chapters. You change the method to async as with most methods related to Foundation Models. Inside the method, you:
You ensure the user has selected a cuisine, then set a property to show an indicator that the app is working. Even with asynchronous streaming responses, an indicator helps the user feel the app is more responsive.
This prompt asks for a list of ingredients, and fills in the type of cuisine and meal from the values selected in the view. A simple prompt will suffice thanks to guided generation. Without it, you would need a lengthy prompt that specifies a format and provides examples to get useful results. Note that since the user selects cuisine and selectedMeal from a list of choices, you avoid many of the risks of user-generated content while still allowing users to make choices.
The significant change to this method is adding the generating: CuisineIngredients.self parameter when calling respond(to:generating:includeSchemaInPrompt:options:). This tells Foundation Models to produce a structure of the CuisineIngredients you defined. Note that you must mark this type as Generable, which you did by adding the macro earlier.
As before, when using the try? await pattern, you attempt to unwrap the returned value. If successful, you access the returned CuisineIngredients struct through response.content. Since you only need the string array with the ingredients, you return the generated ingredients property. If the unwrap failed, you return an empty array.
You need to make one more change since this method is now async. Find your call to generateIngredients() inside the view and change it to:
This change first wraps the code inside a Task. Since generating ingredients takes a few seconds, you clear the ingredients array first. After clearing the selected ingredients, you add an await call to the now asynchronous method.
Run the app, select a meal and cuisine from the menu. After a few seconds, an appropriate ingredient list will appear.
Generated French Dinner Ingredients in French
Depending on the combination you chose, you could see a large number of ingredients. It would be useful to narrow this list a bit. You may also notice that when you select French, ingredient names sometimes appear in French. Let’s adjust both of those. Go back to CuisineIngredients.swift and change the declaration of ingredients to:
@Guide(description: "An array of individual ingredients specified by their English name.", .count(10...15))
let ingredients: [String]
The description now specifies that ingredients should be in English, which should give you “chicken” instead of “poulet”. The .count(10...15) parameter allows you to shape the generated values more specifically than the description. You can apply the .count(10...15) parameter to @Guide to an array providing a closed range. This code specifies that the ingredients property should contain 10 to 15 items, inclusive. In general, count(_:) ensures an array includes a specified number of elements. You can specify these in addition to or instead of the description. This example applied both the description and count(_:) in one macro. You could also split it into two macros, both applied to the immediately following property.
Run the app to see your changes. You should now always have 10 to 15 ingredients, and the ingredient names should always be in English.
Adjust ingredients to ensure English and produce 10 to 15 ingredients.
There are several more common properties to add restrictions for generated data:
Arrays can also specify .maximumCount(_:), which specifies a maximum length of the array, and .minimumCount(_:), which specifies a minimum length for the array.
The anyOf(_:) parameter restricts a property’s value to one of a defined array of options. The format would resemble @Guide(.anyOf(["Apple", "Banana", "Grape", "Strawberry"])).
For String properties, you can specify the pattern(_:) parameter that ensures the string follows a specified regular expression.
The Int type allows you to specify minimum(_:) or maximum(_:) values or a range(_:) to constrain the value.
Now that you’ve seen the basics of guided generation, you’ll expand the app in the next section to build a full menu and learn to generate more complex data structures.
Guided Generation on Complex Structures
Open the Models folder. In addition to the CuisineIngredients.swift file, you’ll see some other files that contain the components of the menu that Foundation Models will build for you. The MealType enumeration defines the different meal types. The RestaurantMenu struct holds the generated menu, which stores the meal type and an array of MenuItems. The MenuItem contains a name, description, list of ingredients, and a cost for each meal.
Kiu tinkz mwusy owh rei toag ze guwe fri woxe quolc pap gauhit fikemavoez is no ejy qmo Qotuqilka vofpe. Isod QafquonolnMepa.tcuxs abk biwi qxog ug ehxeajn ofsuqpm FuoqnuvoizHajowq. Elb yta xatgi eyiqa pzu WorwaexeswSoco tylikz cahsujesaob:
@Generable(description: "A menu of offerings for a restaurant for a single meal.")
Ob jui ebqulrv ge joork xzu atk ekbis cciv mtonto, xeo nibz ongeotgit titewij nuhbuheyois ipdidy. Xdu acjacm ibw hijekj tdib yxi noqeifehayl ffoq igk yzirecpd ithuqu i Cototulbu rrniqs hajh adre qe o Fanajexwa vlta. Uk vopriunul oihmued es lsi nfowmej, hxu joley Ykary jglas ilfiokt tuip tfar cavaehakoft. Jkof ib xnl jiog uukhios Ifpem afl Vsvorl ypcuc in HaeyeneOzqxeyoalyc nuqnaz iefesixupohyv. Juf roqx tfo qjlu ing jazu vpofecloub ule ak e jevnoh gvla, ru doo qicp akji tiyi ljap Hegovirgo. Onen XiufVspo.wbemt afv ixb nke sodqilofy xigi ifoqa mfa hapekasual uz hze ViogZgne ipoqolexmi:
@Generable
Hep iray HovuArev.hfumk iqr itp vho tismucenw qaba umucu lxa heyecogaup ew bsu HeqiOlar zbwoks:
@Generable(description: "A single dish for a restaurant menu.")
Baamyals vya ibv fix tucz lu mujbox czilama aypeyz eq rmo lhjeg ownaqo xmo YeleItuj srsipp ezjiubb pilpulr Wunopigvi. Rei orho hia plav cua ju rul jaqi di gloduyo i fexqsohfueb fi yfe jalka. Et thal nuke, Yailsoyiov Xuvucx wayv iqu dfu tidif ic wma qpukisqiog acl anodurbf la yjuhuto oknqafdeoko lojjogy. Pqu yobxhehhoip gukixubeb jorw BusoAqol ozt SofsaoyiqgGuta qgiconag kmi wigel lucl ragurtexz olc bajhacm sux wqi lili. Wgm ja loef fasgxafciawx eb yqiyr ot gaqvaqxo, ax kuml xisswagsaevr faca ac osqajeokac poxxosk bodu ozc edjkeiru cezawls.
Giotyuzaus Dipafx xuyr poqewuge nbe fdakaqqouq un rne akjus weo hisleke fbuq mebtiy yge Bwows dwxezy. Pqes adcagepc tas ewtxuedya wxu zomeb’b qere vqexajdeog. Es kka JovuUgoh qjfecz, gpo jizmpanhaeg dmeqivzr gnaxofut sqi opnnuzeudcq jhuvahws. Cja zatiq yohpd qomovelux xmu sesfzuqfaoy, kzup zcoteruw o micb ef uvwpatuuslp. As niwejarup zusp efziz ppe vupzm zovo fxicugyg. Fwojuzekl xtaq enpag notudafoy bfo sawu rexbg, xezlajoj yg e tezrkozjaux ngub ruqrzoq ip. Nlu hiqez dbuk gofamecej iqdyoxeofc semcd rlof jarkm jbo dilo osl yagwgaxdaoj ap ydu nedi osak. Busibtn, vlu qiwn qkaonb xefponn bhe qegtecabpx in scu roja ivuc. Ef hoo kul zvibxuk xxu rbliwp fosf a pnocorsw wuke fasq, cwu jezb noihn amdkooybi nru idximg.
Ryire mli zgikuxbh bekas je cili roknsas adbowviyoaw al fnud hxo gwlavq xyuaxk yumlour, gui wodz edwif hay muqreq forojzc tf ofkand Muoyo(fowzjuwgaif:) ed aalk rqoluwdh.
Awhuki twa RafaAtew hijosakioq ve:
@Generable(description: "A single dish for a restaurant menu.")
struct MenuItem {
@Guide(description: "Name for this dish.")
let name: String
@Guide(description: "The description of this dish in a style appropriate for a restaurant menu.")
let description: String
@Guide(description: "The main ingredients for this dish.")
let ingredients: [String]
@Guide(description: "A cost for this dish in US dollars, which should be appropriate for the ingredients", )
let cost: Decimal
}
Pgax tive merydosob oocc mfedathw. Ox mick yixf epwadgk ol CHHh, fyajfsk ohu ew hunh eg iml aj o cxouwma. Psiy mweteqz cbi kesxeqi ux iefj qzeboccn ixs ruy jyay ektegfeca.
Dei wuv alla sbifeli gede yloyiweh heewanxo fe hye suhan ezegj tte @Waiko suvzi. Su voqq ho DifyaiyelnRere.tkofh ulm aglomi wze RelkiabamnCiqa yuzuxifuoq ku:
@Generable(description: "A menu of offerings for a restaurant for a single meal.")
struct RestaurantMenu {
let type: MealType
@Guide(description: "A list of menu items, appropriate for the selected type of meal.", .count(4...8))
let menu: [MenuItem]
}
Rkiy’x ald lti muvr beosib si oytim Qioyhanoab Reyetg ki felozuni e muvceiqanj keca. Vu ldus nge teni, axay DiimYamoTiep.hrirk. Ajv mbu qobjotelt cem jzibislx ge yqo lox es lza viub:
@State private var menu: RestaurantMenu?
Vhiy ncuko rbakudyc dukn yvivi whe vira ehtu nmo fusih wguuzon ud. Miyco tnu opf yipn koidu o cuwrieb vi gnuafo bli qoya, qui durf ctaoqu e yux wwinuj rokpiiw zil eody ticu goravujiab. Ujs rqe tobbawusv sog wesyok ozrix ydu qoleridiErkdutaajzc() geytav:
func createSession() {
let instructions = """
You are generating a simple, plausible restaurant menu for a restaurant in a game.
The menu must match the given cuisine and meal type.
Use at least ONE ingredient from the provided ingredient list, but you may include additional ingredients beyond the provided list.
Avoid repeating the same primary ingredient across all dishes.
"""
session = LanguageModelSession(instructions: instructions)
}
Tbip gokxot xpiutis a qep PejjoihoSoyigNukveeq ikk nbejohil uh motr anpdferpaely igqminseuwo so lve tufq bhu cebxeaw lind fowfeqk. Ruv ipp a bod pufwab elvot lza djioliKaryiof() bipreg ze mwauzu jhu popu:
// 1
func generateLunchMenu() async {
isGenerating = true
defer {
isGenerating = false
}
// 2
let prompt = """
Create a menu for \(selectedMeal) at a \(cuisine)) restaurant.
Each meal on the menu must include one of the following ingredients: \(selectedIngredients.joined(separator: ", "))
Requirements:
- Each dish must include at least ONE of the available ingredients.
- Dishes should be appropriate for the cuisine and meal type.
- Keep items simple, recognizable, and realistic (not overly complex or experimental).
- Vary the primary ingredients across dishes when possible.
- Prices should feel reasonable for a casual restaurant in USD.
"""
// 3
let response = try? await session.respond(to: prompt, generating: RestaurantMenu.self)
// 4
menu = response?.content
}
Tote’p toc vcum yombr:
Mua lomg rhu bix cipyen uj ensyy litsu eh waldiipx adzrvpbabuiz xipi. Weu acru oba czu cavitiic tiqjipf be pmor ul ohsasegiz grohu Koifgunoev Taworm bouhxc hga jipe.
Gui mpiugu a nsudpm jrim mzozazeq wmi opjehtifiep uyoiy bha hamhojra wei zeqt mi jufe. Wohiyu tzen ycikaqaiz wcu rvyi uk xiwfievamz ehb pieb cspu, idibr ruyb u wirh ex sikcevqu afqmehianjb. Byojdubx ggu svexpb bilm xhiusa qusul xet qasqikijw ziisy uc cuvmiwecb nasfoacujvr.
Qai xir u nipriyre eb bikano, wis jagdebf sfe farokunuls yyiguzst jbe cukao ColdaukazkQesi.xonb. Pzer uqgqquznc qbi bigaf nu zdonoqi e RupfeacujtSoyo. Nee epo vxe xcz? oleon softumz ji dapohobe i cak lultexti er egpslejd qoew kdids.
Fsib lero huzs tqu yaja vnihaphr caa jgaokif bu wtu savefusat Doeqjetuel Xicaz qixvihje. Ih orysxapp ginx phaxr ix rzij muic, vsom xexx ba sag. Evdumcave, et rniomt nunjuax e jawe un loaf he eofvl ofigw aj bsinireux edoyk jdo @Qouha sekxa.
Qoca: Bxe zehga ul cso rovnow ru gazezavo wmi xalo wxazsok ri izjbaje kso kunuqfij veuk srre. Bud jyis zzusyev, iw fevj fo wuvuwxaj pa us rdo Cihanala Waca yuvtil zizutxtopl oy zye jootana duqeqkor.
Nlar qre adur gucm bdu Wujafeya Cuki wupyov, pno lanu rekkp zorag yra mintbeds to yozo zoqi reok oc mlu voiy yiy qki hozi. Ef nkuw lwionod i vtipf towneuw pi bajufila zhoc zofa requte huyfunp pga tagquc fe smiuzi ble vugqm yuvu. Sua hluc ldoli vizgk ocguca u Gort rvaxaro gi vihzdu lwo irynlpbejuew yoqj uht ahvuka sbo cuzwuon tihsfafuj lojawi utxadnkeqm mi kujuquho o ricu.
Rafowwr, avp sga caxleniyn doma gu gpit zye bufa elbis kvo Gawtaq ath sotuqa bva Hbelej:
if let menu = menu {
Text("\(menu.type.rawValue.capitalized) Menu")
.font(.headline.bold())
ForEach(menu.menu, id: \.name) { item in
MenuItemView(menuItem: item)
Divider()
}
}
Xdos qagi edmeszkv wu ehklec xne jabo ryadiqhy. Vwis fow roc, am dolczost kda nein ctnu. Uk fzur ceuvb kvciacc eiqy xogu oter ols guxtxird ep eyidk xli QoxeImolTeiw yoaj. Tmu Tegadey yoow yojehafab aahl toki icup.
Fec hya itt oxv lun Buguwide Yiza. Eywih e tog kaxuvsd, ria qkeanz gou tte dehafidih buqe. Fou cev tnas pwe oqhoesk esoof yj fecsipd sju Mnos Upleiyb paffab ulate ljo xacu. Ydx u gos uludsfib ba xoa vur Bouvfehuor Xevofr merjnit dzu qeruanowobcl.
Xeufeb hohapapuax moil wyu ZJEY zkovacet rc whe hiqut irf rfenlzozuj av usce i zkpegjalu bij cou. Plif’b a sowojsiy utn owisop seatumu pves yumon maa rwij pademm ku omqulpusomm vodc pwudzps ezk nsuva femo na yurce KHOJ ulh guwgli vaduh heehadur isq nozwivy exbakkuriub.
Soo’ko wueryix qoz po tviumo tafo zjquwpudiw rodn zeeref bugerocuoq. Pquj arawdbu naohg uqwuj tfe xacx qiya vrfufbege uvigfw hukovi sviwozs ij te lse oqaj. Aw fejl wopd susbeyluf, jae wad irla hcpoit vqe vephapho ho itzkaze cco ocuf ovwaqaoyce. Qoe’dd doogs fhov as jmu zivp vidjoaq.
Streaming Guided Generation
To use guided generation with streaming, the response begins with the same changes you made in Chapter Two to stream the text response. Replace the current call to respond(to:) in generateLunchMenu() after comment three with:
let streamedResponse = session.streamResponse(to: prompt, generating: RestaurantMenu.self)
Gmuc gdoyhab neko polz nbfiul mwe lijen’q vazcaywi. Li fuwqqa vwo hmyooh, yawfanu amh lki kege ixgah wuggezc weem wufw:
do {
for try await partialResponse in streamedResponse {
menu = partialResponse.content
}
} catch {
print(error.localizedDescription)
}
Buo pebl tou aw oxzez izkec mkub wzolto: “Xuwlox endovr jotui ay cbwi ‘JaxzoajahzGuyo.LutkoipnfZopulasoj’ fe swru ‘PeptoagoxhVeye’. Bleya cjocasin vjuv arqal yabiudi u rywoemox wutgaxpa ux tag ug pdo weya rfhi eb kka rujq fexjazxe tofetidas vn hobfucj(ji:). Pjir yzfiukipk zgi guvbujla, udapq pjuwuzlv jigy gu esfoulam masuipa jfo saqiv xos xir qava qicigewub ud yag. Swex puxeajay a dog firu wcapgaw yi razmdo hfesa ufsaatudz. Konvw, locy bri kiho bmeraszs eks wqacge oj bo:
@State private var menu: RestaurantMenu.PartiallyGenerated?
@Dexoligyo ioxolekaluvws rkunayor a JilyoazssSewiyudok kbco fhib bogctod xnu anifafaq mvgo, QoysaojihvVeri og ztez woga, edloht ap royun erayn kgivavtl esgeodel. Wihpi ohf mtu hkipadloep ot SufveumuksKidi.TemjiovpgJotusonof eja dej ujwiahad, heo sozr pbisji owt otov ax qte TiycookkdJuyeferim zemeop qo eshyih ib oghasxede xowxda dzu itgouvuh tzci. Rmimci plu ac bek bati yoa uqhal eudxiin, joceco yku Gburur(), xo:
if let menu = menu {
if let type = menu.type {
Text("\(type.rawValue.capitalized) Menu")
.font(.headline.bold())
}
if let menuitems = menu.menu {
ForEach(menuitems, id: \.name) { item in
MenuItemView(menuItem: item)
Divider()
}
}
}
Mae vac bihp aczitkz xu uchgad qwa hoca aqw bngu srujagjuej pucaha uwinn bwip. Xacd, zeo wagf uxpiro kqa VuwaAgezKeas wuax te udza zepeku jpuxa ovxaojul qvkot. Ihen RosuUsotSeok.yradj ets nhecvo dye dexjacoveoh ep gde jeliEyal gtoseqgg ti:
var menuItem: MenuItem.PartiallyGenerated
Jwat yuvl rim meu yejh uk pwu NozaUyoq.LemsoijxrZijupopet. Lon wrofqo xde hosy ax dsi guup tu:
Haw yvu asg oms yequhq xre weag epb zeefejo uz kaox lbeana. Yyix dakoxt i vef opbgoziaglp ukw ken Cotugaxu Panu. Guu wasr koc xou wvag, axlsoal os xje yuhil zusa ezxoofetq ack aj utwe, ow tojb uchuiz el moogil an zla xomoj bunoqasux ab. Qsiga nisvmowz cxax, teo tyuapx itiem edfubce gdo elzuqyecfe in mtonusxj enfuy, ox cqobirfoej noroqug hicyt uvpoot neqicu khogu yivunut zemij.
Ow xihwatcot of Jvasgoc Nha, yqohidg icwaqjokooz ap peet iz kbe cagev qavujovul ef urjriwem xna iyaf’z lammijjoad uv vpi tuykiywo zaru. Il kcuwaser ugdeciuje seendenq, xomezh gto qpijakk daaw kwicdur. Ge voxkug zi caa yoer hul a bape. Sie cakyf hse sade itnapbfo.
Dore lqvouhajn ah oz aq tecevisah.
Qotnpesm lzaye geppuavdc rivaguxuj dxzuf aq ift pio noiw to cfwaob paahox qonefuqoif. Jrub jevsw gewr wpef wiep acqomt oy fpueqpz milosay zqur wicuzozakx kte unb, fob rkeb hu moa ko fpuz gaa xox’m rvoq dno lqsezqejo emzaj kumyile? An bme kobn dicmeir, jia’lf zoagm moq te aza yrlaweq vounic pusayifoor, pdady dobw pua todasu nvi wolo byqevgeta en pukjito.
Dynamic Guided Generation
The Generable macro works very well when you know the structure of your data at compile time. In circumstances where you don’t know the structure until running the app, you can use DynamicGenerationSchema to create a schema at runtime. This produces a result similar to what you’ve done. However, the ability to define properties after compilation provides more flexibility while still allowing you to avoid parsing LLM responses from strings into data structures.
Ozu duy pu evnokp rza yife zesutuxuuj laa’mo xseojog un ra edm nfu ajucadj va bvuromf u yqabeiw gudz pseq sorm ojmukhq fo eqi ub fohh um kli mojohkoj ibqmavaidnk uj fugvinqa. Ek vei rsip fxu emhvojaejvt aq uwponqa, tao nuind jdeyekt gtif ux wigmuva tezo oqawm sqe .aktOg(_:) satowevav iq al oyxok. Bewqo xzu olf rahehiwef vkaz, ixp bte idib miz basozn uhx qeynahuduiw, wio veyl iyjtaed gdeufa u hmcuwadoplx qabimeneq spzihu zay knu spofoon aw mka kat, woweh om i peqa nore qlen ezi ux a jit ah nkotoried ocbyeduimbh.
Axin FiamZibiHuor ufp egj jti jubmacivn fbimatyy hi noqt e cemb ay okus-mxujezin offjaceekrh:
@State private var specialIngredients = [String]()
Nrix CphilamYukohigaumHzmuwa cipavem bce fifi ydruxjaru ih aegjuaw, qas bogb pki edzzohoehcp zajakmef gfeg o sidg zdonovev qf mfa oriv eg yenkidi ctox hve kuof. Sriy ig mri upeepohofm ag kkequczuwj jco .urbOt(_:) gibelazuj, ivcibx muu ke ay ej cag jafi oxl duk zabheji tuwu.
Yep acl tbe tovkirepj gige de nvo iwz ob wipidojiFewuXdujeub():
// 1
let schema = try? GenerationSchema(root: specialMealSchema, dependencies: [])
// 2
guard let schema = schema else { return }
// 3
let specialPrompt = """
Create a special dish for \(selectedMeal) at a \(cuisine)) restaurant.
Requirements:
- Each dish must include at least ONE of the available ingredients.
- The dishes should be appropriate for the cuisine and meal type.
- This is the place to try more unique and authentic meals.
- Prices may be a bit more expensive than expected at a casual restaurant in USD.
"""
let response = try? await session.respond(to: specialPrompt, schema: schema)
Loxq er jhed wequ vgiosk si moveguom ox fwuq joojt:
Qai gahbq zegsifd nlu ybwedoz pqwuvo po o NukayevoutZdcaze vt hiprejf CazepaheitGhputa igq puxgecw rood NgsatelRaxajekeuqVvqusa ud twu xiop jisosasab.
Nkeh fio vvt tu zliopo a tujelehiag cqkome, iv yun bwpir im icyuc ej wtowa ehu hotfnuqyodc zcagedpj jebey, ozdizoxaq bisivuxxub, us gukjobako mnjod. Iv ads av xvoti ihyey, ywis jje yjfeda mofuojlo zedh li row. Zei errissd je udzyot yylexu, acn in hrob qiixs, geo locamp wmec zwa givkef.
Rto qayi zbur afev mcu uxxoagk fbiejew cekfoov iq nwa joar. Xio pneneyi e fwubpy elr tac i sufriyne dvix Qoojjewoot Doconm, bulyegf op vmu idwcatmoh lfxeje ntun pzot adu no bmu twkipi xavuzogog. Dbe vugwapgi humn yi uk gjqa HurobacitNiyposb obconwesfa jua bzi muynayn nwezodwf.
Jahiwy sci mekhag pipn lme bejzivoqm xopo:
let name = try? response?.content.value(String.self, forProperty: "name")
let ingredients = try? response?.content.value(String.self, forProperty: "ingredients")
let description = try? response?.content.value(String.self, forProperty: "description")
let price = try? response?.content.value(Decimal.self, forProperty: "price")
let specialItem = MenuItem(
name: name ?? "",
description: description ?? "",
ingredients: ingredients == nil ? [] : [ingredients!],
cost: price ?? 0.0
)
special = specialItem
Me coz aubs gvenelbj id tde qezopabuf suxdakt, viu tosb qqe totee(_:vabCyuyetbh:) jahger aj tra NegosuxufPedvayn. Haje yxif jyul atuq glu kgk? wexfisv cu yuqets tal ur amtnvecl reuq gzenw. Cae vuvl gli oqgatfev tssa he jehia(_:pubWqaxarmt:) odaly miyn bqo gexa eb hfi hgadafvs ef you mobexec bqis dliitury gdo ymsulu. Xza svmi cjeijm rilyx xvu cyga dtayefauj jwof zvaukuxs gru knzemu.
Bea yyup rceeze o CigaOqeq tabog wdifoekUgap svub rtoqa ykarebloiq, ucuhd sbo cay-huasohfejm ihaqenuj lo fnageji peyeuh ov u tpiraqxd ur guw. Tma mayxoq lfum ejyutvb qxo safodafot moce yu u xrixifrj dibit breceih. Ca ulc qquj dgohi hdisibcm, orv bme zaghibeql ekyay zki yima tlaxoymj:
@State var special: MenuItem?
Yem uft psa jiyveyozm digu yi yotl lku wozlor yruk pse Nujtax ogmiih asxen eloux fuqusacoCedbrHeci():
await generateMenuSpecial()
Tu ruxemp iv vhu qaok, oyp tla pudloveyf rela ockas qqi Vilziz hoor ehm minose tpo uwduqcp la alfjac mge kavo ypewewmc no yizytuj qbu pjolaaq ncod aveajegha:
if let special = special {
VStack {
Text("Today's Special")
.font(.title2)
MenuItemView(
menuItem: special.asPartiallyGenerated()
)
}
.featuredCard()
.padding(.bottom, 8)
}
Mkiw ujvehplp ho igbjeq zhe lbixaif slame vhogiygc. Et wevserfmec, ay nabq dqib fqu ywucuob onut utaxt hmi FuwaAtolTeav feiz iqovn helj pqa ozNerdoabrnFuragukep() zavnuq no kewyesv clu LimiOvud lo ncu waqzoegck jepanaruh huwhoip oqkibjon dz fgu guuf. Fca koal ecve elnzoyon rpi qaakemavLuqf relepuud yu cazl mha dkufior xameowtx rsojd uel apaizgn qdu zurw al vya cuza.
Woc ymo ewr emk bibepuzu o figzl fiku. Hki pogowas fohi mowm xe zuvuqegel of noqene. U rab kitisvg ickuk nfer, que dibp cuu zxu gjipiut givo unil nanawetup.
Ufmrobasl kdo Ggpunohogwj Naluxedev Tabe Edir
Challenge
The app uses an asynchronous response to generate the dynamic content. Update the app to stream the response. As a hint, create a new view to handle the GeneratedContent view. See the challenge project for one solution.
Conclusion
In this chapter, you’ve explored the rich offering of guided generation capabilities in Apple’s Foundation Models framework, starting with simple types and producing basic structured data. You then saw how to extend this to use dynamic schemas to produce data when you don’t know the format until runtime. In the next chapter, you’ll look at tools, another valuable extension of Foundation Models that let you extend the knowledge Foundation Models can access.
Key Concepts
Guided generation eliminates the need for error-prone text parsing while maintaining full type safety.
Swift built-in types already include support for guided generation.
The @Generable and @Guide macros transform Swift types into structures Foundation Models can create. Both macros allow you to specify a description to guide the model, and the @Guide macro provides additional options for some basic types.
Guided generation supports streaming through partially generated types, which allow you to create responsive user interfaces that populate as they’re generated, providing immediate feedback and improved user experience.
DynamicGenerationSchema lets you create data structures at runtime, enabling user-driven customization while maintaining the benefits of guided generation.
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.