Duarte O.Carmohttps://duarteocarmo.com/2024-02-26T20:30:00+01:00NewsHavn: Danish news, in English2024-02-26T20:30:00+01:002024-02-26T20:30:00+01:00Duarte O.Carmotag:duarteocarmo.com,2024-02-26:/blog/newshavn-danish-news-in-english.html<p><em>Conversas de café</em>. Literally translated, means "coffee shop conversations". </p>
<p>An upcoming election, the weather next week, a corruption scandal, a new policy. Just some examples of <em>Conversas de café</em>. </p>
<p>As an expat living in Denmark for the past 7 years (without speaking the language), that's perhaps one of the things …</p><p><em>Conversas de café</em>. Literally translated, means "coffee shop conversations". </p>
<p>An upcoming election, the weather next week, a corruption scandal, a new policy. Just some examples of <em>Conversas de café</em>. </p>
<p>As an expat living in Denmark for the past 7 years (without speaking the language), that's perhaps one of the things I miss most. Maybe it's because of where I'm from, but for me, water cooler conversations <em>are</em> Culture. </p>
<p><em>Learn the language</em>, <em>use Google Translate</em>, <em>read <a href="https://www.thelocal.dk/">some</a> expat focused website</em>. No thanks. I want to read the same stuff people around me read. I want to understand what worries <em>them</em>, not other expats.</p>
<p>Enter <a href="https://newshavn.duarteocarmo.com/">NewsHavn</a>.</p>
<p><center>
<a href="https://newshavn.duarteocarmo.com" target="_blank">
<img src="https://duarteocarmo.com/images/63/website.png" alt="Newshavn.duarteocarmo.com"
style="max-width:100%;border-radius: 2px"></p>
<figcaption></figcaption>
<p></a>
</center></p>
<p>Newshavn parses the RSS feeds of a couple of big Danish newspapers and uses <a href="https://github.com/duarteocarmo/NewsHavn/blob/8758d1f8214e2c54c24c06d0c0ba42b92e78c474/parser/parse.go#L173">Mistral 7B</a> to translate them. The design is inspired by <a href="https://text.npr.org/">NPR</a>. The code is all <a href="https://github.com/duarteocarmo/NewsHavn">opensource</a>. </p>
<p>For this one, I decided to use Go (again). I must say, Go is growing on me. Rust is fun and efficient, but I feel like Go strikes the right balance between strictness and flexibility. Another thing I love about Go is its concurrency model. <a href="https://gobyexample.com/goroutines">Goroutines</a> are just beautiful, and make me want to write more concurrent code. It feels like it's a no-bullshit language, and I'm a fan of no-bullshit. </p>mistral-doc: Fine-tuning an LLM on my ChatGPT conversations2024-02-09T13:00:00+01:002024-02-09T13:00:00+01:00Duarte O.Carmotag:duarteocarmo.com,2024-02-09:/blog/mistral-doc-fine-tuning-an-llm-on-my-chatgpt-conversations.html<p><i><a href="https://github.com/duarteocarmo/mistral-doc" target="_blank">Step-by-step instructions to do it yourself</a></i></p>
<p>If you ever read this blog, you probably already know by now. For the past couple of months, I've been trying to create my <em>very own</em> Large Language Model. </p>
<p>OpenAI's models have had a significant impact on my productivity. But something still bothers me …</p><p><i><a href="https://github.com/duarteocarmo/mistral-doc" target="_blank">Step-by-step instructions to do it yourself</a></i></p>
<p>If you ever read this blog, you probably already know by now. For the past couple of months, I've been trying to create my <em>very own</em> Large Language Model. </p>
<p>OpenAI's models have had a significant impact on my productivity. But something still bothers me. My data, my preferences, my history, my concerns, all going into the hands of a single company. </p>
<p>But <em>this</em> time, <em>this</em> time I think I got really close! The result is <code>mistral-doc</code>, a Mistral fine-tune on all my ChatGPT conversations. </p>
<p><center>
<img src="https://duarteocarmo.com/images/62/ollama.png" alt="Ollama SwiftUI with mistral-doc running"
style="max-width:100%;border-radius: 2px"></p>
<figcaption></figcaption>
<p></center></p>
<p>The goal is to emulate my current ChatGPT plus experience. My favorite thing about GPT4, is how obedient it is to <a href="https://github.com/duarteocarmo/mistral-doc/blob/846bff73cdf065620d529b2024e7cfba774dc0a5/Modelfile#L24">my system prompt</a>. <em>Especially</em> when I just want a short and concise answer. <a href="https://chat.openai.com/share/84a98280-ac66-41b4-9158-cbccc149cbdd">When I ask who was the first king of Portugal</a>, I want the answer to be short (and sure, correct is also good). </p>
<p>Over the past year, I've accumulated a little over 1000(!) conversations with ChatGPT. Thankfully, OpenAI actually makes exporting all my data pretty straightforward. So, I built a small <a href="https://github.com/duarteocarmo/mistral-doc/blob/main/process_gpt_export.py">script</a> that could process the export, and store all of my conversations as a Hugging Face dataset. It's private, of course, but you can use the same script to build yours. </p>
<p>There are thousands of models I could potentially fine-tune on my conversations. And the model choice will <em>for sure</em>, have an impact on the quality of the results. But I decided to go with something small, so that I could train everything in about ~2 hours with <a href="https://github.com/OpenAccess-AI-Collective/axolotl">Axolotl</a>. I decided to go with <code>Mistral-7B-Instruct-v0.2</code>. Yes, a base model would likely learn a bit more. But I don't want to teach a model to chat, I want to teach a model to learn from <em>my</em> chats. </p>
<p><center>
<img src="https://duarteocarmo.com/images/62/merged.png" alt="Mistral-doc instruct merged on hugging face"
style="max-width:100%;border-radius: 2px"></p>
<figcaption></figcaption>
<p></center></p>
<p>With Axolotl and a 40GB/RAM GPU machine in runpod, the fine-tuning process took around 2.5 hours. Here's the <a href="https://github.com/duarteocarmo/mistral-doc/blob/main/configs/mistral-doc-instruct.yml">config</a> I used by the way. Once the training was done, I had to <em>merge the model back to base</em> (we trained a <a href="https://magazine.sebastianraschka.com/p/practical-tips-for-finetuning-llms">Lora adapter</a>, but want the whole thing). Thankfully, Axolotl also <a href="https://github.com/OpenAccess-AI-Collective/axolotl?tab=readme-ov-file#merge-lora-to-base">handles this</a>. In the end of the process, I successfully had my entire ~15 GB model in a repository I called <code>mistral-doc-instruct-v4-merged</code>. Yes, there were 3 other versions where I screwed things up. </p>
<p>With the entire fine-tuned model ready, it was now time to run it on my machine. Before I did that, I had to ensure the model was going to be of a reasonable size and speed. I used <a href="https://github.com/ggerganov/llama.cpp">llama.cpp</a> to first convert the model to the <code>GGUF</code> format, and then to <a href="https://sebastianraschka.com/blog/2023/llm-mixed-precision-copy.html#quantization">quantize</a> it to 4-bits. This process resulted in a <em>single</em> file, called <code>mistral-doc.gguf</code>, which is ~4.5 GB in size. </p>
<p>Now we can take for a spin! Using <a href="https://ollama.ai/">Ollama</a>, I can create a <a href="https://github.com/duarteocarmo/mistral-doc/blob/main/Modelfile"><code>Modelfile</code></a> with all the details and configuration I need. With that file, I can now create my own model in the Ollama format with:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># create the model with ollama</span>
$<span class="w"> </span>ollama<span class="w"> </span>create<span class="w"> </span>mistral-doc<span class="w"> </span>-f<span class="w"> </span>./Modelfile
<span class="c1"># chat with your fine tune</span>
$<span class="w"> </span>ollama<span class="w"> </span>run<span class="w"> </span>mistral-doc
>>><span class="w"> </span>vv<span class="w"> </span>jasmin<span class="w"> </span>or<span class="w"> </span>basmati<span class="w"> </span>rice<span class="w"> </span>with<span class="w"> </span>falafel?
</code></pre></div>
<p>Running the model in the terminal is all fine and dandy, but I want something that can actually replace the instinct of going into a browser and typing <code>chat.openai.com</code>. I downloaded a small app called <a href="https://github.com/kghandour/Ollama-SwiftUI"><code>Ollama-SwiftUI</code></a> that lets me run my model in a nice little Mac app. Currently, I'm jumping around between using that, and <a href="https://lmstudio.ai/">LM Studio</a> to interact with <code>mistral-doc</code>. </p>
<p><center>
<img src="https://duarteocarmo.com/images/62/lmstudio.png" alt="Mistral doc in action in LMStudio"
style="max-width:100%;border-radius: 2px"></p>
<figcaption></figcaption>
<p></center></p>
<p>How has the experience been so far? Well for starters, its much better than any off-the-shelf ~7 billion parameter model I've tried before. For simple and straightforward tasks, it's a great alternative to ChatGPT Plus. I should note that it's not better because it's smarter or does math better. This model is better because it has learned how <em>I</em> like questions to be answered. This of course does <em>not</em> mean you will like it, which is why I'm not going to publish it. We could make it even better! I could fine-tune something like <a href="https://huggingface.co/mistralai/Mixtral-8x7B-Instruct-v0.1">Mixtral</a>, which would surely make it even more powerful! But I would probably not be able to run it on my laptop, and would have to pay someone else to host it. I could also generate even more data, increase the number of epochs, teach it more things about me. </p>
<p>Not sure I will; but this process definitely looks promising.</p>What's in my NOW?2024-02-01T10:00:00+01:002024-02-01T10:00:00+01:00Duarte O.Carmotag:kk.org,2024-02-01:/cooltools/whats-in-my-now-duarte-o-carmo/Self-hosting my personal LLM (but not quite)2024-01-21T22:35:00+01:002024-01-21T22:35:00+01:00Duarte O.Carmotag:duarteocarmo.com,2024-01-21:/blog/self-hosting-llm-ambrosio.html<p>ChatGPT is now part of our daily lives. A quick question, an extra input, some quick feedback, I always reach for it. AGI or not AGI, I certainly can't deny the impact it has had on our lives. It's pretty incredible!</p>
<p>But that small voice just won't go away. <em>"Where …</em></p><p>ChatGPT is now part of our daily lives. A quick question, an extra input, some quick feedback, I always reach for it. AGI or not AGI, I certainly can't deny the impact it has had on our lives. It's pretty incredible!</p>
<p>But that small voice just won't go away. <em>"Where is all this data going? Should I really be telling this bot this much? What if someone else sees this?"</em>
In a way, it feels like everything I tell this bot is going into a void I have no control of. I can't be the only one feeling it.</p>
<p>And I don't like it. It's a bit like putting all my eggs in a single basket. As engineers, we know how bad having a single point of failure is. Resilience! That's what we were taught. </p>
<p>Given that I already started building <a href="https://github.com/duarteocarmo/ambrosio">Ambrosio</a>, so why not use it to self-host my own LLM?</p>
<p><center>
<a href="https://duarteocarmo.com/images/60/ambrosio.png" target="_blank">
<img src="https://duarteocarmo.com/images/60/ambrosio.png" alt="Ambrosio chat and generate photo" style="max-width:95%;border-radius: 2px"></p>
<figcaption></figcaption>
<p></a>
</center></p>
<h2 id="self-hosting-with-the-help-of-llamacpp">Self-hosting with the help of Llama.cpp</h2>
<p>I'm not really interested in spending 500 USD/month to run a model that requires 40 GB of VRAM on a large GPU. So I had to lower my standards a little bit. The premise was now: What models can I run on a 15 USD/month server? </p>
<p>I started looking at the <a href="https://huggingface.co/spaces/lmsys/chatbot-arena-leaderboard">only LLM leaderboard I trust</a>. There aren't many options with 7 billion parameters. The best one seems to be <a href="https://huggingface.co/berkeley-nest/Starling-LM-7B-alpha">Starling-LM-7B-alpha</a>, out of Berkeley. <a href="https://huggingface.co/TheBloke/Starling-LM-7B-alpha-GGUF#provided-files">Quantized</a>, it should just about run on a cheap Hetzner box. Getting it up and running on a small box with <a href="https://github.com/ggerganov/llama.cpp/blob/master/examples/server/README.md">llama.cpp</a> is as easy as:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># download model</span>
$<span class="w"> </span>wget<span class="w"> </span>https://huggingface.co/TheBloke/Starling-LM-7B-alpha-GGUF/resolve/main/starling-lm-7b-alpha.Q5_K_M.gguf?download<span class="o">=</span><span class="nb">true</span>
<span class="c1"># setup llama cpp API with ./server</span>
$<span class="w"> </span>git<span class="w"> </span>clone<span class="w"> </span>https://github.com/ggerganov/llama.cpp
$<span class="w"> </span><span class="nb">cd</span><span class="w"> </span>llama.cpp
$<span class="w"> </span>make<span class="w"> </span>
$<span class="w"> </span>./server<span class="w"> </span>-m<span class="w"> </span>starling-lm-7b-alpha.Q5_K_M.gguf<span class="w"> </span>-c<span class="w"> </span><span class="m">8192</span><span class="w"> </span>--temp<span class="w"> </span><span class="m">0</span>.0<span class="w"> </span>--repeat_penalty<span class="w"> </span><span class="m">1</span>.1<span class="w"> </span>-n<span class="w"> </span>-1<span class="w"> </span>-p<span class="w"> </span><span class="s2">"GPT4 User: {prompt}<|end_of_turn|>GPT4 Assistant:"</span>
</code></pre></div>
<p>And just like that, you're running your own OpenAI compatible (<em>ugh</em>, I hate that term) API serving that very 7B model. </p>
<p>Now, don't get me wrong, I think this model is great! But I'm looking for something that will replace my daily use of ChatGPT. After integrating with <a href="https://github.com/duarteocarmo/ambrosio">Ambrosio</a> the limitations were obvious. The first issue: It's slow, painfully slow (which was expected on my small machine). And even though it's pretty incredible for a small model, it's not going to replace even the most basic use cases. </p>
<p>And if it sounds unfair in any way, it's because it is! How could I expect the same level of quality from something that can run on a cheap VM, to something like ChatGPT? And you're right. We can't. So what else can we do?</p>
<h2 id="mixtral-8x7b-and-the-rice-test">Mixtral 8x7B and the rice test</h2>
<p>Let's say I was going to rent a bigger machine for a better model. What would I run on it? Certainly not a 7B model! Looking at the rankings again, the best open source thing currently is <a href="https://huggingface.co/TheBloke/Mixtral-8x7B-Instruct-v0.1-GGUF">Mixtral 8x7b</a>, a mixture-of-experts model from <a href="https://mistral.ai/">Mistral</a>. Just glancing at the <a href="https://huggingface.co/TheBloke/Mixtral-8x7B-Instruct-v0.1-GGUF#provided-files">requirements</a>, and it was pretty clear this needed to be run on someone else's box. I decided to give <a href="https://www.together.ai">together.ai</a> a go. Their pricing is pretty much unbeatable and their inference speed is <em>blazingly</em> fast. And of course they have an <a href="https://docs.together.ai/docs/openai-api-compatibility">Open AI compatible API</a>. </p>
<p><center>
<a href="https://duarteocarmo.com/images/60/ambrosio_vs_chatgpt.png" target="_blank">
<img src="https://duarteocarmo.com/images/60/ambrosio_vs_chatgpt.png" alt="Ambrosio vs. ChatGPT vs. GPT-4" style="max-width:100%;border-radius: 2px">
</a></p>
<figcaption> </figcaption>
<p></center></p>
<p>Cool, it's fast and cheap. Is it any good? </p>
<p>Everyone has their own way of testing the quality of a model. Mine is what I call the <em>"rice test"</em>. <a href="https://github.com/duarteocarmo/ambrosio/blob/master/prompts/system.txt">My system prompt</a>, stolen from Jeremy Howard contains the following clause:</p>
<div class="codehilite"><pre><span></span><code>if the request begins with the string "vv" [...] make your response as concise as possible
</code></pre></div>
<p>The question above is a simple and straightforward scenario. I'm at the supermarket, I need to buy some rice to cook with my falafel. I open my phone and: "vv jasmin or basmati rice with falafel?". As you can see above, while GPT-4 gives me <em>exactly</em> what I need, we can't say the same for Mixtral or GPT-3.5. I just want a quick and dirty answer, I don't want something complicated, I certainly do not want any Python code. So yeah, it doesn't quite pass the jasmin rice test. But we're getting closer. And I will keep testing it in the future. </p>
<p>And sure, Mixtral may <a href="https://huggingface.co/mistralai/Mixtral-8x7B-Instruct-v0.1">not have been</a> trained with a system prompt, but it should, <a href="https://web.archive.org/web/20231030013339/https://docs.mistral.ai/usage/guardrailing/#appendix">in principle</a>, support it. </p>
<h2 id="thoughts-and-taking-ambrosio-further">Thoughts and taking Ambrosio further</h2>
<p>Since I ended up using together's API, I decided to also add image generation to Ambrosio (something like I have with DALL·E 2). Together supports most Stable Diffusion models. My feelings about them are largely the same as my feelings about Mixtral and GPT-4. The open source models are good! But they are also a bit rough, and don't come quite close to what Open AI is giving us. At least yet.</p>
<p>So, will Ambrosio <em>completely</em> replace my use of GPT-4? Will I cancel my ChatGPT plus subscription? Not really. At least, <em>not yet</em>. </p>
<p>Every time I use these open source models, I feel like I'm missing out on a better answer. In a way, I've become spoiled by GPT-4. It just grasps what I want in a better way, and most importantly, it passes the rice test with flying colors!</p>
<p>But the truth also is, that for most tasks, Mixtral is good enough. And it's a big leap forward from what the open source community previously had. I can only imagine what comes next. </p>
<p>Exciting times. </p>Rebuilding /photos2024-01-02T22:35:00+01:002024-01-02T22:35:00+01:00Duarte O.Carmotag:duarteocarmo.com,2024-01-02:/blog/rebuilding-photos.html<p>A couple of years ago, I decided to remove all my photos from Instagram. I wanted something for myself. Something that suited what I needed. The result was <a href="/photos.html">/photos</a>. I wrote about it when I built it <a href="https://duarteocarmo.com/blog/self-hosting-instagram-python.html">too</a>. Here's a snippet from that post:</p>
<p><em>[...] Uploading is by no means as …</em></p><p>A couple of years ago, I decided to remove all my photos from Instagram. I wanted something for myself. Something that suited what I needed. The result was <a href="/photos.html">/photos</a>. I wrote about it when I built it <a href="https://duarteocarmo.com/blog/self-hosting-instagram-python.html">too</a>. Here's a snippet from that post:</p>
<p><em>[...] Uploading is by no means as simple as opening an app and snapping a picture. But I've created a small Python script that processes a photo, generates a thumbnail, asks some questions about it, and uploads it to S3 and my blog. And that's good enough [...]</em></p>
<p>It wasn't good enough. I guess some <a href="https://course.ccs.neu.edu/cs5500f14/Notes/Prototyping1/planToThrowOneAway.html">principles</a> are just timeless. It needed to be thrown away.</p>
<h2 id="one-to-throw-away">One to throw away</h2>
<p>Quickly after making it, it was pretty obvious it was a solution to throw into the trash. In 2 years, I published a little over 10 photos. It's not that I want to publish thousands of photos, but I've always enjoyed taking and sharing them. But that whole run a script thing was just not working for me.</p>
<p>In a way, it's a lot like writing. Add a little bit of friction to the process, and nobody will use it at all. The script I originally built quickly got lost and stopped working. Whenever I wanted to share a photo, my laptop wasn't around. When the laptop was around, I wasn't thinking of sharing photos. So no, not good enough. </p>
<p>Whatever I was going to build to replace the old system, needed to do one thing really well: get out of the way. </p>
<p>I thought about it a bunch. An API? Should I interact with that API via shortcuts? Should I just build an entire front-end? What if I give <a href="https://leptos.dev/">leptos</a> a shot? Should I rclone a google photos album? It can't be that hard. I needed something that got out of the way.</p>
<p><center>
<img src="https://duarteocarmo.com/images/59/ambrosio.png" alt="Ambrosio create photo" style="max-width:95%;border-radius: 2px"></p>
<figcaption></figcaption>
<p></center></p>
<h2 id="ambrosio">Ambrosio</h2>
<p>I needed something that was already part of my routine. The result is <a href="https://github.com/duarteocarmo/ambrosio">Ambrosio</a>. Some will recognize the <a href="https://youtu.be/oSKi309VnG8?si=92t2m6KNgsX092FX&t=9">name</a>. Ambrosio is a Telegram bot that was designed to be my personal assistant. </p>
<p>I designed Ambrosio to be able to have different <a href="https://github.com/duarteocarmo/ambrosio/tree/master/modes"><em>modes</em></a>. The first one is the <code>photo</code> mode. It's responsible for performing <a href="https://www.crowdstrike.com/cybersecurity-101/observability/crud/">CRUD</a> operations on an <a href="https://www.cloudflare.com/developer-platform/r2/">R2 bucket</a>. To maintain the speed of /photos, it also generates a <code>webp</code> thumbnail with reduced quality. If needed, it triggers a rebuild of my website using a <a href="https://developers.cloudflare.com/pages/configuration/deploy-hooks/">deploy hook</a>.</p>
<p>Instead of having to create a markdown page for every new photo, I've built another small pelican <a href="https://github.com/duarteocarmo/duarteocarmo.com/blob/master/plugins/photos/photos.py">plugin</a>. Before building the website, it downloads all the metadata for each photo, and generates the pages that it needs to. So that website builds remain fast on my local machine, I also added disk caching. Remember: get out of the way!</p>
<h2 id="on-go">On Go</h2>
<p>I decided to build Ambrosio using something I've never used before: Go. I've tinkered with a couple of code bases but never really used it to build something from scratch. The idea of something not as strict as Rust, but also not as flexible as Python really sparked my curiosity. </p>
<p>Go gives me mixed feelings, but Go gives me hope. It is strict, but not <em>too</em> strict. It gives me the confidence when writing code that Python has never given me. And gives me guarantees that if the compiler does not complain, things will mostly work fine. There are some things I still don't understand about Go. The first is error handling. Having a bunch if <code>if err == nil</code> throughout the code base is not particularly nice to look at. Also hesitant about the whole one letter variable names thing. Things tend to become cryptic. </p>
<p>It's fun how programming languages all start looking like the same the more you use them. For now, I'm curious to see how my opinion about Go evolves with time. </p>
<p>One thing is clear though: Whatever technology you use, whatever framework you go with, technology is beautiful when it <em>gets out of the way</em>. </p>You can now listen to this blog2023-12-08T05:00:00+01:002023-12-08T05:00:00+01:00Duarte O.Carmotag:duarteocarmo.com,2023-12-08:/blog/you-can-now-listen-to-this-blog.html<p>One of my favorite <a href="https://www.publico.pt/autor/joao-miguel-tavares">Portuguese columnists</a> has this weird thing about his column. Maybe it's more common than I thought. For every piece he publishes, he also publishes a podcast version along with it. </p>
<p>Now, either <a href="https://www.publico.pt/">Publico</a> has 27th century text-to-speech (TTS) technology, or he's <em>actually</em> reading them. I don't …</p><p>One of my favorite <a href="https://www.publico.pt/autor/joao-miguel-tavares">Portuguese columnists</a> has this weird thing about his column. Maybe it's more common than I thought. For every piece he publishes, he also publishes a podcast version along with it. </p>
<p>Now, either <a href="https://www.publico.pt/">Publico</a> has 27th century text-to-speech (TTS) technology, or he's <em>actually</em> reading them. I don't have a problem with that, but I'm <em>pretty</em> sure we could automate that part of the process with today's tech. </p>
<p>And yeah, I've heard all the rage about voice cloning services like <a href="https://elevenlabs.io/pricing">ElevenLabs</a>. But if you've been following this blog for a while, you probably guessed that we're not just gonna use an API. We're probably gonna build one from scratch. </p>
<h2 id="an-engine">An engine</h2>
<p>The premise did not appear simple to build, but was easy to understand. Something that transcribes every new article of this blog using <em>my own</em> voice. It needs to be cheap, seamless, and most importantly, not get in the way. Writing is <em>enough</em> work as is. </p>
<p>The result is <a href="https://github.com/duarteocarmo/podcaster/">podcaster</a>. It runs 100% on GitHub Actions, it scans every new blog post in my RSS feed and uses <a href="https://huggingface.co/coqui/XTTS-v2">XTTS-v2</a> to transcribe it. The only thing it needs from me is a 1-min audio file. I tried <a href="https://tts.readthedocs.io/en/latest/models/bark.html">Bark</a> and a couple of other models, but this was the only one that made Vittoria come into the room when I was testing things around. </p>
<p>It's not that I hate infrastructure, I just wanted the whole thing to run on CI. All these TTS models are slow when running on the CPU. But instead of embarking on another painful journey through the world of GPU computing, I found <a href="https://modal.com">Modal</a>. I'm happy to report that I've regained faith in the future of serverless GPUs:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># define the image</span>
<span class="n">MODAL_IMAGE</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">modal</span><span class="o">.</span><span class="n">Image</span><span class="o">.</span><span class="n">debian_slim</span><span class="p">()</span>
<span class="o">.</span><span class="n">pip_install_from_pyproject</span><span class="p">(</span><span class="s2">"pyproject.toml"</span><span class="p">)</span>
<span class="o">.</span><span class="n">apt_install</span><span class="p">(</span><span class="s2">"ffmpeg"</span><span class="p">)</span>
<span class="p">)</span>
<span class="n">stub</span> <span class="o">=</span> <span class="n">modal</span><span class="o">.</span><span class="n">Stub</span><span class="p">(</span><span class="s2">"modal-app"</span><span class="p">,</span> <span class="n">image</span><span class="o">=</span><span class="n">MODAL_IMAGE</span><span class="p">)</span>
<span class="c1"># create the function</span>
<span class="nd">@stub</span><span class="o">.</span><span class="n">function</span><span class="p">(</span><span class="n">gpu</span><span class="o">=</span><span class="s2">"any"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">transcribe</span><span class="p">(</span>
<span class="n">article</span><span class="p">:</span> <span class="n">ParsedArticle</span><span class="p">,</span>
<span class="n">voice_file</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">VOICE_FILE</span><span class="p">,</span>
<span class="n">model_name</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">MODEL_NAME</span><span class="p">,</span>
<span class="n">language</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">LANGUAGE</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-></span> <span class="nb">bytes</span><span class="p">:</span>
<span class="c1"># this part is executed in a GPU powered machine</span>
<span class="c1"># ...</span>
</code></pre></div>
<p>The engine stores all transcripts in S3, automatically generates a podcast feed from them (using <a href="https://feedgen.kiesow.be/">feedgen</a>), and uses web hooks to trigger a new build of this blog. Again, pretty much for free. If you're curious or interested in taking it for a spin, <a href="https://github.com/duarteocarmo/podcaster#readme">should be straightforward</a> to get started.</p>
<h2 id="integrating-with-pelican">Integrating with Pelican</h2>
<p>As I said before: I really <em>don't</em> like adding friction to my writing. It's already hard as is! The challenge then was to figure a way of automagically updating the blog with available transcripts after I publish, without me having to do anything at all. </p>
<p>Fortunately, <a href="https://justinmayer.com/about/">Justin</a> besides being great company at PyCon Italia every year, has also built a pretty <a href="https://docs.getpelican.com/en/latest/plugins.html">robust plugin system for Pelican</a>. All I had to do, was to add a <a href="https://github.com/duarteocarmo/duarteocarmo.com/blob/master/plugins/podcast/podcast.py"><code>podcaster</code> plugin</a> to this website. The plugin automatically matches articles to corresponding episodes, and adds that short html snippet you're seeing above. Should be <em>build once</em> and let run. Hopefully at least.</p>
<h2 id="final-thoughts">Final thoughts</h2>
<p>I had a lot of fun building this, and also learned a lot. First, it demystified the whole podcast hosting thing for me. Turns out, it's just a bunch of mp3 files in a bucket with <a href="https://podcasts.apple.com/dk/podcast/duarte-o-carmos-articles/id1719493997">a rss feed</a>. </p>
<p>Often I've settled for running ML models on CPU just because deploying with a GPU was much more of a pain, and didn't add any happiness to the process. At least for now, GPUs are here to stay, hopefully so are services like <a href="https://modal.com/">Modal</a>. Pythonic, easy to use, and easy to isolate from the rest of the code base.</p>
<p>Finally, I was very impressed with the state of TTS and voice cloning technology. Is it perfect? No. Does it have some artifacts? Yes. Does it sound like a robot sometimes? Sure. But remember, I <em>only gave it a minute</em> of my voice.</p>
<p>Open source never ceases to amaze me.</p>Should you go into management consulting? Maybe.2023-11-08T08:00:00+01:002023-11-08T08:00:00+01:00Duarte O.Carmotag:duarteocarmo.com,2023-11-08:/blog/management-consulting.html<p>A couple of days ago, someone shared <a href="https://www.youtube.com/watch?v=AiOUojVd6xQ">this</a> John Oliver video with me. In it, he shows all the ways McKinsey is a terrible organization. Not a minute in and I was already thinking about that management consulting blog post I <em>always</em> wanted to write.</p>
<p>When I talk with people …</p><p>A couple of days ago, someone shared <a href="https://www.youtube.com/watch?v=AiOUojVd6xQ">this</a> John Oliver video with me. In it, he shows all the ways McKinsey is a terrible organization. Not a minute in and I was already thinking about that management consulting blog post I <em>always</em> wanted to write.</p>
<p>When I talk with people that just finished University a lot of them wonder if it's the right place to go. <em>Of course</em>, by the tasty recruiting videos, it looks like the absolute perfect place for your <em>typical</em> graduate. The reality is a <em>bit</em> more nuanced.</p>
<p><em>Attention</em> to detail. That was the thing that struck me first. From manically aligning elements on a slide, to someone going meticulously through my email signature to ensure everything is as it should be. If you're the type that struggles with detail you'll probably suffer a bit. Truth is, attention to detail is generally something most working environments admire, and strive for (or maybe they should).</p>
<p>In a way, management consulting feels like an extension of a University. Everything is <em>pre</em> structured, everything is <em>pre</em> defined. Even before you get your hands dirty, you'll know exactly the path that you're expected to follow, and how fast you're expected to follow it. <em>Up or out</em>, that's a good summary of the approach. If you're not being promoted, then you should probably get out. Naturally, most people stay 2 years and leave. In any case - a structured and defined environment is where many are able to learn at their best. </p>
<p>What I miss the most is by far the <em>people</em>. I know - I sound just like a propaganda boy. But there's nothing I enjoy more than being the dumbest in the room. Most people in these places are driven, motivated, and hard-working. You'll meet the smartest people you will probably ever work with. Like in the military, you'll make long lasting bonds over traumatic experiences (e.g., long nights, tough clients). You'll build a network of great people - with whom you'll stay connected for the rest of your career. I certainly did.</p>
<p>But it's not all rainbows and unicorns.</p>
<p>Let's start with the thing most people fear. The hours. Yes, the hours are long. I generally don't dislike long hours. With an important premise: I <em>have</em> to be doing something I <em>really</em> enjoy. But in these firms, the hours are not long because they <em>need</em> to be. The hours are long because you want to show your client (and your firm) that you are <em>always</em> available. Sure, this means working longer hours - but less intense hours. For some, this will look like an absolute waste of time - why the hell are we here? It's not about doing the required work. It's about <em>being there</em>. Or worse, it's about <em>showing</em> that you were there. </p>
<p>Soon, you'll realize you don't really have <em>choices</em>. You <em>don't</em> get to decide what projects you work on. You <em>don't</em> get to decide what business area you specialize in. You <em>don't</em> get to decide when and where you work. You don't get to decide what dinners, events, and gatherings you go to (a common strategy to work a bit less). If you have no clue what you want to do - this is great. You just need to go along. If you know what you want to do - this becomes <em>problematic</em>.</p>
<p>Which brings me to my last point. Management consulting, from my experience, is a mix of a University and Military Service. You are <em>not</em> rewarded for thinking differently. You are <em>not</em> rewarded for exploring things others have not. Your innovative way of solving a problem is a risk, rather than an opportunity. For those who just want to do work, this is great - you don't really have to think about it. For the creatives, that want to spend time in things they like, and want to solve problems in crazy ways - this can be painful. </p>
<p>Is management consulting for you? I have no clue. </p>
<p>My experience was positive. Until it wasn't. It can be great step for those of us who have absolutely no idea what they want to do after university. It's an opportunity to see a lot of different things - with a smart bunch of people. For those who know exactly what they want - it might feel like a slow down. For most of us, it's a mix.</p>
<p>In any case. At least now you know what you're getting yourself into. </p>
<p>I sure wasn't. But I can't say I regret it.</p>
<hr />
<p><em>Disclaimer: This post is highly biased towards my experience. As it should - this is MY blog after all.</em></p>Changelog neural search2023-10-06T05:00:00+02:002023-10-06T05:00:00+02:00Duarte O.Carmotag:duarteocarmo.com,2023-10-06:/blog/changelog-neural-search-superduperdb.html<p>Search is one of the most important breakthroughs of the internet. Some are saying a list of blue links is not enough - and that AI <em>will</em> overthrow search. I don't know if we're about to witness a revolution. But as with most things - there's only one way to know - to …</p><p>Search is one of the most important breakthroughs of the internet. Some are saying a list of blue links is not enough - and that AI <em>will</em> overthrow search. I don't know if we're about to witness a revolution. But as with most things - there's only one way to know - to build and use it <em>myself</em>. </p>
<p>I like podcasts a lot. There's really nothing like hearing people talk about things I know <em>nothing</em> about. Some of my favorite podcasts are produced by the <a href="https://changelog.com/">Changelog</a> network. More than once, I've had to use their <a href="https://changelog.com/search?q=embedding">search engine</a> when researching something that was said during an episode.</p>
<p>One of the best things about the Changelog is that the <a href="https://github.com/thechangelog">whole thing is open source</a>. From the podcast engine itself, to the <a href="https://github.com/thechangelog/transcripts">transcripts of every episode</a>. Why not take all of these transcripts and build an AI-powered™ search engine around them?</p>
<p><center>
<a href="https://changelog.duarteocarmo.com">
<img src="https://duarteocarmo.com/images/56/search.png" alt="Neural search for the changelog" style="max-width:100%;margin-bottom:-1em;">
</a></p>
<figcaption><a target="_blank" href="https://changelog.duarteocarmo.com">changelog.duarteocarmo.com</a></figcaption>
<p></center></p>
<h2 id="how-its-built">How it's built</h2>
<p>Before I describe the stack, let's get the obvious out of the way: the whole thing is open source. Both the <a href="https://github.com/duarteocarmo/thechangelogbot-backend">back-end</a> and the <a href="https://github.com/duarteocarmo/thechangelogbot-frontend">front-end</a>. If you prefer to go and poke around the code yourself, be my guest.</p>
<p>I love the chunk-embed-search-retrieve dance as much as the next guy, but for this one, I wanted to keep things a bit simpler, so I'm letting <a href="https://www.superduperdb.com/">SuperDuperDB</a> do most of the heavy lifting for me. With it, all I really need to do is add the embedding model to my serverless MongoDB instance, and it handles the rest for me:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># add model to DB</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">SentenceTransformer</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
<span class="n">db</span><span class="o">.</span><span class="n">add</span><span class="p">(</span>
<span class="n">VectorIndex</span><span class="p">(</span>
<span class="n">identifier</span><span class="o">=</span><span class="n">index_id</span><span class="p">,</span>
<span class="n">indexing_listener</span><span class="o">=</span><span class="n">Listener</span><span class="p">(</span>
<span class="n">model</span><span class="o">=</span><span class="n">model</span><span class="p">,</span>
<span class="n">key</span><span class="o">=</span><span class="n">key</span><span class="p">,</span>
<span class="n">select</span><span class="o">=</span><span class="n">collection</span><span class="o">.</span><span class="n">find</span><span class="p">(),</span>
<span class="p">),</span>
<span class="p">)</span>
<span class="p">)</span>
<span class="c1"># search the DB</span>
<span class="n">cur</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span>
<span class="n">collection</span><span class="o">.</span><span class="n">find</span><span class="p">({</span><span class="s2">"$regex"</span><span class="p">:</span> <span class="p">{</span><span class="s2">"podcast"</span><span class="p">:</span> <span class="s2">"practicalai"</span><span class="p">}})</span><span class="o">.</span><span class="n">like</span><span class="p">(</span>
<span class="p">{</span><span class="s2">"text"</span><span class="p">:</span> <span class="s2">"What are embeddings"</span><span class="p">},</span> <span class="n">n</span><span class="o">=</span><span class="n">limit</span><span class="p">,</span> <span class="n">vector_index</span><span class="o">=</span><span class="n">index_id</span>
<span class="p">)</span>
<span class="p">)</span>
</code></pre></div>
<p>For the front-end, I finally took <a href="https://nextjs.org/">NextJS</a> for a spin. Love the productivity gains - especially when we're talking about developer experience. <a href="https://vercel.com/">Vercel</a> is absolutely killing the developer experience side of things. On the other side, I have no clue how most of the magic is working - and I'm not sure that's a good thing.</p>A poor man's guide to fine-tuning Llama 22023-09-26T13:00:00+02:002023-09-26T13:00:00+02:00Duarte O.Carmotag:duarteocarmo.com,2023-09-26:/blog/fine-tune-llama-2-telegram.html<p>Last Friday, <a href="https://orbit.dtu.dk/en/persons/konstantinos-kalogeropoulos">Kostas</a> and I found ourselves discussing AI over beers again. He was telling me how he thinks everyone else is <em>decades</em> away from OpenAI - and that they likely won't catch up soon. I disagreed. In <em>fact</em>, I think open source is quickly catching up, and getting <a href="https://huggingface.co/spaces/lmsys/chatbot-arena-leaderboard">closer</a> by …</p><p>Last Friday, <a href="https://orbit.dtu.dk/en/persons/konstantinos-kalogeropoulos">Kostas</a> and I found ourselves discussing AI over beers again. He was telling me how he thinks everyone else is <em>decades</em> away from OpenAI - and that they likely won't catch up soon. I disagreed. In <em>fact</em>, I think open source is quickly catching up, and getting <a href="https://huggingface.co/spaces/lmsys/chatbot-arena-leaderboard">closer</a> by the day. </p>
<p>Around four months ago, I <a href="/blog/fine-tune-flan-t5-telegram.html">wrote a small tutorial</a> on fine-tuning Flan T5 to generate conversations in my friends group chat. It worked <em>ok(ish)</em>, but the process was clunky and took way too long. </p>
<p>So, here we are, four months later, with the same question: How easy is it to train an LLM on my friend's group chat? Turns out, for a couple of dollars and one hour you can get pretty far.</p>
<p><center>
<br></p>
<video style="max-width:100%;border-radius: 2px" autoplay loop muted playsinline>
<source src="https://duarteocarmo.com/images/55/llama-tiger-optimized.mp4" type="video/mp4" >
</video>
<figcaption><em>Tiger-llama in action, simulating a Telegram conversation</em></figcaption>
<p></center></p>
<h2 id="data">Data</h2>
<p>The goal is clear: fine-tune <a href="https://huggingface.co/meta-llama/Llama-2-7b-hf">Llama 2</a>, to automatically generate conversations that would normally happen in the group chat that I've held with my close friends for years now. The first step is to export the data from Telegram (which is pretty <a href="https://telegram.org/blog/export-and-more">easy</a>).</p>
<p>For most LLMs, you need to massage the data into a specific format before training. This means providing things like the <code>instruction</code>, the <code>input</code>, the <code>system_prompt</code>, etc. But all I wanted was to generate conversations, so I started by creating a large <code>jsonl</code> file with chunks of conversations separated by a <code>###</code> token to indicate the speaker. </p>
<div class="codehilite"><pre><span></span><code><span class="c1"># dataset.jsonl</span>
<span class="p">{</span><span class="s2">"text"</span><span class="p">:</span> <span class="s2">"### Friend 1: This is a question### Friend 2: This is a reply### Friend 3: What the hell are you guys talking about?"</span><span class="p">}</span>
<span class="p">{</span><span class="s2">"text"</span><span class="p">:</span> <span class="s2">"### Friend 4: Who's coming tonight?### Friend 2: No one, it's literally Monday."</span><span class="p">}</span>
<span class="c1">#...</span>
</code></pre></div>
<p>After getting the data ready, I went ahead and pushed it to the hugging face hub: </p>
<div class="codehilite"><pre><span></span><code><span class="c1"># huggingface-cli login --token hf_XXXXXXXX (to log into Hugging Face)</span>
<span class="c1"># read and split</span>
<span class="n">tiger_llama</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">read_json</span><span class="p">(</span><span class="s1">'dataset.jsonl'</span><span class="p">,</span> <span class="n">lines</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">train_tiger</span><span class="p">,</span> <span class="n">test_tiger</span> <span class="o">=</span> <span class="n">train_test_split</span><span class="p">(</span>
<span class="n">tiger_llama</span><span class="p">,</span> <span class="n">test_size</span><span class="o">=</span><span class="mf">0.15</span><span class="p">,</span> <span class="n">random_state</span><span class="o">=</span><span class="mi">42</span><span class="p">,</span> <span class="n">shuffle</span><span class="o">=</span><span class="kc">True</span>
<span class="p">)</span>
<span class="c1"># push to hub</span>
<span class="n">train_tiger</span> <span class="o">=</span> <span class="n">Dataset</span><span class="o">.</span><span class="n">from_pandas</span><span class="p">(</span><span class="n">train_tiger</span><span class="p">)</span>
<span class="n">test_tiger</span> <span class="o">=</span> <span class="n">Dataset</span><span class="o">.</span><span class="n">from_pandas</span><span class="p">(</span><span class="n">test_tiger</span><span class="p">)</span>
<span class="n">ds</span> <span class="o">=</span> <span class="n">DatasetDict</span><span class="p">()</span>
<span class="n">ds</span><span class="p">[</span><span class="s2">"train"</span><span class="p">]</span> <span class="o">=</span> <span class="n">train_tiger</span>
<span class="n">ds</span><span class="p">[</span><span class="s2">"test"</span><span class="p">]</span> <span class="o">=</span> <span class="n">test_tiger</span>
<span class="n">dataset_name</span> <span class="o">=</span> <span class="s2">"duarteocarmo/tiger-llama"</span>
<span class="n">ds</span><span class="o">.</span><span class="n">push_to_hub</span><span class="p">(</span><span class="n">dataset_name</span><span class="p">,</span> <span class="n">branch</span><span class="o">=</span><span class="s2">"main"</span><span class="p">,</span> <span class="n">private</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</code></pre></div>
<p>With all the conversations pushed to the hub (<em>cough</em> - privacy - <em>cough</em>), it was now time to train this model.</p>
<h2 id="training-with-axolotl">Training with axolotl</h2>
<p>For the first couple of days, I got a bit frustrated. I tested a bunch of <a href="https://huggingface.co/blog/llama2#fine-tuning-with-peft">different</a> <a href="https://github.com/brevdev/notebooks/blob/main/llama2-finetune.ipynb">tutorials</a> on how to fine tune LLama-2. But none of them really got me anywhere. Some took way too long to train, others resulted in a model that didn't really generate anything interesting. I confess I <a href="https://platform.openai.com/docs/guides/fine-tuning">almost fell to the dark side</a>! But then I stumbled upon <a href="https://github.com/OpenAccess-AI-Collective/axolotl">axolotl</a>.</p>
<p><a href="https://github.com/OpenAccess-AI-Collective/axolotl">Axolotl</a> is designed to "<em>streamline the fine-tuning of LLMs</em>". It supports a bunch of different models and training configurations. The best part? To fine-tune a model, all you is pretty much a config file. Yes, you heard that right - <em>just</em> a <code>yaml</code> file. The only things I needed to tweak were the base model (in our case, Llama 2 - <code>meta-llama/Llama-2-7b-hf</code>), and the dataset sections:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># llama-tiger.yaml</span>
<span class="c1"># base model</span>
<span class="nt">base_model</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">meta-llama/Llama-2-7b-hf</span>
<span class="nt">base_model_config</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">meta-llama/Llama-2-7b-hf</span>
<span class="nt">model_type</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">LlamaForCausalLM</span>
<span class="nt">tokenizer_type</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">LlamaTokenizer</span>
<span class="nt">is_llama_derived_model</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
<span class="c1"># ... </span>
<span class="c1"># my dataset</span>
<span class="c1"># other formats: https://github.com/OpenAccess-AI-Collective/axolotl#dataset</span>
<span class="nt">datasets</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">duarteocarmo/tiger-llama</span>
<span class="w"> </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">completion</span><span class="w"> </span><span class="c1"># </span>
<span class="w"> </span><span class="nt">field</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">text</span>
<span class="nt">dataset_prepared_path</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">last_run_prepared</span>
<span class="nt">hub_model_id</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">duarteocarmo/tiger-llama</span>
<span class="nt">val_set_size</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">0.01</span>
<span class="nt">output_dir</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">./qlora-out</span>
<span class="c1"># wandb monitoring</span>
<span class="nt">wandb_project</span><span class="p">:</span><span class="w"> </span><span class="s">"llama-tiger"</span>
<span class="nt">wandb_log_model</span><span class="p">:</span><span class="w"> </span><span class="s">"checkpoint"</span>
<span class="c1">### ... </span>
</code></pre></div>
<details>
<summary>Expand for the full <code>tiger-llama.yaml</code> file</summary>
<div class="codehilite"><pre><span></span><code><span class="c1"># Image: winglian/axolotl:main-py3.10-cu118-2.0.1 </span>
<span class="nt">base_model</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">meta-llama/Llama-2-7b-hf</span>
<span class="nt">base_model_config</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">meta-llama/Llama-2-7b-hf</span>
<span class="nt">model_type</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">LlamaForCausalLM</span>
<span class="nt">tokenizer_type</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">LlamaTokenizer</span>
<span class="nt">is_llama_derived_model</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
<span class="nt">load_in_8bit</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">false</span>
<span class="nt">load_in_4bit</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
<span class="nt">strict</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">false</span>
<span class="nt">datasets</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">path</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">duarteocarmo/tiger-llama</span>
<span class="w"> </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">completion</span>
<span class="w"> </span><span class="nt">field</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">text</span>
<span class="nt">dataset_prepared_path</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">last_run_prepared</span>
<span class="nt">hub_model_id</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">duarteocarmo/tiger-llama</span>
<span class="nt">val_set_size</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">0.01</span>
<span class="nt">output_dir</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">./qlora-out</span>
<span class="nt">adapter</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">qlora</span>
<span class="nt">lora_model_dir</span><span class="p">:</span>
<span class="nt">sequence_len</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">4096</span>
<span class="nt">sample_packing</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
<span class="nt">pad_to_sequence_len</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
<span class="nt">lora_r</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">32</span>
<span class="nt">lora_alpha</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">16</span>
<span class="nt">lora_dropout</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">0.05</span>
<span class="nt">lora_target_modules</span><span class="p">:</span>
<span class="nt">lora_target_linear</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
<span class="nt">lora_fan_in_fan_out</span><span class="p">:</span>
<span class="nt">wandb_project</span><span class="p">:</span><span class="w"> </span><span class="s">"llama-tiger"</span>
<span class="nt">wandb_entity</span><span class="p">:</span>
<span class="nt">wandb_watch</span><span class="p">:</span>
<span class="nt">wandb_run_id</span><span class="p">:</span>
<span class="nt">wandb_log_model</span><span class="p">:</span><span class="w"> </span><span class="s">"checkpoint"</span>
<span class="nt">gradient_accumulation_steps</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">4</span>
<span class="nt">micro_batch_size</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">2</span>
<span class="nt">num_epochs</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">3</span>
<span class="nt">optimizer</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">paged_adamw_32bit</span>
<span class="nt">lr_scheduler</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">cosine</span>
<span class="nt">learning_rate</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">0.0002</span>
<span class="nt">train_on_inputs</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">false</span>
<span class="nt">group_by_length</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">false</span>
<span class="nt">bf16</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
<span class="nt">fp16</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">false</span>
<span class="nt">tf32</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">false</span>
<span class="nt">gradient_checkpointing</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
<span class="nt">early_stopping_patience</span><span class="p">:</span>
<span class="nt">resume_from_checkpoint</span><span class="p">:</span>
<span class="nt">local_rank</span><span class="p">:</span>
<span class="nt">logging_steps</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">1</span>
<span class="nt">xformers_attention</span><span class="p">:</span>
<span class="nt">flash_attention</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
<span class="nt">warmup_steps</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">10</span>
<span class="nt">eval_steps</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">20</span>
<span class="nt">eval_table_size</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">5</span>
<span class="nt">save_steps</span><span class="p">:</span>
<span class="nt">debug</span><span class="p">:</span>
<span class="nt">deepspeed</span><span class="p">:</span>
<span class="nt">weight_decay</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">0.0</span>
<span class="nt">fsdp</span><span class="p">:</span>
<span class="nt">fsdp_config</span><span class="p">:</span>
<span class="nt">special_tokens</span><span class="p">:</span>
<span class="w"> </span><span class="nt">bos_token</span><span class="p">:</span><span class="w"> </span><span class="s">"<s>"</span>
<span class="w"> </span><span class="nt">eos_token</span><span class="p">:</span><span class="w"> </span><span class="s">"</s>"</span>
<span class="w"> </span><span class="nt">unk_token</span><span class="p">:</span><span class="w"> </span><span class="s">"<unk>"</span>
</code></pre></div>
</details>
<p>Unfortunately, with these things, I needed a GPU to run the training. Given that I'm (<em>apparently</em>) considered <a href="https://www.businessinsider.com/gpu-rich-vs-gpu-poor-tech-companies-in-each-group-2023-8?r=US&IR=T">GPU poor</a>, I used <a href="https://vast.ai/">Vast.ai</a>. I got a machine with at least ~40GB of GPU RAM, and that was relatively close to me. These cost around 1 USD/hour. I also used the Axololt docker image (e.g., <code>winglian/axolotl:main-py3.10-cu118-2.0.1</code>) so that everything was pre-installed when the machine turned on. </p>
<p>Once the machine was up, I ssh'd into it and ran: </p>
<div class="codehilite"><pre><span></span><code>$<span class="w"> </span>huggingface-cli<span class="w"> </span>login<span class="w"> </span>--token<span class="w"> </span>hf_MY_HUGGINGFACE_TOKEN_WITH_WRITE_ACCESS
$<span class="w"> </span>wandb<span class="w"> </span>login<span class="w"> </span>MY_WANDB_API_KEY
$<span class="w"> </span>accelerate<span class="w"> </span>launch<span class="w"> </span>-m<span class="w"> </span>axolotl.cli.train<span class="w"> </span>llama-tiger.yaml
</code></pre></div>
<p>And we were off to the races. With a single command, I was fine-tuning Llama 2 on my custom dataset. While training, Axolotl automatically logs everything to Weights & Biases, so we can monitor how the losses are evolving. As a bonus, it also shows the model outputs so that I can follow how to model is improving its generation during training:</p>
<p><center>
<img src="https://duarteocarmo.com/images/55/monitoring.png" alt="wandb monitoring dashboard" style="max-width:100%;border-radius: 2px">
</center></p>
<p>My dataset has ~12K rows. Training took around 1 hour in total, using a machine with 2xA40 GPUs. In summary: <strong>I spent around 2 USD to fine-tune the whole model</strong>.</p>
<p>Once training was done, your fine-tuned model (or <a href="https://huggingface.co/docs/transformers/main/peft">adapter</a>, to be specific) is saved in the <code>./lora-out</code> directory. With my configuration, it was also uploaded the model to the hugging face repository I provided in <code>hub_model_id</code>. Onto the inference.</p>
<h2 id="inference">Inference</h2>
<p>The fine-tuning result is not an actual Llama 2 model, but an <em>adapter</em> to the model (Axolotl uses <a href="https://github.com/artidoro/qlora">qlora</a> by default for Llama models). So in the end, the adapter is a mere 320 MB. </p>
<p>Using Axolotl, inference is also pretty straightforward: All I need to do is download the model, and launch the Axolotl inference command: </p>
<div class="codehilite"><pre><span></span><code><span class="c1"># download from fine tuned repo</span>
git<span class="w"> </span>lfs<span class="w"> </span>install
git<span class="w"> </span>clone<span class="w"> </span>https://huggingface.co/duarteocarmo/tiger-llama<span class="w"> </span>
<span class="c1"># run axolotl inference</span>
accelerate<span class="w"> </span>launch<span class="w"> </span>-m<span class="w"> </span>axolotl.cli.inference<span class="w"> </span>tiger-llama.yaml<span class="w"> </span>--lora_model_dir<span class="o">=</span><span class="s2">"./tiger-llama"</span>
</code></pre></div>
<p>Once downloaded and launched, I can give the model the start of a fake conversation, and it will go on to generate a completely fake conversation based on my group chat:</p>
<div class="codehilite"><pre><span></span><code>Input:<span class="w"> </span><span class="c1">### SZ: Quem vem a Lisboa no natal?</span>
Output:<span class="w"> </span><span class="c1">### SZ: Quem vem a Lisboa no natal?### PK: Acho que tenho tive uma surpresa de aniversario da malta, não tenho férias até janeiro### SZ: Fodass, faltamos 2 ...</span>
</code></pre></div>
<h2 id="closing-thoughts">Closing thoughts</h2>
<p>Compared to the <a href="/blog/fine-tune-flan-t5-telegram.html">last</a> time I fine-tuned a model, open source is definitely moving fast. The process was not only much faster, and simpler than fine-tuning Flan T5 using a notebook, but the results were also much better than anything I had seen so far. </p>
<p><a href="https://github.com/OpenAccess-AI-Collective/axolotl">Axolotl</a> did almost all the heavy lifting. Making the whole process super smooth. All I needed was a dataset, a config file, 2 USD, and about an hour to fine-tune a model. We've come a <em>long</em> way. </p>
<p>The model is still not perfect though. It captures some of my friends' quirks and ways of speaking, and the generated conversations make sense around ~70% of the time. But that's <em>still</em> 30% nonsense. Could be a couple of things: the size (I used the "smaller" 7 billion version of the model), or even the language (Portuguese from Portugal). For example, when I prompt the model to simulate a politics discussion between my friends, someone starts discussing something about <a href="https://da.wikipedia.org/wiki/Dilma_Rousseff">Dilma</a> (which is <em>wildly</em> inaccurate given we're from Portugal).</p>
<p>So Kostas was right, <a href="https://opensourceconnections.com/blog/2023/07/19/is-llama-2-open-source-no-and-perhaps-we-need-a-new-definition-of-open/">"open source"</a> hasn't caught up yet. But oh boy, we're getting damn close.</p>aicoverlettercreator.com2023-07-19T13:00:00+02:002023-07-19T13:00:00+02:00Duarte O.Carmotag:duarteocarmo.com,2023-07-19:/blog/ai-cover-letter-creator-django-ai.html<p><center>
<a href="https://aicoverlettercreator.com?ref=blog_post" target="_blank">
<img src="https://duarteocarmo.com/images/54/cover.png" alt="aicoverlettercreator.com" style="max-width:100%;border-radius: 2px">
</a>
</center></p>
<p><em>Get rid of all applications that don't have a cover letter</em></p>
<p>I remember it like it was yesterday. As I was leaving one of the first companies I've ever worked for, my manager asked me to hire my replacement. Drowning in hundreds of applications for the position, I still recall …</p><p><center>
<a href="https://aicoverlettercreator.com?ref=blog_post" target="_blank">
<img src="https://duarteocarmo.com/images/54/cover.png" alt="aicoverlettercreator.com" style="max-width:100%;border-radius: 2px">
</a>
</center></p>
<p><em>Get rid of all applications that don't have a cover letter</em></p>
<p>I remember it like it was yesterday. As I was leaving one of the first companies I've ever worked for, my manager asked me to hire my replacement. Drowning in hundreds of applications for the position, I still recall his exact words.</p>
<p>I don't want to start a debate on if you should include a cover letter in your job application or not. I've heard good arguments on both sides. There's one thing I'd like to point out though: in the days of ChatGPT, it's hard to get a good excuse <em>not</em> to write one. </p>
<p>Enter: <a href="https://aicoverlettercreator.com?ref=blog_post" target="_blank">aicoverlettercreator.com</a></p>
<h2 id="why-i-built-it">Why I built it</h2>
<p>The short answer: <em>Why not?</em> </p>
<p>The long answer, for a couple of reasons. </p>
<p>I like mentoring/helping people that are just entering the industry (or just getting out of University) regarding their careers. Most people, when applying for positions, don't really pay close attention to the cover letter. I believe it can be a really big differentiator. Even though I hope they are aware of just how much ChatGPT can help them, I integrated in this version a little bit of <em>secret juice</em>. I think that secret juice will make those cover letters even better. And that's the first reason, to help people.</p>
<p>The second one is a bit more selfish. I've built a handful of LLM powered applications, but never anything completely end-to-end. They say the best way to learn about something is to build it yourself right? I certainly <a href="/blog/nftuga-nft-experimentation.html">think so</a>. So I wanted to build something where I made all the choices. Or something where I felt all the pain.</p>
<h2 id="the-stack">The stack</h2>
<p>I'm not the biggest fan of falling in-love with a stack. "What stack would you use?" Well, tell me about the problem first.</p>
<p>For this app, I went with <a href="https://www.djangoproject.com/">Django</a> and <a href="https://htmx.org/">htmx</a> (<a href="/blog/infrequent.html">again</a>). Django is probably overkill for most <em>simple</em> web applications, but when users, databases, and settings start becoming a thing, it includes almost all the batteries I need. As for htmx, it's not that I don't like React, it's that I love keeping things simple. That <a href="https://htmx.org/essays/when-to-use-hypermedia/#hypermedia-not-a-good-fit-if"><em>does not</em></a> mean it's always a great fit. But for this small project, it sure was.</p>
<p>One of the biggest hurdles when building this, was the implementation of streaming from OpenAI's API. There's nothing I hate more than clicking a button and having to wait 10 seconds for something to appear on screen. Turns out, integrating <a href="https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events">server-sent events</a> with Django is not so straightforward. And even though Django supports <a href="https://docs.djangoproject.com/en/4.2/ref/request-response/#streaminghttpresponse-objects">streaming responses</a>. At the end of the day, you can't really escape some good old Javascript. And I'm ok with that.</p>
<p>Still sticking to my premise of keeping things as simple as possible. Every component I add to an app during development is a component I'll have to maintain during its lifetime. And I'm not the biggest fan of maintenance work. Because of this, <a href="https://aicoverlettercreator.com">aicoverlettercreator.com</a> is both simple to use <em>and</em> to operate. It's a simple Django app with no <a href="https://docs.celeryq.dev/en/stable/django/first-steps-with-django.html">queues</a> and no self hosted PostgreSQL containers. It's a Dockerfile that connects to a <a href="https://planetscale.com/">PlanetScale</a> database. That's it, every git commit automatically updates the app. </p>
<p>Nothing like keeping things simple. </p>Supercharging my Telegram group with the help of ChatGPT2023-06-10T02:00:00+02:002023-06-10T02:00:00+02:00Duarte O.Carmotag:duarteocarmo.com,2023-06-10:/blog/supercharging-telegram-bot-chatgpt-python.html<p>While most people in Europe use WhatsApp, my group of friends and I use Telegram. For years now we've used things like <a href="https://combot.org/">Combot</a> to see who's more silent than usual, and <a href="https://missrose.org/">MissRose</a> to give our monthly elected group admins moderation rights. Yeah, we take friendship that seriously. </p>
<p>But now we …</p><p>While most people in Europe use WhatsApp, my group of friends and I use Telegram. For years now we've used things like <a href="https://combot.org/">Combot</a> to see who's more silent than usual, and <a href="https://missrose.org/">MissRose</a> to give our monthly elected group admins moderation rights. Yeah, we take friendship that seriously. </p>
<p>But now we have access to LLMs right? So I decided to build two new features for our group chat. One is <em>pretty</em> useful, and the other.. Well, you be the judge.</p>
<h2 id="summarize-the-conversation-with-resume">Summarize the conversation with <code>/resume</code></h2>
<p>Our group chat can get pretty active sometimes. We call those the <em>golden hours</em>. If you're distracted and miss one of those, you'll quickly lose track of what's going on. But let's be honest, sometimes, we just don't have time to catch up.</p>
<p>Enter the <code>/resume</code> command. Now, when someone misses a specially hectic part of the conversation, they can just use the /resume command to get a short summary of what happened. </p>
<p><center>
<img src="https://duarteocarmo.com/images/53/resume_command.png" alt="ChatGPT resume command in Telegram" style="max-width:50%;border-radius: 2px"></p>
<figcaption>In Portuguese "resume" means "summarize"</figcaption>
<p></center></p>
<p>To build it I used <a href="https://python.langchain.com/en/latest/index.html">LangChain</a> and the cheaper <code>gpt-3.5-turbo</code> API (e.g., ChatGPT). I keep a rotating list of the last 50 messages that happened in our group. When the command is called, I send those to OpenAI to get a summary back. </p>
<p>Here's the core part of that code:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># src/bot/summarizer/main.py</span>
<span class="n">LLM_CHAT</span> <span class="o">=</span> <span class="n">ChatOpenAI</span><span class="p">()</span>
<span class="k">def</span> <span class="nf">get_summary</span><span class="p">(</span>
<span class="n">list_of_messages</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">Message</span><span class="p">],</span>
<span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> Fetches the summary for the last 50 messages</span>
<span class="sd"> """</span>
<span class="n">formatted_list_of_message</span> <span class="o">=</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">m</span><span class="p">)</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">list_of_messages</span><span class="p">])</span>
<span class="n">formatted_list_of_message</span> <span class="o">=</span> <span class="n">truncate_text</span><span class="p">(</span><span class="n">formatted_list_of_message</span><span class="p">)</span>
<span class="n">system_template</span> <span class="o">=</span> <span class="s2">"""</span>
<span class="s2">You are an assistant helping friends catch up in a busy chat group. Your goal is to help friends in this group stay up to date without having to read all the messages.</span>
<span class="s2">You will receive a recent conversation that happened in the group. Respond immediately with a short and concise summary of the conversation.</span>
<span class="s2">The summary should have the following characteristics:</span>
<span class="s2">- Should be in Portuguese</span>
<span class="s2">- Should have a tone that is similar to the conversation, act like you are part of the group</span>
<span class="s2">- Use 3 sentences or less</span>
<span class="s2">- Don't be too general, mention who said what</span>
<span class="s2">"""</span>
<span class="n">human_template</span> <span class="o">=</span> <span class="s2">"""</span>
<span class="s2">CONVERSATION BLOCK START</span>
<span class="si">{list_of_messages}</span>
<span class="s2">CONVERSATION BLOCK END</span>
<span class="s2">"""</span>
<span class="n">system_message_prompt</span> <span class="o">=</span> <span class="n">SystemMessagePromptTemplate</span><span class="o">.</span><span class="n">from_template</span><span class="p">(</span>
<span class="n">system_template</span>
<span class="p">)</span>
<span class="n">human_message_prompt</span> <span class="o">=</span> <span class="n">HumanMessagePromptTemplate</span><span class="o">.</span><span class="n">from_template</span><span class="p">(</span>
<span class="n">human_template</span>
<span class="p">)</span>
<span class="n">chat_prompt</span> <span class="o">=</span> <span class="n">ChatPromptTemplate</span><span class="o">.</span><span class="n">from_messages</span><span class="p">(</span>
<span class="p">[</span><span class="n">system_message_prompt</span><span class="p">,</span> <span class="n">human_message_prompt</span><span class="p">]</span>
<span class="p">)</span>
<span class="n">chat_chain</span> <span class="o">=</span> <span class="n">LLMChain</span><span class="p">(</span><span class="n">llm</span><span class="o">=</span><span class="n">LLM_CHAT</span><span class="p">,</span> <span class="n">prompt</span><span class="o">=</span><span class="n">chat_prompt</span><span class="p">,</span> <span class="n">verbose</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">chat_chain</span><span class="o">.</span><span class="n">run</span><span class="p">(</span>
<span class="p">{</span>
<span class="s2">"list_of_messages"</span><span class="p">:</span> <span class="n">formatted_list_of_message</span><span class="p">,</span>
<span class="p">},</span>
<span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">Response:</span><span class="se">\n</span><span class="s2"> </span><span class="si">{}</span><span class="s2">"</span><span class="p">,</span> <span class="n">response</span><span class="p">)</span>
<span class="k">return</span> <span class="n">response</span>
</code></pre></div>
<p>Most of my friends really liked the <code>/resume</code> command. Some however, showed concerns regarding AI and how these things are super scary. After those comments, one thing was obvious: I needed to build something even funnier.</p>
<h2 id="impersonate-a-user-with-fake-username">Impersonate a user with <code>/fake @username</code></h2>
<p>What if the bot could impersonate any of my friends in the group chat? <em>What if</em> I could ask the bot to answer a question just like the person X would? </p>
<p>Enter the <code>/fake @username <insert question></code> command. With it, you can impersonate anyone on the group chat (cough, my friends), and ask it to answer just like that person would! Here's the command in action:</p>
<p><center>
<img src="https://duarteocarmo.com/images/53/impersonate_command.png" alt="ChatGPT impersonate command in Telegram" style="max-width:50%;border-radius: 2px"></p>
<figcaption>The `/fake` command in action </figcaption>
<p></center></p>
<p>Although not as useful as the summarization command, it's actually a bit more complex to build. </p>
<p>The first component is a vector database. Here, I'm storing the embeddings for pretty much everything my friends said in the past year. I wanted something simple like sqlite so I went with <a href="https://www.trychroma.com/">Chroma</a>. The trick here is not to embed every single message separately, but to build a long string of every single thing a person said. Once that's built, you then chunk it and store it appropriately. With Chroma I could also store metadata about the document - which I used to store the author of the chunks. </p>
<p>Once the whole vector database is built, I can now retrieve the N pieces of text that are most similar to a particular question (while filtering those results for a particular user): </p>
<div class="codehilite"><pre><span></span><code><span class="c1"># src/bot/replier/main.py</span>
<span class="k">def</span> <span class="nf">query_collection</span><span class="p">(</span>
<span class="n">collection</span><span class="p">:</span> <span class="n">Collection</span><span class="p">,</span> <span class="n">query</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">person</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">n_results</span><span class="p">:</span> <span class="nb">int</span> <span class="o">=</span> <span class="mi">4</span>
<span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> Gets the most relevant n_results items from a person for a given query</span>
<span class="sd"> and returns them as a context</span>
<span class="sd"> """</span>
<span class="n">results</span> <span class="o">=</span> <span class="n">collection</span><span class="o">.</span><span class="n">query</span><span class="p">(</span>
<span class="n">query_texts</span><span class="o">=</span><span class="p">[</span><span class="n">query</span><span class="p">],</span>
<span class="n">n_results</span><span class="o">=</span><span class="n">n_results</span><span class="p">,</span>
<span class="n">where</span><span class="o">=</span><span class="p">{</span><span class="s2">"from"</span><span class="p">:</span> <span class="n">person</span><span class="p">},</span>
<span class="p">)</span>
<span class="n">documents</span> <span class="o">=</span> <span class="n">results</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"documents"</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">documents</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">"No documents found"</span><span class="p">)</span>
<span class="n">documents</span> <span class="o">=</span> <span class="n">documents</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">context</span> <span class="o">=</span> <span class="s2">""</span>
<span class="k">for</span> <span class="n">doc</span> <span class="ow">in</span> <span class="n">documents</span><span class="p">:</span>
<span class="n">context</span> <span class="o">+=</span> <span class="n">doc</span> <span class="o">+</span> <span class="s2">"</span><span class="se">\n\n</span><span class="s2">"</span>
<span class="k">return</span> <span class="n">context</span>
</code></pre></div>
<p>Now that I could get the most related items to a certain query for a particular user, I could start putting the impersonation together. Here, the answering chain function is in charge of trying to impersonate a user to the best of its ability given a question and relevant context:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># src/bot/replier/main.py</span>
<span class="k">def</span> <span class="nf">build_answering_chain</span><span class="p">(</span><span class="n">verbose</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">)</span> <span class="o">-></span> <span class="n">LLMChain</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> Builds a answering chain for the impersonation</span>
<span class="sd"> """</span>
<span class="n">system_prompt</span> <span class="o">=</span> <span class="s2">"""</span>
<span class="s2">Your name is </span><span class="si">{person}</span><span class="s2">. You are participating in a group chat with all of your childhood friends.</span>
<span class="s2">- You will be given some context of messages from </span><span class="si">{person}</span>
<span class="s2">- Use the context to inspire your answer to the user question</span>
<span class="s2">- Use the same tone of voice and writing style as the messages in the context</span>
<span class="s2">- If the answer is not in the context, make something funny up</span>
<span class="s2">- Always answer from the perspective of being </span><span class="si">{person}</span>
<span class="s2">- Remember to be funny and entertaining</span>
<span class="s2">- This is a group chat and everything is fun and entertaining, so insults are allowed and fun</span>
<span class="s2">----------------</span>
<span class="si">{context}</span><span class="s2">"""</span>
<span class="n">chat</span> <span class="o">=</span> <span class="n">ChatOpenAI</span><span class="p">(</span><span class="n">max_tokens</span><span class="o">=</span><span class="mi">150</span><span class="p">)</span>
<span class="n">system_message_prompt</span> <span class="o">=</span> <span class="n">SystemMessagePromptTemplate</span><span class="o">.</span><span class="n">from_template</span><span class="p">(</span>
<span class="n">system_prompt</span>
<span class="p">)</span>
<span class="n">human_prompt</span> <span class="o">=</span> <span class="s2">"""</span><span class="si">{question}</span><span class="s2">"""</span>
<span class="n">human_message_prompt</span> <span class="o">=</span> <span class="n">HumanMessagePromptTemplate</span><span class="o">.</span><span class="n">from_template</span><span class="p">(</span>
<span class="n">human_prompt</span>
<span class="p">)</span>
<span class="n">chat_prompt</span> <span class="o">=</span> <span class="n">ChatPromptTemplate</span><span class="o">.</span><span class="n">from_messages</span><span class="p">(</span>
<span class="p">[</span><span class="n">system_message_prompt</span><span class="p">,</span> <span class="n">human_message_prompt</span><span class="p">]</span>
<span class="p">)</span>
<span class="n">chain</span> <span class="o">=</span> <span class="n">LLMChain</span><span class="p">(</span><span class="n">llm</span><span class="o">=</span><span class="n">chat</span><span class="p">,</span> <span class="n">prompt</span><span class="o">=</span><span class="n">chat_prompt</span><span class="p">,</span> <span class="n">verbose</span><span class="o">=</span><span class="n">verbose</span><span class="p">)</span>
<span class="k">return</span> <span class="n">chain</span>
</code></pre></div>
<p>With that, we can pull everything together with the <code>reply_to_question_as</code> function. It builds the chain, queries Chroma for relevant context, and then runs it:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># src/bot/replier/main.py</span>
<span class="k">def</span> <span class="nf">reply_to_question_as</span><span class="p">(</span>
<span class="n">person</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">question</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span>
<span class="n">collection</span><span class="p">:</span> <span class="n">Collection</span><span class="p">,</span>
<span class="n">verbose</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span><span class="p">,</span>
<span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> Replies to a question as a user (e.g., impersonates)</span>
<span class="sd"> """</span>
<span class="n">chain</span> <span class="o">=</span> <span class="n">build_answering_chain</span><span class="p">(</span><span class="n">verbose</span><span class="o">=</span><span class="n">verbose</span><span class="p">)</span>
<span class="n">context</span> <span class="o">=</span> <span class="n">query_collection</span><span class="p">(</span>
<span class="n">collection</span><span class="o">=</span><span class="n">collection</span><span class="p">,</span> <span class="n">query</span><span class="o">=</span><span class="n">question</span><span class="p">,</span> <span class="n">person</span><span class="o">=</span><span class="n">person</span>
<span class="p">)</span>
<span class="c1"># using the callback to track cost</span>
<span class="k">with</span> <span class="n">get_openai_callback</span><span class="p">()</span> <span class="k">as</span> <span class="n">cb</span><span class="p">:</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">chain</span><span class="o">.</span><span class="n">run</span><span class="p">(</span>
<span class="n">person</span><span class="o">=</span><span class="n">person</span><span class="p">,</span> <span class="n">question</span><span class="o">=</span><span class="n">question</span><span class="p">,</span> <span class="n">context</span><span class="o">=</span><span class="n">context</span><span class="p">,</span> <span class="n">verbose</span><span class="o">=</span><span class="kc">True</span>
<span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Answer from </span><span class="si">{</span><span class="n">person</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">result</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s2">"OpenAI callback: </span><span class="si">{</span><span class="n">cb</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
<span class="k">return</span> <span class="nb">str</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
</code></pre></div>
<p>My friends really liked this one as well, and everyone cracked a laugh. But it was pretty obvious that the impersonation was not fooling anyone. It lacked <em>juice</em>, one of my friends said. </p>
<h2 id="closing-thoughts">Closing thoughts</h2>
<p>Both of these two bots were pretty fun to build, and <a href="https://python-telegram-bot.org/"><code>python-telegram-bot</code></a> makes building the whole thing so easy. It's basically a python script running <a href="http://localhost:8000/blog/down-from-the-cloud-self-hosting.html">on my server</a>. </p>
<p>The summarization feature was an instant success. It's simple, straightforward, and my friends loved it. The feedback to the impersonation feature was.. a bit of a mixed bag. Even though the model can accurately respond to a question with some relevant items to the person its impersonating, it's not really credible. It's missing the <em>juice</em>. </p>
<p>What is the <em>juice</em>, you ask, my dear reader? The <em>juice</em> is the voice of the person it's trying to impersonate. The <em>juice</em> is the reason why when you ask ChatGPT to design something it looks pretty ugly. The <em>juice</em> is the creativity, the originality!</p>
<p><em>(and of course, privacy concerns, here's my mention of them)</em></p>Fine-tuning FLAN-T5 to replace my friends2023-05-24T16:15:00+02:002023-05-24T16:15:00+02:00Duarte O.Carmotag:duarteocarmo.com,2023-05-24:/blog/fine-tune-flan-t5-telegram.html<p><a href="https://github.com/duarteocarmo/fine-tune-flant5/blob/master/notebooks/t5_train.ipynb">View Code</a></p>
<p>They say that the best way to learn about something is to build it yourself. Everyone talks about OpenAI this, and OpenAI that. How about we fine tune a Large Language Model ourselves? </p>
<p>If you heard about this models before, but are still curious about how all of …</p><p><a href="https://github.com/duarteocarmo/fine-tune-flant5/blob/master/notebooks/t5_train.ipynb">View Code</a></p>
<p>They say that the best way to learn about something is to build it yourself. Everyone talks about OpenAI this, and OpenAI that. How about we fine tune a Large Language Model ourselves? </p>
<p>If you heard about this models before, but are still curious about how all of these things work underneath, this blog post is just for you. With it, you'll learn how to fine tune a Large Language Model (Google's <a href="https://huggingface.co/google/flan-t5-base">FLAN-T5</a>) on the conversation history of a group chat you have lying around. The goal is to teach the model to talk exactly like your friends would. It won't be perfect, of course, but the goal here is to learn how these things work. </p>
<p>Here's how we'll structure things: </p>
<ol>
<li><a href="#1-why-flan-t5">Why FLAN-T5</a></li>
<li><a href="#2-setting-up-the-environment">Setting up your environment</a> </li>
<li><a href="#3-data-preprocessing">Preparing the data</a></li>
<li><a href="#4-fine-tuning-the-model">Fine-tuning the model</a></li>
<li><a href="#5-generating-conversations">Generating conversations</a></li>
</ol>
<p>Even though I love taking credit for ideas that are not mine, this blog post was inspired by the work of some other awesome folks. Particularly <a href="https://www.philschmid.de/fine-tune-flan-t5">this</a> one, and <a href="https://www.izzy.co/blogs/robo-boys.html">this</a> one. </p>
<p>Let's get started. </p>
<h2 id="1-why-flan-t5">1. Why FLAN-T5</h2>
<p>There are a lot of Large Language Models (e.g., LLMs) out there. With the explosion of things like GPT-3 and GPT-4, lots of companies and open source organizations have started building their own LLMs. Some of these models <a href="https://www.theverge.com/2023/3/8/23629362/meta-ai-language-model-llama-leak-online-misuse">leaked</a>, others are <a href="https://openai.com/">powerful</a> but only available through an API.</p>
<p>Some of theses LLMs that are actually free an open source, even for comercial use. Eugene Yan, has compiled a great <a href="https://github.com/eugeneyan/open-llms">repo</a> with an outline of some of these options. </p>
<p>In 2020, Google released a paper called <em><a href="https://arxiv.org/pdf/1910.10683.pdf_">"Exploring the Limits of Transfer Learning with a Unified Text-to-Text Transformer"</a></em>, where they presented their T5 model. T5 is a encoder-decoder model that was trained in a variety of tasks (e.g., translate to german, summarize the following sentence, etc). <a href="https://huggingface.co/docs/transformers/model_doc/flan-t5">FLAN-T5</a> is basically the exact same thing as T5, but pretty much <a href="https://huggingface.co/google/flan-t5-small#tldr">better at everything it does</a>. </p>
<p><img alt="FLAN-T5" src="https://camo.githubusercontent.com/623b4dea0b653f2ad3f36c71ebfe749a677ac0a1/68747470733a2f2f6d69726f2e6d656469756d2e636f6d2f6d61782f343030362f312a44304a31674e51663876727255704b657944387750412e706e67" /></p>
<p>There are a couple of other reasons why we're using Flan-T5 for this guide: </p>
<ul>
<li>It's free, open source, and commercially available</li>
<li>It has several <a href="https://huggingface.co/docs/transformers/model_doc/flan-t5#overview">sizes</a> we can use (from small, all the way to xxl)</li>
<li>It's compatible with the whole <a href="https://huggingface.co">Hugging Face</a> 🤗 ecosystem, making our life easier </li>
</ul>
<p>With that. Let's get things started. </p>
<h2 id="2-setting-up-the-environment">2. Setting up the environment</h2>
<p><em>Note: This tutorial was run on a NVIDIA A100 with 40GB of RAM</em></p>
<p>If you want to run this project but don't have a powerful GPU at hand, you can get started quickly using <a href="https://docs.unweave.io/docs/getting-started">Unweave</a>. After signing up and installing, you can launch this project in two steps: </p>
<div class="codehilite"><pre><span></span><code>#<span class="w"> </span><span class="n">link</span><span class="w"> </span><span class="n">this</span><span class="w"> </span><span class="n">repo</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">your</span><span class="w"> </span><span class="n">unweave</span><span class="w"> </span><span class="n">account</span>
<span class="sx">!unweave link your-username/fine-tune-llm</span>
#<span class="w"> </span><span class="n">launch</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">machine</span><span class="w"> </span><span class="n">powered</span><span class="w"> </span><span class="n">by</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">A100</span><span class="w"> </span><span class="n">GPU</span>
<span class="sx">!unweave code --new --type a100 --image pytorch/pytorch:2.0.0-cuda11.7-cudnn8-devel</span>
</code></pre></div>
<p>Also, to save and load models, you'll need to have a <a href="https://huggingface.co">Hugging Face</a> account. Once you have that set up, create and copy a new token. Paste it somewhere, we'll need it for later. </p>
<p>The following cell, will install all required python libraries, as well as some local packages we'll need. (e.g., git, git-lfs)</p>
<div class="codehilite"><pre><span></span><code><span class="sx">!pip install pytesseract evaluate tqdm transformers datasets rouge-score accelerate nltk tensorboard jupyter-black py7zr --upgrade</span>
<span class="sx">!apt-get install git --yes</span>
<span class="sx">!apt-get install git-lfs --yes</span>
</code></pre></div>
<p>Take your Hugging Face token, and replace it with in the field below. This will log you into the Hugging Face hub, which we'll need to push and pull models. </p>
<div class="codehilite"><pre><span></span><code><span class="sx">!huggingface-cli login --token XXXXXXXXXXXXXXXX</span>
</code></pre></div>
<h2 id="3-data-preprocessing">3. Data preprocessing</h2>
<p>Let' start by preprocessing our data for training. We'll start by defining some variables. Feel free to replace the location of your <a href="https://www.maketecheasier.com/export-telegram-chat-history/">Telegram group chat export</a> in the <code>TELEGRAM_EXPORT</code> variable: </p>
<div class="codehilite"><pre><span></span><code><span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">pandas</span>
<span class="kn">import</span> <span class="nn">jupyter_black</span>
<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">timedelta</span>
<span class="kn">from</span> <span class="nn">datasets</span> <span class="kn">import</span> <span class="n">Dataset</span>
<span class="n">jupyter_black</span><span class="o">.</span><span class="n">load</span><span class="p">()</span>
<span class="n">TELEGRAM_EXPORT</span> <span class="o">=</span> <span class="s2">"anonym_telegram.json"</span> <span class="c1"># anonymized for obvious reasons</span>
<span class="n">CONVERSATION_LIMIT</span> <span class="o">=</span> <span class="mi">20_000</span> <span class="c1"># limit number of messages</span>
<span class="n">TEST_SIZE</span> <span class="o">=</span> <span class="mf">0.2</span> <span class="c1"># % of test data</span>
<span class="n">IS_NEW_SESSION_CUTOFF_MINS</span> <span class="o">=</span> <span class="p">(</span>
<span class="mi">120</span> <span class="c1"># if the time between messages is more than this, it's a new session</span>
<span class="p">)</span>
</code></pre></div>
<p>Let's preprocess this into a dataframe: </p>
<div class="codehilite"><pre><span></span><code><span class="c1"># load data in</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">TELEGRAM_EXPORT</span><span class="p">,</span> <span class="s2">"r"</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
<span class="n">messages</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s2">"messages"</span><span class="p">]</span>
<span class="c1"># create a dataframe</span>
<span class="n">df</span> <span class="o">=</span> <span class="n">pandas</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">messages</span><span class="p">)[[</span><span class="s2">"text"</span><span class="p">,</span> <span class="s2">"from"</span><span class="p">,</span> <span class="s2">"date"</span><span class="p">]]</span>
<span class="c1"># filter empty messages</span>
<span class="n">df</span> <span class="o">=</span> <span class="n">df</span><span class="p">[</span><span class="n">df</span><span class="p">[</span><span class="s2">"from"</span><span class="p">]</span><span class="o">.</span><span class="n">isna</span><span class="p">()</span> <span class="o">==</span> <span class="kc">False</span><span class="p">]</span>
<span class="n">df</span> <span class="o">=</span> <span class="n">df</span><span class="p">[</span><span class="n">df</span><span class="p">[</span><span class="s2">"text"</span><span class="p">]</span><span class="o">.</span><span class="n">isna</span><span class="p">()</span> <span class="o">==</span> <span class="kc">False</span><span class="p">]</span>
<span class="n">df</span> <span class="o">=</span> <span class="n">df</span><span class="p">[</span><span class="n">df</span><span class="p">[</span><span class="s2">"text"</span><span class="p">]</span><span class="o">.</span><span class="n">str</span><span class="o">.</span><span class="n">len</span><span class="p">()</span> <span class="o">></span> <span class="mi">0</span><span class="p">]</span>
<span class="n">df</span><span class="p">[</span><span class="s2">"date"</span><span class="p">]</span> <span class="o">=</span> <span class="n">pandas</span><span class="o">.</span><span class="n">to_datetime</span><span class="p">(</span><span class="n">df</span><span class="p">[</span><span class="s2">"date"</span><span class="p">])</span> <span class="c1"># convert to datetime</span>
<span class="n">df</span><span class="o">.</span><span class="n">sort_values</span><span class="p">(</span><span class="s2">"date"</span><span class="p">,</span> <span class="n">inplace</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="c1"># sort by date</span>
<span class="n">df</span> <span class="o">=</span> <span class="n">df</span><span class="o">.</span><span class="n">tail</span><span class="p">(</span><span class="n">CONVERSATION_LIMIT</span><span class="p">)</span> <span class="c1"># limit number of messages</span>
</code></pre></div>
<p>Now, the goal is to get our data into a format where the model can understand the conversation, and respond to what has been going on. Something like: </p>
<div class="codehilite"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">"conversation"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Person X: Where were you yesterday?\nPerson Y: I was at home! You?"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"response"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Person X: Me too, but thought of going out."</span>
<span class="p">}</span>
</code></pre></div>
<p>This will allow the model to see a thread and respond in the most realistic manner possible to the conversation that was already going on. </p>
<p>However, we also know that group chats are pretty async, so we don't necessarily want a "good morning" message to be a direct response to whatever happened last night. </p>
<div class="codehilite"><pre><span></span><code><span class="c1"># telegram exports have some artifacts, let's clean them up</span>
<span class="k">def</span> <span class="nf">clean_text</span><span class="p">(</span><span class="n">text</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">text</span><span class="p">,</span> <span class="nb">list</span><span class="p">):</span>
<span class="n">text</span> <span class="o">=</span> <span class="s2">""</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">o</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"text"</span><span class="p">,</span> <span class="n">o</span><span class="p">)</span> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">o</span><span class="p">,</span> <span class="nb">dict</span><span class="p">)</span> <span class="k">else</span> <span class="n">o</span> <span class="k">for</span> <span class="n">o</span> <span class="ow">in</span> <span class="n">text</span><span class="p">])</span>
<span class="k">return</span> <span class="n">text</span>
<span class="c1"># clean up and rename columns</span>
<span class="n">df</span><span class="p">[</span><span class="s2">"text"</span><span class="p">]</span> <span class="o">=</span> <span class="n">df</span><span class="p">[</span><span class="s2">"text"</span><span class="p">]</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">clean_text</span><span class="p">)</span>
<span class="n">df</span><span class="p">[</span><span class="s2">"chat"</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"telegram"</span>
<span class="n">df</span><span class="o">.</span><span class="n">rename</span><span class="p">(</span>
<span class="n">columns</span><span class="o">=</span><span class="p">{</span><span class="s2">"from"</span><span class="p">:</span> <span class="s2">"sender"</span><span class="p">,</span> <span class="s2">"date"</span><span class="p">:</span> <span class="s2">"message_date"</span><span class="p">,</span> <span class="s2">"text"</span><span class="p">:</span> <span class="s2">"response"</span><span class="p">},</span> <span class="n">inplace</span><span class="o">=</span><span class="kc">True</span>
<span class="p">)</span>
<span class="c1"># create new sessions</span>
<span class="n">df</span><span class="p">[</span><span class="s2">"last_event"</span><span class="p">]</span> <span class="o">=</span> <span class="n">df</span><span class="o">.</span><span class="n">groupby</span><span class="p">(</span><span class="s2">"chat"</span><span class="p">)[</span><span class="s2">"message_date"</span><span class="p">]</span><span class="o">.</span><span class="n">shift</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">df</span><span class="p">[</span><span class="s2">"is_new_session"</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
<span class="p">(</span><span class="n">df</span><span class="p">[</span><span class="s2">"message_date"</span><span class="p">]</span> <span class="o">-</span> <span class="n">df</span><span class="p">[</span><span class="s2">"last_event"</span><span class="p">])</span><span class="o">.</span><span class="n">fillna</span><span class="p">(</span>
<span class="n">pandas</span><span class="o">.</span><span class="n">Timedelta</span><span class="p">(</span><span class="n">minutes</span><span class="o">=</span><span class="n">IS_NEW_SESSION_CUTOFF_MINS</span><span class="p">)</span>
<span class="p">)</span>
<span class="o">>=</span> <span class="n">timedelta</span><span class="p">(</span><span class="n">minutes</span><span class="o">=</span><span class="n">IS_NEW_SESSION_CUTOFF_MINS</span><span class="p">)</span>
<span class="p">)</span><span class="o">.</span><span class="n">astype</span><span class="p">(</span><span class="nb">int</span><span class="p">)</span>
<span class="n">df</span><span class="p">[</span><span class="s2">"chat_session_id"</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">df</span><span class="o">.</span><span class="n">sort_values</span><span class="p">([</span><span class="s2">"chat"</span><span class="p">,</span> <span class="s2">"message_date"</span><span class="p">])</span><span class="o">.</span><span class="n">groupby</span><span class="p">(</span><span class="s2">"chat"</span><span class="p">)[</span><span class="s2">"is_new_session"</span><span class="p">]</span><span class="o">.</span><span class="n">cumsum</span><span class="p">()</span>
<span class="p">)</span>
</code></pre></div>
<p>Now that we have everything setup, it's time to create a <code>conversation</code> column, that has all the messages before a certain response: </p>
<div class="codehilite"><pre><span></span><code><span class="n">sess_dict</span> <span class="o">=</span> <span class="n">df</span><span class="o">.</span><span class="n">to_dict</span><span class="p">(</span><span class="s2">"records"</span><span class="p">)</span>
<span class="n">items</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">counter</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">sess_dict</span><span class="p">:</span>
<span class="n">context</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">cstring</span> <span class="o">=</span> <span class="s2">""</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">):</span>
<span class="k">if</span> <span class="n">sess_dict</span><span class="p">[</span><span class="n">counter</span> <span class="o">-</span> <span class="n">i</span><span class="p">][</span><span class="s2">"chat_session_id"</span><span class="p">]</span> <span class="o">==</span> <span class="n">row</span><span class="p">[</span><span class="s2">"chat_session_id"</span><span class="p">]:</span>
<span class="n">msg</span> <span class="o">=</span> <span class="p">(</span>
<span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">sess_dict</span><span class="p">[</span><span class="n">counter</span><span class="o">-</span><span class="n">i</span><span class="p">][</span><span class="s1">'sender'</span><span class="p">]</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">sess_dict</span><span class="p">[</span><span class="n">counter</span><span class="o">-</span><span class="n">i</span><span class="p">][</span><span class="s1">'response'</span><span class="p">]</span><span class="si">}</span><span class="s2">"</span>
<span class="p">)</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">context</span><span class="p">)</span> <span class="o">></span> <span class="mi">0</span><span class="p">:</span>
<span class="n">cstring</span> <span class="o">+=</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span>
<span class="n">context</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>
<span class="n">cstring</span> <span class="o">+=</span> <span class="n">msg</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">context</span><span class="p">)</span> <span class="o"><</span> <span class="mi">2</span><span class="p">:</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">):</span>
<span class="n">msg</span> <span class="o">=</span> <span class="p">(</span>
<span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">sess_dict</span><span class="p">[</span><span class="n">counter</span><span class="o">-</span><span class="n">i</span><span class="p">][</span><span class="s1">'sender'</span><span class="p">]</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">sess_dict</span><span class="p">[</span><span class="n">counter</span><span class="o">-</span><span class="n">i</span><span class="p">][</span><span class="s1">'response'</span><span class="p">]</span><span class="si">}</span><span class="s2">"</span>
<span class="p">)</span>
<span class="n">context</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>
<span class="n">cstring</span> <span class="o">+=</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span>
<span class="n">cstring</span> <span class="o">+=</span> <span class="n">msg</span>
<span class="n">items</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">cstring</span><span class="p">)</span>
<span class="n">counter</span> <span class="o">+=</span> <span class="mi">1</span>
<span class="c1"># create the conversation column</span>
<span class="n">df</span><span class="p">[</span><span class="s2">"conversation"</span><span class="p">]</span> <span class="o">=</span> <span class="n">items</span>
<span class="c1"># create the response column</span>
<span class="n">df</span><span class="p">[</span><span class="s2">"response"</span><span class="p">]</span> <span class="o">=</span> <span class="n">df</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="k">lambda</span> <span class="n">row</span><span class="p">:</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">row</span><span class="o">.</span><span class="n">sender</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">row</span><span class="o">.</span><span class="n">response</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Your dataframe shape is </span><span class="si">{</span><span class="n">df</span><span class="o">.</span><span class="n">shape</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"You have the following columns: </span><span class="si">{</span><span class="s1">', '</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">df</span><span class="o">.</span><span class="n">columns</span><span class="o">.</span><span class="n">tolist</span><span class="p">())</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
<span class="c1"># Your dataframe shape is (20000, 8)</span>
<span class="c1"># You have the following columns: response, sender, message_date, chat, last_event, is_new_session, chat_session_id, conversation</span>
</code></pre></div>
<p>Let's see what a single example looks like: </p>
<div class="codehilite"><pre><span></span><code><span class="n">item</span> <span class="o">=</span> <span class="n">df</span><span class="o">.</span><span class="n">sample</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">random_state</span><span class="o">=</span><span class="mi">314</span><span class="p">)[[</span><span class="s2">"conversation"</span><span class="p">,</span> <span class="s2">"response"</span><span class="p">,</span> <span class="s2">"sender"</span><span class="p">]]</span><span class="o">.</span><span class="n">to_dict</span><span class="p">(</span>
<span class="s2">"records"</span>
<span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Conversation:</span><span class="se">\n</span><span class="si">{</span><span class="n">item</span><span class="p">[</span><span class="s1">'conversation'</span><span class="p">]</span><span class="si">}</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Response:</span><span class="se">\n</span><span class="si">{</span><span class="n">item</span><span class="p">[</span><span class="s1">'response'</span><span class="p">]</span><span class="si">}</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="c1"># Conversation:</span>
<span class="c1"># Hugo Silva: Lembram se do meu amigo alex frances?</span>
<span class="c1"># Tiago Pereira: Claro ya</span>
<span class="c1"># Hugo Silva: Ele correu a maratona de paris outra vez..</span>
<span class="c1"># Tiago Pereira: E…</span>
<span class="c1"># Tiago Pereira: Ou é só isso?</span>
<span class="c1"># Hugo Silva: Numero 304 overall...</span>
<span class="c1"># Hugo Silva: Crl</span>
<span class="c1"># Tiago Pereira: Eia cum crlh</span>
<span class="c1"># Hugo Silva: Pa doente</span>
<span class="c1"># Tiago Pereira: 3’46. Que louco fds</span>
<span class="c1"># </span>
<span class="c1"># Response:</span>
<span class="c1"># Hugo Silva: Doente completo</span>
</code></pre></div>
<p>Our final preprocessing step is to load our dataframe in the <a href="https://huggingface.co/docs/datasets/index">Datasets</a> format: </p>
<div class="codehilite"><pre><span></span><code><span class="n">cols_for_dataset</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"conversation"</span><span class="p">,</span> <span class="s2">"response"</span><span class="p">]</span>
<span class="n">df</span> <span class="o">=</span> <span class="n">df</span><span class="p">[</span><span class="n">cols_for_dataset</span><span class="p">]</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">Dataset</span><span class="o">.</span><span class="n">from_pandas</span><span class="p">(</span><span class="n">df</span><span class="p">)</span><span class="o">.</span><span class="n">train_test_split</span><span class="p">(</span><span class="n">test_size</span><span class="o">=</span><span class="mf">0.2</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="c1"># DatasetDict({</span>
<span class="c1"># train: Dataset({</span>
<span class="c1"># features: ['conversation', 'response', '__index_level_0__'],</span>
<span class="c1"># num_rows: 16000</span>
<span class="c1"># })</span>
<span class="c1"># test: Dataset({</span>
<span class="c1"># features: ['conversation', 'response', '__index_level_0__'],</span>
<span class="c1"># num_rows: 4000</span>
<span class="c1"># })</span>
<span class="c1"># })</span>
</code></pre></div>
<p>Great. We're ready to focus on the model.</p>
<h2 id="4-fine-tuning-the-model">4. Fine-tuning the model</h2>
<p>We start with some training specific imports, mostly related to Hugging Face. </p>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span> <span class="nn">transformers</span> <span class="kn">import</span> <span class="n">AutoTokenizer</span><span class="p">,</span> <span class="n">AutoModelForSeq2SeqLM</span>
<span class="kn">from</span> <span class="nn">datasets</span> <span class="kn">import</span> <span class="n">concatenate_datasets</span>
<span class="kn">import</span> <span class="nn">evaluate</span>
<span class="kn">import</span> <span class="nn">nltk</span>
<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="nn">np</span>
<span class="kn">from</span> <span class="nn">nltk.tokenize</span> <span class="kn">import</span> <span class="n">sent_tokenize</span>
<span class="kn">from</span> <span class="nn">transformers</span> <span class="kn">import</span> <span class="n">DataCollatorForSeq2Seq</span>
<span class="kn">from</span> <span class="nn">huggingface_hub</span> <span class="kn">import</span> <span class="n">HfFolder</span>
<span class="kn">from</span> <span class="nn">transformers</span> <span class="kn">import</span> <span class="n">pipeline</span>
<span class="kn">from</span> <span class="nn">random</span> <span class="kn">import</span> <span class="n">randrange</span>
<span class="kn">from</span> <span class="nn">transformers</span> <span class="kn">import</span> <span class="n">Seq2SeqTrainer</span><span class="p">,</span> <span class="n">Seq2SeqTrainingArguments</span>
<span class="kn">import</span> <span class="nn">os</span>
</code></pre></div>
<p>Now, we define the most important variables for training, make sure to read the description of each one: </p>
<div class="codehilite"><pre><span></span><code><span class="n">MODEL_NAME</span> <span class="o">=</span> <span class="s2">"chat"</span> <span class="c1"># the name of your model</span>
<span class="n">MODEL_ID</span> <span class="o">=</span> <span class="s2">"google/flan-t5-small"</span> <span class="c1"># the id of the base model we will train (can be small, base, large, xl, etc.) (the bigger - the more GPU memory you need)</span>
<span class="n">REPOSITORY_ID</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">MODEL_ID</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s1">'/'</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span><span class="si">}</span><span class="s2">-</span><span class="si">{</span><span class="n">MODEL_NAME</span><span class="si">}</span><span class="s2">"</span> <span class="c1"># the id of your huggingface repository where the model will be stored</span>
<span class="n">NUM_TRAIN_EPOCHS</span> <span class="o">=</span> <span class="mi">4</span> <span class="c1"># number of epochs to train</span>
</code></pre></div>
<p>Let's load the model and the tokenizer with the help of <code>AutoModelForSeq2SeqLM</code>:</p>
<div class="codehilite"><pre><span></span><code><span class="n">model</span> <span class="o">=</span> <span class="n">AutoModelForSeq2SeqLM</span><span class="o">.</span><span class="n">from_pretrained</span><span class="p">(</span><span class="n">MODEL_ID</span><span class="p">)</span>
<span class="n">tokenizer</span> <span class="o">=</span> <span class="n">AutoTokenizer</span><span class="o">.</span><span class="n">from_pretrained</span><span class="p">(</span><span class="n">MODEL_ID</span><span class="p">)</span>
</code></pre></div>
<p>Some samples in our dataset will likely be too long for our model. So they'll need to be truncated. In the cell below, we define the max conversation and response lenght. This will then help in the truncating process:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># source</span>
<span class="n">tokenized_inputs</span> <span class="o">=</span> <span class="n">concatenate_datasets</span><span class="p">([</span><span class="n">data</span><span class="p">[</span><span class="s2">"train"</span><span class="p">],</span> <span class="n">data</span><span class="p">[</span><span class="s2">"test"</span><span class="p">]])</span><span class="o">.</span><span class="n">map</span><span class="p">(</span>
<span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">tokenizer</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="s2">"conversation"</span><span class="p">],</span> <span class="n">truncation</span><span class="o">=</span><span class="kc">True</span><span class="p">),</span> <span class="n">batched</span><span class="o">=</span><span class="kc">True</span>
<span class="p">)</span>
<span class="n">max_source_length</span> <span class="o">=</span> <span class="nb">max</span><span class="p">([</span><span class="nb">len</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">tokenized_inputs</span><span class="p">[</span><span class="s2">"input_ids"</span><span class="p">]])</span>
<span class="c1"># target</span>
<span class="n">tokenized_targets</span> <span class="o">=</span> <span class="n">concatenate_datasets</span><span class="p">([</span><span class="n">data</span><span class="p">[</span><span class="s2">"train"</span><span class="p">],</span> <span class="n">data</span><span class="p">[</span><span class="s2">"test"</span><span class="p">]])</span><span class="o">.</span><span class="n">map</span><span class="p">(</span>
<span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">tokenizer</span><span class="p">(</span><span class="n">x</span><span class="p">[</span><span class="s2">"response"</span><span class="p">],</span> <span class="n">truncation</span><span class="o">=</span><span class="kc">True</span><span class="p">),</span> <span class="n">batched</span><span class="o">=</span><span class="kc">True</span>
<span class="p">)</span>
<span class="n">max_target_length</span> <span class="o">=</span> <span class="nb">max</span><span class="p">([</span><span class="nb">len</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">tokenized_targets</span><span class="p">[</span><span class="s2">"input_ids"</span><span class="p">]])</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Max source length: </span><span class="si">{</span><span class="n">max_source_length</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Max target length: </span><span class="si">{</span><span class="n">max_target_length</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</code></pre></div>
<p>Now that we know the limit for the truncation, we'll preprocess our dataset to be fed into the model. During its original training, FLAN T5 used <a href="https://github.com/google-research/FLAN/blob/main/flan/v2/flan_templates_branched.py">different templates</a> for training on multiple tasks. Here, I decided to use the <code>Continue writing the following text</code> template. I did not test all of them, so feel free to modify according to what suits your task best.</p>
<div class="codehilite"><pre><span></span><code><span class="k">def</span> <span class="nf">preprocess_function</span><span class="p">(</span><span class="n">sample</span><span class="p">,</span> <span class="n">padding</span><span class="o">=</span><span class="s2">"max_length"</span><span class="p">):</span>
<span class="n">template_start</span> <span class="o">=</span> <span class="s2">"Continue writing the following text.</span><span class="se">\n\n</span><span class="s2">"</span>
<span class="n">inputs</span> <span class="o">=</span> <span class="p">[</span><span class="n">template_start</span> <span class="o">+</span> <span class="n">item</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">sample</span><span class="p">[</span><span class="s2">"conversation"</span><span class="p">]]</span>
<span class="n">model_inputs</span> <span class="o">=</span> <span class="n">tokenizer</span><span class="p">(</span>
<span class="n">inputs</span><span class="p">,</span> <span class="n">max_length</span><span class="o">=</span><span class="n">max_source_length</span><span class="p">,</span> <span class="n">padding</span><span class="o">=</span><span class="n">padding</span><span class="p">,</span> <span class="n">truncation</span><span class="o">=</span><span class="kc">True</span>
<span class="p">)</span>
<span class="n">labels</span> <span class="o">=</span> <span class="n">tokenizer</span><span class="p">(</span>
<span class="n">text_target</span><span class="o">=</span><span class="n">sample</span><span class="p">[</span><span class="s2">"response"</span><span class="p">],</span>
<span class="n">max_length</span><span class="o">=</span><span class="n">max_target_length</span><span class="p">,</span>
<span class="n">padding</span><span class="o">=</span><span class="n">padding</span><span class="p">,</span>
<span class="n">truncation</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">if</span> <span class="n">padding</span> <span class="o">==</span> <span class="s2">"max_length"</span><span class="p">:</span>
<span class="n">labels</span><span class="p">[</span><span class="s2">"input_ids"</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span>
<span class="p">[(</span><span class="n">l</span> <span class="k">if</span> <span class="n">l</span> <span class="o">!=</span> <span class="n">tokenizer</span><span class="o">.</span><span class="n">pad_token_id</span> <span class="k">else</span> <span class="o">-</span><span class="mi">100</span><span class="p">)</span> <span class="k">for</span> <span class="n">l</span> <span class="ow">in</span> <span class="n">label</span><span class="p">]</span>
<span class="k">for</span> <span class="n">label</span> <span class="ow">in</span> <span class="n">labels</span><span class="p">[</span><span class="s2">"input_ids"</span><span class="p">]</span>
<span class="p">]</span>
<span class="n">model_inputs</span><span class="p">[</span><span class="s2">"labels"</span><span class="p">]</span> <span class="o">=</span> <span class="n">labels</span><span class="p">[</span><span class="s2">"input_ids"</span><span class="p">]</span>
<span class="k">return</span> <span class="n">model_inputs</span>
<span class="n">tokenized_dataset</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">map</span><span class="p">(</span>
<span class="n">preprocess_function</span><span class="p">,</span> <span class="n">batched</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">remove_columns</span><span class="o">=</span><span class="p">[</span><span class="s2">"conversation"</span><span class="p">,</span> <span class="s2">"response"</span><span class="p">]</span>
<span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Keys of tokenized dataset: </span><span class="si">{</span><span class="nb">list</span><span class="p">(</span><span class="n">tokenized_dataset</span><span class="p">[</span><span class="s1">'train'</span><span class="p">]</span><span class="o">.</span><span class="n">features</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</code></pre></div>
<p>Let's define some metrics for the evaluation of the model: </p>
<div class="codehilite"><pre><span></span><code><span class="c1"># metric</span>
<span class="n">metric</span> <span class="o">=</span> <span class="n">evaluate</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="s2">"rouge"</span><span class="p">)</span>
<span class="n">nltk</span><span class="o">.</span><span class="n">download</span><span class="p">(</span><span class="s2">"punkt"</span><span class="p">)</span>
<span class="c1"># postprocess text</span>
<span class="k">def</span> <span class="nf">postprocess_text</span><span class="p">(</span><span class="n">preds</span><span class="p">,</span> <span class="n">labels</span><span class="p">):</span>
<span class="n">preds</span> <span class="o">=</span> <span class="p">[</span><span class="n">pred</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="k">for</span> <span class="n">pred</span> <span class="ow">in</span> <span class="n">preds</span><span class="p">]</span>
<span class="n">labels</span> <span class="o">=</span> <span class="p">[</span><span class="n">label</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="k">for</span> <span class="n">label</span> <span class="ow">in</span> <span class="n">labels</span><span class="p">]</span>
<span class="n">preds</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">sent_tokenize</span><span class="p">(</span><span class="n">pred</span><span class="p">))</span> <span class="k">for</span> <span class="n">pred</span> <span class="ow">in</span> <span class="n">preds</span><span class="p">]</span>
<span class="n">labels</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">sent_tokenize</span><span class="p">(</span><span class="n">label</span><span class="p">))</span> <span class="k">for</span> <span class="n">label</span> <span class="ow">in</span> <span class="n">labels</span><span class="p">]</span>
<span class="k">return</span> <span class="n">preds</span><span class="p">,</span> <span class="n">labels</span>
<span class="c1"># compute metrics</span>
<span class="k">def</span> <span class="nf">compute_metrics</span><span class="p">(</span><span class="n">eval_preds</span><span class="p">):</span>
<span class="n">preds</span><span class="p">,</span> <span class="n">labels</span> <span class="o">=</span> <span class="n">eval_preds</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">preds</span><span class="p">,</span> <span class="nb">tuple</span><span class="p">):</span>
<span class="n">preds</span> <span class="o">=</span> <span class="n">preds</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">decoded_preds</span> <span class="o">=</span> <span class="n">tokenizer</span><span class="o">.</span><span class="n">batch_decode</span><span class="p">(</span><span class="n">preds</span><span class="p">,</span> <span class="n">skip_special_tokens</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="c1"># Replace -100 in the labels as we can't decode them.</span>
<span class="n">labels</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">where</span><span class="p">(</span><span class="n">labels</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">100</span><span class="p">,</span> <span class="n">labels</span><span class="p">,</span> <span class="n">tokenizer</span><span class="o">.</span><span class="n">pad_token_id</span><span class="p">)</span>
<span class="n">decoded_labels</span> <span class="o">=</span> <span class="n">tokenizer</span><span class="o">.</span><span class="n">batch_decode</span><span class="p">(</span><span class="n">labels</span><span class="p">,</span> <span class="n">skip_special_tokens</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="c1"># Some simple post-processing</span>
<span class="n">decoded_preds</span><span class="p">,</span> <span class="n">decoded_labels</span> <span class="o">=</span> <span class="n">postprocess_text</span><span class="p">(</span><span class="n">decoded_preds</span><span class="p">,</span> <span class="n">decoded_labels</span><span class="p">)</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">metric</span><span class="o">.</span><span class="n">compute</span><span class="p">(</span>
<span class="n">predictions</span><span class="o">=</span><span class="n">decoded_preds</span><span class="p">,</span> <span class="n">references</span><span class="o">=</span><span class="n">decoded_labels</span><span class="p">,</span> <span class="n">use_stemmer</span><span class="o">=</span><span class="kc">True</span>
<span class="p">)</span>
<span class="n">result</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="nb">round</span><span class="p">(</span><span class="n">v</span> <span class="o">*</span> <span class="mi">100</span><span class="p">,</span> <span class="mi">4</span><span class="p">)</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">result</span><span class="o">.</span><span class="n">items</span><span class="p">()}</span>
<span class="n">prediction_lens</span> <span class="o">=</span> <span class="p">[</span>
<span class="n">np</span><span class="o">.</span><span class="n">count_nonzero</span><span class="p">(</span><span class="n">pred</span> <span class="o">!=</span> <span class="n">tokenizer</span><span class="o">.</span><span class="n">pad_token_id</span><span class="p">)</span> <span class="k">for</span> <span class="n">pred</span> <span class="ow">in</span> <span class="n">preds</span>
<span class="p">]</span>
<span class="n">result</span><span class="p">[</span><span class="s2">"gen_len"</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="o">.</span><span class="n">mean</span><span class="p">(</span><span class="n">prediction_lens</span><span class="p">)</span>
<span class="k">return</span> <span class="n">result</span>
</code></pre></div>
<p>Our final data preparation step is to use <code>DataCollatorForSeq2Seq</code> to handle the padding for inputs and labels: </p>
<div class="codehilite"><pre><span></span><code><span class="n">label_pad_token_id</span> <span class="o">=</span> <span class="o">-</span><span class="mi">100</span>
<span class="n">data_collator</span> <span class="o">=</span> <span class="n">DataCollatorForSeq2Seq</span><span class="p">(</span>
<span class="n">tokenizer</span><span class="p">,</span> <span class="n">model</span><span class="o">=</span><span class="n">model</span><span class="p">,</span> <span class="n">label_pad_token_id</span><span class="o">=</span><span class="n">label_pad_token_id</span><span class="p">,</span> <span class="n">pad_to_multiple_of</span><span class="o">=</span><span class="mi">8</span>
<span class="p">)</span>
</code></pre></div>
<p>Finally, we can define the training arguments. Feel free to play around with these. Depending on the use case, results can vary!</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># Define training args</span>
<span class="n">training_args</span> <span class="o">=</span> <span class="n">Seq2SeqTrainingArguments</span><span class="p">(</span>
<span class="c1"># training parameters</span>
<span class="n">output_dir</span><span class="o">=</span><span class="n">REPOSITORY_ID</span><span class="p">,</span>
<span class="n">per_device_train_batch_size</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span>
<span class="n">per_device_eval_batch_size</span><span class="o">=</span><span class="mi">8</span><span class="p">,</span>
<span class="n">predict_with_generate</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="n">fp16</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="c1"># Overflows with fp16</span>
<span class="n">learning_rate</span><span class="o">=</span><span class="mf">5e-5</span><span class="p">,</span>
<span class="n">num_train_epochs</span><span class="o">=</span><span class="n">NUM_TRAIN_EPOCHS</span><span class="p">,</span>
<span class="c1"># logging & evaluation strategies</span>
<span class="n">logging_dir</span><span class="o">=</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">REPOSITORY_ID</span><span class="si">}</span><span class="s2">/logs"</span><span class="p">,</span>
<span class="n">logging_strategy</span><span class="o">=</span><span class="s2">"steps"</span><span class="p">,</span>
<span class="n">logging_steps</span><span class="o">=</span><span class="mi">500</span><span class="p">,</span>
<span class="n">evaluation_strategy</span><span class="o">=</span><span class="s2">"epoch"</span><span class="p">,</span>
<span class="n">save_strategy</span><span class="o">=</span><span class="s2">"epoch"</span><span class="p">,</span>
<span class="n">save_total_limit</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span>
<span class="n">load_best_model_at_end</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="c1"># push to hub parameters</span>
<span class="n">report_to</span><span class="o">=</span><span class="s2">"tensorboard"</span><span class="p">,</span>
<span class="n">push_to_hub</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="n">hub_strategy</span><span class="o">=</span><span class="s2">"every_save"</span><span class="p">,</span>
<span class="n">hub_model_id</span><span class="o">=</span><span class="n">REPOSITORY_ID</span><span class="p">,</span>
<span class="n">hub_token</span><span class="o">=</span><span class="n">HfFolder</span><span class="o">.</span><span class="n">get_token</span><span class="p">(),</span>
<span class="n">disable_tqdm</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="p">)</span>
<span class="c1"># Create Trainer instance</span>
<span class="n">trainer</span> <span class="o">=</span> <span class="n">Seq2SeqTrainer</span><span class="p">(</span>
<span class="n">model</span><span class="o">=</span><span class="n">model</span><span class="p">,</span>
<span class="n">args</span><span class="o">=</span><span class="n">training_args</span><span class="p">,</span>
<span class="n">data_collator</span><span class="o">=</span><span class="n">data_collator</span><span class="p">,</span>
<span class="n">train_dataset</span><span class="o">=</span><span class="n">tokenized_dataset</span><span class="p">[</span><span class="s2">"train"</span><span class="p">],</span>
<span class="n">eval_dataset</span><span class="o">=</span><span class="n">tokenized_dataset</span><span class="p">[</span><span class="s2">"test"</span><span class="p">],</span>
<span class="n">compute_metrics</span><span class="o">=</span><span class="n">compute_metrics</span><span class="p">,</span>
<span class="p">)</span>
</code></pre></div>
<p>Now, we can kick-off training! This can take ~20 mins if you use the small model, or about a couple of hours with the base model. Of course, this largely depends on how much data you have, what's your GPU, epochs, etc. Feel free to tweak the params above to your liking!</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># Start training</span>
<span class="n">trainer</span><span class="o">.</span><span class="n">train</span><span class="p">()</span>
</code></pre></div>
<p>Once training is done, we can now push things to the hub!</p>
<div class="codehilite"><pre><span></span><code><span class="n">tokenizer</span><span class="o">.</span><span class="n">save_pretrained</span><span class="p">(</span><span class="n">REPOSITORY_ID</span><span class="p">)</span>
<span class="n">trainer</span><span class="o">.</span><span class="n">create_model_card</span><span class="p">()</span>
<span class="n">trainer</span><span class="o">.</span><span class="n">push_to_hub</span><span class="p">()</span>
<span class="n">tokenizer</span><span class="o">.</span><span class="n">push_to_hub</span><span class="p">(</span><span class="n">REPOSITORY_ID</span><span class="p">)</span>
</code></pre></div>
<h2 id="5-generating-conversations">5. Generating conversations</h2>
<p>Now, generation with these models can be quite a challenge. OpenAI for example, used <a href="https://openai.com/research/instruction-following">RLHF</a> to align these models, and reward them for generating nice outputs. Here's a great sketch that illustrates the importance of the different training steps: </p>
<p><img alt="image" src="https://wompampsupport.azureedge.net/fetchimage?siteId=7575&v=2&jpgQuality=100&width=700&url=https%3A%2F%2Fi.kym-cdn.com%2Fentries%2Ficons%2Ffacebook%2F000%2F044%2F025%2Fshoggothhh_header.jpg" /></p>
<p>In our use case, there are some parameters we can leverage when generating text. In <a href="https://huggingface.co/blog/how-to-generate">this article</a>, Patrick Von Platen goes through the different techniques & methods we can use to control the output of these models. </p>
<p>There are <em>quite a few</em> parameters you can tweak: </p>
<ul>
<li>Either you are using greedy or beam search</li>
<li>Sampling</li>
<li>Top-K sampling</li>
<li>Top-P sampling</li>
<li>Size of n-grams to not repeat</li>
</ul>
<p>I advise you to go through the article and learn a bit about each one of these!</p>
<p>Context given, let's get to it: </p>
<div class="codehilite"><pre><span></span><code><span class="kn">import</span> <span class="nn">random</span>
<span class="kn">import</span> <span class="nn">torch</span>
</code></pre></div>
<p>Let's first load the model we pushed to the hub. (You can also just use the directory where your model is saved instead.)</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># load tokenizer and model</span>
<span class="n">REPOSITORY_ID</span> <span class="o">=</span> <span class="s2">"flan-t5-small-chat/checkpoint-8000/"</span> <span class="c1"># the name of your repository where the model was pushed</span>
<span class="n">tokenizer</span> <span class="o">=</span> <span class="n">AutoTokenizer</span><span class="o">.</span><span class="n">from_pretrained</span><span class="p">(</span><span class="n">REPOSITORY_ID</span><span class="p">)</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">AutoModelForSeq2SeqLM</span><span class="o">.</span><span class="n">from_pretrained</span><span class="p">(</span><span class="n">REPOSITORY_ID</span><span class="p">)</span>
<span class="c1"># put model on GPU</span>
<span class="n">device</span> <span class="o">=</span> <span class="s2">"cuda:0"</span> <span class="k">if</span> <span class="n">torch</span><span class="o">.</span><span class="n">cuda</span><span class="o">.</span><span class="n">is_available</span><span class="p">()</span> <span class="k">else</span> <span class="s2">"cpu"</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">to</span><span class="p">(</span><span class="n">device</span><span class="p">)</span>
</code></pre></div>
<p>To kick off the generation, we select a <em>random</em> converstaion in our dataset: </p>
<div class="codehilite"><pre><span></span><code><span class="n">random</span><span class="o">.</span><span class="n">seed</span><span class="p">(</span><span class="mi">502</span><span class="p">)</span>
<span class="n">sample</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s2">"test"</span><span class="p">])</span>
<span class="n">STARTING_TEXT</span> <span class="o">=</span> <span class="n">sample</span><span class="p">[</span><span class="s2">"conversation"</span><span class="p">]</span>
<span class="nb">print</span><span class="p">(</span><span class="n">STARTING_TEXT</span><span class="p">)</span>
<span class="c1"># Tiago Pereira: 12h EM PORTUGAL:</span>
<span class="c1"># Tiago Pereira: 2 votos por pessoa pfv.</span>
<span class="c1"># Hugo Silva: Nao é anonymous?</span>
<span class="c1"># Tiago Pereira: Não. Tudo visivel</span>
<span class="c1"># Luís Rodrigues: Foi uma bela administração sim senhor.</span>
<span class="c1"># Leonardo Soares: Obrigado a esta administração! Dinâmica, Pacífica, Estruturadora, Libertadora!</span>
<span class="c1"># Leonardo Soares: #XeJonnyLegislativas2026</span>
<span class="c1"># Leonardo Soares: (2026 right? 😅)</span>
<span class="c1"># André Ferreira: PORTUGAL HOJE</span>
<span class="c1"># Raul Carvalho: Ahahaha vamos!!!!</span>
</code></pre></div>
<div class="codehilite"><pre><span></span><code><span class="c1"># remember to learn and tweak these params</span>
<span class="n">generation_params</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">"max_length"</span><span class="p">:</span> <span class="mi">600</span><span class="p">,</span>
<span class="s2">"no_repeat_ngram_size"</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
<span class="s2">"do_sample"</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
<span class="s2">"top_k"</span><span class="p">:</span> <span class="mi">50</span><span class="p">,</span>
<span class="s2">"top_p"</span><span class="p">:</span> <span class="mf">0.95</span><span class="p">,</span>
<span class="s2">"temperature"</span><span class="p">:</span> <span class="mf">0.7</span><span class="p">,</span>
<span class="s2">"num_return_sequences"</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
<span class="s2">"repetition_penalty"</span><span class="p">:</span> <span class="mf">1.3</span><span class="p">,</span>
<span class="p">}</span>
</code></pre></div>
<div class="codehilite"><pre><span></span><code><span class="n">encoded_conversation</span> <span class="o">=</span> <span class="n">tokenizer</span><span class="p">(</span><span class="n">STARTING_TEXT</span><span class="p">,</span> <span class="n">return_tensors</span><span class="o">=</span><span class="s2">"pt"</span><span class="p">)</span><span class="o">.</span><span class="n">input_ids</span><span class="o">.</span><span class="n">to</span><span class="p">(</span>
<span class="n">device</span>
<span class="p">)</span>
<span class="n">output_encoded</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">generate</span><span class="p">(</span><span class="n">encoded_conversation</span><span class="p">,</span> <span class="o">**</span><span class="n">generation_params</span><span class="p">)</span>
<span class="n">output_decoded</span> <span class="o">=</span> <span class="n">tokenizer</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="n">output_encoded</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">skip_special_tokens</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Response:</span><span class="se">\n</span><span class="si">{</span><span class="n">output_decoded</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
<span class="c1"># Response:</span>
<span class="c1"># Raul Carvalho: Mas é uma bela</span>
</code></pre></div>
<p>Another fun thing to do, is to let the model generate conversations completely by himself. </p>
<p>The idea here is to: </p>
<ol>
<li>Start with a real conversation (5 replies)</li>
<li>Generate a response using our model </li>
<li>Create a new exchange (4 real replies + 1 AI generated)</li>
<li>Generate a response </li>
<li>Create a new exchange (3 real replies + 2 AI generated)</li>
<li>etc.. </li>
</ol>
<p>Eventually, we'll end up with a bunch of AI generated conversations from our model! Here's the code to do that: </p>
<div class="codehilite"><pre><span></span><code><span class="n">conversation</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">NUMBER_OF_ROUNDS</span> <span class="o">=</span> <span class="mi">5</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">NUMBER_OF_ROUNDS</span><span class="p">):</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">conversation</span><span class="p">:</span>
<span class="n">conversation</span> <span class="o">=</span> <span class="n">STARTING_TEXT</span>
<span class="n">encoded_conversation</span> <span class="o">=</span> <span class="n">tokenizer</span><span class="p">(</span><span class="n">conversation</span><span class="p">,</span> <span class="n">return_tensors</span><span class="o">=</span><span class="s2">"pt"</span><span class="p">)</span><span class="o">.</span><span class="n">input_ids</span><span class="o">.</span><span class="n">to</span><span class="p">(</span>
<span class="n">device</span>
<span class="p">)</span>
<span class="n">output_encoded</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">generate</span><span class="p">(</span><span class="n">encoded_conversation</span><span class="p">,</span> <span class="o">**</span><span class="n">generation_params</span><span class="p">)</span>
<span class="n">output_decoded</span> <span class="o">=</span> <span class="n">tokenizer</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="n">output_encoded</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">skip_special_tokens</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">conversation</span> <span class="o">=</span> <span class="n">conversation</span> <span class="o">+</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span> <span class="o">+</span> <span class="n">output_decoded</span>
<span class="n">conversation</span> <span class="o">=</span> <span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">conversation</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)[</span><span class="mi">1</span><span class="p">:])</span> <span class="c1"># remove first intervention</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"New conversation:</span><span class="se">\n</span><span class="si">{</span><span class="n">conversation</span><span class="si">}</span><span class="se">\n</span><span class="s2">----"</span><span class="p">)</span>
<span class="c1"># New conversation:</span>
<span class="c1"># Tiago Pereira: 2 votos por pessoa pfv.</span>
<span class="c1"># Hugo Silva: Nao é anonymous?</span>
<span class="c1"># Tiago Pereira: Não. Tudo visivel</span>
<span class="c1"># Luís Rodrigues: Foi uma bela administração sim senhor.</span>
<span class="c1"># Leonardo Soares: Obrigado a esta administração! Dinâmica, Pacífica, Estruturadora, Libertadora!</span>
<span class="c1"># Leonardo Soares: #XeJonnyLegislativas2026</span>
<span class="c1"># Leonardo Soares: (2026 right? 😅)</span>
<span class="c1"># André Ferreira: PORTUGAL HOJE</span>
<span class="c1"># Raul Carvalho: Ahahaha vamos!!!!</span>
<span class="c1"># Raul Carvalho: Ahaha </span>
<span class="c1"># ----</span>
<span class="c1"># New conversation:</span>
<span class="c1"># Hugo Silva: Nao é anonymous?</span>
<span class="c1"># Tiago Pereira: Não. Tudo visivel</span>
<span class="c1"># Luís Rodrigues: Foi uma bela administração sim senhor.</span>
<span class="c1"># Leonardo Soares: Obrigado a esta administração! Dinâmica, Pacífica, Estruturadora, Libertadora!</span>
<span class="c1"># Leonardo Soares: #XeJonnyLegislativas2026</span>
<span class="c1"># Leonardo Soares: (2026 right? 😅)</span>
<span class="c1"># André Ferreira: PORTUGAL HOJE</span>
<span class="c1"># Raul Carvalho: Ahahaha vamos!!!!</span>
<span class="c1"># Raul Carvalho: Ahaha </span>
<span class="c1"># André Ferreira: Pa no estou?</span>
<span class="c1"># ----</span>
<span class="c1"># New conversation:</span>
<span class="c1"># Tiago Pereira: Não. Tudo visivel</span>
<span class="c1"># Luís Rodrigues: Foi uma bela administração sim senhor.</span>
<span class="c1"># Leonardo Soares: Obrigado a esta administração! Dinâmica, Pacífica, Estruturadora, Libertadora!</span>
<span class="c1"># Leonardo Soares: #XeJonnyLegislativas2026</span>
<span class="c1"># Leonardo Soares: (2026 right? 😅)</span>
<span class="c1"># André Ferreira: PORTUGAL HOJE</span>
<span class="c1"># Raul Carvalho: Ahahaha vamos!!!!</span>
<span class="c1"># Raul Carvalho: Ahaha </span>
<span class="c1"># André Ferreira: Pa no estou?</span>
<span class="c1"># André Ferreira: No estou a caralhar</span>
<span class="c1"># ----</span>
<span class="c1"># New conversation:</span>
<span class="c1"># Luís Rodrigues: Foi uma bela administração sim senhor.</span>
<span class="c1"># Leonardo Soares: Obrigado a esta administração! Dinâmica, Pacífica, Estruturadora, Libertadora!</span>
<span class="c1"># Leonardo Soares: #XeJonnyLegislativas2026</span>
<span class="c1"># Leonardo Soares: (2026 right? 😅)</span>
<span class="c1"># André Ferreira: PORTUGAL HOJE</span>
<span class="c1"># Raul Carvalho: Ahahaha vamos!!!!</span>
<span class="c1"># Raul Carvalho: Ahaha </span>
<span class="c1"># André Ferreira: Pa no estou?</span>
<span class="c1"># André Ferreira: No estou a caralhar</span>
<span class="c1"># André Ferreira: Ainda no estou?</span>
<span class="c1"># ----</span>
<span class="c1"># New conversation:</span>
<span class="c1"># Leonardo Soares: Obrigado a esta administração! Dinâmica, Pacífica, Estruturadora, Libertadora!</span>
<span class="c1"># Leonardo Soares: #XeJonnyLegislativas2026</span>
<span class="c1"># Leonardo Soares: (2026 right? 😅)</span>
<span class="c1"># André Ferreira: PORTUGAL HOJE</span>
<span class="c1"># Raul Carvalho: Ahahaha vamos!!!!</span>
<span class="c1"># Raul Carvalho: Ahaha </span>
<span class="c1"># André Ferreira: Pa no estou?</span>
<span class="c1"># André Ferreira: No estou a caralhar</span>
<span class="c1"># André Ferreira: Ainda no estou?</span>
<span class="c1"># Raul Carvalho: Haha nvel queres meeses</span>
<span class="c1"># ----</span>
</code></pre></div>Governo Sombra transcripts2023-04-19T16:30:00+02:002023-04-19T16:30:00+02:00Duarte O.Carmotag:duarteocarmo.com,2023-04-19:/blog/governo-sombra-transcripts.html<p><center>
<a href="https://governosombra.duarteocarmo.com" target="_blank">
<img src="https://duarteocarmo.com/images/51/website.png" alt="governosombra.duarteocarmo.com" style="max-width:100%;border-radius: 2px">
</a>
</center></p>
<p>7 years. That's how long I've lived in Denmark for. I love it, but Portugal is still close to my heart. As an emigrant, it's always hard to stay connected to what's going on in Portugal. What are people talking about? What's in the news? What worries people? What is …</p><p><center>
<a href="https://governosombra.duarteocarmo.com" target="_blank">
<img src="https://duarteocarmo.com/images/51/website.png" alt="governosombra.duarteocarmo.com" style="max-width:100%;border-radius: 2px">
</a>
</center></p>
<p>7 years. That's how long I've lived in Denmark for. I love it, but Portugal is still close to my heart. As an emigrant, it's always hard to stay connected to what's going on in Portugal. What are people talking about? What's in the news? What worries people? What is everyone arguing about over morning coffee? </p>
<p>One of the ways I like to stay in touch is by listening to <em>Governo Sombra</em> (now cleverly called <em>Program whose name we are legally prevented from saying</em>, after changing networks). It's a weekly show where the 3 guests (+1 host) comment on Portuguese and World news. Besides being funny, I also love the fact that the 3 guests represent different parts of the political spectrum, so I can get a good idea about how most of the people are feeling. </p>
<p>Inspired by <a href="https://karpathy.ai/lexicap/">Lexicap</a>, I decided to build a <a href="https://governosombra.duarteocarmo.com">website</a> with the transcripts for all of the episodes of the show. More than once I've listened to a particular part of an episode and wanted to share it with a friend. Now, <a href="https://governosombra.duarteocarmo.com/episodes/171#170">I can do it</a>. </p>
<p>For the transcription, I used OpenAI's Open Source <a href="https://github.com/openai/whisper">Whisper</a> model. With a <em>small</em> caveat: the whole thing (serving + transcribing) needed to run in my 20 EUR/month <a href="/blog/down-from-the-cloud-self-hosting.html">VM</a>. So it needed to be small <em>and</em> efficient. </p>
<p>I like Python, but Rust was the obvious choice. For the transcription part, I used <a href="https://github.com/tazz4843/whisper-rs">whisper.rs</a> (Rust bindings for <a href="https://github.com/ggerganov/whisper.cpp/">whisper.cpp</a>). For serving the app, I went with <a href="https://actix.rs/">Actix Web</a> - it's small, efficient, and reminds me a lot of Flask. Incredible how a small Linux box can handle transcribing 60min+ episodes without hiccuping much. </p>
<p>The quality of the transcription is something like a 6/10. I did use the <a href="https://github.com/openai/whisper#available-models-and-languages">base</a> model so there is <em>clearly</em> space for improvement. Maybe when I get a dedicated box. </p>
<p>The entire thing is up on <a href="https://github.com/duarteocarmo/governosombra">GitHub</a>. </p>LLMs in production: lessons learned2023-03-26T20:35:00+02:002023-03-26T20:35:00+02:00Duarte O.Carmotag:duarteocarmo.com,2023-03-26:/blog/llms-lessons-learned.html<p><center>
<img src="https://duarteocarmo.com/images/50/openai_3.png" alt="OpenAI image 1" style="max-width:100%;border-radius: 2px">
</center></p>
<p>A couple of months ago nobody asked me about my work. <em>Something</em> related to computers and AI. Fast forward to today, even my uncle asks me about ChatGPT. The <a href="https://www.urbandictionary.com/define.php?term=hype"><em>hype</em></a> is real. Only time will tell if the hype will materialize. But while the world wonders, work goes on. </p>
<p>In …</p><p><center>
<img src="https://duarteocarmo.com/images/50/openai_3.png" alt="OpenAI image 1" style="max-width:100%;border-radius: 2px">
</center></p>
<p>A couple of months ago nobody asked me about my work. <em>Something</em> related to computers and AI. Fast forward to today, even my uncle asks me about ChatGPT. The <a href="https://www.urbandictionary.com/define.php?term=hype"><em>hype</em></a> is real. Only time will tell if the hype will materialize. But while the world wonders, work goes on. </p>
<p>In the last couple of months, I've helped develop a product that leverages this tech at its core. It was - to say the least - a learning experience. Full of lessons learned, full of little traumas and things I would've done better. In the hopes of helping someone out there, here are some lessons I've learned along the way. </p>
<h3 id="know-your-use-case">Know your use case</h3>
<p>With so much hype surrounding LLMs, it's easy to think they'll solve all problems in Machine Learning. Or at least the ones related to NLP. From what I've seen, this is hardly the case. Let's split Machine Learning tasks into two types. (1) Predictive tasks, such as classifying the sentiment of a tweet, and (2) generative tasks, such as summarizing the content of an article.</p>
<p>GPT is <em>great</em> at generative tasks. Writing an email with context, writing a summary of a web page, and creating an article given some ideas. These are a very specific subset of Machine Learning. Most of the problems we face are predictive problems: what is the sentiment of this tweet? What is the class of this image? It's hard to tell exactly how good these models will become for the predictive use case. But before throwing GPT at whatever you're facing, think about the use case. This leads me to my next point.</p>
<h3 id="deterministic-vs-stochastic">Deterministic vs. stochastic</h3>
<p>Do you know the classic "<em>I cannot reproduce this issue</em>" we've said oh so many times? Well, welcome to a whole other level of that. "<em>The AI said something wrong</em>" is a very common issue I've faced with these models. At the core, LLMs are stochastic, and not deterministic. Before LLMs, whatever model we were building, given an input, would always produce the same output. With LLMs, given the same input, the output is <em>rarely</em> the same.</p>
<p>This is amazing for generative tasks but can become a real problem for predictive tasks. The problem of reproducibility. To avoid this issue, you can play around with some of the parameters of this model such as the <a href="https://lukesalamone.github.io/posts/what-is-temperature/">temperature</a> or the presence penalty. This further reinforces the idea that these models are great for generating text - where the cost of failure is low. If you're predicting something with a high cost of failure - best beware.</p>
<h3 id="prepare-for-the-future">Prepare for the future</h3>
<p>This tech is moving incredibly fast. Yes, even for <em>us</em>, the group of people that <em>loves</em> to move fast. OpenAI, is releasing models and updates at an astronomical pace. By the time you finished developing that shiny new product, there will probably be a new one. This happened to us actually. We started developing a system based on GPT-3 (e.g., <code>text-davinci-003</code>). Shortly after, OpenAI released the ChatGPT model (e.g., <code>gpt-3.5-turbo</code>). Two days before we went to production - GPT-4 (e.g., <code>gpt-4</code>) was here. </p>
<p>These models use different APIs, structures, and behaviors. Thankfully, I'd spent a Friday afternoon implementing the <a href="https://refactoring.guru/design-patterns/strategy/python/example">Strategy Pattern</a>, so that we could support both <a href="https://platform.openai.com/docs/guides/completion">Text Completion</a> and <a href="https://platform.openai.com/docs/guides/chat">Chat Completion</a> for our system. Turned out to be time well spent, and adopting GPT-4 was a moderate one-line code change. Whenever a new model comes out, expect to be rate limited, and expect timeouts. Especially with these technologies, it's worth preparing for the future, and anticipating what <em>might</em> be released. Without <a href="/blog/simple-software.html">exaggerating</a>, of course. </p>
<p><center>
<img src="https://duarteocarmo.com/images/50/openai_2.png" alt="OpenAI image 2" style="max-width:100%;border-radius: 2px">
</center></p>
<h3 id="streaming-vs-batching">Streaming vs. Batching</h3>
<p>Yes, it comes down to that, a single API call to OpenAI. (Well, at least while we don't have a solid open-source alternative). Given a large enough prompt, these models can take quite a while to return a result. There's nothing worse than making a user wait for 20-30 seconds before showing some action on the screen - especially when that request ends up failing sometimes. After some days of frustration, a co-worker sent me <a href="https://github.com/openai/openai-cookbook/blob/main/examples/How_to_stream_completions.ipynb">this</a> link. </p>
<p>Instead of waiting for the whole completion to be finished, consider streaming the response. In short, it allows you to start receiving completion tokens as soon as they're generated. Together with FastAPI's excellent implementation of <a href="https://fastapi.tiangolo.com/advanced/custom-response/#streamingresponse"><code>StreamingResponse</code></a>, it allows you to show the completion happening in real-time to users. This pattern is widely used by implementations such as <a href="https://www.notion.so/product/ai">Notion's</a>. Now that all we have is an API, customer experience is even more differentiating. </p>
<h3 id="prompt-engineering-is-hard">Prompt engineering is hard</h3>
<p>We have prompt engineers now. No wonder. I prefer the term prompt <em>artists</em>. As soon as we had to put a system in place we struggled. We are used to fancy tools to track every parameter of an experiment. Now that we're designing prompts for a stochastic system the game has changed. How can know the impact of every little change in the prompt? How can I know how one instruction affects another instruction? What really defines a <em>good</em> prompt? You see where I'm getting at. For now, it's an art - more than engineering. </p>
<p>Very soon, our prompt was a list of 10-15 instructions giving very specific directions on what we needed to generate. To battle this, we created a set of scripts that would allow us to quickly compare the impact of small changes in the prompt. This is a costly exercise - given a stochastic system - since we have to call a paid API 2/3x to compare the effect of prompt changes. This allowed us to at least get a decent direction on how good the prompt is. Still, I feel like prompt engineering is still a lot of shooting in the dark. </p>
<h3 id="conclusion-not-the-hammer-you-were-looking-for">Conclusion: Not the hammer you were looking for</h3>
<p>LLMs are incredibly powerful tools. From generating text to now even supporting images - it's hard to tell where the field will lead us. For creative and generative tasks they shine like nothing before in our field. Being able to have access to such a powerful system will be groundbreaking in a lot of fields of machine learning. But with great power comes great responsibility - or <em>baggage</em>. </p>
<p>Putting an LLM into production is a challenging problem with a lot of unknowns. From depending on a simple API call, to not being able to reproduce results - it can get complicated. </p>
<p>If the task is simple enough (e.g., classification) it's still hard to justify a more expensive, less explainable, and albeit slower system than <em>traditional</em> methods. I don't think this is the hammer for all our problems. At least not <em>yet</em>. </p>parlabot - ask the Portuguese parliament2023-02-27T18:55:00+01:002023-02-27T18:55:00+01:00Duarte O.Carmotag:duarteocarmo.com,2023-02-27:/blog/parlabot.html<p>Large language models (LLM) are really <a href="https://www.theverge.com/2023/2/8/23590864/google-ai-chatbot-bard-mistake-error-exoplanet-demo">dumb</a>. I mean, how can you fail when the question is as simple as "<em>What is 23 times 18</em>"? Even though they're making most headlines, at the end of the day, these models are, predicting the next token based on the previous ones. If …</p><p>Large language models (LLM) are really <a href="https://www.theverge.com/2023/2/8/23590864/google-ai-chatbot-bard-mistake-error-exoplanet-demo">dumb</a>. I mean, how can you fail when the question is as simple as "<em>What is 23 times 18</em>"? Even though they're making most headlines, at the end of the day, these models are, predicting the next token based on the previous ones. If we ask a super simple question without any context to an LLM, the performance will only depend on <a href="https://arxiv.org/pdf/2202.07206.pdf">how much the model has seen that example</a>.</p>
<p>But LLMs are also amazing. Have you used <a href="https://github.com/features/copilot">GitHub copilot</a> lately? I don't trust it to write my functions for me, but damn it writes a good boilerplate. It's like auto-complete, but <em>better</em>. It doesn't only know your imports. It knows where you are in the code base, and can suggest based on that. </p>
<p>The difference? <em>Context</em>. When using copilot, your code <em>is</em> the context, and that's why copilot knows exactly what to suggest. So how can I give the right context to one of these models? To answer this, I built <a href="https://parlabot.duarteocarmo.com/">parlabot</a>. Parlabot (<a href="https://www.collinsdictionary.com/dictionary/portuguese-english/parlamento">parlamento</a> + bot) uses all transcripts from the Portuguese parliament to answer any question you might have about Portuguese politics. It also (tries) to do so in the most truthful way it can, with the information it has.</p>
<p><a target="_blank" href="https://parlabot.duarteocarmo.com">
<img src="https://duarteocarmo.com/images/49/parlabot-screenshot.png" alt="Parlabot website" style="max-width:100%;">
</a></p>
<p>There are two things at play when you ask a question to parlabot. Below is a sketch that might make things easier to follow.</p>
<p>The first part is the search engine. To make this work, I scrapped all transcripts from the Portuguese parliament and used a multilingual embedding model to transform them into vectors. Whenever you type in a question, I embed it using the same exact model, transforming it into another vector. I then find the top k most similar reference vectors to the query vector. This is the same as finding the top K most relevant speech segments for that question. </p>
<p>Once I have the most relevant speech segments, it's time to build the <em>prompt</em>. The prompt, has two parts, the <em>context</em>, and the <em>direction</em>. The context, is simply the most relevant speech segments, the corresponding speakers, and the political parties. In the direction part of the prompt, I ask GPT3 to answer a given question using the segments from the context.</p>
<p><a target="_blank" href="https://parlabot.duarteocarmo.com">
<img src="https://duarteocarmo.com/images/49/LLM-sketch.png" alt="LLM Question/Answer system" style="max-width:100%;border-radius: 2px">
</a></p>
<p>The results are pretty good! The bot is very capable of using the context given to answer most questions. Of course, the context is not always relevant to a question. For example, if you ask "How to bake a cake?", it's unlikely we'll find the answer in the data set of parliament transcriptions. With good prompt design, we can make the bot answer "<em>I don't know</em>" when this is the case. </p>
<p>The mix of LLMs, politics, and poorly written code is a great recipe for disaster. Although disaster does sound pretty fun, I don't expect this bot to answer <em>truthfully</em> any of the questions Portuguese tax-payers have about elected parties. These answers should be taken with a massive grain of salt and skepticism. LLMs are stochastic beasts that might predict two different outputs with the exact same set of inputs. </p>
<p>Still, this system might be interesting to solve problems where the cost of failure is not catastrophic. Without forgetting, that a bit of skepticism is a great foundation for any ML system. </p>An opinionated Python boilerplate2023-02-18T00:00:00+01:002023-02-18T00:00:00+01:00Duarte O.Carmotag:duarteocarmo.com,2023-02-18:/blog/opinionated-python-boilerplate.html<p>There's nothing quite like starting a new project. A greenfield, <em>filled</em> with possibilities. It's a privilege many don't come across. A lot of us, get thrown into projects with a lot of legacy code. But sometimes, we start from scratch.</p>
<p>This is the time. The time to make all the …</p><p>There's nothing quite like starting a new project. A greenfield, <em>filled</em> with possibilities. It's a privilege many don't come across. A lot of us, get thrown into projects with a lot of legacy code. But sometimes, we start from scratch.</p>
<p>This is the time. The time to make all the right calls. The time to use the right tools, the right abstractions, and the right structure. The unfortunate truth is, <a href="/blog/simple-software.html">there is no <em>right</em> way</a>. There are just <em>ways.</em> Most of us use the tools we're comfortable with. We've tried things in the past. Some worked, some didn't. </p>
<p>I've started my fair share of Python projects. By failing, <em>a lot</em>, I've converged to a set of tools. These will change over time. But in the hope to help a fellow Pythonista out there, let's talk about them. </p>
<h2 id="pip-tools-for-dependency-management"><a href="https://pip-tools.readthedocs.io/en/latest/">Pip-tools</a> for dependency management</h2>
<p>Now I don't want to start a packaging war. If <a href="https://python-poetry.org/">Poetry</a> works for you, then by all means, go for it. I've tried most of the stuff out there, from the good old <code>pip freeze > requirements.txt</code>, <a href="https://pipenv.pypa.io/en/latest/">pipenv</a>, all the way to Poetry. After many battles, I've stuck with <a href="https://github.com/jazzband/pip-tools">pip-tools</a>. Pip-tools strikes the right balance between simplicity, effectiveness, and speed. And yes, <em>speed</em> matters. I don't want to wait a whole minute for my dependencies to compile. </p>
<p>With recent pip updates, I can just specify my dependencies in a <code>pyproject.toml</code> and install them with <code>pip install -e .</code>. However, there are benefits to pinning your dependencies using something like <a href="https://github.com/jazzband/pip-tools#pip-tools--pip-compile--pip-sync">pip-tools</a>. Especially in Machine Learning environments. Yes Anaconda exists - but speed <em>is</em> a requirement. </p>
<p>The folks at <a href="https://jazzband.co/">Jazzband</a> have created an easy-to-use tool that has yet to let me down. For example, suppose I have a <code>dreambox</code> project. Here's an example <code>pyproject.toml</code> file:</p>
<div class="codehilite"><pre><span></span><code><span class="k">[build-system]</span>
<span class="n">requires</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">"hatchling"</span><span class="p">]</span>
<span class="n">build-backend</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"hatchling.build"</span>
<span class="k">[project]</span>
<span class="n">name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"dreambox"</span>
<span class="n">version</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"42"</span>
<span class="n">dependencies</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">"pandas>=1.5.3"</span><span class="p">,</span><span class="w"> </span><span class="s2">"numpy"</span><span class="p">,</span><span class="w"> </span><span class="s2">"fastapi"</span><span class="p">]</span>
<span class="k">[project.optional-dependencies]</span>
<span class="n">dev</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">"pytest"</span><span class="p">]</span>
</code></pre></div>
<p>To create a pinned and hashed <code>requirements</code> file , all you need to do is:</p>
<div class="codehilite"><pre><span></span><code><span class="o">(</span>env<span class="o">)</span><span class="w"> </span>$<span class="w"> </span>pip-compile<span class="w"> </span>--generate-hashes<span class="w"> </span>--output-file<span class="o">=</span>requirements.txt<span class="w"> </span>pyproject.toml
<span class="o">(</span>env<span class="o">)</span><span class="w"> </span>$<span class="w"> </span>pip-compile<span class="w"> </span>--generate-hashes<span class="w"> </span>--extra<span class="o">=</span>dev<span class="w"> </span>--output-file<span class="o">=</span>requirements-dev.txt<span class="w"> </span>pyproject.toml
</code></pre></div>
<p>That ensures whatever you build in production is reproducible in my own machine, to the exact dependency and hash. </p>
<h2 id="pyprojecttoml-for-configuration"><a href="https://peps.python.org/pep-0621/">Pyproject.toml</a> for configuration</h2>
<p>Who likes configuration files? I certainly don't. There's nothing nice about having 15 configuration files at the root of my project. One for test coverage, one for linting, one for GitHub, one for formatting, and another one for CI. No thanks.</p>
<p>Fortunately, <a href="https://peps.python.org/pep-0621/">PEP 621</a> happened. And with it, a (mostly) common way to store all of the metadata and configuration for a Python project. Using a <em>single</em> <code>pyproject.toml</code>, I can define my local package name and details, my pinned dependencies, my pytest coverage configuration, my formatting configuration, my... You get me. All the configurations, in a <em>single</em> file. Expand the example below for an example.</p>
<details>
<summary>An example <code>pyproject.toml</code></summary>
<div class="codehilite"><pre><span></span><code><span class="c1"># packaging information</span>
<span class="k">[build-system]</span>
<span class="n">requires</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">"hatchling"</span><span class="p">]</span>
<span class="n">build-backend</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"hatchling.build"</span>
<span class="c1"># project information</span>
<span class="k">[project]</span>
<span class="n">name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"dreambox"</span>
<span class="n">version</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"23.1.26"</span>
<span class="n">readme</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"README.md"</span>
<span class="n">requires-python</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">">=3.10"</span>
<span class="c1"># requirements.txt generated from here</span>
<span class="n">dependencies</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="s2">"Jinja2>=3.1.2"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"loguru>=0.6.0"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"fastapi>=0.88.0"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"uvicorn>=0.20.0"</span><span class="p">,</span>
<span class="p">]</span>
<span class="c1"># requirements-dev.txt generated from here</span>
<span class="k">[project.optional-dependencies]</span>
<span class="n">dev</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span>
<span class="w"> </span><span class="s2">"black>=22.10.0"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"isort>=5.10.1"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"pip-tools>=6.10.0"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"pytest>=7.2.0"</span><span class="p">,</span>
<span class="w"> </span><span class="s2">"pytest-cov>=4.0.0"</span><span class="p">,</span>
<span class="p">]</span>
<span class="c1"># linting config</span>
<span class="k">[tool.ruff]</span>
<span class="n">ignore</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">"E501"</span><span class="p">]</span>
<span class="c1"># isort config</span>
<span class="k">[tool.isort]</span>
<span class="n">profile</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"black"</span>
<span class="n">line_length</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">79</span>
<span class="n">skip</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">".env/"</span><span class="p">,</span><span class="w"> </span><span class="s2">"venv"</span><span class="p">,</span><span class="w"> </span><span class="s2">".venv"</span><span class="p">]</span>
<span class="c1"># coverage config</span>
<span class="k">[tool.coverage.paths]</span>
<span class="n">source</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s2">"src"</span><span class="p">]</span>
<span class="k">[tool.coverage.run]</span>
<span class="n">branch</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">true</span>
<span class="n">relative_files</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">true</span>
<span class="k">[tool.coverage.report]</span>
<span class="n">show_missing</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">true</span>
<span class="n">fail_under</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">80</span>
<span class="c1"># formatting config</span>
<span class="k">[tool.black]</span>
<span class="n">line-length</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">79</span>
<span class="n">extend-exclude</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'''</span>
<span class="s1">/(</span>
<span class="s1"> | .env</span>
<span class="s1"> | .venv</span>
<span class="s1"> | venv</span>
<span class="s1"> | notebooks</span>
<span class="s1">)/</span>
<span class="s1">'''</span>
</code></pre></div>
</details>
<h2 id="makefiles-for-common-sense"><a href="https://makefiletutorial.com/#top">Makefiles</a> for common sense</h2>
<p>I clone a new repo. Now, where the hell do I start? How do I run the tests? How do I run the API? There should be a common standard for these things right? <em>Wrong</em>. Every project is different. Every project has its pet peeves. I don't really like pet peeves. Anyone should be able to pick up my project and get up and running straight away. No meetings, no calls, just start working. A well-documented <code>README.MD</code> might work. But you'll get lazy. </p>
<p>So what is the easiest way to add a good project "map", without much work? Enter my Makefile. With a Makefile, I define all of the main project commands in a single file. For example: </p>
<div class="codehilite"><pre><span></span><code><span class="c">## Install for production</span>
<span class="nf">install</span><span class="o">:</span>
<span class="w"> </span>python<span class="w"> </span>-m<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>--upgrade<span class="w"> </span>pip
<span class="w"> </span>python<span class="w"> </span>-m<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>-e<span class="w"> </span>.
<span class="c">## Install for development </span>
<span class="nf">install-dev</span><span class="o">:</span><span class="w"> </span><span class="n">install</span>
<span class="w"> </span>python<span class="w"> </span>-m<span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>-e<span class="w"> </span><span class="s2">".[dev]"</span>
<span class="c">## Build dependencies</span>
<span class="nf">build</span><span class="o">:</span><span class="w"> </span>
<span class="w"> </span>pip-compile<span class="w"> </span>--resolver<span class="o">=</span>backtracking<span class="w"> </span>--output-file<span class="o">=</span>requirements.txt<span class="w"> </span>pyproject.toml
<span class="w"> </span>pip-compile<span class="w"> </span>--resolver<span class="o">=</span>backtracking<span class="w"> </span>--extra<span class="o">=</span>dev<span class="w"> </span>--output-file<span class="o">=</span>requirements-dev.txt<span class="w"> </span>pyproject.toml
</code></pre></div>
<p>If I want to install the dependencies on a project, all I do is <code>make install</code>. Or <code>make install-dev</code> for the dev dependencies as well. This is nice. But my <em>favorite</em> feature is this:</p>
<p><center>
<img src="https://duarteocarmo.com/images/48/make-help.png" alt="Make help command" style="max-width:100%;border-radius: 2px">
</center>
With the help of <a href="https://gist.github.com/klmr/575726c7e05d8780505a">this</a> small script at the end of my Makefile, I can generate a map for my project. Now, whenever someone new comes in, all they have to do is <code>make help</code>, and they'll get a good idea of how to navigate things. The script takes the comment above every rule in the Makefile, so it's super easy to add new commands to it. </p>
<p>Now isn't that nice? </p>
<h2 id="ruff-for-linting"><a href="https://github.com/charliermarsh/ruff">Ruff</a> for linting</h2>
<p>I like Python, but I also like <a href="/blog/on-rust.html">Rust</a> a lot. <a href="https://github.com/charliermarsh/ruff">Ruff</a> is a new (and shiny) Python linter written in Rust. It's probably the most modern project in my boilerplate. It does what any linter should do, it should flag errors and bad practices. I like catching errors before they blow up in the user's face.</p>
<p>Most importantly, Ruff is fast. <a href="https://www.reddit.com/r/ProgrammingLanguages/comments/v69shk/what_makes_languages_blazingly_fast/"><em>Blazingly</em></a> fast one might say? Running <code>ruff</code> in our project will probably take less than half a second. Also, like all other tools I mentioned here, Ruff supports <code>pyproject.toml</code> for configuration. So you don't have to have to maintain <em>yet</em> another file. (I'm looking at you <a href="https://github.com/PyCQA/flake8/issues/234">flake8</a>)</p>
<h2 id="black-isort-for-formatting"><a href="https://black.readthedocs.io/en/stable/">Black</a> & <a href="https://pycqa.github.io/isort/">isort</a> for formatting</h2>
<p>I never got the whole tabs vs. spaces thing. But I do know programmers have opinions. So many opinions. A cool thing about working in software is that you can use software to <em>squash</em> those opinions. We just agree on using a couple of tools to format our code, all other discussions become useless. So thanks, <a href="https://lukasz.langa.pl/">Łukasz</a>, for creating <a href="https://github.com/psf/black">Black</a>. </p>
<p>Most of my projects have a great <code>make format</code> rule, that runs <code>black</code> and <code>isort</code>. The configuration? It's in my <code>pyproject.toml</code> file above. </p>
<div class="codehilite"><pre><span></span><code><span class="c">## Format files using black</span>
<span class="nf">format</span><span class="o">:</span>
<span class="w"> </span>isort<span class="w"> </span>.
<span class="w"> </span>black<span class="w"> </span>.
</code></pre></div>
<p><em>Note: Apparently ruff <a href="https://twitter.com/charliermarsh/status/1597661264800813056">supports</a> import sorting now? Wow. My boilerplate is already obsolete.</em> </p>
<h2 id="pre-commit-hooks-i-dont">pre-commit hooks (I don't)</h2>
<p>I've seen a lot of projects adopt <a href="https://pre-commit.com/">pre-commit</a> hooks as a way of enforcing standards for code. Whether it's to make sure tests pass or to ensure nothing gets raised by linters, pre-commit hooks are all the rage. The thing is, git is already <em>pretty</em> complicated. I mostly work with data scientists, and most of them already face a steep curve in adopting software practices. From my (opinionated) experience, pre-commit hooks make things even more complicated.</p>
<p>But yes, some standards should be enforced, otherwise, something will break for sure. But isn't that what CI is for? Enforcing something like formatting and linting is easy with the <code>--check</code> flag: </p>
<div class="codehilite"><pre><span></span><code><span class="c">## Run checks (ruff + test)</span>
<span class="nf">check</span><span class="o">:</span>
<span class="w"> </span>ruff<span class="w"> </span>.
<span class="w"> </span>isort<span class="w"> </span>--check<span class="w"> </span>.<span class="w"> </span>
<span class="w"> </span>black<span class="w"> </span>--check<span class="w"> </span>.
</code></pre></div>
<p>If I run <code>make check</code> and something doesn't comply, I'll get an error. When opening a PR with a new feature, CI can take care of all of those checks: </p>
<div class="codehilite"><pre><span></span><code><span class="nt">on</span><span class="p">:</span>
<span class="w"> </span><span class="nt">pull_request</span><span class="p">:</span>
<span class="nt">jobs</span><span class="p">:</span>
<span class="w"> </span><span class="nt">test</span><span class="p">:</span>
<span class="w"> </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">ubuntu-latest</span>
<span class="w"> </span><span class="nt">steps</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">actions/checkout@v2</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Install dev requirements</span>
<span class="w"> </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">make install-dev</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Check formatting</span><span class="w"> </span><span class="c1"># <- if this does not pass</span>
<span class="w"> </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">make check</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Run tests</span><span class="w"> </span><span class="c1"># <- you don't get here</span>
<span class="w"> </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">make test</span>
</code></pre></div>
<p>If something doesn't run, CI doesn't pass. No need to mess around with git in everyone's machine. Everyone is free to commit whatever they want - and will get notified if something is not working. That's good enough. </p>
<h2 id="an-example-project">An example project</h2>
<p>At some of my previous <a href="/talks">talks</a>, people normally ask me to share my project template (e.g., my <a href="https://cookiecutter.readthedocs.io/en/stable/">cookiecutter</a>). For me, sharing project templates it's a bit like copying someone else's Vim config. As soon as you need to tweak something (and trust me, you will), you'll have a headache. </p>
<p>This boilerplate is made of choices (or traumas) I've experienced over time. It's tailored exactly to <em>my</em> needs (e.g., data science, machine learning, API design). I like <a href="/blog/simple-software.html">simple</a> things a lot. </p>
<p>I do think it could serve some as a starting point for their own <em>opinionated</em> boilerplate. So <a href="https://github.com/duarteocarmo/boilerplate">here's</a> the code, fellow Pythonista. Have fun out there. </p>
<hr>
<h4 id="updates-notes">Updates & notes</h4>
<ul>
<li>This post was featured in <a href="https://www.youtube.com/live/Mh760W_M2ro?feature=share&t=1040">Episode #326</a> of the PythonBytes podcast </li>
</ul>On Rust2023-01-02T00:00:00+01:002023-01-02T00:00:00+01:00Duarte O.Carmotag:duarteocarmo.com,2023-01-02:/blog/on-rust.html<p>It's that time of the year again. The family is getting together and celebrating. Grandma is cooking something amazing for dinner. I'm trying to solve <a href="https://adventofcode.com/">Advent of Code</a> puzzles. This year, I decided to do something <em>different</em>. Instead of solving the puzzles in Python, I decided that I would try …</p><p>It's that time of the year again. The family is getting together and celebrating. Grandma is cooking something amazing for dinner. I'm trying to solve <a href="https://adventofcode.com/">Advent of Code</a> puzzles. This year, I decided to do something <em>different</em>. Instead of solving the puzzles in Python, I decided that I would try to solve them in <a href="https://www.rust-lang.org/">Rust</a>. Why?</p>
<p>Rust has been getting a lot of attention lately. The language is in its <em>7th</em> year as the <a href="https://survey.stackoverflow.co/2022/#technology-most-loved-dreaded-and-wanted">most loved programming language</a> according to the latest Stack Overflow developer survey. Why do people love it so much? So I decided to learn it. What better way to get frustrated during my Christmas break?</p>
<h2 id="things-i-like">Things I like</h2>
<p><strong>Speed.</strong> That's the first thing I noticed. I brute force <em>a lot</em> of these AoC puzzles. Rust handled them without hiccups. It's a bit like the feeling of using Numpy if you're a Python dev. Having been one for some years, I never got much exposure to compiled languages like C++ or Java. I can't help but notice a pretty big difference in speed compared to Python or JavaScript.</p>
<p><strong>Effectiveness.</strong> Most puzzles I solved were right on the first try. This is rarely the case with Python. Rather than using types as more of a <em>decorative/ergonomic</em> feature like in Python, in Rust, these types are strictly enforced at compile time. This made me think twice about the code I wrote. But also lead to more correct code. <a href="https://rust-analyzer.github.io/">Rust-analyzer</a>, Rust's LSP, was also a great experience. Giving timely, useful, and clear messages about what was wrong. </p>
<p><strong>Syntax.</strong> The syntax is not that different from Python. For loops are easy and readable with the <code>for x in y</code> syntax, for example. <a href="https://doc.rust-lang.org/beta/rust-by-example/fn/closures.html">Closures</a> remind me a lot of lambda functions in Python. I can also see why Python adopted the <a href="https://doc.rust-lang.org/rust-by-example/flow_control/match.html">match</a> statement. In general, Rust was readable. Whenever code got complicated and repetitive, things like <a href="https://doc.rust-lang.org/rust-by-example/macros.html">macros</a> came to the rescue. </p>
<p><strong>Ecosystem.</strong> Compared to Pip, <a href="https://doc.rust-lang.org/cargo/guide/index.html">Cargo</a> is a breath of fresh air. Installing packages is as easy as copy-pasting into your <code>Cargo.toml</code> file. In my experience, even larger packages such as <a href="https://docs.rs/nalgebra/latest/nalgebra/">naglebra</a> have been fast to install. To check the documentation of all packages installed locally, you can also use <code>cargo doc --open</code>, which is great for offline development. There are also good resources online when you're feeling stuck, like the <a href="https://doc.rust-lang.org/book/">Rust Programming Language Book</a>, or the more practical <a href="https://doc.rust-lang.org/stable/rust-by-example/">Rust by Example</a>. </p>
<h2 id="things-i-dont-like-yet">Things I don't like (yet)</h2>
<p><strong>Efficiency.</strong> Rust takes longer to write. Probably, due to my lack of experience. I get the impression programs need to be better thought out. You'll take longer to write code, but it will be more <em>effective</em> code. This makes Rust great for production. However, it's hard to think of Rust as a good language to experiment, explore, or even iterate quickly. Experimentation is a great advantage of languages like Python or JavaScript. It's a trade-off. </p>
<p><strong>Types.</strong> I like types. I've been using types in most of my Python production applications. Not only that, but I believe I now understand better why Python doesn't <em>enforce</em> types. Types help you write more <em>correct</em> programs, but it's easy to get stuck in type hell. I don't know if I want a <code>usize</code> or an <code>int32</code>. I don't care if it's a <code>Matrix</code> or a <code>DMatrix</code>, or <code>f32</code> or <code>f64</code>. The Rust compiler does. When I'm focused on solving a problem, I'm not interested in solving a <em>type</em> problem. Types are great. But if you get too strict about them, types can get in the way. I felt Rust types got in the way a lot of times.</p>
<p><strong>Ecosystem.</strong> Rust's ecosystem is still young. Yes, AoC puzzles are very specific and don't represent the real world. But when looking for libraries, for example, it appears Rust is still trying to figure out where does lie. This is normal. There are not that many resources on the internet <em>yet</em>. For a beginner programmer in any language, the quality of web resources is everything. When looking for answers and resources on Rust, it takes longer to find the right resources. When looking for libraries, it's tough to understand which libraries are the most popular ones, or the ones to go from. Even though things are developing <a href="https://lib.rs/">quickly</a>. </p>
<div class="codehilite"><pre><span></span><code><span class="k">struct</span> <span class="nc">Vector3</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">x</span>: <span class="kt">f32</span><span class="p">,</span>
<span class="w"> </span><span class="n">y</span>: <span class="kt">f32</span><span class="p">,</span>
<span class="w"> </span><span class="n">z</span>: <span class="kt">f32</span>
<span class="p">}</span>
<span class="k">fn</span> <span class="nf">dot_product</span><span class="p">(</span><span class="n">a</span>: <span class="nc">Vector3</span><span class="p">,</span><span class="w"> </span><span class="n">b</span>: <span class="nc">Vector3</span><span class="p">)</span><span class="w"> </span>-> <span class="nc">float</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">a</span><span class="p">.</span><span class="n">x</span><span class="o">*</span><span class="n">b</span><span class="p">.</span><span class="n">x</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">a</span><span class="p">.</span><span class="n">y</span><span class="o">*</span><span class="n">b</span><span class="p">.</span><span class="n">y</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">a</span><span class="p">.</span><span class="n">z</span><span class="o">*</span><span class="n">b</span><span class="p">.</span><span class="n">z</span>
<span class="p">}</span>
<span class="k">fn</span> <span class="nf">do_math_by_copy</span><span class="p">(</span><span class="n">p1</span>: <span class="nc">Vector3</span><span class="p">,</span><span class="w"> </span><span class="n">p2</span>: <span class="nc">Vector3</span><span class="p">,</span><span class="w"> </span><span class="n">d1</span>: <span class="nc">Vector3</span><span class="p">,</span><span class="w"> </span><span class="n">d2</span>: <span class="nc">Vector3</span><span class="p">,</span><span class="w"> </span><span class="n">s</span>: <span class="kt">f32</span><span class="p">,</span><span class="w"> </span><span class="n">t</span>: <span class="kt">f32</span><span class="p">)</span><span class="w"> </span>-> <span class="kt">f32</span> <span class="p">{</span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">p1</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">s</span><span class="o">*</span><span class="n">d1</span><span class="p">;</span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">p2</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">s</span><span class="o">*</span><span class="n">d2</span><span class="p">;</span>
<span class="w"> </span><span class="n">dot_product</span><span class="p">(</span><span class="n">b</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">a</span><span class="p">,</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">a</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">fn</span> <span class="nf">do_math_by_borrow</span><span class="p">(</span><span class="n">p1</span>: <span class="kp">&</span><span class="nc">Vector3</span><span class="p">,</span><span class="w"> </span><span class="n">p2</span>: <span class="kp">&</span><span class="nc">Vector3</span><span class="p">,</span><span class="w"> </span><span class="n">d1</span>: <span class="kp">&</span><span class="nc">Vector3</span><span class="p">,</span><span class="w"> </span><span class="n">d2</span>: <span class="kp">&</span><span class="nc">Vector3</span><span class="p">,</span><span class="w"> </span><span class="n">s</span>: <span class="kt">f32</span><span class="p">,</span><span class="w"> </span><span class="n">t</span>: <span class="kt">f32</span><span class="p">)</span><span class="w"> </span>-> <span class="kt">f32</span> <span class="p">{</span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">p1</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="o">&</span><span class="p">(</span><span class="o">&</span><span class="n">d1</span><span class="o">*</span><span class="n">s</span><span class="p">);</span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">b</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">p2</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="o">&</span><span class="p">(</span><span class="o">&</span><span class="n">d2</span><span class="o">*</span><span class="n">t</span><span class="p">);</span>
<span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">dot_product</span><span class="p">(</span><span class="o">&</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="o">&</span><span class="n">a</span><span class="p">),</span><span class="w"> </span><span class="o">&</span><span class="p">(</span><span class="o">&</span><span class="n">b</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="o">&</span><span class="n">a</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div>
<p><strong>Borrowing.</strong> References and borrowing have been the hardest concepts to grasp for me. Again. This might be very well due to my lack of experience in compiled languages. Look at the example above, taken from <a href="https://www.forrestthewoods.com/blog/should-small-rust-structs-be-passed-by-copy-or-by-borrow/">this</a> great post. There is no obvious reason why you would go with <code>do_math_by_borrow</code>. It's uglier, less readable, and to the best of my knowledge, <em>not</em> significantly faster. This whole borrowing and ownership dance is probably necessary for Rust. But I felt like doing a lot of <code>.Clone()</code> and <code>.Copy()</code> to escape this problem. </p>
<h2 id="closing-thoughts">Closing thoughts</h2>
<p>AoC was great to learn a new language! Perhaps next year something easier though. I didn't finish all the puzzles <a href="https://github.com/duarteocarmo/advent2022/">by any means</a>. But by day 10, I had a good grasp of the basics of Rust and could write simple programs without too much hassle. The problem with AoC is the steep curve in puzzle difficulty. By day 15, I was already spending one hour just to parse the input correctly. </p>
<p>I can understand why Rust is loved. It's fast, effective, and it makes you a better programmer. It requires you to make deliberate choices on every variable you create, and every statement you write. This is a double-edged sword. On one side, it makes you write better and safer code. On the other side, it makes you write code slower, and experiments should be fast. It does look great for production. But it's <a href="https://mdwdotla.medium.com/using-rust-at-a-startup-a-cautionary-tale-42ab823d9454">early</a> still. </p>
<p>I would love to try and write some Machine Learning APIs in Rust. Written in Rust, they might be safer and faster! But for that to happen, I would need to be able to load models using Rust. This means loading Scikit, Transformer, or even PyTorch models with Rust. I don't think we are there yet. But when we are, I would love to give it a go. </p>Scaling Machine Learning microservices2022-12-18T00:00:00+01:002022-12-18T00:00:00+01:00Duarte O.Carmotag:semaphoreci.com,2022-12-18:/blog/machine-learning-microserviceMonitoring Machine Learning APIs2022-12-06T10:30:00+01:002022-12-06T10:30:00+01:00Duarte O.Carmotag:duarteocarmo.com,2022-12-06:/blog/monitoring-machine-learning-apis.html<p>Last Friday I <a href="/talks">presented</a> at PyData Global. I talked about <em>monitoring</em>, but felt like there was more I should've said. So this article is just about that. </p>
<p>Even though the number of models in the wild is growing, the field of monitoring is still green and full of unknowns. </p>
<p>Almost …</p><p>Last Friday I <a href="/talks">presented</a> at PyData Global. I talked about <em>monitoring</em>, but felt like there was more I should've said. So this article is just about that. </p>
<p>Even though the number of models in the wild is growing, the field of monitoring is still green and full of unknowns. </p>
<p>Almost all models I've put into customers' hands have had some sort of monitoring. In my head, I've divided ML monitoring in three main areas. </p>
<p>Let's explore them.</p>
<h2 id="logs-error-monitoring">Logs & Error monitoring</h2>
<p>This first area is responsible for monitoring three things: </p>
<ol>
<li><em>Errors</em>: Something in the application blew up, and needs to be checked (e.g., trace backs, etc.)</li>
<li><em>Logs</em>: What's going on? When is it going on? </li>
<li><em>Performance</em>: How fast is the API? How much load can it take?</li>
</ol>
<p>This is very similar to traditional software observability. And yes, most machine learning applications - are, in fact, <em>software</em> applications. This means we have all the concerns of traditional software, and <em>then some</em>. </p>
<p>When it comes to logging, <a href="https://github.com/Delgan/loguru">loguru</a> has made life easier. At the end of the day, who likes to configure loggers? </p>
<p><center>
<img src="https://duarteocarmo.com/images/45/monitoring-sketch-1.png" alt="Logs/Error monitoring of ML Apps" style="max-width:100%;border-radius: 2px">
</center></p>
<p>Another less known component is <a href="https://opentelemetry.io/">OpenTelemetry</a>. OpenTelemetry has slowly become the standard in observability. Think of it as a wrapper that allows you to capture useful statistics on the performance of your app. It also allows you to capture some custom events/data that are useful for debugging. </p>
<p>Here's an example:</p>
<div class="codehilite"><pre><span></span><code><span class="kn">import</span> <span class="nn">fastapi</span>
<span class="kn">from</span> <span class="nn">opentelemetry</span> <span class="kn">import</span> <span class="n">trace</span>
<span class="kn">from</span> <span class="nn">opentelemetry.exporter.otlp.proto.http.trace_exporter</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">OTLPSpanExporter</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span> <span class="nn">opentelemetry.instrumentation.fastapi</span> <span class="kn">import</span> <span class="n">FastAPIInstrumentor</span>
<span class="kn">from</span> <span class="nn">opentelemetry.sdk.trace</span> <span class="kn">import</span> <span class="n">TracerProvider</span>
<span class="kn">from</span> <span class="nn">opentelemetry.sdk.trace.export</span> <span class="kn">import</span> <span class="n">BatchSpanProcessor</span>
<span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="n">Result</span><span class="p">,</span> <span class="n">Item</span>
<span class="c1"># set up tracing and open telemetry </span>
<span class="n">provider</span> <span class="o">=</span> <span class="n">TracerProvider</span><span class="p">()</span>
<span class="n">processor</span> <span class="o">=</span> <span class="n">BatchSpanProcessor</span><span class="p">(</span><span class="n">OTLPSpanExporter</span><span class="p">())</span>
<span class="n">provider</span><span class="o">.</span><span class="n">add_span_processor</span><span class="p">(</span><span class="n">processor</span><span class="p">)</span>
<span class="n">trace</span><span class="o">.</span><span class="n">set_tracer_provider</span><span class="p">(</span><span class="n">provider</span><span class="p">)</span>
<span class="n">tracer</span> <span class="o">=</span> <span class="n">trace</span><span class="o">.</span><span class="n">get_tracer</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
<span class="c1"># instrument FastAPI</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">fastapi</span><span class="o">.</span><span class="n">FastAPI</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="s2">"demo"</span><span class="p">)</span>
<span class="n">FastAPIInstrumentor</span><span class="o">.</span><span class="n">instrument_app</span><span class="p">(</span><span class="n">app</span><span class="p">)</span>
<span class="nd">@app</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s2">"/predict/"</span><span class="p">,</span> <span class="n">reponse_model</span><span class="o">=</span><span class="n">Result</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">predict</span><span class="p">(</span><span class="n">features</span><span class="p">:</span> <span class="n">Item</span><span class="p">):</span>
<span class="c1"># get the current span</span>
<span class="n">current_span</span> <span class="o">=</span> <span class="n">trace</span><span class="o">.</span><span class="n">get_current_span</span><span class="p">()</span>
<span class="c1"># hash input</span>
<span class="n">input_hash</span> <span class="o">=</span> <span class="nb">hash</span><span class="p">(</span><span class="n">features</span><span class="p">)</span>
<span class="c1"># save hash to opentelemetry</span>
<span class="n">current_span</span><span class="o">.</span><span class="n">set_attribute</span><span class="p">(</span><span class="s2">"app.demo.input_hash"</span><span class="p">,</span> <span class="n">features_hash</span><span class="p">)</span> <span class="c1"># <- Saves attribute</span>
<span class="c1"># return predictions</span>
<span class="n">prediction</span> <span class="o">=</span> <span class="n">get_prediction_for</span><span class="p">(</span><span class="n">features</span><span class="p">)</span>
<span class="k">return</span> <span class="n">prediction</span>
</code></pre></div>
<p>Let's walk through the example: </p>
<ul>
<li>We kick off manual instrumentation using the <code>TracerProvider</code>(<a href="https://opentelemetry.io/docs/instrumentation/python/manual/">docs</a>)</li>
<li>We add automatic instrumentation with the FastAPIInstrumentator (<a href="https://opentelemetry-python-contrib.readthedocs.io/en/latest/instrumentation/fastapi/fastapi.html">docs</a>)</li>
<li>We have the ability to send custom events with the <code>current_span.set_attribute</code> function (<a href="https://opentelemetry.io/docs/instrumentation/python/manual/#add-attributes-to-a-span">docs</a>)</li>
</ul>
<p>If you're using something like <a href="https://www.datadoghq.com/">DataDog</a>, <a href="https://www.honeycomb.io/">Honeycomb</a>, or any other provider that supports OpenTelemetry - you should get all this information on your service's dashboard. You'll get all the stats related to your application, and all the custom events you are sending in as well. </p>
<p>This is particularly interesting to understand, for example, when your API is breaking, and <em>what</em> is making it break!</p>
<h2 id="driftdegradation-monitoring">Drift/Degradation monitoring</h2>
<p>The second area of monitoring is about model degradation in the face of new data. This usually happens as models in production start being outdated. Trying to make predictions on types of data your model has never seen before, usually leads to problems. This concept is known as <em>data drift</em>. </p>
<p><center>
<img src="https://duarteocarmo.com/images/45/monitoring-sketch-2.png" alt="Drift monitoring" style="max-width:100%;border-radius: 2px">
</center></p>
<p>In a <a href="/blog/monitoring-ml-models-fastapi-evidently.html">previous</a> article, I talked extensively about this topic. I explained how to leverage FastAPI and Evidently to monitor drift, in real-time, for your ml application.<a href="/blog/monitoring-ml-models-fastapi-evidently.html"> So go read that if you're interested</a>. </p>
<p>There is, however, one concept I should double down on. The fact of storing all inputs (e.g., requests) and outputs (e.g., predictions) of your model. Here's an example of doing so - without increasing response latency:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># ...</span>
<span class="nd">@app</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s2">"/predict/"</span><span class="p">,</span> <span class="n">reponse_model</span><span class="o">=</span><span class="n">Result</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">predict</span><span class="p">(</span><span class="n">features</span><span class="p">:</span> <span class="n">Item</span><span class="p">,</span> <span class="n">background_tasks</span><span class="p">:</span> <span class="n">fastapi</span><span class="o">.</span><span class="n">BackgroundTasks</span><span class="p">,):</span>
<span class="n">prediction</span> <span class="o">=</span> <span class="n">get_prediction_for</span><span class="p">(</span><span class="n">features</span><span class="p">)</span>
<span class="c1"># saves both inputs and outputs as json to our predictions database</span>
<span class="c1"># runs in the background - doesn't make anyone wait</span>
<span class="n">background_tasks</span><span class="o">.</span><span class="n">add_task</span><span class="p">(</span>
<span class="n">save_to_database</span><span class="p">,</span>
<span class="nb">input</span><span class="o">=</span><span class="n">features</span><span class="o">.</span><span class="n">dict</span><span class="p">(),</span>
<span class="n">output</span><span class="o">=</span><span class="n">asdict</span><span class="p">(</span><span class="n">prediction</span><span class="p">),</span>
<span class="n">created_at</span><span class="o">=</span><span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">prediction</span>
<span class="c1"># ... </span>
</code></pre></div>
<p>This <em>prediction sink</em> (red in the image above), is key. As described in the previous article, it allows you to monitor drift. But it <em>also</em> allows you to get insights into the third area of monitoring. Let's talk about that one.</p>
<h2 id="business-monitoringreporting">Business monitoring/reporting</h2>
<p>The third and final area of monitoring relates to <em>everything else</em> you might want to keep track of. Your team might want to know how many predictions the API has made in the past month, or how many times you've predicted a certain class. Maybe you, or some other team, is tracking KPIs that are highly related to your model. Maybe the finance dept. wants to know the new CTR based on your recommendations. </p>
<p>The answers to these questions often come in the form of a dashboard.
<center>
<img src="https://duarteocarmo.com/images/45/monitoring-sketch-complete.png" alt="Business monitoring" style="max-width:100%;border-radius: 2px">
</center></p>
<p>Fortunately, if we store our inputs and predictions in a flexible enough format (e.g., <code>json</code>), we'll be able to take almost any off-the-shelf tool and make a dashboard. Designing <a href="https://www.metabase.com/">Metabase</a> dashboard from your historical <code>json</code> predictions stored in BigQuery should be straightforward. You could also stick to Google Data Studio. Or use Excel. You get my point, you can use whatever. <code>json</code> is flexible enough to be sorted by <code>created_at</code> and pushed into a dashboard.</p>
<p>Although often <em>overlooked</em>, this third level of reporting will often debunk the whole "your model is a black box" paradigm. It allows other stakeholders to know exactly what is going on in your model. </p>
<h2 id="closing-thoughts">Closing thoughts</h2>
<p>Yes. Adding all of these different types of monitoring requires <em>some</em> boilerplate code. And of course, setting this up might take some time. <em>Especially</em> if you do these to every model in production. </p>
<p>However, it's certainly impressive just how much insight you can get from some OpenTelemetry auto-instrumentation and a background job to save all your predictions. </p>
<p>Sufficiently monitoring your ML model increases your team's confidence when putting models out there. It's a bit like testing - you are now more sure things are happening as they should. With the third area of monitoring, you can then extend that feeling to the rest of the organization. </p>
<p>"Machine learning is such a black box". Open some doors to the box, and let other people in. </p>Goodbye Apple Watch2022-10-29T12:00:00+02:002022-10-29T12:00:00+02:00Duarte O.Carmotag:duarteocarmo.com,2022-10-29:/blog/coros-pace-2-apple-watch.html<p><center>
<img src="https://duarteocarmo.com/images/44/cover_small_optim.png" alt="Coros pace 2 outside shot" style="max-width:100%;border-radius: 2px">
</center></p>
<p>1768 days. </p>
<p>That's how long I've used the Apple Watch. Just a little under 5 years, in case you're wondering. I really love it. I don't know about "future of computing" and all that, but it's definitely a device I've fallen in love with. Last week, for the first time …</p><p><center>
<img src="https://duarteocarmo.com/images/44/cover_small_optim.png" alt="Coros pace 2 outside shot" style="max-width:100%;border-radius: 2px">
</center></p>
<p>1768 days. </p>
<p>That's how long I've used the Apple Watch. Just a little under 5 years, in case you're wondering. I really love it. I don't know about "future of computing" and all that, but it's definitely a device I've fallen in love with. Last week, for the first time, I ditched it. Let me explain why. </p>
<p>My last marathon didn't go that well. A story for another day. In the aftermath, I've been thinking about my training process. What went well, what went wrong, you know, introspection and all that. So I did what I do best. I got too deep into the topic. I research how other people train. I explore the vast sea of resources about running. You come across some <a href="https://fellrnr.com/wiki/Main_Page">pretty cool</a> resources. And some <a href="http://www.electricblues.com/html/runpro.html">scary</a> ones. </p>
<p>I was watching Kipchoge, and how he just <a href="https://worldathletics.org/news/report/eliud-kipchoge-world-record-berlin-marathon-2022">broke the WR in Berlin</a>. What a guy. You know what watch he uses for running? It's called <a href="https://www.coros.com/pace2">Coros Pace 2</a>. I'm far from a Kipchoge, but for 200 EUR, I had to know more. After some weeks of <em>e-window</em> shopping and a lot of YouTube reviews, I ordered it. </p>
<h2 id="the-good">The good</h2>
<p>20 days. That's how much this watch can last in a single charge. Yes, you read it right. <em>20 days</em>. For someone who is used to charging an Apple Watch every single day, that's a pretty nice upgrade. I don't have to worry about charging it every night, I don't have to carry an extra cable every single time I travel. I just go, and it will last the whole trip.</p>
<p>Obviously, I bought this watch for the fitness capabilities. Compared to the Apple Watch, it delivers. Setting up the Apple Watch for interval training, or any type of specific workout can be a pain. It doesn't even come <em>close</em> to the Coros. The workout views are much more informative and the after-workout analyses are much more insightful. That'
s expected. What I didn't expect, is a full web-based training portal where I can track all my workout metrics. Now that's a nice surprise.</p>
<p><center>
<img src="https://duarteocarmo.com/images/44/traininghub.png" alt="Coros training hub" style="max-width:100%;border-radius: 2px">
</center></p>
<p>The training hub and the Coros app (which is not <em>that</em> bad) give me much better control of my training plan. I can plan 3 months in advance and design all my workouts exactly like I want. For every workout, Coros gives me the Aerobic and Anaerobic training effect, my effort, my performance, so I know exactly what went down.</p>
<p>Sleep tracking. You know that thing you <em>sometimes</em> do with your Apple Watch, but not <em>too</em> often since you don't know if you'll have time to charge in the morning? Yup. Since I don't have to charge the Coros overnight, I get access to all my Sleep stats. I know exactly how much and how well I've slept over time. You know, 'cause sleep <a href="https://www.nature.com/articles/4371207a">matters</a>. </p>
<h2 id="the-bad">The bad</h2>
<p>It's not an Apple Watch. Yes, I could write about the fact that some parts of the Coros app are kinda rough, or the fact that the watch interface is a bit clunky. Or even the fact that it uses some sort of weird proprietary charger. But the bottom line is, I keep comparing it to the Apple Watch. </p>
<p>One side of me now understands why Apple has never given us custom watch faces. Coros has <em>at least</em> 100 watch faces to chose from, and they all look… well, not great. This watch is clearly missing the aesthetic appeal that the Apple Watch has.</p>
<p>I have a love/hate relationship with Apple's beautiful walled garden of an ecosystem. How can I miss paying with my wrist so much? How can I miss controlling music playback on my wrist so much? Seeing those circles close in every widget I own. Getting all the notifications in your watch. The next event in your calendar at wrist glance. The "Do not disturb until I leave this location", two taps away. Even the haptic motor. </p>
<p>I miss the cozy ecosystem. It's a bit like a withdrawal - it will fade. I think.</p>
<p><center>
<img src="https://duarteocarmo.com/images/44/home.png" alt="Coros pace 2 outside shot at home" style="max-width:100%;border-radius: 2px">
</center></p>
<h2 id="the-end">The end</h2>
<p>I don't think there's a winner. They're <em>different</em> devices - with different goals, and different target audiences. One, focuses on design, ecosystem, wellness, and lifestyle. The other is a powerful fitness tracker, and does it very well. </p>
<p>I <em>could</em> just use both. But I don't want to add that stress to my life. For now, a good run brings me more joy than paying with my wrist. A good night of sleep is more important than seeing all my calendar events in my wrist. <em>Focus</em>, is more important than constant notifications. </p>
<p>So I'll stick to the Coros for now. </p>infrequent.app - stay in touch with those who matter2022-10-23T19:00:00+02:002022-10-23T19:00:00+02:00Duarte O.Carmotag:duarteocarmo.com,2022-10-23:/blog/infrequent.html<p>Some months ago, I <a href="infrequent-tiny-crm.html">built</a> a small script to help me stay in touch with those who matter to me. The concept is fairly simple: I want to stay in touch with person <em>p</em> every <em>t</em> period of time. If <em>t</em> has passed, and you haven't talked to <em>p</em>, you …</p><p>Some months ago, I <a href="infrequent-tiny-crm.html">built</a> a small script to help me stay in touch with those who matter to me. The concept is fairly simple: I want to stay in touch with person <em>p</em> every <em>t</em> period of time. If <em>t</em> has passed, and you haven't talked to <em>p</em>, you get a reminder. </p>
<p>I've been using this script/system for the past 5 months, it has served me well. I've been keeping up with mentors, ex-managers, family, and friends - without much effort. Which is the goal. It's not that I don't like editing a bunch of markdown files every week - but I wanted something <em>smoother</em>.</p>
<p>Also, the more I've told people about my system (which is <a href="https://sive.rs/hundreds">not even mine</a>), the more I've realized that I'm not the only one who needs something like this. Generally, people have a <em>hard</em> time keeping in touch. It's not that we don't care - it's that life gets in the way. </p>
<p><a href="https://infrequent.app">
<img src="https://duarteocarmo.com/images/43/website.png" alt="Infrequent dashboard" style="max-width:100%;">
</a></p>
<p>And so I built <a href="https://infrequent.app">infrequent</a>.</p>
<p>Infrequent is a system to stay in touch with those I care about. A system that I built <em>literally</em> for myself, to scratch my own itch. But also a system that I hope helps others out there. </p>
<p><a href="https://infrequent.app">
<img src="https://duarteocarmo.com/images/43/dashboard.png" alt="Infrequent dashboard" style="max-width:100%;">
</a></p>
<p>I'm not gonna lie, it's been pretty fun to get back into web development. I love AI&ML, but there's something <em>special</em> about web development. And <a href="https://www.djangoproject.com/">Django</a>, <a href="https://htmx.org/">htmx</a>, and <a href="https://tailwindcss.com/">tailwind</a> have been a joy to work with. The stack is not straightforward to set up, but once you get going, it's a breeze to work with. Django is an <em>incredibly</em> powerful framework. </p>
<p>I don't have million-dollar plans for infrequent just yet. For now, I plan to continue using it, and entice others to do so too. I'll keep adding features to it, as mine (and maybe your) needs evolve. Feel free to give it a spin, and don't hesitate to <a href="mailto:me@duarteocarmo.com">email me</a> if you like it, or think something is missing. </p>Monitoring ML models with FastAPI and Evidently AI2022-09-17T15:00:00+02:002022-09-17T15:00:00+02:00Duarte O.Carmotag:duarteocarmo.com,2022-09-17:/blog/monitoring-ml-models-fastapi-evidently.html<p>I've deployed a good amount of ML models to production. For many, deployment to production is the last step of the process. Once that's done, work is done. This is far from true. Once your model is out there, problems <em>will</em> start to arise. Some predictions will be wrong. Some …</p><p>I've deployed a good amount of ML models to production. For many, deployment to production is the last step of the process. Once that's done, work is done. This is far from true. Once your model is out there, problems <em>will</em> start to arise. Some predictions will be wrong. Some labels will occur more often than they should, and some examples <em>will</em> surprise the model. </p>
<p>Setting up the right lenses & triggers <em>into</em> your model is critical. It helps to ensure everything is running smoothly, or to know when issues need to be tackled. Let's open up the black box. </p>
<h2 id="setting-up-fastapi">Setting up FastAPI</h2>
<p>I've previously <a href="/blog/serving-ml-models-fastapi.html">written</a> about how to serve your ML model with FastAPI. Let's assume we're serving our model with FastAPI and our <code>src</code> folder looks something like:</p>
<div class="codehilite"><pre><span></span><code>src
├──<span class="w"> </span>__init__.py
├──<span class="w"> </span>api<span class="w"> </span><-<span class="w"> </span>your<span class="w"> </span>Fast<span class="w"> </span>API<span class="w"> </span>folder
│<span class="w"> </span>├──<span class="w"> </span>__init__.py
│<span class="w"> </span>├──<span class="w"> </span>models.py
│<span class="w"> </span>└──<span class="w"> </span>main.py
├──<span class="w"> </span>pipeline
│<span class="w"> </span>├──<span class="w"> </span>__init__.py
│<span class="w"> </span>├──<span class="w"> </span>...
│<span class="w"> </span>└──<span class="w"> </span>train.py
└──<span class="w"> </span>setup.py
</code></pre></div>
<p>The <code>main.py</code> file is where our views are defined. Below, our main file, with a <code>/predict</code> endpoint, that serves predictions. </p>
<div class="codehilite"><pre><span></span><code><span class="c1"># app.py</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Optional</span>
<span class="kn">from</span> <span class="nn">fastapi</span> <span class="kn">import</span> <span class="n">FastAPI</span>
<span class="kn">from</span> <span class="nn">src.pipeline</span> <span class="kn">import</span> <span class="n">get_prediction_for</span>
<span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="n">Result</span><span class="p">,</span> <span class="n">Item</span>
<span class="kn">import</span> <span class="nn">joblib</span>
<span class="c1"># create FastAPI app and load model</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">FastAPI</span><span class="p">()</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">joblib</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="s2">"model.joblib"</span><span class="p">)</span>
<span class="c1"># create an endpoint that receives POST requests</span>
<span class="nd">@app</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s2">"/predict/"</span><span class="p">,</span> <span class="n">reponse_model</span><span class="o">=</span><span class="n">Result</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">predict</span><span class="p">(</span><span class="n">features</span><span class="p">:</span> <span class="n">Item</span><span class="p">):</span>
<span class="c1"># some processing</span>
<span class="n">prediction</span> <span class="o">=</span> <span class="n">get_prediction_for</span><span class="p">(</span><span class="n">features</span><span class="p">)</span>
<span class="k">return</span> <span class="n">prediction</span>
</code></pre></div>
<h2 id="prerequisite-storing-all-predictions">Prerequisite: Storing all predictions</h2>
<p>To monitor our model, we must first make sure two things are happening:</p>
<ul>
<li>Prediction logging: We're actively logging all predictions our model is making</li>
<li>Access to a reference dataset: We have access to the dataset where our model was trained (e.g., the training data)</li>
</ul>
<p>Logging all predictions your model makes can be done using some managed database service (e.g., think Aurora, BigQuery, etc.). Ideally, we want to do this without increasing our prediction latency. </p>
<p>Fortunately, Fast API provides gives a great tool to do this: <code>BackgroundTasks</code>. We start by creating a function that saves our data (in this example, to BigQuery):</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># monitoring.py</span>
<span class="c1"># ...</span>
<span class="k">def</span> <span class="nf">save_to_database</span><span class="p">(</span><span class="nb">input</span><span class="p">:</span> <span class="n">Item</span><span class="p">,</span> <span class="n">result</span><span class="p">:</span> <span class="n">Result</span><span class="p">)</span> <span class="o">-></span> <span class="kc">None</span><span class="p">:</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> Saves input/output dicts to bigquery</span>
<span class="sd"> """</span>
<span class="n">client</span> <span class="o">=</span> <span class="n">BigQuery</span><span class="o">.</span><span class="n">client</span><span class="p">()</span>
<span class="n">table</span> <span class="o">=</span> <span class="s2">"your_cool_bq_table"</span>
<span class="n">current_time</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span>
<span class="n">rows_to_insert</span> <span class="o">=</span> <span class="p">[(</span><span class="n">current_time</span><span class="p">,</span> <span class="nb">input</span><span class="o">.</span><span class="n">json</span><span class="p">(),</span> <span class="n">result</span><span class="o">.</span><span class="n">json</span><span class="p">())]</span>
<span class="n">errors</span> <span class="o">=</span> <span class="n">client</span><span class="o">.</span><span class="n">insert_rows</span><span class="p">(</span><span class="n">table</span><span class="p">,</span>
<span class="n">rows_to_insert</span><span class="p">)</span>
<span class="k">if</span> <span class="n">errors</span><span class="p">:</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Error: </span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">errors</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
<span class="k">return</span>
<span class="n">logging</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="s2">"Saved prediction"</span><span class="p">)</span>
</code></pre></div>
<p>We can now add it to our API as a background task:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># app.py</span>
<span class="c1"># ...</span>
<span class="kn">from</span> <span class="nn">fastapi</span> <span class="kn">import</span> <span class="n">FastAPI</span><span class="p">,</span> <span class="n">BackgroundTasks</span>
<span class="kn">from</span> <span class="nn">.monitoring</span> <span class="kn">import</span> <span class="n">save_to_database</span>
<span class="c1"># ...</span>
<span class="c1"># create an endpoint that receives POST requests</span>
<span class="nd">@app</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s2">"/predict/"</span><span class="p">,</span>
<span class="n">reponse_model</span><span class="o">=</span><span class="n">Result</span><span class="p">,</span>
<span class="n">background_tasks</span><span class="p">:</span> <span class="n">BackgroundTasks</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">predict</span><span class="p">(</span><span class="n">features</span><span class="p">:</span> <span class="n">Item</span><span class="p">):</span>
<span class="c1"># some processing</span>
<span class="n">prediction</span> <span class="o">=</span> <span class="n">get_prediction_for</span><span class="p">(</span><span class="n">features</span><span class="p">)</span>
<span class="n">background_tasks</span><span class="o">.</span><span class="n">add_task</span><span class="p">(</span><span class="n">save_to_bq</span><span class="p">,</span> <span class="nb">input</span><span class="o">=</span><span class="n">features</span><span class="p">,</span> <span class="n">result</span><span class="o">=</span><span class="n">prediction</span><span class="p">)</span>
<span class="k">return</span> <span class="n">prediction</span>
</code></pre></div>
<p>Notice how the background task does not block the prediction time. Allowing us to keep prediction latency as low as possible, while <em>still</em>, saving all predictions. </p>
<h2 id="setting-up-the-monitoring">Setting up the monitoring</h2>
<p><a href="https://docs.evidentlyai.com/">Evidently</a> is a great open-source tool that allows you to set up monitoring for your ML models. It's not the only one, there's a myriad of them, actually. <a href="https://www.nannyml.com/">nannyML</a> is another one.</p>
<p>Evidently allows you to generate a <a href="https://docs.evidentlyai.com/features/dashboards/input_data#dataset-structure">bunch of different reports</a> you can generate. In this example, I'll focus on the Data Drift dashboard. </p>
<p>The Data Drift dashboard allows you to measure the difference in distribution between the predictions you are making, and the labels of your training set. When these two start to become <em>significantly</em> different, you are likely encountering some drift. </p>
<p>Alright, let's build it. We start by creating a couple of functions in our <code>monitoring.py</code> module: </p>
<div class="codehilite"><pre><span></span><code><span class="c1"># ... rest of the monitoring.py</span>
<span class="n">DATA_WINDOW_SIZE</span> <span class="o">=</span> <span class="mi">3000</span> <span class="c1"># how many predictions to load</span>
<span class="c1"># loads our training/reference dataset</span>
<span class="k">def</span> <span class="nf">load_train_data</span><span class="p">()</span> <span class="o">-></span> <span class="n">pandas</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">:</span>
<span class="n">train_file</span> <span class="o">=</span> <span class="s2">"static/train_data.csv"</span>
<span class="n">train_df</span> <span class="o">=</span> <span class="n">pandas</span><span class="o">.</span><span class="n">read_csv</span><span class="p">(</span><span class="n">train_file</span><span class="p">)</span>
<span class="k">return</span> <span class="n">train_df</span>
<span class="c1"># loads our latest predictions </span>
<span class="k">def</span> <span class="nf">load_last_predictions</span><span class="p">()</span> <span class="o">-></span> <span class="n">pandas</span><span class="o">.</span><span class="n">DataFrame</span><span class="p">:</span>
<span class="n">query</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"""</span>
<span class="s2"> SELECT created_at, input, output</span>
<span class="s2"> FROM `my_cool_bgq_table` </span>
<span class="s2"> ORDER BY created_at DESC</span>
<span class="s2"> LIMIT </span><span class="si">{</span><span class="n">DATA_WINDOW_SIZE</span><span class="si">}</span><span class="s2">;</span>
<span class="s2"> """</span>
<span class="n">prediction_data</span> <span class="o">=</span> <span class="n">pandas</span><span class="o">.</span><span class="n">read_gbq</span><span class="p">(</span><span class="n">query</span><span class="o">=</span><span class="n">query</span><span class="p">)</span>
<span class="k">return</span> <span class="n">prediction_data</span>
</code></pre></div>
<p>Now that we're able to fetch both our reference data and our past predictions, we're ready to build our Data Drift dashboard: </p>
<div class="codehilite"><pre><span></span><code><span class="c1"># ... rest of the monitoring.py</span>
<span class="c1"># this function generates a dashboard from our reference and prediction data</span>
<span class="c1"># which is then saved to a `drift.html` file</span>
<span class="k">def</span> <span class="nf">generate_dashboard</span><span class="p">()</span> <span class="o">-></span> <span class="nb">str</span><span class="p">:</span>
<span class="n">dasboard_name</span> <span class="o">=</span> <span class="s2">"static/drift.html"</span>
<span class="n">data_drift_dashboard</span> <span class="o">=</span> <span class="n">Dashboard</span><span class="p">(</span>
<span class="n">tabs</span><span class="o">=</span><span class="p">[</span>
<span class="n">DataDriftTab</span><span class="p">(</span><span class="n">verbose_level</span><span class="o">=</span><span class="mi">0</span><span class="p">),</span>
<span class="p">]</span>
<span class="p">)</span>
<span class="n">reference_data</span> <span class="o">=</span> <span class="n">load_reference_data</span><span class="p">()</span>
<span class="n">current_data</span> <span class="o">=</span> <span class="n">load_last_predictions</span><span class="p">()</span>
<span class="n">data_drift_dashboard</span><span class="o">.</span><span class="n">calculate</span><span class="p">(</span>
<span class="n">reference_data</span><span class="o">=</span><span class="n">reference_data</span><span class="p">,</span>
<span class="n">current_data</span><span class="o">=</span><span class="n">current_data</span><span class="p">,</span>
<span class="n">column_mapping</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">data_drift_dashboard</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">dasboard_name</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">info</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Dashboard saved to </span><span class="si">{</span><span class="n">dasboard_name</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
<span class="k">return</span> <span class="n">dasboard_name</span>
</code></pre></div>
<p>Notice how we're creating our dashboard, and then saving it to a <code>static/drift.html</code> file. The idea is then to serve this dashboard in one of our FastAPI endpoints. </p>
<h2 id="monitoring-dashboard">Monitoring dashboard</h2>
<p>Let's serve our data drift dashboard: </p>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span> <span class="nn">.monitoring</span> <span class="kn">import</span> <span class="n">generate_dashboard</span>
<span class="c1"># ... rest of the main.py</span>
<span class="nd">@app</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"/monitoring"</span><span class="p">,</span> <span class="n">tags</span><span class="o">=</span><span class="p">[</span><span class="s2">"Other"</span><span class="p">])</span>
<span class="k">def</span> <span class="nf">monitoring</span><span class="p">():</span>
<span class="n">dashboard_location</span> <span class="o">=</span> <span class="n">generate_dashboard</span><span class="p">()</span>
<span class="k">return</span> <span class="n">FileResponse</span><span class="p">(</span><span class="n">dashboard_location</span><span class="p">)</span>
</code></pre></div>
<p>Every time we visit <code>/monitoring</code>, Fast API will run the <code>generate_dashboard</code> function, and return an <code>html</code> file:</p>
<p><img src="https://duarteocarmo.com/images/42/dashboard.png" alt="Monitoring Dashboard" style="max-width:100%;"></p>
<p>As you can see, this dashboard compares the distribution of our reference and <em>current</em> dataset. The current dataset being the latest Y predictions we've made.</p>
<h2 id="closing-thoughts">Closing thoughts</h2>
<p>I've found this to be a <em>relatively</em> straightforward way of adding a bit of visibility to what's really happening in my production models. If those distributions are looking particularly skewed: you know it's time to act. </p>
<p><a href="https://evidentlyai.com/">Evidently</a> allows us to generate much more than just a data drift dashboard. You can also generate dashboards to monitor data quality, the performance of a regression, classification performance, and many more. It's worth taking a look at their docs to see what fits your use case best. </p>
<p>There's a way we could increase the speed here. Instead of computing the entire dashboard every time we visit <code>/monitoring</code>, we <a href="https://fastapi-utils.davidmontague.xyz/user-guide/repeated-tasks/#the-repeat_every-decorator">could</a> compute it every X time period in the <em>background</em>. This would result in much faster response from the <code>/monitoring</code> endpoint. </p>
<p>Is this dashboard enough to make sure everything is going well in production? No. But it's a <em>great</em> first step towards figuring out what's <em>really</em> going on. </p>
<hr>
<h4 id="updates-notes">Updates & notes</h4>
<ul>
<li><a href="https://mlops.community/monitoring-ml-models-with-fastapi-and-evidently-ai/">This post was republished by the MLOps Community blog</a></li>
<li>I also wrote a <a href="/blog/monitoring-machine-learning-apis.html">more general post</a> on how to monitor machine learning APIs </li>
</ul>Down from the Cloud2022-08-05T11:00:00+02:002022-08-05T11:00:00+02:00Duarte O.Carmotag:duarteocarmo.com,2022-08-05:/blog/down-from-the-cloud-self-hosting.html<p>I love the Cloud. For years, I've been deploying software to it. Azure, GCP, AWS, you name it. I've used most of them. To be honest, they're the same pig, but with different lipstick (like the Danes say). Package up your app, make some CI/CD magic, select your service …</p><p>I love the Cloud. For years, I've been deploying software to it. Azure, GCP, AWS, you name it. I've used most of them. To be honest, they're the same pig, but with different lipstick (like the Danes say). Package up your app, make some CI/CD magic, select your service, and I'm good to go. Still remember when I helped a whole bank move to the Public Cloud. The benefits are mostly obvious. </p>
<p>But I'm no bank. And it's not all rainbows and unicorns. For starters, those 10 elastic beanstalk applications can start adding up. What if I want to change from Cloud A to Cloud B? It's not like Amazon is going to make my life easy. It's a convenience/lock-in trade-off. What about user data? What about <em>my</em> data? Some of the <a href="https://marco.org/2014/02/23/the-value-of-background-fetch">best</a> <a href="https://twitter.com/levelsio/status/1308145873843560449">software</a> I use doesn't even use the Cloud. </p>
<p>Let's come down from the Cloud (at least the public one): Self-hosting. How <em>hard</em> is it, really? </p>
<h2 id="get-a-server">Get a server</h2>
<p>This one should be straightforward. There's no shortage of server providers. Just browsed <a href="https://lowendbox.com/">LowEndBox</a> for a while I decided to go with a dedicated server from <a href="https://www.hetzner.com/">Hetzner</a>. Something relatively close to Copenhagen to ensure my connection to the server is snappy enough. </p>
<p>I don't run a lot of very high traffic sites (yet!). Something around the 50 EUR/month price point serves just fine. You'll be surprised with how much stuff you can run in this machine. I have 10 services running and my memory barely goes above 10%. Let's not jinx it. </p>
<h2 id="containerize-all-the-things">Containerize all the things</h2>
<p>I have a love-hate relationship with Docker. For me, it's still the most straightforward way of exchanging and packaging up software to ensure nothing breaks. But how I hate when my container starts getting fat. I'm talking about you, PyTorch. </p>
<p>Every application will run inside its own containerized environment. To ensure this doesn't get overly complicated, I went with <code>docker compose</code>. Why not Kubernetes you may ask? Because I have other things to do. </p>
<p>Inside the server, things look a little something like: </p>
<div class="codehilite"><pre><span></span><code><span class="p">|</span>--<span class="w"> </span>Caddyfile<span class="w"> </span><-<span class="w"> </span>more<span class="w"> </span>on<span class="w"> </span>this<span class="w"> </span>later
<span class="sb">`</span>--<span class="w"> </span>projects
<span class="w"> </span><span class="p">|</span>--<span class="w"> </span>project-1<span class="w"> </span><-<span class="w"> </span>first<span class="w"> </span>application
<span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="p">|</span>--<span class="w"> </span>...
<span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="p">|</span>--<span class="w"> </span>Dockerfile
<span class="w"> </span><span class="p">|</span><span class="w"> </span><span class="sb">`</span>--<span class="w"> </span>docker-compose.yml<span class="w"> </span><-<span class="w"> </span>docker<span class="w"> </span>compose<span class="w"> </span>file
<span class="w"> </span><span class="sb">`</span>--<span class="w"> </span>project-2<span class="w"> </span><-<span class="w"> </span>second<span class="w"> </span>application
<span class="w"> </span><span class="p">|</span>--<span class="w"> </span>...
<span class="w"> </span><span class="p">|</span>--<span class="w"> </span>Dockerfile
<span class="w"> </span><span class="sb">`</span>--<span class="w"> </span>docker-compose.yml<span class="w"> </span><-<span class="w"> </span>second<span class="w"> </span>docker<span class="w"> </span>compose<span class="w"> </span>file
</code></pre></div>
<p>Every project gets its own <code>docker-compose.yml</code> file. Every project runs on its specific server port. For example, to run <code>project-1</code>, I <code>cd</code> into the directory and start the container: <code>docker compose up --force-recreate --build -d</code>. This automatically starts the service on the port I specify on the <code>docker-compose.yml</code> file. </p>
<p>Using the process above, I can have a bunch of different applications running on a lot of different ports, but in a single server. Hopefully (1) saving money, and (2) increasing the power and control over them. </p>
<p>Hopefully, I won't land on dependency-nightmare-land.</p>
<h2 id="continuously-deploy">Continuously deploy</h2>
<p>Self-hosting sounds great. Having to <code>ssh</code> into a server <em>every time</em> I want to update a service, doesn't. If there's one thing I'm not willing to compromise on, it's continuous deployments. The whole <code>git push</code> automatically updates the app thing is super convenient. </p>
<p>Enter GitHub actions. With them, you can automate the ssh'ing and re-deployment part. It's not the most <em>secure</em> option. But hey, it works pretty well. Surprisingly, it's also much faster than deploying on Elastic Beanstalk or Cloud Run. </p>
<p>Here's what these actions look like:</p>
<div class="codehilite"><pre><span></span><code><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Deploy to server</span>
<span class="nt">on</span><span class="p">:</span>
<span class="w"> </span><span class="nt">push</span><span class="p">:</span>
<span class="w"> </span><span class="nt">branches</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">master</span><span class="w"> </span>
<span class="nt">jobs</span><span class="p">:</span>
<span class="w"> </span><span class="nt">build</span><span class="p">:</span>
<span class="w"> </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">ubuntu-latest</span>
<span class="w"> </span><span class="nt">steps</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Checkout source code</span>
<span class="w"> </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">actions/checkout@v1</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">actions/checkout@master</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Copies repository to server</span>
<span class="w"> </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">appleboy/scp-action@master</span>
<span class="w"> </span><span class="nt">with</span><span class="p">:</span>
<span class="w"> </span><span class="nt">host</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">${{ secrets.HOST }} <- these are defined in your repo settings.</span>
<span class="w"> </span><span class="nt">username</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">${{ secrets.USERNAME }}</span>
<span class="w"> </span><span class="nt">password</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">${{ secrets.PASSWORD }}</span>
<span class="w"> </span><span class="nt">port</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">22</span>
<span class="w"> </span><span class="nt">overwrite</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">true</span>
<span class="w"> </span><span class="nt">source</span><span class="p">:</span><span class="w"> </span><span class="s">"."</span>
<span class="w"> </span><span class="nt">target</span><span class="p">:</span><span class="w"> </span><span class="s">"/root/projects/project-X"</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">appleboy/ssh-action@master</span>
<span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Stops and updates docker container as deamon</span>
<span class="w"> </span><span class="nt">with</span><span class="p">:</span>
<span class="w"> </span><span class="nt">host</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">${{ secrets.HOST }}</span>
<span class="w"> </span><span class="nt">username</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">${{ secrets.USERNAME }}</span>
<span class="w"> </span><span class="nt">password</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">${{ secrets.PASSWORD }}</span>
<span class="w"> </span><span class="nt">port</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">22</span>
<span class="w"> </span><span class="nt">script</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">|</span>
<span class="w"> </span><span class="no">cd projects/project-X</span>
<span class="w"> </span><span class="no">docker compose down</span>
<span class="w"> </span><span class="no">docker compose up --force-recreate --build -d</span>
<span class="w"> </span><span class="no">docker ps</span>
</code></pre></div>
<h2 id="https-we-meet-again">HTTPS, we meet again</h2>
<p>Alright, it's time to expose these apps to the world. I'll admit it. The sheer mentioning of <em>https certificates</em> or <em>DNS</em> runs a chill down my spine. After loosing a couple of hours in the <a href="https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/">reverse proxy documentation for Nginx</a> and getting a bit mad, I found this little thing called <a href="https://caddyserver.com/">Caddy</a>. Oh boy, that was easy.</p>
<p>Caddy solves the whole subdomain, reverse proxy, multiple websites on the same server, HTTPS <em>mambo jumbo</em>. The docs are great, and it's super straightforward to use. I definitely recommend their <a href="https://caddyserver.com/docs/getting-started">Getting Started</a> docs. </p>
<p>First step is to point some A record in your DNS to your server's IP address. I use Cloudflare for this, do recommend. Once Caddy is installed in the server, all you need to do is create a <code>Caddyfile</code>:</p>
<div class="codehilite"><pre><span></span><code>project-1.mydomain.com {
reverse_proxy localhost:3000
}
project-2.mydomain.com {
reverse_proxy localhost:5000
}
home.mydomain.com {
respond "Base domain"
}
</code></pre></div>
<p>After that, run <code>caddy start</code>, and we're done. Yes. Your eyes are not kidding you. That's absolutely it. <code>project-1.mydomain.com</code> is connected to my app running on port <code>3000</code>, and <code>project-2.mydomain.com</code> is connected to the container on port <code>5000</code>. HTTPS? Automatic. Reverse proxy? Done. </p>
<p>Caddy automatically enables HTTPS for all of the apps you specify on your <code>Caddyfile</code>. It also automatically issues new certificates and renews them. Changes? A simple <code>caddy reload</code> and you're up and running again.</p>
<p>I can have as many subdomains/domains pointing to the same server as I want, as long as the server can handle it. </p>
<h2 id="closing-thoughts">Closing thoughts</h2>
<p><img src="https://duarteocarmo.com/images/41/glances.png" alt="Glances" style="max-width:100%;"></p>
<p>One of the services I'm currently self hosting is called <a href="https://nicolargo.github.io/glances/">Glances</a>. With it, all of my server's metrics an url away. With about 5 containers, the CPU is still below 10%. </p>
<p>No. I don't have all the elasticity that the Public Cloud gives me. But do I need it? The deployment method is the same (<code>git push</code>), the speed of services are the same (mostly static with Cloudflare on top), the cost is lower, and data is controlled by me. Sounds like a treat.</p>A recipe recommendation system2022-06-26T11:55:00+02:002022-06-26T11:55:00+02:00Duarte O.Carmotag:duarteocarmo.com,2022-06-26:/blog/scandinavia-food-python-recommendation-systems.html<p>You arrive home and turn on Netflix. On the front page: hundreds of shows. They're not ordered randomly. Netflix has been perfecting the science of recommending shows for years now. Google has perfected the science of sorting search results. </p>
<p>To this day, no one knows exactly how Google sorts their …</p><p>You arrive home and turn on Netflix. On the front page: hundreds of shows. They're not ordered randomly. Netflix has been perfecting the science of recommending shows for years now. Google has perfected the science of sorting search results. </p>
<p>To this day, no one knows exactly how Google sorts their search results. Recommendation systems are gold, and a big part of the success of big tech. </p>
<p>Yeah, this article is not about food. It's about <em>recommender systems</em>. </p>
<p>While building one, my assumption that Scandinavian food was not for me, was debunked. Turns out, it's one of my favourites (at least according to what I built). Hard to believe? </p>
<h2 id="on-cooking">On cooking</h2>
<p>I'm not a fan of the culinary arts (the opposite really). But I decided to build a dataset of recipes. 160.000 recipes. Each one has a name, a region, a link, and ingredients. I scraped them from <a href="https://cosylab.iiitd.edu.in/recipedb/">RecipeDB</a>. RecipeDB scrapped them from somewhere else - the data is <em>ok-ish</em> quality. </p>
<p>Here's a sample: </p>
<p><img alt="table data" style="border-radius: 5px;" src="https://duarteocarmo.com/images/40/table.png"></p>
<p>And here's there distribution of recipes across regions:</p>
<p><img alt="value counts" style="border-radius: 5px;" src="https://duarteocarmo.com/images/40/value_counts.png"></p>
<h2 id="vectors-are-dope-more-of-those">Vectors are dope, more of those</h2>
<p>Data is messy. Images, text, audio... They come in thousands of formats. But there's a common language to every data type: <strong>vectors</strong> (or arrays, whatever). </p>
<p>In machine learning, vectors that represent data are referred to as <em>embeddings</em>. Transforming a word or a sentence in to an embedding it straightforward nowadays:</p>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span> <span class="nn">flair.embeddings</span> <span class="kn">import</span> <span class="n">WordEmbeddings</span>
<span class="kn">from</span> <span class="nn">flair.data</span> <span class="kn">import</span> <span class="n">Sentence</span>
<span class="c1"># create embedder Glove in this case</span>
<span class="n">glove_embedding</span> <span class="o">=</span> <span class="n">WordEmbeddings</span><span class="p">(</span><span class="s1">'glove'</span><span class="p">)</span>
<span class="c1"># create a sentemce</span>
<span class="n">sentence</span> <span class="o">=</span> <span class="n">Sentence</span><span class="p">(</span><span class="s1">'pineapple pizza'</span><span class="p">)</span>
<span class="c1"># embed a sentence </span>
<span class="n">glove_embedding</span><span class="o">.</span><span class="n">embed</span><span class="p">(</span><span class="n">sentence</span><span class="p">)</span>
<span class="c1"># you can get the embedding for the whole sentence</span>
<span class="n">sentence_embedding</span> <span class="o">=</span> <span class="n">sentence</span><span class="o">.</span><span class="n">embedding</span>
<span class="c1"># or check the embedding for each word (e.g., token)</span>
<span class="k">for</span> <span class="n">token</span> <span class="ow">in</span> <span class="n">sentence</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="n">token</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">token</span><span class="o">.</span><span class="n">embedding</span><span class="p">)</span>
<span class="c1"># prints... </span>
<span class="c1"># Token[0]: "pineapple"</span>
<span class="c1"># tensor([-1.3641, 0.2901, ...]) </span>
<span class="c1"># Token[0]: "pineapple"</span>
<span class="c1"># tensor([-1.3641, 0.2901, ...]) </span>
</code></pre></div>
<p>Getting the vector for a sentence, is done by averaging the vectors of the words inside of it. We could use also BERT to <a href="https://www.sbert.net/">generate</a> embeddings for sentences. </p>
<p>There's one big advantage of these pertained models like BERT: the embeddings preserve the semantic meaning of the words. So, in theory, two sentences with similar meanings, <em>should</em> have similar vectors.</p>
<p>These fancy embeddings take time to compute. In the interest of time, I went with <em><a href="https://nlp.stanford.edu/projects/glove/">Glove</a></em> to calculate them. </p>
<h2 id="a-galaxy-of-recipes">A galaxy of recipes</h2>
<p>Let's leverage the technique above to embed all the recipes in our dataset. We take the <code>ingredient_string</code> of each recipe, and use Glove to generate a matrix of embeddings:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># create embeddings for all of them</span>
<span class="n">sentence_list</span> <span class="o">=</span> <span class="p">[</span><span class="n">Sentence</span><span class="p">(</span><span class="n">text</span><span class="p">)</span> <span class="k">for</span> <span class="n">text</span> <span class="ow">in</span> <span class="n">df</span><span class="o">.</span><span class="n">ingredient_string</span><span class="p">]</span>
<span class="n">document_embeddings</span><span class="o">.</span><span class="n">embed</span><span class="p">(</span><span class="n">sentences</span><span class="o">=</span><span class="n">sentence_list</span><span class="p">)</span>
<span class="n">embedding_matrix</span> <span class="o">=</span> <span class="n">numpy</span><span class="o">.</span><span class="n">array</span><span class="p">([</span><span class="n">s</span><span class="o">.</span><span class="n">embedding</span><span class="o">.</span><span class="n">numpy</span><span class="p">()</span> <span class="k">for</span> <span class="n">s</span> <span class="ow">in</span> <span class="n">sentence_list</span><span class="p">])</span>
<span class="nb">print</span><span class="p">(</span><span class="n">embedding_matrix</span><span class="o">.</span><span class="n">shape</span><span class="p">)</span> <span class="c1"># prints (115657, 100)</span>
</code></pre></div>
<p>That's a pretty large matrix. 115657 vectors, with 100 dimensions each one. Now, we can visualise 3 dimensions - but not 100. </p>
<p>To visualise them, we need to reduce the dimensionality of these vectors. UMAP does just that:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># let's use UMAP to help us visualize these vectors</span>
<span class="c1"># you could use t-SNE, PCA, etc.</span>
<span class="n">umap_fit</span> <span class="o">=</span> <span class="n">umap</span><span class="o">.</span><span class="n">UMAP</span><span class="p">()</span>
<span class="n">umap_matrix</span> <span class="o">=</span> <span class="n">umap_fit</span><span class="o">.</span><span class="n">fit_transform</span><span class="p">(</span><span class="n">embedding_matrix</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">umap_matrix</span><span class="o">.</span><span class="n">shape</span><span class="p">)</span> <span class="c1"># (115657, 2)</span>
</code></pre></div>
<p>Alright, now we have a 2D matrix of our 116.000 recipes. That's <em>visualisable</em>. For the sake of your browser, here's a random set of 2000 recipes in 2D space:</p>
<div id="vis-1"></div>
<script>
(function(vegaEmbed) {
var spec = {"config": {"view": {"continuousWidth": 400, "continuousHeight": 300}}, "data": {"name": "data-87be018bf2fe12092f9c6c0475c82a77"}, "mark": "point", "encoding": {"color": {"field": "region", "type": "nominal"}, "tooltip": [{"field": "recipe", "type": "nominal"}, {"field": "region", "type": "nominal"}, {"field": "url", "type": "nominal"}], "x": {"field": "umap_0", "type": "quantitative"}, "y": {"field": "umap_1", "type": "quantitative"}}, "height": 500, "selection": {"selector001": {"type": "interval", "bind": "scales", "encodings": ["x", "y"]}}, "title": "Visualizing 2000 recipes", "width": 500, "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", "datasets": {"data-87be018bf2fe12092f9c6c0475c82a77": [{"umap_0": -1.3918496370315552, "umap_1": 11.757913589477539, "region": "Mexican", "recipe": "Salsa Del Lopez", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83033"}, {"umap_0": -1.0309573411941528, "umap_1": 9.523167610168457, "region": "French", "recipe": "Crock Pot Chicken Provencal", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/116730"}, {"umap_0": -1.2424802780151367, "umap_1": 6.40226936340332, "region": "Deutschland", "recipe": "Swiss Steak for Two (Crock Pot)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/117709"}, {"umap_0": 10.127331733703613, "umap_1": 5.45508337020874, "region": "Eastern European", "recipe": "Drop Scones (So Easy)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/133616"}, {"umap_0": -1.9859997034072876, "umap_1": 5.981219291687012, "region": "Australian", "recipe": "Greek Veggie Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/5164"}, {"umap_0": -2.2660439014434814, "umap_1": 7.329191207885742, "region": "Greek", "recipe": "Grilled Mediterranean Salad Stuffed Peppers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/111022"}, {"umap_0": -2.0031380653381348, "umap_1": 8.42020320892334, "region": "Italian", "recipe": "Insalata Primavera (Italian Spring Salad)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120536"}, {"umap_0": 3.126434564590454, "umap_1": 8.945534706115723, "region": "Chinese and Mongolian", "recipe": "Chinese Pork Chops (Diabetic)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56844"}, {"umap_0": 9.458781242370605, "umap_1": 7.472686290740967, "region": "Canadian", "recipe": "Baked Rice Cream", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144214"}, {"umap_0": 0.10703326016664505, "umap_1": 9.786750793457031, "region": "Mexican", "recipe": "Chicken Enchiladas With Roasted Tomatillo Chile Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/88978"}, {"umap_0": -1.4782341718673706, "umap_1": 8.419039726257324, "region": "Greek", "recipe": "Bobby Flay's Kentucky Ham Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/109617"}, {"umap_0": 0.31108716130256653, "umap_1": 4.9014973640441895, "region": "South American", "recipe": "Easy Supreme Beef Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/99412"}, {"umap_0": 3.222634792327881, "umap_1": 9.869194984436035, "region": "Thai", "recipe": "Ginger Broccoli", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/59579"}, {"umap_0": -1.4622187614440918, "umap_1": 5.559756278991699, "region": "US", "recipe": "Pittsburgh Football Sunday Pasta Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/13975"}, {"umap_0": 1.8007495403289795, "umap_1": 5.676237106323242, "region": "Mexican", "recipe": "Chipotle Sandwich Wrap", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/78116"}, {"umap_0": -0.52838134765625, "umap_1": 10.330512046813965, "region": "Caribbean", "recipe": "Barbecued Pig", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/8039"}, {"umap_0": 8.998263359069824, "umap_1": 7.855962753295898, "region": "Indian Subcontinent", "recipe": "Silver Moon", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67682"}, {"umap_0": 0.10560809075832367, "umap_1": 9.160552024841309, "region": "US", "recipe": "Big B's Collard Greens", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16113"}, {"umap_0": -0.3880225718021393, "umap_1": 5.414238452911377, "region": "Deutschland", "recipe": "Authentic Switzerland Fondue", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118188"}, {"umap_0": -0.6247455477714539, "umap_1": 7.495125770568848, "region": "Irish", "recipe": "Yummy Brussels Sprouts With Bacon & Onion", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/135938"}, {"umap_0": 1.7616580724716187, "umap_1": 4.886806011199951, "region": "Mexican", "recipe": "Mandy's Lamb Enchiladas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6121"}, {"umap_0": 11.793554306030273, "umap_1": 8.38292407989502, "region": "Rest Africa", "recipe": "Peppermint Crisp Tart - Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/51420"}, {"umap_0": 0.8003747463226318, "umap_1": 12.410970687866211, "region": "Indian Subcontinent", "recipe": "Taj Maholla! Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64042"}, {"umap_0": 0.9994710087776184, "umap_1": 8.146405220031738, "region": "Southeast Asian", "recipe": "Filipino Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63370"}, {"umap_0": 10.199616432189941, "umap_1": 10.071054458618164, "region": "Central American", "recipe": "Killer Sangria", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92985"}, {"umap_0": 1.4438186883926392, "umap_1": 5.494691371917725, "region": "Mexican", "recipe": "Mexican Omelet Roll-Ups With Avocado Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81023"}, {"umap_0": -0.7491047382354736, "umap_1": 4.932082176208496, "region": "Spanish and Portuguese", "recipe": "Potato and Leek Frittata", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142057"}, {"umap_0": 9.100556373596191, "umap_1": 9.097440719604492, "region": "Rest Africa", "recipe": "Clementines in Ginger Syrup, Algerian", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48573"}, {"umap_0": -1.7490047216415405, "umap_1": 8.839705467224121, "region": "Italian", "recipe": "Savino's Herb and Olive Chicken Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/10408"}, {"umap_0": -0.7827649712562561, "umap_1": 11.357047080993652, "region": "French", "recipe": "Flavoured Vinegar", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112016"}, {"umap_0": -0.24351391196250916, "umap_1": 10.631551742553711, "region": "South American", "recipe": "Colombian Chicken Soup a La Emeril", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/93821"}, {"umap_0": 0.2858981788158417, "umap_1": 9.938416481018066, "region": "Mexican", "recipe": "Chuckwagon Beans (Frijoles a La Charra)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77883"}, {"umap_0": -0.34065333008766174, "umap_1": 8.353398323059082, "region": "South American", "recipe": "Beef and Asparagus Roll-Ups", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/95130"}, {"umap_0": 1.8140946626663208, "umap_1": 6.912238121032715, "region": "Italian", "recipe": "Italian Hot & Spicy Oven Fried Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/127354"}, {"umap_0": -1.529252529144287, "umap_1": 6.6026506423950195, "region": "Italian", "recipe": "Italian 1 Pot Meal", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/126272"}, {"umap_0": 0.8462070226669312, "umap_1": 8.389432907104492, "region": "Deutschland", "recipe": "Swiss Steak Bh&g Year 1937", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118043"}, {"umap_0": 11.02765941619873, "umap_1": 7.757143974304199, "region": "French", "recipe": "Godiva Marjolaine", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114348"}, {"umap_0": 0.47562727332115173, "umap_1": 9.728699684143066, "region": "Mexican", "recipe": "Mexican Rice III", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6340"}, {"umap_0": 1.5462573766708374, "umap_1": 4.492384910583496, "region": "French", "recipe": "Taco Salad With Doritos & French Dressing", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115615"}, {"umap_0": 0.2590952217578888, "umap_1": 10.38813591003418, "region": "Italian", "recipe": "Mexican Pesto", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/10900"}, {"umap_0": -1.8283843994140625, "umap_1": 9.035175323486328, "region": "Italian", "recipe": "Calamari for a King", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132357"}, {"umap_0": 2.496938943862915, "umap_1": 10.862029075622559, "region": "Southeast Asian", "recipe": "Bun Chay (Vietnamese Veggie Rice Vermicelli Salad)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/62370"}, {"umap_0": -1.1525416374206543, "umap_1": 5.221553325653076, "region": "Italian", "recipe": "Sorrento Stuffed Chicken Breasts", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122560"}, {"umap_0": -2.449894428253174, "umap_1": 9.124031066894531, "region": "South American", "recipe": "Grilled Mesquite Beef Fajitas (Tex-Mex)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/97756"}, {"umap_0": -1.6584727764129639, "umap_1": 12.030065536499023, "region": "US", "recipe": "Easy Guacamole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/18256"}, {"umap_0": -0.9459820985794067, "umap_1": 5.569516658782959, "region": "Italian", "recipe": "Roasted Asparagus with Brown Butter and Pecorino", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/119717"}, {"umap_0": 2.6394083499908447, "umap_1": 10.345782279968262, "region": "Rest Africa", "recipe": "Oluwombo", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48916"}, {"umap_0": -2.517686605453491, "umap_1": 8.030699729919434, "region": "Greek", "recipe": "Best Greek Quinoa Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/9252"}, {"umap_0": 0.5090325474739075, "umap_1": 12.251130104064941, "region": "Indian Subcontinent", "recipe": "Lamb Sukuti (Crispy Smoked Lamb Marinated in Nepali Spices)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/59612"}, {"umap_0": 11.56545639038086, "umap_1": 10.310689926147461, "region": "Caribbean", "recipe": "Caribbean Cassis", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/90958"}, {"umap_0": -0.14634838700294495, "umap_1": 4.6056599617004395, "region": "Canadian", "recipe": "Bacon Cheddar Deviled Eggs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145752"}, {"umap_0": 1.8354699611663818, "umap_1": 7.335993766784668, "region": "Northern Africa", "recipe": "Chicken Croquettes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/49792"}, {"umap_0": 1.5767450332641602, "umap_1": 9.15180778503418, "region": "Belgian", "recipe": "Dutch Baked Beans", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134503"}, {"umap_0": 10.784056663513184, "umap_1": 7.630938529968262, "region": "US", "recipe": "Brigid's Blackberry Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/14165"}, {"umap_0": 0.8465257287025452, "umap_1": 4.669475555419922, "region": "Mexican", "recipe": "Cheesy Taco Sloppy Joes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79294"}, {"umap_0": 0.4976460933685303, "umap_1": 8.070438385009766, "region": "Italian", "recipe": "Pat's Standard Meatballs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/127380"}, {"umap_0": 11.347732543945312, "umap_1": 7.652974605560303, "region": "Irish", "recipe": "Mint Chocolate Brownies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/136180"}, {"umap_0": 1.5803881883621216, "umap_1": 10.38937759399414, "region": "Caribbean", "recipe": "Slow Cooker Tropical Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/8173"}, {"umap_0": 1.237654209136963, "umap_1": 6.316675186157227, "region": "Caribbean", "recipe": "Spicy Black Bean Sandwiches With Chipotle Mayonnaise", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92535"}, {"umap_0": 3.1554439067840576, "umap_1": 9.233389854431152, "region": "Chinese and Mongolian", "recipe": "Spicy Hotpot Broth (Sichuan) -- Hong Tang Lu", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53201"}, {"umap_0": 1.0343331098556519, "umap_1": 5.574160099029541, "region": "Mexican", "recipe": "Mexican Jack Cheese Omelet", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87188"}, {"umap_0": 1.652122974395752, "umap_1": 6.311713695526123, "region": "Mexican", "recipe": "Family Mexican Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79325"}, {"umap_0": 0.025085465982556343, "umap_1": 9.81269645690918, "region": "Japanese", "recipe": "Mexican Tortilla Chicken Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/71738"}, {"umap_0": 1.4926679134368896, "umap_1": 6.970399856567383, "region": "Eastern European", "recipe": "Zelova Vomacka (Sauerkraut Gravy)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142408"}, {"umap_0": 3.6649651527404785, "umap_1": 10.051774024963379, "region": "Chinese and Mongolian", "recipe": "Another Chinese Chicken Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56547"}, {"umap_0": -2.7004785537719727, "umap_1": 7.23246431350708, "region": "Italian", "recipe": "Eggplant (Aubergine) Almost Parmigiano", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/124072"}, {"umap_0": 0.025644266977906227, "umap_1": 8.840983390808105, "region": "Italian", "recipe": "Italian Tuscan Potato and Sausage Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120374"}, {"umap_0": 10.697286605834961, "umap_1": 7.963949203491211, "region": "French", "recipe": "Amazingly Delicious Chocolate Mousse", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/111370"}, {"umap_0": 0.8622411489486694, "umap_1": 6.402688503265381, "region": "Mexican", "recipe": "Mexican Cornbread II", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82970"}, {"umap_0": 9.412566184997559, "umap_1": 9.212646484375, "region": "Canadian", "recipe": "Jello Smoothie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148065"}, {"umap_0": -1.1330090761184692, "umap_1": 10.193440437316895, "region": "Deutschland", "recipe": "German Cukes & Tomatoes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137511"}, {"umap_0": 9.357527732849121, "umap_1": 6.522380828857422, "region": "Italian", "recipe": "Italian Genetti Cake 1962", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125165"}, {"umap_0": 1.3735902309417725, "umap_1": 4.824747085571289, "region": "Mexican", "recipe": "Mom's Easy Enchilada Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81346"}, {"umap_0": 0.6354721784591675, "umap_1": 8.935464859008789, "region": "Canadian", "recipe": "Give Thanks Pumpkin Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146551"}, {"umap_0": 1.4770550727844238, "umap_1": 12.153374671936035, "region": "Indian Subcontinent", "recipe": "Charishma's Brown Rice and Puliogare Rice Mix", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64932"}, {"umap_0": 1.3660162687301636, "umap_1": 10.005030632019043, "region": "South American", "recipe": "Double Cooked Beef Ribs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/98818"}, {"umap_0": -1.5219566822052002, "umap_1": 11.854148864746094, "region": "Mexican", "recipe": "Shrimp Ceviche on Endive", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83367"}, {"umap_0": 8.880476951599121, "umap_1": 7.366859436035156, "region": "Canadian", "recipe": "Fresh Peach Cake (Gluten Free)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147998"}, {"umap_0": 9.366851806640625, "umap_1": 9.195884704589844, "region": "Greek", "recipe": "Perfect Cup of Greek Tea", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110667"}, {"umap_0": -1.3214271068572998, "umap_1": 9.422991752624512, "region": "Deutschland", "recipe": "Quioa With Swiss Chard and Chick Peas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118442"}, {"umap_0": 0.37308236956596375, "umap_1": 8.61596393585205, "region": "Deutschland", "recipe": "Goulash Soup- German", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138722"}, {"umap_0": 2.2169711589813232, "umap_1": 11.16247844696045, "region": "Thai", "recipe": "Citrusy Tom Yum Chicken Stew With Yams & Kale (Slow Cooker)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/58929"}, {"umap_0": 1.4431850910186768, "umap_1": 9.236349105834961, "region": "Mexican", "recipe": "Mexican Fried Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/78284"}, {"umap_0": -0.14353497326374054, "umap_1": 6.9521613121032715, "region": "Australian", "recipe": "Bubble and Squeak Slice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75660"}, {"umap_0": 11.5856351852417, "umap_1": 8.733628273010254, "region": "Italian", "recipe": "Stella Doro Italian Rum Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120610"}, {"umap_0": 9.757328987121582, "umap_1": 6.803773403167725, "region": "US", "recipe": "Hawaiian Sweet Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16611"}, {"umap_0": 10.156984329223633, "umap_1": 6.4957122802734375, "region": "French", "recipe": "Superbly Rich Chocolate Tart", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112719"}, {"umap_0": 10.60612964630127, "umap_1": 7.962582111358643, "region": "Spanish and Portuguese", "recipe": "Spanish Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/141278"}, {"umap_0": 3.416504383087158, "umap_1": 9.423063278198242, "region": "Japanese", "recipe": "Okura and Sakura Shrimp Japanese-Style Spaghetti", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/5062"}, {"umap_0": -2.2897472381591797, "umap_1": 8.184566497802734, "region": "Italian", "recipe": "Simple Low-Fat Turkey Meatballs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120260"}, {"umap_0": 1.1479551792144775, "umap_1": 9.258878707885742, "region": "South American", "recipe": "Beef 'n Bean Burrito Stack (Crock Pot, Slow Cooker)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/95374"}, {"umap_0": 10.10209846496582, "umap_1": 7.524328231811523, "region": "UK", "recipe": "Louise Read's Coffee-Crunch Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/104370"}, {"umap_0": -1.838333010673523, "umap_1": 9.036421775817871, "region": "Middle Eastern", "recipe": "Preserved Lemons(ATK)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61208"}, {"umap_0": 10.957182884216309, "umap_1": 9.251062393188477, "region": "French", "recipe": "freedom fruit tart", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114699"}, {"umap_0": 2.8964154720306396, "umap_1": 10.311013221740723, "region": "Korean", "recipe": "Flash Korean Japanese Style Cucumber and Daikon Pickles", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69573"}, {"umap_0": -1.9289010763168335, "umap_1": 6.805454254150391, "region": "Italian", "recipe": "Spring Primavera", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120340"}, {"umap_0": -0.52470862865448, "umap_1": 8.281837463378906, "region": "French", "recipe": "Fish Fillets in Parchment With Asparagus & Orange", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115053"}, {"umap_0": 2.278409481048584, "umap_1": 11.373751640319824, "region": "Thai", "recipe": "Tom Yum Koong Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3190"}, {"umap_0": 2.523908853530884, "umap_1": 10.419310569763184, "region": "Southeast Asian", "recipe": "Indonesian Peanut Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/59869"}, {"umap_0": 3.3184008598327637, "umap_1": 10.022841453552246, "region": "US", "recipe": "Sesame Chicken Pasta Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/14761"}, {"umap_0": -1.1145869493484497, "umap_1": 4.25117826461792, "region": "US", "recipe": "Pepperoni Stuffed Zucchini", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/15553"}, {"umap_0": -0.16297447681427002, "umap_1": 8.082793235778809, "region": "French", "recipe": "Chicken Breasts With Mushroom Cream Sauce over Egg Noodles", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/116923"}, {"umap_0": 10.027602195739746, "umap_1": 9.561647415161133, "region": "Canadian", "recipe": "Apple Cinnamon Infused Vodka", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146576"}, {"umap_0": 9.60172176361084, "umap_1": 6.984546661376953, "region": "Indian Subcontinent", "recipe": "West Indian Coconut Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/66590"}, {"umap_0": -2.0326576232910156, "umap_1": 8.155261039733887, "region": "Greek", "recipe": "Greek Fit-For-The-Gods Salad With Spicy Cucumber Dressing", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110536"}, {"umap_0": -2.1525142192840576, "umap_1": 8.909070014953613, "region": "French", "recipe": "Scallops With Seaweed Butter", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115524"}, {"umap_0": 8.234896659851074, "umap_1": 6.744616985321045, "region": "Spanish and Portuguese", "recipe": "Portuguese Doughnuts", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118756"}, {"umap_0": -1.0125579833984375, "umap_1": 4.652006149291992, "region": "Italian", "recipe": "Spaghetti Torte", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/131940"}, {"umap_0": 0.3390287160873413, "umap_1": 9.763676643371582, "region": "Middle Eastern", "recipe": "Persian Pasta Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/60046"}, {"umap_0": 3.8986332416534424, "umap_1": 9.398303985595703, "region": "Japanese", "recipe": "Reconstituted Shitake Mushrooms", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/71034"}, {"umap_0": 1.6634480953216553, "umap_1": 8.457387924194336, "region": "South American", "recipe": "Tender Roast from Economical Cuts of Beef", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/94444"}, {"umap_0": 11.147115707397461, "umap_1": 5.5801167488098145, "region": "UK", "recipe": "Gluten Free Melt-In-Your-Mouth Shortbread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101540"}, {"umap_0": 10.615638732910156, "umap_1": 9.423094749450684, "region": "Australian", "recipe": "Boysenberry Kiwi Smoothie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76789"}, {"umap_0": 1.1105831861495972, "umap_1": 5.7901082038879395, "region": "Irish", "recipe": "Potatoes, Peppers, and Beer", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/136496"}, {"umap_0": 1.6699894666671753, "umap_1": 10.233530044555664, "region": "Chinese and Mongolian", "recipe": "Cantonese Meatballs (Appetizers)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/51995"}, {"umap_0": -1.6061029434204102, "umap_1": 5.809832572937012, "region": "Italian", "recipe": "Pizza Pasta Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/124814"}, {"umap_0": 0.43345507979393005, "umap_1": 10.59730339050293, "region": "Mexican", "recipe": "Baja Fish Wraps With Chipotle-Lime Slaw", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84865"}, {"umap_0": 9.462594032287598, "umap_1": 5.876317024230957, "region": "Rest Africa", "recipe": "North Africian Cardamom Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/49008"}, {"umap_0": 3.5356295108795166, "umap_1": 9.975740432739258, "region": "Chinese and Mongolian", "recipe": "Vegetarian Bean Sauce Noodles", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56500"}, {"umap_0": -0.7860097289085388, "umap_1": 11.373174667358398, "region": "Eastern European", "recipe": "Belarussian Carrot Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100784"}, {"umap_0": -1.3339581489562988, "umap_1": 9.327593803405762, "region": "Canadian", "recipe": "Spinach with Lentils", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148944"}, {"umap_0": 9.967204093933105, "umap_1": 7.210781574249268, "region": "Scandinavian", "recipe": "Swedish Rice Pudding", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/9129"}, {"umap_0": 3.366657257080078, "umap_1": 9.275442123413086, "region": "Japanese", "recipe": "Chicken Hekka", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/5083"}, {"umap_0": 0.8274092078208923, "umap_1": 8.276862144470215, "region": "South American", "recipe": "Brandied Beef Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/99647"}, {"umap_0": 1.087394118309021, "umap_1": 11.729743003845215, "region": "Indian Subcontinent", "recipe": "Kali Mirch Murg (Chicken Curry With Black Pepper)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64743"}, {"umap_0": -1.6914072036743164, "umap_1": 9.18214225769043, "region": "Eastern European", "recipe": "Basturma (russian Marinated Skewered Beef)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100510"}, {"umap_0": 0.9825918078422546, "umap_1": 10.085289001464844, "region": "US", "recipe": "Down-South Style Green Beans", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16128"}, {"umap_0": -0.2914678156375885, "umap_1": 7.806410789489746, "region": "Canadian", "recipe": "Cheeseburger Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145147"}, {"umap_0": -1.6939055919647217, "umap_1": 9.070364952087402, "region": "Australian", "recipe": "Pasta With Leeks and Parsley", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/72937"}, {"umap_0": 9.658759117126465, "umap_1": 5.5048627853393555, "region": "UK", "recipe": "Brown Sugar Shortbread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101438"}, {"umap_0": 1.2865381240844727, "umap_1": 7.969576835632324, "region": "Canadian", "recipe": "Susan's Best Cabbage Rolls", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147297"}, {"umap_0": 1.439955234527588, "umap_1": 5.958235740661621, "region": "Mexican", "recipe": "Elise's Quesadilla Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80657"}, {"umap_0": 2.4584014415740967, "umap_1": 5.440091133117676, "region": "South American", "recipe": "Low Cal Beef Taco Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/99840"}, {"umap_0": 1.5317089557647705, "umap_1": 5.783588409423828, "region": "Mexican", "recipe": "Chimichangas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/86813"}, {"umap_0": 10.646544456481934, "umap_1": 8.213096618652344, "region": "Mexican", "recipe": "Mexican Bread Pudding Capidotada", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83221"}, {"umap_0": -0.8091127872467041, "umap_1": 5.588508129119873, "region": "Italian", "recipe": "Alfredo Sauce (Of Death)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/127508"}, {"umap_0": 0.225128635764122, "umap_1": 12.402318000793457, "region": "Indian Subcontinent", "recipe": "Low Fat Aloo Gobi", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/68531"}, {"umap_0": -1.2968248128890991, "umap_1": 4.513106346130371, "region": "French", "recipe": "Meaty French Bread Pizza", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114503"}, {"umap_0": -2.5366716384887695, "umap_1": 8.779463768005371, "region": "Italian", "recipe": "Bread Salad With Fresh Tomatoes (panzanella)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/129737"}, {"umap_0": 10.623146057128906, "umap_1": 7.5068488121032715, "region": "Canadian", "recipe": "Real Canadian Butter Tarts", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/143510"}, {"umap_0": -2.386587381362915, "umap_1": 8.732303619384766, "region": "Australian", "recipe": "Cauliflower, Anchovy and Olive salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75638"}, {"umap_0": 3.113199472427368, "umap_1": 10.272427558898926, "region": "Australian", "recipe": "Marinated Prawns", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74652"}, {"umap_0": 10.777298927307129, "umap_1": 8.428910255432129, "region": "French", "recipe": "French Toast With Pineapple-Fig Flambe", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113306"}, {"umap_0": 7.68690824508667, "umap_1": 6.4767351150512695, "region": "Spanish and Portuguese", "recipe": "Ojaldas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/140733"}, {"umap_0": 1.9333122968673706, "umap_1": 10.470117568969727, "region": "Australian", "recipe": "Chicken With Cranberries and Orange", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75169"}, {"umap_0": -0.4192400574684143, "umap_1": 6.965161323547363, "region": "Canadian", "recipe": "Salmon Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148789"}, {"umap_0": -2.6806905269622803, "umap_1": 9.345675468444824, "region": "Greek", "recipe": "Granny's Greek Fried Potatoes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110992"}, {"umap_0": -0.20145563781261444, "umap_1": 10.386892318725586, "region": "Chinese and Mongolian", "recipe": "Spicy Orange Beef Kabobs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56952"}, {"umap_0": 0.10434052348136902, "umap_1": 8.132986068725586, "region": "South American", "recipe": "Sandaidh's Crock Pot Beef Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/99856"}, {"umap_0": 2.9792513847351074, "umap_1": 9.98609447479248, "region": "Chinese and Mongolian", "recipe": "Cream Cheese, Chinese Garlic-Hot Sauce, & Kim Chee Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/52425"}, {"umap_0": 11.401833534240723, "umap_1": 9.952619552612305, "region": "Rest Africa", "recipe": "Fruit and Nuts With Cream", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/51173"}, {"umap_0": -1.1528853178024292, "umap_1": 4.63319730758667, "region": "Italian", "recipe": "Delicate Cheese Ravioli Ala Filomena (And Baked Version, Too!)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132849"}, {"umap_0": -0.07309368252754211, "umap_1": 11.330818176269531, "region": "South American", "recipe": "Beef Brisket With Oranges", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96549"}, {"umap_0": 11.925108909606934, "umap_1": 8.318337440490723, "region": "Eastern European", "recipe": "Sliwka Naleczowska W Czekoladzie -- Polish Chocolate Plums", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/133650"}, {"umap_0": 1.4653419256210327, "umap_1": 9.624805450439453, "region": "Spanish and Portuguese", "recipe": "Memory Lane Spanish Roast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/140359"}, {"umap_0": 3.3458211421966553, "umap_1": 10.333921432495117, "region": "Chinese and Mongolian", "recipe": "Beef & Cashew Stir Fry", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/52853"}, {"umap_0": -0.9238266348838806, "umap_1": 6.956496715545654, "region": "Australian", "recipe": "Salmon & Leek Filo Parcels", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76031"}, {"umap_0": 10.662707328796387, "umap_1": 10.810108184814453, "region": "Mexican", "recipe": "Watermelon-Basil Margaritas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82476"}, {"umap_0": 0.18920071423053741, "umap_1": 5.791487693786621, "region": "Deutschland", "recipe": "Creamy Swiss & Ham Stuffed Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/117728"}, {"umap_0": -1.0673952102661133, "umap_1": 9.55289077758789, "region": "Mexican", "recipe": "Cancun Pescado Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87770"}, {"umap_0": 1.3067034482955933, "umap_1": 4.882326126098633, "region": "Mexican", "recipe": "Mom's Mexican Chicken (Jennifer Sue Jacks Henley)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6661"}, {"umap_0": 9.685789108276367, "umap_1": 8.276434898376465, "region": "Canadian", "recipe": "Heisenberg\u2019s Blue Rock \u201cMeth\u201d Candy", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146079"}, {"umap_0": 0.756194531917572, "umap_1": 9.154415130615234, "region": "Deutschland", "recipe": "Apricot Curried Rice with Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137196"}, {"umap_0": -1.0771478414535522, "umap_1": 9.509602546691895, "region": "US", "recipe": "Easy Roast Leg of Lamb", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16521"}, {"umap_0": -1.094968318939209, "umap_1": 4.1139020919799805, "region": "Italian", "recipe": "Spinach & Ravioli Lasagna", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/129917"}, {"umap_0": 2.24851655960083, "umap_1": 7.521053791046143, "region": "US", "recipe": "Mom's Texas Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/17565"}, {"umap_0": -0.38590046763420105, "umap_1": 8.061714172363281, "region": "Canadian", "recipe": "Southern Pecan crusted Chicken with Mustard sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146719"}, {"umap_0": 0.3166462182998657, "umap_1": 9.926994323730469, "region": "Mexican", "recipe": "Fish Tacos - Baja Style", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84042"}, {"umap_0": 8.933710098266602, "umap_1": 6.923816204071045, "region": "French", "recipe": "Cherry Crepes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114439"}, {"umap_0": 1.037848949432373, "umap_1": 5.429193019866943, "region": "Mexican", "recipe": "Monterey Ole' Mexican Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84613"}, {"umap_0": 11.82238483428955, "umap_1": 7.95355224609375, "region": "Deutschland", "recipe": "German Chocolate Cream Cheese Brownies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137649"}, {"umap_0": 2.0246706008911133, "umap_1": 6.24749231338501, "region": "Mexican", "recipe": "Fire-Roasted Corn and Poblano Tacos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87477"}, {"umap_0": -1.6825156211853027, "umap_1": 10.868810653686523, "region": "Northern Africa", "recipe": "Roasted Carrots -Memories of Morocco (Ww Core)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/49537"}, {"umap_0": 0.9019862413406372, "umap_1": 7.4742655754089355, "region": "Deutschland", "recipe": "Tyrolean Bacon-Dumpling Soup (Speckknodelsuppe)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/107418"}, {"umap_0": 1.742106318473816, "umap_1": 10.877889633178711, "region": "Indian Subcontinent", "recipe": "Curried Sweet Potatoes With Green Peas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64254"}, {"umap_0": 1.005946159362793, "umap_1": 9.449018478393555, "region": "Caribbean", "recipe": "Jamaican Beef Patties (Beef in Pastry)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/90703"}, {"umap_0": 0.5261460542678833, "umap_1": 10.313401222229004, "region": "Irish", "recipe": "Ancho Beer Chili", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134708"}, {"umap_0": 9.465495109558105, "umap_1": 8.637487411499023, "region": "Greek", "recipe": "Greek Pasteli (Sesame Seed & Honey Snacks)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/109056"}, {"umap_0": -1.575779676437378, "umap_1": 9.492369651794434, "region": "Middle Eastern", "recipe": "Garlic Rice with Pine Nuts", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61731"}, {"umap_0": 10.504138946533203, "umap_1": 8.11951732635498, "region": "Deutschland", "recipe": "Apple Strudel Two Ways", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137673"}, {"umap_0": 0.4395843744277954, "umap_1": 8.232477188110352, "region": "South American", "recipe": "Favorite Beef Vegetable Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/98710"}, {"umap_0": -0.8889778256416321, "umap_1": 4.557959079742432, "region": "Italian", "recipe": "Italian Omelette", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123885"}, {"umap_0": -1.4320403337478638, "umap_1": 8.87225341796875, "region": "French", "recipe": "Bistro Bouillabaisse", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/116716"}, {"umap_0": 0.4621977210044861, "umap_1": 5.162688255310059, "region": "Irish", "recipe": "Full Ulster Fry", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/135213"}, {"umap_0": 0.31085625290870667, "umap_1": 8.173240661621094, "region": "Australian", "recipe": "Salt and Pepper Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73573"}, {"umap_0": 9.681034088134766, "umap_1": 5.524683475494385, "region": "Irish", "recipe": "Herb Irish Soda Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/135927"}, {"umap_0": 0.5853262543678284, "umap_1": 4.925212860107422, "region": "Australian", "recipe": "Cheese and Leek Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74478"}, {"umap_0": 2.3423733711242676, "umap_1": 9.730361938476562, "region": "South American", "recipe": "Beef With Cabbage and Mushrooms", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/98989"}, {"umap_0": 11.362954139709473, "umap_1": 10.082721710205078, "region": "Irish", "recipe": "Tipperary", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134675"}, {"umap_0": 2.0764663219451904, "umap_1": 5.409379482269287, "region": "Mexican", "recipe": "Vegetarian Nachos Especial", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87135"}, {"umap_0": -0.14368288218975067, "umap_1": 5.6611151695251465, "region": "Chinese and Mongolian", "recipe": "Anne-Marie's Budget Saving Cheesie Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53689"}, {"umap_0": 11.728506088256836, "umap_1": 8.229470252990723, "region": "Canadian", "recipe": "Cheesecake Supreme", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/143316"}, {"umap_0": 3.080148696899414, "umap_1": 9.291823387145996, "region": "UK", "recipe": "Beef, Guinness and Mushroom Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/102578"}, {"umap_0": -1.6427479982376099, "umap_1": 10.05509090423584, "region": "Northern Africa", "recipe": "Moroccan Spiced Olives", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/49677"}, {"umap_0": 0.8318037390708923, "umap_1": 7.997498512268066, "region": "Deutschland", "recipe": "Joe's Swiss Roast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/117526"}, {"umap_0": 0.2965645492076874, "umap_1": 5.572545528411865, "region": "Deutschland", "recipe": "Ham and Swiss in a Bun", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118133"}, {"umap_0": 0.19851399958133698, "umap_1": 12.055628776550293, "region": "Indian Subcontinent", "recipe": "Long Beans With Tomatoes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67135"}, {"umap_0": 1.0551636219024658, "umap_1": 8.346288681030273, "region": "South American", "recipe": "Potted Stuffed Beef Heart and Madeira Gravy", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/94815"}, {"umap_0": 11.078954696655273, "umap_1": 7.712956428527832, "region": "Spanish and Portuguese", "recipe": "Spanish Spiced Hot Chocolate", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/141503"}, {"umap_0": 1.8542250394821167, "umap_1": 6.653536796569824, "region": "Mexican", "recipe": "The Ospidillo Cafe Chilies Rellenos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80807"}, {"umap_0": -1.3142787218093872, "umap_1": 8.45578384399414, "region": "French", "recipe": "Veal Medallions With French Morels", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113561"}, {"umap_0": -1.462088704109192, "umap_1": 8.64195728302002, "region": "US", "recipe": "Sloppy Joe with Ground Turkey", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/15744"}, {"umap_0": 2.9857001304626465, "umap_1": 6.698624610900879, "region": "UK", "recipe": "Marmite and Cheese Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/102443"}, {"umap_0": 1.0651118755340576, "umap_1": 12.153023719787598, "region": "Indian Subcontinent", "recipe": "Vegetable Biryani", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4018"}, {"umap_0": -1.4966187477111816, "umap_1": 12.058318138122559, "region": "Mexican", "recipe": "Super Fabulous Guacamole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/85691"}, {"umap_0": -1.5947813987731934, "umap_1": 8.943644523620605, "region": "Italian", "recipe": "Olive Garden Pollo Limone (Lemon Chicken)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122863"}, {"umap_0": 10.104763984680176, "umap_1": 6.601298809051514, "region": "Italian", "recipe": "Chocolate Citrus Biscotti", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120967"}, {"umap_0": -2.2293882369995117, "umap_1": 9.31502628326416, "region": "South American", "recipe": "Chimichurri Muy Pefecto", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/8507"}, {"umap_0": -1.3183051347732544, "umap_1": 10.387813568115234, "region": "Greek", "recipe": "Lentils Esau", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/109245"}, {"umap_0": 0.051858969032764435, "umap_1": 6.969412803649902, "region": "Canadian", "recipe": "Holiday Pecan Stuffing", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142646"}, {"umap_0": 1.5572264194488525, "umap_1": 5.45778751373291, "region": "Mexican", "recipe": "Alpo Dip!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79243"}, {"umap_0": 2.7580223083496094, "umap_1": 10.663866996765137, "region": "Rest Africa", "recipe": "Congo Tofu (Or Chicken)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48628"}, {"umap_0": -0.2753370404243469, "umap_1": 6.4594926834106445, "region": "Spanish and Portuguese", "recipe": "Double Decker Tomato Sandwiches", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/140916"}, {"umap_0": -2.074056625366211, "umap_1": 6.940325736999512, "region": "Italian", "recipe": "Berry Bruschetta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132207"}, {"umap_0": 0.08646221458911896, "umap_1": 8.49849796295166, "region": "Italian", "recipe": "Italian Dressing Meatloaf", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125058"}, {"umap_0": -2.5336055755615234, "umap_1": 9.157170295715332, "region": "Greek", "recipe": "Skorthalia (Greek Garlic Sauce)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/109394"}, {"umap_0": -1.004734992980957, "umap_1": 9.219395637512207, "region": "French", "recipe": "Fish Soup Provencale", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112973"}, {"umap_0": 2.7159018516540527, "umap_1": 8.857605934143066, "region": "Japanese", "recipe": "Avocado Sushi with Brown Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/5118"}, {"umap_0": 10.541696548461914, "umap_1": 7.53225564956665, "region": "Italian", "recipe": "Have It Your Way Biscotti", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120803"}, {"umap_0": 2.7782957553863525, "umap_1": 10.272409439086914, "region": "Southeast Asian", "recipe": "Adobo Style Shrimp (Filipino)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63692"}, {"umap_0": 10.56124210357666, "umap_1": 10.568076133728027, "region": "Mexican", "recipe": "Perro Salado (Tequila Salty Dog)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81265"}, {"umap_0": -1.3881385326385498, "umap_1": 7.135460376739502, "region": "Italian", "recipe": "Cheat's Easy Salmon Risotto (Rice Cooker)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125824"}, {"umap_0": -0.8828059434890747, "umap_1": 5.964145183563232, "region": "Scandinavian", "recipe": "Artichoke-Red Pepper Pesto Spread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/139781"}, {"umap_0": 0.9058073163032532, "umap_1": 5.742369174957275, "region": "Mexican", "recipe": "Mexican Chicken Rolls", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/88682"}, {"umap_0": 2.0204532146453857, "umap_1": 6.9913482666015625, "region": "Mexican", "recipe": "Easy Tamale Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83037"}, {"umap_0": -1.793311595916748, "umap_1": 8.244132041931152, "region": "US", "recipe": "Southern Turnip Greens with Sausage", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16160"}, {"umap_0": -1.4402920007705688, "umap_1": 12.00793743133545, "region": "Mexican", "recipe": "Los Salsa Roja de Grackles", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87851"}, {"umap_0": 1.8460345268249512, "umap_1": 7.46370792388916, "region": "Japanese", "recipe": "Curry", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/71497"}, {"umap_0": 3.2214860916137695, "umap_1": 9.551199913024902, "region": "Japanese", "recipe": "Izakaya Sakura Five Spice Soba", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/71902"}, {"umap_0": 0.057061370462179184, "umap_1": 8.298545837402344, "region": "South American", "recipe": "Low Fat Wok Strogonof", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/98141"}, {"umap_0": 10.255284309387207, "umap_1": 10.028037071228027, "region": "US", "recipe": "Virgin Strawberry Daiquiri", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16080"}, {"umap_0": 2.56575870513916, "umap_1": 10.922219276428223, "region": "South American", "recipe": "Sweet beef curry with corn and peas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/99522"}, {"umap_0": -0.36123520135879517, "umap_1": 9.023611068725586, "region": "Spanish and Portuguese", "recipe": "Arroz De Cabidela", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/119185"}, {"umap_0": -0.7476745247840881, "umap_1": 8.673479080200195, "region": "US", "recipe": "Original Blue Cheese Coleslaw", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/17603"}, {"umap_0": -1.8240654468536377, "umap_1": 8.180423736572266, "region": "Italian", "recipe": "Italian Tuna, Oven-Roasted Tomato, and Arugula Panini", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130315"}, {"umap_0": 10.154010772705078, "umap_1": 7.700729846954346, "region": "Italian", "recipe": "Cannoli III", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/11127"}, {"umap_0": 10.479533195495605, "umap_1": 8.134147644042969, "region": "Caribbean", "recipe": "Caribbean Key Lime Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/90104"}, {"umap_0": 2.5467443466186523, "umap_1": 10.30854606628418, "region": "US", "recipe": "Sharkey's Barbequed Trout", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/14146"}, {"umap_0": -2.552872896194458, "umap_1": 8.35036849975586, "region": "Italian", "recipe": "Easy Uncooked Tomato Sauce for Pasta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/126605"}, {"umap_0": 1.908292293548584, "umap_1": 7.644710540771484, "region": "Australian", "recipe": "Lamb Haters Crumbed Cutlets", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75985"}, {"umap_0": -2.313588857650757, "umap_1": 10.131288528442383, "region": "Canadian", "recipe": "Spinach, Mandarin & Cashew Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146450"}, {"umap_0": -1.7652684450149536, "umap_1": 7.72715425491333, "region": "Italian", "recipe": "Garlic Shrimp and Pasta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130743"}, {"umap_0": -1.013270616531372, "umap_1": 8.606904029846191, "region": "Irish", "recipe": "Gorgeous Vegetarian Rice Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/136462"}, {"umap_0": 2.834089994430542, "umap_1": 9.519465446472168, "region": "US", "recipe": "Garlic-Ginger Chicken Wings", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/17777"}, {"umap_0": 0.09859195351600647, "umap_1": 11.320109367370605, "region": "South American", "recipe": "Chuckwagon Beef Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/95600"}, {"umap_0": 0.3424185514450073, "umap_1": 8.87253189086914, "region": "Central American", "recipe": "Poyha (Old Native American Recipe) Meat & Cormeal", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/93001"}, {"umap_0": 0.7457483410835266, "umap_1": 10.03559398651123, "region": "Mexican", "recipe": "Fab-u-lous Refried Beans!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6175"}, {"umap_0": 1.8115586042404175, "umap_1": 7.452395439147949, "region": "Eastern European", "recipe": "Chicken Paprikash With Spaetzle", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105547"}, {"umap_0": -1.4686909914016724, "umap_1": 8.575615882873535, "region": "Middle Eastern", "recipe": "Authentic Lebanese Fattoush", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3818"}, {"umap_0": 7.602921485900879, "umap_1": 7.916861057281494, "region": "Japanese", "recipe": "Make-Ahead Sushi Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/71172"}, {"umap_0": 2.607903003692627, "umap_1": 10.810440063476562, "region": "Thai", "recipe": "Slow Cooker Thai Pork With Peanut Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/58172"}, {"umap_0": 3.679088592529297, "umap_1": 9.638720512390137, "region": "Chinese and Mongolian", "recipe": "Beef With Broccoli", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55821"}, {"umap_0": 10.81221866607666, "umap_1": 7.724643230438232, "region": "Deutschland", "recipe": "Chocolate Cheese Fondue", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118572"}, {"umap_0": 3.12463116645813, "umap_1": 7.510646820068359, "region": "Italian", "recipe": "Focaccia Buns", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/124056"}, {"umap_0": 2.524719715118408, "umap_1": 10.462780952453613, "region": "Mexican", "recipe": "Smashed Mexican Black Beans", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/78044"}, {"umap_0": 3.2224416732788086, "umap_1": 10.0649995803833, "region": "Chinese and Mongolian", "recipe": "Cantonese Roast Duck", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55276"}, {"umap_0": 2.668879747390747, "umap_1": 10.186763763427734, "region": "Chinese and Mongolian", "recipe": "Chicken, Cashews and Red Pepper Stir-Fry", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56201"}, {"umap_0": -1.5967803001403809, "umap_1": 8.705949783325195, "region": "Northern Africa", "recipe": "Fish Tagine With Tomatoes, Capers, and Cinnamon", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/49753"}, {"umap_0": 10.841547012329102, "umap_1": 6.848720550537109, "region": "UK", "recipe": "Easy Mexican Hot Chocolate", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/8887"}, {"umap_0": 10.348551750183105, "umap_1": 7.828114986419678, "region": "Italian", "recipe": "Spumetti (Chocolate-Hazelnut Meringues)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120851"}, {"umap_0": 11.177433013916016, "umap_1": 7.558730125427246, "region": "Australian", "recipe": "Dessert Jaffles", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74634"}, {"umap_0": 11.351784706115723, "umap_1": 8.262283325195312, "region": "Italian", "recipe": "Italian Rice Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/121492"}, {"umap_0": 0.8606560826301575, "umap_1": 5.519354820251465, "region": "US", "recipe": "Louisiana Shrimp Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16983"}, {"umap_0": 10.583642959594727, "umap_1": 7.005478858947754, "region": "Australian", "recipe": "Easy Chocolate Pancakes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73963"}, {"umap_0": 0.2288971096277237, "umap_1": 5.716791152954102, "region": "Caribbean", "recipe": "Trinidad Pepper Quiche", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91522"}, {"umap_0": -1.0484470129013062, "umap_1": 9.63629150390625, "region": "Middle Eastern", "recipe": "Middle Eastern Beef Burgers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/62952"}, {"umap_0": 10.229118347167969, "umap_1": 7.130414009094238, "region": "Australian", "recipe": "Hot Cross Buns I", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/5368"}, {"umap_0": 9.117935180664062, "umap_1": 7.722469806671143, "region": "Japanese", "recipe": "Apricot Mochi", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70999"}, {"umap_0": 0.8308312296867371, "umap_1": 10.961265563964844, "region": "Mexican", "recipe": "Low Carb Mexican \"rice\"", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77998"}, {"umap_0": 10.630115509033203, "umap_1": 7.235660076141357, "region": "Chinese and Mongolian", "recipe": "Rice Pudding (For One)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53455"}, {"umap_0": 2.0343143939971924, "umap_1": 5.875593185424805, "region": "Spanish and Portuguese", "recipe": "Roti", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/141768"}, {"umap_0": 1.26576828956604, "umap_1": 11.896153450012207, "region": "Indian Subcontinent", "recipe": "The New Exotic Marigold Curry Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/65176"}, {"umap_0": -1.100703477859497, "umap_1": 7.347123146057129, "region": "Irish", "recipe": "Brussels Sprouts wth Pecans, Basil and Garlic", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/135767"}, {"umap_0": -0.2541266083717346, "umap_1": 10.549250602722168, "region": "Mexican", "recipe": "Frijoles Rancheros", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81632"}, {"umap_0": 0.041061025112867355, "umap_1": 10.655411720275879, "region": "Indian Subcontinent", "recipe": "Bengali Dhal", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3711"}, {"umap_0": 2.986401081085205, "umap_1": 9.628595352172852, "region": "Chinese and Mongolian", "recipe": "Chinese Five Spice Salmon With Ginger Broth", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55266"}, {"umap_0": 10.449230194091797, "umap_1": 9.624399185180664, "region": "Rest Africa", "recipe": "Papaya Candy", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/49316"}, {"umap_0": -1.1819052696228027, "umap_1": 9.288045883178711, "region": "Spanish and Portuguese", "recipe": "Traditional Garlic Shrimp", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118998"}, {"umap_0": 9.8220796585083, "umap_1": 9.752531051635742, "region": "Rest Africa", "recipe": "Tej (Ethiopian Honey Wine)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/51512"}, {"umap_0": 7.734805583953857, "umap_1": 7.846033096313477, "region": "Chinese and Mongolian", "recipe": "Helen's Cheese Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/54520"}, {"umap_0": 3.1828866004943848, "umap_1": 9.53073501586914, "region": "Chinese and Mongolian", "recipe": "Noble House Beef Tomato Chow Mein", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56985"}, {"umap_0": -0.10581226646900177, "umap_1": 8.19990062713623, "region": "UK", "recipe": "Bubble and Squeak Cakes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/102609"}, {"umap_0": 2.2212445735931396, "umap_1": 8.82559871673584, "region": "Australian", "recipe": "Eira's Australian Mayonnaise", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75289"}, {"umap_0": 0.9013664722442627, "umap_1": 7.409241199493408, "region": "South American", "recipe": "Beef Rissoles (Kind of Like Hamburgers)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/95751"}, {"umap_0": 2.173975944519043, "umap_1": 7.53801965713501, "region": "Rest Africa", "recipe": "Potato Stuffed With Egg (Nafaqo)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47508"}, {"umap_0": 9.074942588806152, "umap_1": 9.018590927124023, "region": "Indian Subcontinent", "recipe": "Spicy Chai Tea", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67728"}, {"umap_0": 10.422380447387695, "umap_1": 5.937242031097412, "region": "Greek", "recipe": "Kourabiedes (Greek Butter Cookies)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/107846"}, {"umap_0": 0.8908785581588745, "umap_1": 10.590702056884766, "region": "Indian Subcontinent", "recipe": "Fried Pineapple Rice(Vegan)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64804"}, {"umap_0": -1.793685793876648, "umap_1": 8.096028327941895, "region": "French", "recipe": "Pecan-Stuffed Mushrooms", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114945"}, {"umap_0": 3.816594123840332, "umap_1": 10.079052925109863, "region": "Canadian", "recipe": "Sesame Green Beans & Peppers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/143645"}, {"umap_0": 1.8684269189834595, "umap_1": 7.361056804656982, "region": "South American", "recipe": "Savory Beef and Noodles", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/94767"}, {"umap_0": 1.890509843826294, "umap_1": 8.794905662536621, "region": "Spanish and Portuguese", "recipe": "Authentic Spanish Rice--From Famed De Grazia", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/141990"}, {"umap_0": 1.9873422384262085, "umap_1": 5.860854625701904, "region": "Mexican", "recipe": "Potato Rolled Tacos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/78600"}, {"umap_0": 10.642098426818848, "umap_1": 8.38407039642334, "region": "Canadian", "recipe": "Nettie Cronish's Chocolate Tofu Cheesecake for Nonbelievers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148992"}, {"umap_0": -0.5446988344192505, "umap_1": 10.437939643859863, "region": "Spanish and Portuguese", "recipe": "Lobster and Scallop Ceviche", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/140254"}, {"umap_0": -1.2126994132995605, "umap_1": 4.494453430175781, "region": "Italian", "recipe": "Bruschetta for One or Two", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132854"}, {"umap_0": 10.421103477478027, "umap_1": 10.151790618896484, "region": "UK", "recipe": "Pimm's With Lemonade", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101429"}, {"umap_0": 1.2626316547393799, "umap_1": 12.198409080505371, "region": "Indian Subcontinent", "recipe": "One Dish Meal: Carrot and Tomato Pulao", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/68159"}, {"umap_0": 9.729538917541504, "umap_1": 5.6272172927856445, "region": "Canadian", "recipe": "Maple Grandfathers (Grands-Peres a L\u2019erable)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/143062"}, {"umap_0": 10.417007446289062, "umap_1": 10.08156681060791, "region": "Australian", "recipe": "Lychee Lime Sparkler", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74145"}, {"umap_0": 0.23629122972488403, "umap_1": 13.682601928710938, "region": "Indian Subcontinent", "recipe": "Curry Powder - Jaffrey", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67123"}, {"umap_0": 1.7171356678009033, "umap_1": 10.082113265991211, "region": "Caribbean", "recipe": "Caribbean Chicken With Black Beans", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91036"}, {"umap_0": 2.4276649951934814, "umap_1": 8.936891555786133, "region": "Thai", "recipe": "Thai Beef With Broccoli in Oyster Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/57561"}, {"umap_0": -1.6275815963745117, "umap_1": 8.326469421386719, "region": "Scandinavian", "recipe": "Danish Blue Cheese Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101027"}, {"umap_0": -1.5368634462356567, "umap_1": 9.103995323181152, "region": "Deutschland", "recipe": "Potato and Parsley Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/139022"}, {"umap_0": 0.023742470890283585, "umap_1": 5.643985271453857, "region": "Canadian", "recipe": "Gourmet Potato Skins", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144027"}, {"umap_0": 9.981390953063965, "umap_1": 9.217269897460938, "region": "Northern Africa", "recipe": "Moroccan Spiced Oranges", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/50927"}, {"umap_0": 2.500869035720825, "umap_1": 6.922139644622803, "region": "Irish", "recipe": "St Patrick's Day Muffins (Savoury Potato Muffins)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/136401"}, {"umap_0": 0.5113669037818909, "umap_1": 10.425747871398926, "region": "Mexican", "recipe": "Spicy Shredded Brisket", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81207"}, {"umap_0": -1.8251659870147705, "umap_1": 8.923802375793457, "region": "UK", "recipe": "Easy One Tray Roasted Onions and Root Vegetables", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/104652"}, {"umap_0": 10.66236686706543, "umap_1": 9.936712265014648, "region": "Caribbean", "recipe": "Charle's Caribbean", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/90065"}, {"umap_0": 10.87686824798584, "umap_1": 8.276996612548828, "region": "Rest Africa", "recipe": "Banana & Date Dessert", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/49057"}, {"umap_0": 1.2176278829574585, "umap_1": 12.627145767211914, "region": "Indian Subcontinent", "recipe": "Simple Microwave Vegetable Pulao", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/66305"}, {"umap_0": -1.8016960620880127, "umap_1": 5.661343574523926, "region": "Italian", "recipe": "Grilled Garden Vegetable Sandwiches", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/129354"}, {"umap_0": -0.481958270072937, "umap_1": 12.602921485900879, "region": "Caribbean", "recipe": "Jamaican Jerk Dry Rub", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/90764"}, {"umap_0": 9.189184188842773, "umap_1": 7.048974514007568, "region": "Scandinavian", "recipe": "Swedish Apple Yeast Bread-Betty Crocker Recipe Cards", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/106270"}, {"umap_0": -2.47800874710083, "umap_1": 8.358266830444336, "region": "Greek", "recipe": "Greek Salad by Ina Garten (Barefoot Contessa)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/107657"}, {"umap_0": 0.019511450082063675, "umap_1": 10.462817192077637, "region": "Indian Subcontinent", "recipe": "Twisted Beef Koftas (Middle-Eastern Meatballs)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/66126"}, {"umap_0": 10.196945190429688, "umap_1": 6.3405303955078125, "region": "Spanish and Portuguese", "recipe": "Sponge Cake (Portuguese Pao De Lo)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118818"}, {"umap_0": 0.25186988711357117, "umap_1": 10.787273406982422, "region": "Middle Eastern", "recipe": "Dopiazeh", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61272"}, {"umap_0": -1.9276808500289917, "umap_1": 8.147125244140625, "region": "Greek", "recipe": "Greek-Style Spaghetti", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110587"}, {"umap_0": 11.401742935180664, "umap_1": 6.709829807281494, "region": "Deutschland", "recipe": "Mary's German Chocolate Cake Icing", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137602"}, {"umap_0": -1.5942800045013428, "umap_1": 10.639989852905273, "region": "Middle Eastern", "recipe": "Turkish Spiced Tomato Soup (Soguk Domates Corbasi)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69984"}, {"umap_0": 10.645520210266113, "umap_1": 10.292980194091797, "region": "Spanish and Portuguese", "recipe": "Crazy Huey Martini", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118678"}, {"umap_0": -2.68239688873291, "umap_1": 7.819113731384277, "region": "Greek", "recipe": "Grecian Grilled Cheese", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110785"}, {"umap_0": 3.7801709175109863, "umap_1": 10.404820442199707, "region": "Korean", "recipe": "The Kim Family Korean Beef Recipe", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69133"}, {"umap_0": -1.2185335159301758, "umap_1": 9.273280143737793, "region": "Spanish and Portuguese", "recipe": "Spanish Spiked Gazpacho in Cucumber Cups", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/141684"}, {"umap_0": -0.8615046143531799, "umap_1": 10.662614822387695, "region": "Mexican", "recipe": "Courgettes (Zucchini) With Cheese and Green Chillies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/78108"}, {"umap_0": -0.5264487862586975, "umap_1": 7.356823444366455, "region": "Italian", "recipe": "Hazelnut Fig Twists", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130746"}, {"umap_0": 8.925804138183594, "umap_1": 6.206500053405762, "region": "UK", "recipe": "Cleaned-Up Scottish Oatcakes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101386"}, {"umap_0": -0.9624252915382385, "umap_1": 7.129757881164551, "region": "Italian", "recipe": "Broccoli Lasagna Rolls", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/124188"}, {"umap_0": 9.628345489501953, "umap_1": 9.630969047546387, "region": "Mexican", "recipe": "Hibiscus Punch", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80752"}, {"umap_0": -2.0603652000427246, "umap_1": 9.247681617736816, "region": "Rest Africa", "recipe": "Moroccan Bread Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48122"}, {"umap_0": 2.4109160900115967, "umap_1": 8.286372184753418, "region": "Deutschland", "recipe": "The Mystery Chef's Swiss Steak", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/117938"}, {"umap_0": 10.97363567352295, "umap_1": 5.934720516204834, "region": "Mexican", "recipe": "Mexican Hot Chocolate Balls", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84584"}, {"umap_0": -0.577545166015625, "umap_1": 8.152962684631348, "region": "Italian", "recipe": "Judy's Hearty Vegetable Minestrone Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/10261"}, {"umap_0": 1.5284250974655151, "umap_1": 9.540640830993652, "region": "Indian Subcontinent", "recipe": "Upma", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67081"}, {"umap_0": 0.9554046392440796, "umap_1": 6.8464226722717285, "region": "French", "recipe": "French Onion Meatballs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114902"}, {"umap_0": -0.20772495865821838, "umap_1": 11.543726921081543, "region": "Indian Subcontinent", "recipe": "Chickpeas With Eggplant (Aubergine) and Spinach", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/65494"}, {"umap_0": 2.403017282485962, "umap_1": 5.687339782714844, "region": "Mexican", "recipe": "Stuffed Clams Roasted in the Coals", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81408"}, {"umap_0": -0.9155511856079102, "umap_1": 8.826055526733398, "region": "Spanish and Portuguese", "recipe": "Pork Loin With Mushroom (Lomo Con Champinones)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/141234"}, {"umap_0": 9.210749626159668, "umap_1": 6.720582485198975, "region": "US", "recipe": "Amish Friendship Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/15560"}, {"umap_0": -2.338742971420288, "umap_1": 7.879636287689209, "region": "Italian", "recipe": "Sicilian Broccoli", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120141"}, {"umap_0": 10.854401588439941, "umap_1": 10.377493858337402, "region": "Mexican", "recipe": "La Vida Mezcal", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6541"}, {"umap_0": -0.7336722016334534, "umap_1": 5.696012020111084, "region": "Italian", "recipe": "Creamy Parmesan Garlic Polenta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/119393"}, {"umap_0": 3.6414594650268555, "umap_1": 9.672829627990723, "region": "Japanese", "recipe": "Tantanmen (Tokyo Style Shoyu Sesame and Chile Ramen)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70604"}, {"umap_0": 9.877556800842285, "umap_1": 9.853166580200195, "region": "Japanese", "recipe": "Black Currant and Primitivo Wine Jam", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70732"}, {"umap_0": 1.227497935295105, "umap_1": 6.651404857635498, "region": "US", "recipe": "Pita Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/14499"}, {"umap_0": 1.8189146518707275, "umap_1": 6.107285022735596, "region": "Mexican", "recipe": "Chicken Tacos With Tomatillo Ranch", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/89414"}, {"umap_0": -2.254770517349243, "umap_1": 8.518220901489258, "region": "Italian", "recipe": "Bruschetta With Roasted Garlic and Cherry Tomatoes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132643"}, {"umap_0": 1.1190015077590942, "umap_1": 7.961056232452393, "region": "Mexican", "recipe": "Tlalpe\u00f1o Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87190"}, {"umap_0": 0.29040607810020447, "umap_1": 10.609500885009766, "region": "Chinese and Mongolian", "recipe": "Easy Authentic Mexican Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/54525"}, {"umap_0": 10.672554016113281, "umap_1": 8.970206260681152, "region": "Middle Eastern", "recipe": "Molasses Cones", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47481"}, {"umap_0": -0.7910933494567871, "umap_1": 6.165074348449707, "region": "UK", "recipe": "Wicklewood's Welsh Mushrooms", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105124"}, {"umap_0": 0.6991746425628662, "umap_1": 10.969401359558105, "region": "US", "recipe": "Smokey Tequila-Lime Marinade", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/17526"}, {"umap_0": 9.667543411254883, "umap_1": 6.912991046905518, "region": "Belgian", "recipe": "Apple Fritters", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134394"}, {"umap_0": 0.2740262746810913, "umap_1": 12.643250465393066, "region": "Southeast Asian", "recipe": "Soup Kambing (Malaysian Lamb Soup)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69789"}, {"umap_0": -1.5580838918685913, "umap_1": 7.757184982299805, "region": "French", "recipe": "Easy Ratatouille", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112268"}, {"umap_0": 10.338214874267578, "umap_1": 6.8388190269470215, "region": "UK", "recipe": "Christmas Cherry Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/103345"}, {"umap_0": 10.939335823059082, "umap_1": 7.31587553024292, "region": "Deutschland", "recipe": "Twelfth Night Cake or King Cake(Galette Des Rois)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/117523"}, {"umap_0": 9.025073051452637, "umap_1": 8.26443862915039, "region": "Indian Subcontinent", "recipe": "Paal Payasam (Indian Rice Pudding)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64656"}, {"umap_0": -1.4741584062576294, "umap_1": 10.426227569580078, "region": "Spanish and Portuguese", "recipe": "Colorful Citrus Spanish Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/140437"}, {"umap_0": 11.548933029174805, "umap_1": 8.305424690246582, "region": "Italian", "recipe": "Tiramisu Cups", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/129284"}, {"umap_0": -0.8882127404212952, "umap_1": 8.422369003295898, "region": "Italian", "recipe": "Salmon and Dill Frittata", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/124918"}, {"umap_0": 1.6205235719680786, "umap_1": 5.287153244018555, "region": "French", "recipe": "A1 Sauce Sweet and Savory Cherry Walnut Polenta Rounds #A1", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/111854"}, {"umap_0": 10.840353012084961, "umap_1": 9.385618209838867, "region": "Australian", "recipe": "Tropical Trifle", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73826"}, {"umap_0": -0.9255848526954651, "umap_1": 4.81312370300293, "region": "Italian", "recipe": "Italian Cutlets", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/124096"}, {"umap_0": 0.039873454719781876, "umap_1": 9.16160774230957, "region": "Italian", "recipe": "Chicken and Capers in Tomato Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/127899"}, {"umap_0": -1.2212255001068115, "umap_1": 4.640003681182861, "region": "Italian", "recipe": "Pesto Manicotti (No Tomatoes)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125988"}, {"umap_0": 0.9044475555419922, "umap_1": 4.555158615112305, "region": "Canadian", "recipe": "Pecan Blue-Cheese Spread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142632"}, {"umap_0": 9.282978057861328, "umap_1": 6.8065972328186035, "region": "Eastern European", "recipe": "Nut and Poppy Seed Rolls (May, 1972)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100528"}, {"umap_0": 8.339744567871094, "umap_1": 6.843602657318115, "region": "Irish", "recipe": "Real Homemade Root Beer", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134684"}, {"umap_0": 9.054905891418457, "umap_1": 6.683651924133301, "region": "Scandinavian", "recipe": "Swedish Kringle", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105982"}, {"umap_0": 1.8756550550460815, "umap_1": 7.322248935699463, "region": "Mexican", "recipe": "Crock Pot Chicken Fajitas--Easy!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/88962"}, {"umap_0": -1.218416690826416, "umap_1": 5.467983245849609, "region": "Italian", "recipe": "Mushroom & Veggie Sausage Lasagna", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123825"}, {"umap_0": 2.0463197231292725, "umap_1": 9.473433494567871, "region": "Scandinavian", "recipe": "Flygande Jacob (Flying Jacob)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/106455"}, {"umap_0": 11.035293579101562, "umap_1": 7.8755974769592285, "region": "Australian", "recipe": "Chocolate Raspberry Waffle Pudding", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74977"}, {"umap_0": 0.14760257303714752, "umap_1": 12.35356616973877, "region": "Southeast Asian", "recipe": "Indonesian Serundeng (Crisp Spiced Coconut with peanuts)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/59870"}, {"umap_0": 2.4332778453826904, "umap_1": 10.291032791137695, "region": "Southeast Asian", "recipe": "Gado Gado (Veggies With Peanut Sauce)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/59790"}, {"umap_0": -1.868709921836853, "umap_1": 5.509363651275635, "region": "Italian", "recipe": "Antipasto Platter", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132681"}, {"umap_0": 2.060631513595581, "umap_1": 9.21524429321289, "region": "Caribbean", "recipe": "Wayne's Famous Beef Ribs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91130"}, {"umap_0": 11.019545555114746, "umap_1": 10.436295509338379, "region": "Irish", "recipe": "Lucky Leprechaun", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/136413"}, {"umap_0": 2.9133384227752686, "umap_1": 10.572333335876465, "region": "Korean", "recipe": "Korean Barbecue Tofu", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69249"}, {"umap_0": 1.4277617931365967, "umap_1": 9.13318920135498, "region": "South American", "recipe": "Patti's Beef Cabbage Rolls", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96187"}, {"umap_0": -0.9506620764732361, "umap_1": 5.715970039367676, "region": "South American", "recipe": "Chili Beef Lasagne", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96069"}, {"umap_0": -0.8096973896026611, "umap_1": 7.222751617431641, "region": "Italian", "recipe": "Fettuccine Primavera", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123210"}, {"umap_0": -1.7326180934906006, "umap_1": 9.430590629577637, "region": "Greek", "recipe": "Nica Chick Orgasmic Chickpeas Bruschetta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/108652"}, {"umap_0": -0.21698667109012604, "umap_1": 9.42712116241455, "region": "South American", "recipe": "Beef Stroganoff Hamburger Dinner", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/97778"}, {"umap_0": 0.5565001368522644, "umap_1": 6.491284370422363, "region": "French", "recipe": "Dora's Rich French Onion Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/116059"}, {"umap_0": 3.490478515625, "umap_1": 9.585389137268066, "region": "Chinese and Mongolian", "recipe": "Zha Xiao Wan Zi (Chinese Fried Meatballs)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55749"}, {"umap_0": 1.04998779296875, "umap_1": 5.903123378753662, "region": "Mexican", "recipe": "Deep-Fried Chile Rellenos Wraps", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84052"}, {"umap_0": -2.2207531929016113, "umap_1": 7.246249675750732, "region": "Greek", "recipe": "Linda's Greek Pasta With Shrimp", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/108567"}, {"umap_0": 0.7537429332733154, "umap_1": 9.549909591674805, "region": "Caribbean", "recipe": "Trinidad Stewed Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/8096"}, {"umap_0": -0.46677491068840027, "umap_1": 8.112070083618164, "region": "Italian", "recipe": "Wild Risotto", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/12662"}, {"umap_0": -0.19594578444957733, "umap_1": 7.825660228729248, "region": "South American", "recipe": "Tenderloin of Beef With Blue Cheese and Herb Crust", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/97863"}, {"umap_0": 10.367473602294922, "umap_1": 8.366002082824707, "region": "Canadian", "recipe": "White Chocolate and Orange Poppy Seed Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146798"}, {"umap_0": 11.226455688476562, "umap_1": 6.152523994445801, "region": "Eastern European", "recipe": "John Hadamuscin's Bohemian Butter Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142515"}, {"umap_0": -0.3826609253883362, "umap_1": 9.954937934875488, "region": "Middle Eastern", "recipe": "Lebanese Koosa (Stuffed Yellow Squash)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/62903"}, {"umap_0": -0.9288316965103149, "umap_1": 8.375051498413086, "region": "Australian", "recipe": "Hopel-Popel", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/72577"}, {"umap_0": -1.1559484004974365, "umap_1": 6.778564453125, "region": "Italian", "recipe": "Chicken Parmigiana", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/131220"}, {"umap_0": 3.0296647548675537, "umap_1": 9.150810241699219, "region": "South American", "recipe": "Stir-Fried Beef With Mushrooms and Asparagus", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/98659"}, {"umap_0": 10.417654991149902, "umap_1": 7.299461364746094, "region": "Irish", "recipe": "Irish Whiskey Brownies With Sticky Toffee & Thick Cream", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/136415"}, {"umap_0": -1.0038859844207764, "umap_1": 4.265255451202393, "region": "Italian", "recipe": "Kim's Manicotti", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/126852"}, {"umap_0": -0.4125710725784302, "umap_1": 9.570051193237305, "region": "Rest Africa", "recipe": "Tunisian-Style Catfish Nuggets", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/2775"}, {"umap_0": -1.6035642623901367, "umap_1": 8.764134407043457, "region": "Italian", "recipe": "Beans, Greens, and Pasta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123493"}, {"umap_0": 10.453985214233398, "umap_1": 7.5885844230651855, "region": "Chinese and Mongolian", "recipe": "Arborio Rice Pudding", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/54356"}, {"umap_0": -2.3142261505126953, "umap_1": 7.850288391113281, "region": "Greek", "recipe": "Greek-Style Shrimp Salad on a Bed of Baby Spinach", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/9571"}, {"umap_0": 9.676576614379883, "umap_1": 7.882186412811279, "region": "Rest Africa", "recipe": "Tarartir-At-Turkman (Bonnets of the Turks)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47738"}, {"umap_0": 2.258389949798584, "umap_1": 9.30316162109375, "region": "Southeast Asian", "recipe": "Indonesian Fried Rice (Nasi Goreng)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3448"}, {"umap_0": 10.483269691467285, "umap_1": 10.343303680419922, "region": "Mexican", "recipe": "Trudy's Mexican Martini", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80511"}, {"umap_0": 1.6706291437149048, "umap_1": 9.118866920471191, "region": "Canadian", "recipe": "Best Meatloaf Ever !!!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/143077"}, {"umap_0": 1.0075185298919678, "umap_1": 8.240187644958496, "region": "South American", "recipe": "Bucks County Beef Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96794"}, {"umap_0": 1.5099126100540161, "umap_1": 8.985830307006836, "region": "Canadian", "recipe": "Mc Donald's Secret Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147357"}, {"umap_0": 11.254157066345215, "umap_1": 9.01680850982666, "region": "UK", "recipe": "Traditional Scottish Cranachan (Dessert for Adults)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101675"}, {"umap_0": 3.140324354171753, "umap_1": 9.999537467956543, "region": "Chinese and Mongolian", "recipe": "P F Chang's Tuna Tataki", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55576"}, {"umap_0": 0.8179575800895691, "umap_1": 6.50093412399292, "region": "Italian", "recipe": "Tvp Spaghetti Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/124413"}, {"umap_0": 8.218727111816406, "umap_1": 7.059240818023682, "region": "Eastern European", "recipe": "Hungarian White Bread With Fennel (Bread Machine)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105702"}, {"umap_0": -1.2702908515930176, "umap_1": 4.4477763175964355, "region": "Deutschland", "recipe": "German Tomato Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/13403"}, {"umap_0": 1.2562682628631592, "umap_1": 12.764361381530762, "region": "Indian Subcontinent", "recipe": "South Indian Lentil Kootu", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4470"}, {"umap_0": 10.969606399536133, "umap_1": 8.996729850769043, "region": "Mexican", "recipe": "Guilt Free Strawberry Liquada", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79569"}, {"umap_0": 8.28555679321289, "umap_1": 7.844581604003906, "region": "Japanese", "recipe": "Simply Mochi", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4937"}, {"umap_0": 10.519747734069824, "umap_1": 7.363301753997803, "region": "Japanese", "recipe": "Japanese Green Tea Petits Fours", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4923"}, {"umap_0": 11.137533187866211, "umap_1": 10.379852294921875, "region": "Scandinavian", "recipe": "Roxy Special", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/139835"}, {"umap_0": -0.5091302394866943, "umap_1": 5.693753719329834, "region": "Canadian", "recipe": "BBQ'd Garlic Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144110"}, {"umap_0": 10.266124725341797, "umap_1": 8.742798805236816, "region": "Caribbean", "recipe": "Caribbean Pavlovas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/90718"}, {"umap_0": 1.4891453981399536, "umap_1": 10.569977760314941, "region": "Middle Eastern", "recipe": "Turkish Chicken Thighs ($400. Winner)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69823"}, {"umap_0": 0.4208536744117737, "umap_1": 12.991476058959961, "region": "Indian Subcontinent", "recipe": "Stir-Fried Cauliflower & Potato W- Crunchy Bengali Spices", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/68652"}, {"umap_0": 1.6420304775238037, "umap_1": 5.930147647857666, "region": "Mexican", "recipe": "Lamb and Bean Nachos With Salsa Fresca", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80014"}, {"umap_0": 0.41553762555122375, "umap_1": 6.457788467407227, "region": "Belgian", "recipe": "Dutch Potatoes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134469"}, {"umap_0": -1.7385210990905762, "umap_1": 8.296869277954102, "region": "Italian", "recipe": "Capers & Sun-Dried Tomato Pasta Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/129297"}, {"umap_0": -0.10568946599960327, "umap_1": 5.9412431716918945, "region": "Eastern European", "recipe": "Caviar Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100407"}, {"umap_0": 1.1807453632354736, "umap_1": 5.82730770111084, "region": "Mexican", "recipe": "Beth's Taco Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83637"}, {"umap_0": 10.269340515136719, "umap_1": 8.13279914855957, "region": "Scandinavian", "recipe": "Jerusalem Pudding", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/9189"}, {"umap_0": -0.036388691514730453, "umap_1": 10.5352144241333, "region": "Mexican", "recipe": "Don Fernando's Green Chile Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84184"}, {"umap_0": 10.067889213562012, "umap_1": 6.525073051452637, "region": "UK", "recipe": "Tiessennau Mel (honey Cakes) Welsh", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105079"}, {"umap_0": -1.534541368484497, "umap_1": 6.266122341156006, "region": "Italian", "recipe": "Bolognese Sauce - Sunday Gravy With Meat", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130856"}, {"umap_0": 0.29097118973731995, "umap_1": 10.859216690063477, "region": "South American", "recipe": "Southwestern Beef Brisket", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100000"}, {"umap_0": 7.8124470710754395, "umap_1": 6.949952125549316, "region": "Italian", "recipe": "Spelt Noodles", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/12283"}, {"umap_0": -1.1623494625091553, "umap_1": 6.1636433601379395, "region": "US", "recipe": "Tim's Sausage Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/18073"}, {"umap_0": 1.3285937309265137, "umap_1": 6.5275797843933105, "region": "Mexican", "recipe": "Mexi Cheeseburger Quiche", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79822"}, {"umap_0": -1.0547816753387451, "umap_1": 9.46082592010498, "region": "Italian", "recipe": "Amazing Spaghetti with Seafood Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122226"}, {"umap_0": 1.477939486503601, "umap_1": 7.1679840087890625, "region": "Spanish and Portuguese", "recipe": "Tortilla Espanola (Spanish Omelet)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/141172"}, {"umap_0": 0.16818618774414062, "umap_1": 9.326894760131836, "region": "South American", "recipe": "Ground Beef-Venison Goulash", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/97264"}, {"umap_0": 1.1907352209091187, "umap_1": 4.826080322265625, "region": "Mexican", "recipe": "Creamy Smothered Chicken Burritos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/88837"}, {"umap_0": -1.8339776992797852, "umap_1": 9.466512680053711, "region": "Caribbean", "recipe": "Avocado Salad (Ensalada De Aguacate)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92340"}, {"umap_0": 0.17207179963588715, "umap_1": 9.50382137298584, "region": "Canadian", "recipe": "Herbed Chicken with Brown Rice Pilaf", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145186"}, {"umap_0": 0.44100239872932434, "umap_1": 5.775967597961426, "region": "US", "recipe": "Sinless Mississippi Sin", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/13847"}, {"umap_0": -0.28121545910835266, "umap_1": 7.490437030792236, "region": "US", "recipe": "Lobster Colorado", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/18215"}, {"umap_0": 11.686797142028809, "umap_1": 8.539962768554688, "region": "Mexican", "recipe": "Creamy Mexican Chocolate Iced Coffee", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/78842"}, {"umap_0": -1.5916171073913574, "umap_1": 8.543956756591797, "region": "Italian", "recipe": "Italian \u201cDrunken\u201d Noodles With Spicy Italian Sausage", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/131564"}, {"umap_0": 10.202253341674805, "umap_1": 7.9820942878723145, "region": "US", "recipe": "Scalloped Sweet Potatoes and Apples", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/14727"}, {"umap_0": 0.40166589617729187, "umap_1": 5.240620136260986, "region": "Italian", "recipe": "Mini Ham 'n' Cheese Frittatas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125634"}, {"umap_0": 1.8688045740127563, "umap_1": 6.32774543762207, "region": "Mexican", "recipe": "Chicken Tortilla Soup II", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/88979"}, {"umap_0": 1.5201773643493652, "umap_1": 7.182694911956787, "region": "Spanish and Portuguese", "recipe": "Spanish Tortilla With Vidalia Onions & Ham", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/140542"}, {"umap_0": 10.239057540893555, "umap_1": 8.936830520629883, "region": "Canadian", "recipe": "Healthy Fruit Candies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/149047"}, {"umap_0": -1.606303334236145, "umap_1": 6.47824764251709, "region": "UK", "recipe": "Easy English Pizza", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/104419"}, {"umap_0": 1.9969687461853027, "umap_1": 5.155827045440674, "region": "South American", "recipe": "Too Easy Vegetable Beef Hot Dish", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/95703"}, {"umap_0": 9.890812873840332, "umap_1": 6.3435139656066895, "region": "Middle Eastern", "recipe": "Honey Oatmeal Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/60766"}, {"umap_0": -1.5631150007247925, "umap_1": 8.137102127075195, "region": "French", "recipe": "Chicken With Shallots, Prunes, and Armagnac", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114868"}, {"umap_0": 0.37364691495895386, "umap_1": 10.663841247558594, "region": "Mexican", "recipe": "Lentil Tacos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6013"}, {"umap_0": -0.2388976812362671, "umap_1": 7.822738170623779, "region": "French", "recipe": "Hachis Parmentier or French Style Shepherd's Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114059"}, {"umap_0": -0.7614589333534241, "umap_1": 7.115261554718018, "region": "Italian", "recipe": "Oven-Baked Red Pepper Risotto", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/124035"}, {"umap_0": 3.422422170639038, "umap_1": 9.77412223815918, "region": "South American", "recipe": "Beef With Bean Sprouts", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/99469"}, {"umap_0": -1.4373353719711304, "umap_1": 9.909008979797363, "region": "Caribbean", "recipe": "Black Beans", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92366"}, {"umap_0": 1.6213314533233643, "umap_1": 6.147777080535889, "region": "Mexican", "recipe": "Mexican Lasagna With Black Beans and Corn", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/86023"}, {"umap_0": -1.0119351148605347, "umap_1": 6.040040969848633, "region": "Italian", "recipe": "Simple Spinach Lasagna", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/12368"}, {"umap_0": 10.456080436706543, "umap_1": 6.678522109985352, "region": "Scandinavian", "recipe": "Swedish Cardamom Coffee Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105886"}, {"umap_0": 11.077064514160156, "umap_1": 6.847013473510742, "region": "Canadian", "recipe": "Chocolate Truffles With Liqueur", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145808"}, {"umap_0": -0.28316232562065125, "umap_1": 10.125900268554688, "region": "Middle Eastern", "recipe": "Lamb, Carrot, and White Bean Curry Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3579"}, {"umap_0": -1.6278572082519531, "umap_1": 9.381786346435547, "region": "Deutschland", "recipe": "Wurstsalat - Sausage Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137610"}, {"umap_0": 10.206049919128418, "umap_1": 6.160872459411621, "region": "Canadian", "recipe": "Warm Apricot Cobbler", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142906"}, {"umap_0": 3.456279754638672, "umap_1": 10.273784637451172, "region": "Chinese and Mongolian", "recipe": "Chinese Hot Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/52512"}, {"umap_0": -0.324316143989563, "umap_1": 11.984728813171387, "region": "Caribbean", "recipe": "Weight Watcher Jerk Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91248"}, {"umap_0": 1.3149811029434204, "umap_1": 7.221072673797607, "region": "Italian", "recipe": "Methodist Spaghetti Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/124533"}, {"umap_0": 0.33363932371139526, "umap_1": 11.082000732421875, "region": "Rest Africa", "recipe": "African Sweet Potato and Peanut Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/49109"}, {"umap_0": 1.6657456159591675, "umap_1": 7.3172221183776855, "region": "South American", "recipe": "Desperation Beef", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/98497"}, {"umap_0": -1.363763451576233, "umap_1": 7.4157915115356445, "region": "Italian", "recipe": "Grpa's Italian Spaghetti Sauce With Meatballs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/131199"}, {"umap_0": 9.219595909118652, "umap_1": 8.402389526367188, "region": "Indian Subcontinent", "recipe": "Gajar Ka Halwa (Carrot Pudding)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/72147"}, {"umap_0": 7.7559814453125, "umap_1": 6.929618835449219, "region": "Italian", "recipe": "Mediterranean Black Olive Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/11255"}, {"umap_0": -0.9790279865264893, "umap_1": 7.3705596923828125, "region": "Australian", "recipe": "Avocado BLT Sandwiches", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77594"}, {"umap_0": 1.893933892250061, "umap_1": 5.844855308532715, "region": "Mexican", "recipe": "Nacho Taco", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82522"}, {"umap_0": 1.3473308086395264, "umap_1": 8.750595092773438, "region": "Canadian", "recipe": "Rice, Corn and Cheese Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148630"}, {"umap_0": -0.34672340750694275, "umap_1": 9.231557846069336, "region": "US", "recipe": "Gluten-Free Chicken and Sausage Gumbo", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/14901"}, {"umap_0": 11.391111373901367, "umap_1": 8.514914512634277, "region": "Australian", "recipe": "Dolly Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74631"}, {"umap_0": -1.7576788663864136, "umap_1": 9.005260467529297, "region": "US", "recipe": "Healthy and Delicious Southern Turnip Greens", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16137"}, {"umap_0": -0.03633185103535652, "umap_1": 9.259231567382812, "region": "Mexican", "recipe": "Spicy Chorizo Stuffed Poblano Peppers With Cheese", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/88000"}, {"umap_0": 3.2821478843688965, "umap_1": 8.846996307373047, "region": "Japanese", "recipe": "Lobster Broth Noodle Bowl", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70774"}, {"umap_0": -2.3274147510528564, "umap_1": 9.041618347167969, "region": "Italian", "recipe": "Southern Italian Traditional Tomato Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/128508"}, {"umap_0": 9.073450088500977, "umap_1": 7.631127834320068, "region": "UK", "recipe": "Gluten Free Hot Cross Buns", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/102760"}, {"umap_0": 1.7751922607421875, "umap_1": 4.635721206665039, "region": "Mexican", "recipe": "Nibbler's Delight", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83665"}, {"umap_0": 3.742229461669922, "umap_1": 10.06087875366211, "region": "Chinese and Mongolian", "recipe": "Sesame Tuna Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/52522"}, {"umap_0": -2.403917074203491, "umap_1": 11.73879623413086, "region": "Italian", "recipe": "Italian Seasoning II", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/11024"}, {"umap_0": -1.2843670845031738, "umap_1": 9.208592414855957, "region": "Northern Africa", "recipe": "Twice-Cooked Marrakech Red Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/50535"}, {"umap_0": 0.23657526075839996, "umap_1": 11.859291076660156, "region": "Indian Subcontinent", "recipe": "Indian Spiced Pea Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/68985"}, {"umap_0": 0.2634831368923187, "umap_1": 4.905213832855225, "region": "South American", "recipe": "Tasty Beef Spread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/97026"}, {"umap_0": -1.8585253953933716, "umap_1": 9.019905090332031, "region": "Australian", "recipe": "Green Olive Relish", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77489"}, {"umap_0": 1.4882398843765259, "umap_1": 8.0390625, "region": "Chinese and Mongolian", "recipe": "Mushroom Oven Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/54772"}, {"umap_0": 2.7530677318573, "umap_1": 9.849610328674316, "region": "Chinese and Mongolian", "recipe": "Chinese (Ramen) Noodle Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/51777"}, {"umap_0": -2.179657220840454, "umap_1": 9.200481414794922, "region": "Italian", "recipe": "Tuscan-Style Cauliflower", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120216"}, {"umap_0": 0.08531598746776581, "umap_1": 4.652676582336426, "region": "Deutschland", "recipe": "Swiss Cheese Pizzas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/117852"}, {"umap_0": 0.7458925843238831, "umap_1": 10.896985054016113, "region": "Middle Eastern", "recipe": "Lamb Stuffed Eggplant (Aubergine) or Zucchini", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61402"}, {"umap_0": -1.0564689636230469, "umap_1": 5.529055595397949, "region": "Italian", "recipe": "Bruschetta Chicken Bake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/131953"}, {"umap_0": 8.587217330932617, "umap_1": 7.322329998016357, "region": "Indian Subcontinent", "recipe": "MAL PUAS", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/66662"}, {"umap_0": -1.2007917165756226, "umap_1": 8.501324653625488, "region": "Canadian", "recipe": "Baked Acorn Squash With Wild Rice Medley", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/143718"}, {"umap_0": -1.7477892637252808, "umap_1": 9.9800386428833, "region": "Eastern European", "recipe": "Griby Marinovannye (Russian Marinated Mushrooms)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100697"}, {"umap_0": 10.324197769165039, "umap_1": 7.699040412902832, "region": "UK", "recipe": "Empire Biscuits", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/8648"}, {"umap_0": -1.35700261592865, "umap_1": 11.375781059265137, "region": "Mexican", "recipe": "Mango Tomatillo Salsa", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83886"}, {"umap_0": 1.6215407848358154, "umap_1": 10.150081634521484, "region": "Chinese and Mongolian", "recipe": "Chinese Barbecue Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56298"}, {"umap_0": 3.040983200073242, "umap_1": 10.141079902648926, "region": "Thai", "recipe": "Sesame Thai Noodles With Shrimp", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/58916"}, {"umap_0": 8.212296485900879, "umap_1": 6.017678260803223, "region": "Indian Subcontinent", "recipe": "Tender Popovers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/66869"}, {"umap_0": 1.4308379888534546, "umap_1": 5.747464656829834, "region": "Mexican", "recipe": "Salsa Chicken Burrito Filling", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/88724"}, {"umap_0": 10.7412691116333, "umap_1": 10.385404586791992, "region": "Caribbean", "recipe": "Almond Cigar", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91835"}, {"umap_0": 1.7323603630065918, "umap_1": 11.296564102172852, "region": "Southeast Asian", "recipe": "Marinade: Grilled Chicken With Lemongrass & Chilli", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/62064"}, {"umap_0": -1.2564170360565186, "umap_1": 9.748128890991211, "region": "Caribbean", "recipe": "Garlicky Cuban Shredded Pork", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92448"}, {"umap_0": -2.280280828475952, "umap_1": 9.997919082641602, "region": "Italian", "recipe": "Super Quick Pasta Al Pomodoro", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130576"}, {"umap_0": 2.1221442222595215, "umap_1": 5.257297515869141, "region": "South American", "recipe": "Make Ahead Chimichangas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/95070"}, {"umap_0": -1.2632070779800415, "umap_1": 5.581155300140381, "region": "Italian", "recipe": "Easy, Healthy Vegetarian Lasagna", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130047"}, {"umap_0": -1.852502703666687, "umap_1": 7.257450103759766, "region": "Italian", "recipe": "Grilled Vegetable Muffuletta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/127919"}, {"umap_0": -0.024608049541711807, "umap_1": 6.620772838592529, "region": "Belgian", "recipe": "Drunken French Country Chicken Au Gratin", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/106671"}, {"umap_0": -1.2357099056243896, "umap_1": 6.988382816314697, "region": "Italian", "recipe": "Bolognese the Old-Fashioned Way!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122642"}, {"umap_0": 1.0163264274597168, "umap_1": 10.669305801391602, "region": "Caribbean", "recipe": "Red Bean Chili", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/90940"}, {"umap_0": 10.18138313293457, "umap_1": 8.957853317260742, "region": "UK", "recipe": "White Fruit Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/8934"}, {"umap_0": 11.172503471374512, "umap_1": 7.698637962341309, "region": "French", "recipe": "Cinnamon Bun French Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114388"}, {"umap_0": -1.2426837682724, "umap_1": 11.372151374816895, "region": "Rest Africa", "recipe": "Eggplant Compote", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47583"}, {"umap_0": -0.24096521735191345, "umap_1": 5.453311443328857, "region": "South American", "recipe": "Beef and Parmesan Sliders", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96326"}, {"umap_0": 9.258859634399414, "umap_1": 6.180406093597412, "region": "Canadian", "recipe": "Awesome Raisin Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145392"}, {"umap_0": 10.568404197692871, "umap_1": 10.613948822021484, "region": "Mexican", "recipe": "Chipotle Grapefruit Margarita", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83910"}, {"umap_0": 9.520296096801758, "umap_1": 7.875370025634766, "region": "Australian", "recipe": "Dumplings and Cocky's Joy (Caramel Sauce)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/5274"}, {"umap_0": 10.333106994628906, "umap_1": 9.611656188964844, "region": "Middle Eastern", "recipe": "Persian Fruit Salad Desser Miveh", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/60334"}, {"umap_0": 0.24702638387680054, "umap_1": 7.763823986053467, "region": "French", "recipe": "Uncle Bill's French Mushroom Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113484"}, {"umap_0": 10.794291496276855, "umap_1": 7.143560886383057, "region": "Scandinavian", "recipe": "Eggedosis", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/107089"}, {"umap_0": 8.341460227966309, "umap_1": 6.825126647949219, "region": "Greek", "recipe": "Quick Yeast Dough", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110031"}, {"umap_0": 3.2276620864868164, "umap_1": 10.498610496520996, "region": "Japanese", "recipe": "Teriyaki Marinade", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/71076"}, {"umap_0": 0.8737309575080872, "umap_1": 7.615300178527832, "region": "UK", "recipe": "Shepherd's Pie Nutrition Loaded Vegan, Low Carb & Low Fat", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/103198"}, {"umap_0": 0.16963794827461243, "umap_1": 5.111111640930176, "region": "Mexican", "recipe": "Mexican Snack", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87050"}, {"umap_0": -0.7524120211601257, "umap_1": 6.655940532684326, "region": "Italian", "recipe": "Hamburger Minestrone Soup (South Beach Diet)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125717"}, {"umap_0": -1.1507580280303955, "umap_1": 11.432164192199707, "region": "Mexican", "recipe": "Fury Salsa", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79201"}, {"umap_0": 1.4013336896896362, "umap_1": 6.757198810577393, "region": "Australian", "recipe": "Creamy Chicken Curry Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73077"}, {"umap_0": -0.451552152633667, "umap_1": 10.86103630065918, "region": "Mexican", "recipe": "Poc Chuc", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83477"}, {"umap_0": 10.563416481018066, "umap_1": 7.145893096923828, "region": "Belgian", "recipe": "Dutch Almond Squares", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134019"}, {"umap_0": 1.0033942461013794, "umap_1": 9.71091365814209, "region": "Irish", "recipe": "Tortured Chicken - Beer Can", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/135358"}, {"umap_0": 0.6945362091064453, "umap_1": 10.473905563354492, "region": "Mexican", "recipe": "Black Bean & Corn Enchiladas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83447"}, {"umap_0": 10.621631622314453, "umap_1": 6.639152526855469, "region": "French", "recipe": "Fresh Peach French Toast Cobbler", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112599"}, {"umap_0": -0.10664887726306915, "umap_1": 10.672699928283691, "region": "Mexican", "recipe": "Home-Style Refried Beans", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/78296"}, {"umap_0": -0.044455137103796005, "umap_1": 7.254788875579834, "region": "Australian", "recipe": "Australian Fish and Spring Onion Pies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76231"}, {"umap_0": 3.8564932346343994, "umap_1": 9.987544059753418, "region": "Japanese", "recipe": "Hiyashi Chuka (Japanese Summer Salad With Egg Noodles, Ham and G", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/71546"}, {"umap_0": 9.169215202331543, "umap_1": 6.046225547790527, "region": "Middle Eastern", "recipe": "Neopolitan Flan (Aka Caramel Flan Cake)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61914"}, {"umap_0": -2.0501248836517334, "umap_1": 8.419882774353027, "region": "French", "recipe": "Soup a L'aille", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/117138"}, {"umap_0": 0.7450438141822815, "umap_1": 10.521781921386719, "region": "Mexican", "recipe": "Y. J. H. Taco Meat", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82972"}, {"umap_0": 1.9771983623504639, "umap_1": 10.00633430480957, "region": "Australian", "recipe": "Spicy Cucumber Relish", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76771"}, {"umap_0": 9.545906066894531, "umap_1": 6.6639180183410645, "region": "Spanish and Portuguese", "recipe": "Portuguese Spice Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118943"}, {"umap_0": 8.845976829528809, "umap_1": 6.484364032745361, "region": "Eastern European", "recipe": "Elsie Hronek's Kolaches", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142377"}, {"umap_0": 1.1501518487930298, "umap_1": 6.484608173370361, "region": "UK", "recipe": "Just an Egg", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/102077"}, {"umap_0": 1.8158323764801025, "umap_1": 7.961818695068359, "region": "Chinese and Mongolian", "recipe": "Chinese Goulash", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56847"}, {"umap_0": -1.1699687242507935, "umap_1": 7.2184343338012695, "region": "Italian", "recipe": "Creamy Lemon-Pesto Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/131276"}, {"umap_0": -1.8316586017608643, "umap_1": 7.719112396240234, "region": "Italian", "recipe": "Red Onion Marmalade and Ricotta Pizza", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/128108"}, {"umap_0": 10.48900032043457, "umap_1": 9.961418151855469, "region": "Caribbean", "recipe": "Island Paradise Smoothie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/90522"}, {"umap_0": -1.7519497871398926, "umap_1": 6.356070041656494, "region": "Italian", "recipe": "Vegetable Manicotti", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123000"}, {"umap_0": 2.333085536956787, "umap_1": 8.439508438110352, "region": "Indian Subcontinent", "recipe": "Frizzled Onions", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4517"}, {"umap_0": 1.4769601821899414, "umap_1": 9.664591789245605, "region": "Rest Africa", "recipe": "Maf\u00e9", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48540"}, {"umap_0": -2.054671287536621, "umap_1": 8.32490062713623, "region": "Canadian", "recipe": "Brussels Sprout Salad With Walnuts", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146692"}, {"umap_0": -1.785033941268921, "umap_1": 8.110569953918457, "region": "Italian", "recipe": "Oven Bake Zucchini Bruschetta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120338"}, {"umap_0": 10.124299049377441, "umap_1": 8.89498519897461, "region": "Irish", "recipe": "Darjeeling Cranberry, Ginger and Orange Tea Loaf (Fat-Free)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134624"}, {"umap_0": -0.7731830477714539, "umap_1": 10.115036010742188, "region": "Spanish and Portuguese", "recipe": "Bibb Salad With Basil Green Goddess Dressing", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/119196"}, {"umap_0": 0.6388297080993652, "umap_1": 5.266788482666016, "region": "Greek", "recipe": "Deer Burgers (Greek Style)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110016"}, {"umap_0": 1.766107201576233, "umap_1": 9.230728149414062, "region": "Canadian", "recipe": "Wickaninnish Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148560"}, {"umap_0": 9.445097923278809, "umap_1": 6.197263240814209, "region": "Canadian", "recipe": "Ginger Molasses Muffins", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/143117"}, {"umap_0": 1.5031625032424927, "umap_1": 4.811975955963135, "region": "Mexican", "recipe": "Easy Layered Mexican Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/89860"}, {"umap_0": 9.703594207763672, "umap_1": 7.011175155639648, "region": "Scandinavian", "recipe": "Danish \"Brun Kager\" Brown Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101037"}, {"umap_0": 2.56091570854187, "umap_1": 10.489656448364258, "region": "Southeast Asian", "recipe": "Faux Chicken and Shrimp Pho", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/62648"}, {"umap_0": 0.0743061900138855, "umap_1": 10.944851875305176, "region": "Caribbean", "recipe": "Callaloo (Creamy Spinach and Okra)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91760"}, {"umap_0": -2.2106070518493652, "umap_1": 8.656437873840332, "region": "Italian", "recipe": "Orzo and Zucchini Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/10397"}, {"umap_0": -1.2049610614776611, "umap_1": 5.853065490722656, "region": "Italian", "recipe": "Pasta With Marinated Artichoke Hearts", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120108"}, {"umap_0": 1.3049952983856201, "umap_1": 4.655038356781006, "region": "Mexican", "recipe": "Tex Mex Layered Taco Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87774"}, {"umap_0": -0.9617817401885986, "umap_1": 4.543949127197266, "region": "Italian", "recipe": "Easy Manicotti Florentine", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/12624"}, {"umap_0": 10.526522636413574, "umap_1": 6.5723466873168945, "region": "Canadian", "recipe": "Semi-Sweet Chocolate Chip Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148178"}, {"umap_0": -1.3855253458023071, "umap_1": 6.555145740509033, "region": "Irish", "recipe": "Radish, Green Onion and Herbed Goat Cheese Stuff", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/136048"}, {"umap_0": 1.6904698610305786, "umap_1": 6.429791450500488, "region": "Mexican", "recipe": "Fish Taquitos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6135"}, {"umap_0": -2.776108980178833, "umap_1": 8.504410743713379, "region": "French", "recipe": "Homemade Croutons", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115131"}, {"umap_0": 11.137245178222656, "umap_1": 7.688751220703125, "region": "French", "recipe": "Macadamia Nut French Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/116138"}, {"umap_0": -1.2505682706832886, "umap_1": 11.424125671386719, "region": "Thai", "recipe": "Nam Prik Num", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/58463"}, {"umap_0": -1.730344533920288, "umap_1": 6.97441291809082, "region": "Italian", "recipe": "Shrimp parmesan", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/124961"}, {"umap_0": -1.742838978767395, "umap_1": 9.430853843688965, "region": "Australian", "recipe": "Fettuccine Pasta With Mushroom & Cashew Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77565"}, {"umap_0": -1.2151837348937988, "umap_1": 11.578920364379883, "region": "Mexican", "recipe": "Kellibou Guacamole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87204"}, {"umap_0": 2.889756441116333, "umap_1": 9.782360076904297, "region": "Chinese and Mongolian", "recipe": "Hunan-Style Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/2939"}, {"umap_0": 11.238444328308105, "umap_1": 7.771546840667725, "region": "Irish", "recipe": "Irish Cream Eggnog", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/135783"}, {"umap_0": 0.23594745993614197, "umap_1": 13.804994583129883, "region": "Indian Subcontinent", "recipe": "Panch Phora (An Indian Spice)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/72165"}, {"umap_0": 0.5237486362457275, "umap_1": 7.872950077056885, "region": "Deutschland", "recipe": "Bierocks (German Meat Turnovers)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138383"}, {"umap_0": 10.590596199035645, "umap_1": 6.287284851074219, "region": "Mexican", "recipe": "Brownies With Kahlua-coffee Glaze", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/86336"}, {"umap_0": 1.289198875427246, "umap_1": 4.7316670417785645, "region": "Mexican", "recipe": "A Healthier Taco Bake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83689"}, {"umap_0": 0.4529319107532501, "umap_1": 6.968672752380371, "region": "Deutschland", "recipe": "German Applesauce Meatloaf", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138652"}, {"umap_0": 0.8903799057006836, "umap_1": 10.439105987548828, "region": "Indian Subcontinent", "recipe": "Sarson Bhara Kekda (Shrimp With Mustard)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64016"}, {"umap_0": -0.4289466440677643, "umap_1": 7.974280834197998, "region": "French", "recipe": "Williams-Sonoma Chicken Breasts With White Wine Dijon Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113282"}, {"umap_0": -1.6823605298995972, "umap_1": 6.716250896453857, "region": "Middle Eastern", "recipe": "Onion and Chive Pitas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/60920"}, {"umap_0": -1.993635654449463, "umap_1": 7.573637008666992, "region": "Italian", "recipe": "Italian Sub Pasta Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120561"}, {"umap_0": -0.11163577437400818, "umap_1": 10.110419273376465, "region": "South American", "recipe": "Chilean Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/93792"}, {"umap_0": 11.22740364074707, "umap_1": 7.716399192810059, "region": "Italian", "recipe": "Italian Sweet Ricotta Pie (Reduced Sugar)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120929"}, {"umap_0": -0.5217500925064087, "umap_1": 10.38526439666748, "region": "Spanish and Portuguese", "recipe": "Cauliflower Fritters", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/140743"}, {"umap_0": 10.67398738861084, "umap_1": 10.782236099243164, "region": "Mexican", "recipe": "Chapala", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/85225"}, {"umap_0": 9.957857131958008, "umap_1": 7.7751851081848145, "region": "UK", "recipe": "Lemon Loaf Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/104135"}, {"umap_0": 3.4244654178619385, "umap_1": 9.992252349853516, "region": "Chinese and Mongolian", "recipe": "Oriental Chicken With Mushrooms", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/57233"}, {"umap_0": 10.09994125366211, "umap_1": 6.611826419830322, "region": "Irish", "recipe": "Honeyed Apple Pratie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/135727"}, {"umap_0": 1.4124523401260376, "umap_1": 8.691213607788086, "region": "South American", "recipe": "Fried Beef Meatballs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/99245"}, {"umap_0": 9.007814407348633, "umap_1": 7.791365146636963, "region": "Middle Eastern", "recipe": "Oatmeal Delight", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/62794"}, {"umap_0": 1.764857292175293, "umap_1": 6.5402607917785645, "region": "Mexican", "recipe": "Pork and Cornbread Mexicana", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84336"}, {"umap_0": 9.328104972839355, "umap_1": 7.645816802978516, "region": "Chinese and Mongolian", "recipe": "Lite Rice Pudding", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/54568"}, {"umap_0": 1.2491569519042969, "umap_1": 4.610762596130371, "region": "Mexican", "recipe": "Super Turkey Enchiladas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/86096"}, {"umap_0": -2.171379804611206, "umap_1": 9.7780122756958, "region": "Spanish and Portuguese", "recipe": "Zucchini Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142099"}, {"umap_0": -0.18648378551006317, "umap_1": 9.990968704223633, "region": "Spanish and Portuguese", "recipe": "Portuguese Potato and Cilantro Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118852"}, {"umap_0": 0.4580736458301544, "umap_1": 13.198898315429688, "region": "Indian Subcontinent", "recipe": "Chicken Achari", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/72169"}, {"umap_0": 10.690690994262695, "umap_1": 6.766312599182129, "region": "Canadian", "recipe": "Rugelach (Cinnamon Chocolate Twist Cookies)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145422"}, {"umap_0": 1.1408361196517944, "umap_1": 8.997994422912598, "region": "Canadian", "recipe": "Spicy Rice, Bean and Lentil Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148970"}, {"umap_0": 3.3390579223632812, "umap_1": 9.92939567565918, "region": "Japanese", "recipe": "Japanese Chicken Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/71048"}, {"umap_0": 2.6195900440216064, "umap_1": 9.598106384277344, "region": "Chinese and Mongolian", "recipe": "Orange Teriyaki Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55770"}, {"umap_0": 10.930742263793945, "umap_1": 7.514244079589844, "region": "Australian", "recipe": "The River Cafe Chocolate Nemisis", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77352"}, {"umap_0": -0.4717872440814972, "umap_1": 5.430980205535889, "region": "Eastern European", "recipe": "Polish Potato Oven Omelet", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/133586"}, {"umap_0": -0.11827484518289566, "umap_1": 8.6296968460083, "region": "South American", "recipe": "California Beef Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/95468"}, {"umap_0": -0.28187525272369385, "umap_1": 10.13260555267334, "region": "Indian Subcontinent", "recipe": "Arabian Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64014"}, {"umap_0": 0.24582378566265106, "umap_1": 10.788599967956543, "region": "Mexican", "recipe": "Tacos al Pastor", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/7006"}, {"umap_0": -2.716320514678955, "umap_1": 7.726858615875244, "region": "Greek", "recipe": "Greek Stuffed Tomatoes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/9612"}, {"umap_0": -0.003000135999172926, "umap_1": 9.355081558227539, "region": "Chinese and Mongolian", "recipe": "Tijuana Kitchen Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53599"}, {"umap_0": -0.5996366143226624, "umap_1": 11.267865180969238, "region": "Deutschland", "recipe": "Chanterelle Goulash", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/107318"}, {"umap_0": 10.01669979095459, "umap_1": 6.219729900360107, "region": "Canadian", "recipe": "Applesauce Spice Muffins", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145300"}, {"umap_0": -0.22979630529880524, "umap_1": 8.075222969055176, "region": "Italian", "recipe": "Bagna Cauda", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132872"}, {"umap_0": -1.4859440326690674, "umap_1": 11.559985160827637, "region": "US", "recipe": "Southern Cajun Boiled Peanuts", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/18523"}, {"umap_0": 2.64054012298584, "umap_1": 10.404324531555176, "region": "Thai", "recipe": "Beef Stew With Star Anise", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/58990"}, {"umap_0": 11.430074691772461, "umap_1": 7.354372024536133, "region": "Canadian", "recipe": "Chocolate Bread Pudding With Grand Marnier Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146222"}, {"umap_0": 0.5669595003128052, "umap_1": 4.472657203674316, "region": "Italian", "recipe": "Italian Crock Pot Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/133236"}, {"umap_0": -0.2746475636959076, "umap_1": 6.1436004638671875, "region": "Italian", "recipe": "Chicken Pecan Fettuccine", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122372"}, {"umap_0": 9.964795112609863, "umap_1": 6.9988884925842285, "region": "Central American", "recipe": "American Kitchen Classic Orange Scones", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/93067"}, {"umap_0": 1.1916712522506714, "umap_1": 10.572083473205566, "region": "Rest Africa", "recipe": "Poulet Seychelles Avec Couscous De Cilantro", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/51445"}, {"umap_0": -0.0804871916770935, "umap_1": 8.373921394348145, "region": "Spanish and Portuguese", "recipe": "Chicken in Pepitoria", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/141671"}, {"umap_0": -2.5202386379241943, "umap_1": 8.427446365356445, "region": "Italian", "recipe": "Scampi Appetizer Alla Buonavia", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132313"}, {"umap_0": 3.305241584777832, "umap_1": 7.8580217361450195, "region": "Indian Subcontinent", "recipe": "Best Healthy Vegan Indian Naan (Or Garlic Naan) Bread!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/68739"}, {"umap_0": 0.9556859135627747, "umap_1": 7.283071994781494, "region": "Canadian", "recipe": "Salmon Noodle Bake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144808"}, {"umap_0": -2.0338566303253174, "umap_1": 8.396404266357422, "region": "Canadian", "recipe": "Olive, Bell Pepper, & Cherry Tomato Pasta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146744"}, {"umap_0": 10.680204391479492, "umap_1": 7.35562801361084, "region": "Caribbean", "recipe": "Diplomatic Pudding", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92474"}, {"umap_0": 0.8323772549629211, "umap_1": 8.162130355834961, "region": "Italian", "recipe": "Italian Hamburger Veggie Soup Like Olive Garden Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/127633"}, {"umap_0": -2.3619329929351807, "umap_1": 8.512286186218262, "region": "Greek", "recipe": "Greece is the word!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110296"}, {"umap_0": -1.4145227670669556, "umap_1": 9.945884704589844, "region": "Rest Africa", "recipe": "Small Fish Balls With Tomato Sauce (Couirat El Hout)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48460"}, {"umap_0": 1.5199891328811646, "umap_1": 10.49068546295166, "region": "Indian Subcontinent", "recipe": "Hot And Spicy Lamb Curry", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/65554"}, {"umap_0": 1.0741924047470093, "umap_1": 12.337237358093262, "region": "US", "recipe": "Summer Sausage", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16524"}, {"umap_0": -1.1129255294799805, "umap_1": 10.725693702697754, "region": "Greek", "recipe": "Grecian Pork Tenderloin", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/9525"}, {"umap_0": 2.6766271591186523, "umap_1": 7.287966728210449, "region": "UK", "recipe": "Toad in the Hole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101253"}, {"umap_0": -1.1776509284973145, "umap_1": 9.082773208618164, "region": "Italian", "recipe": "Chef John's Baby Porchetta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/12083"}, {"umap_0": 0.29402899742126465, "umap_1": 12.527606010437012, "region": "Rest Africa", "recipe": "Paprika Tomatoes With Poached Eggs (Shakshouka)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48697"}, {"umap_0": 9.571575164794922, "umap_1": 6.615438461303711, "region": "South American", "recipe": "Brazilian Honey-Spice Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/93348"}, {"umap_0": -1.374618649482727, "umap_1": 7.029244422912598, "region": "French", "recipe": "Contessa's Heirloom Tomatoes With Blue Cheese Dressing", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/111425"}, {"umap_0": -0.529896080493927, "umap_1": 6.634117126464844, "region": "Greek", "recipe": "Low-Fat Moussaka", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/108925"}, {"umap_0": 9.487479209899902, "umap_1": 6.0801568031311035, "region": "Caribbean", "recipe": "Tropical Coconut Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/90613"}, {"umap_0": 9.085963249206543, "umap_1": 9.023821830749512, "region": "Indian Subcontinent", "recipe": "Kahwah - Indian Green Tea", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67536"}, {"umap_0": 1.8164329528808594, "umap_1": 5.24844217300415, "region": "Indian Subcontinent", "recipe": "Bombay Sandwich #SP5", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/66056"}, {"umap_0": 0.4653521776199341, "umap_1": 11.802844047546387, "region": "Rest Africa", "recipe": "Spinach, Mushroom & Lemon Rice Pilaf", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48740"}, {"umap_0": 3.2062275409698486, "umap_1": 9.970130920410156, "region": "Korean", "recipe": "Korean Grilled Beef Skewers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69244"}, {"umap_0": 10.043781280517578, "umap_1": 7.809237003326416, "region": "Australian", "recipe": "Upside-Down Caramel Banana Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74566"}, {"umap_0": -1.6933401823043823, "umap_1": 9.863703727722168, "region": "Middle Eastern", "recipe": "Almond Tabbouli Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63245"}, {"umap_0": -0.016614174470305443, "umap_1": 9.0322847366333, "region": "Deutschland", "recipe": "Bratwurst", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/107404"}, {"umap_0": 9.67780876159668, "umap_1": 7.556888103485107, "region": "UK", "recipe": "Orkney Broonie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/102075"}, {"umap_0": -1.360687255859375, "umap_1": 6.232619762420654, "region": "South American", "recipe": "Beef, Chilli and Red Wine Casserole With Polenta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/97759"}, {"umap_0": -0.10307172685861588, "umap_1": 11.276639938354492, "region": "Caribbean", "recipe": "BBQ Caribbean Beef Kabobs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91707"}, {"umap_0": 2.862422227859497, "umap_1": 10.620397567749023, "region": "Thai", "recipe": "Spicy Thai Shrimp Pasta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3279"}, {"umap_0": 0.3825432360172272, "umap_1": 7.953254699707031, "region": "South American", "recipe": "Lobster Risotto With Herb-Rubbed Beef Tenderloin", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/99093"}, {"umap_0": 1.4311424493789673, "umap_1": 8.408391952514648, "region": "Chinese and Mongolian", "recipe": "Mushroom Rice With Onion & Shallots", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53560"}, {"umap_0": 1.120116949081421, "umap_1": 10.286821365356445, "region": "Mexican", "recipe": "Pinto Beans for Burritos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83063"}, {"umap_0": 0.5684047937393188, "umap_1": 11.6340970993042, "region": "Northern Africa", "recipe": "Moroccan Tomato Lentil Stew (Soup)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/50026"}, {"umap_0": -1.9199708700180054, "umap_1": 7.6344170570373535, "region": "Canadian", "recipe": "Pizza Roll", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144480"}, {"umap_0": -1.057639241218567, "umap_1": 8.456275939941406, "region": "Spanish and Portuguese", "recipe": "Fava Bean Soup With Portuguese Sausage", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118981"}, {"umap_0": 1.4196845293045044, "umap_1": 6.074916839599609, "region": "Mexican", "recipe": "Beef or Chicken Fajitas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/88189"}, {"umap_0": -1.5638091564178467, "umap_1": 8.615351676940918, "region": "Chinese and Mongolian", "recipe": "Brown Rice & Goat Cheese Cakes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53443"}, {"umap_0": 0.2731707990169525, "umap_1": 7.18326997756958, "region": "Deutschland", "recipe": "Z\u00fcrigschn\u00e4tzlets (Veal in Cream Sauce- Veal Zurich)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118278"}, {"umap_0": 0.0924263596534729, "umap_1": 10.312410354614258, "region": "Eastern European", "recipe": "Blackened Chicken Fettuccine", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105296"}, {"umap_0": 0.2203356772661209, "umap_1": 12.600595474243164, "region": "Rest Africa", "recipe": "Cumin Seed Potatoes, Batata B\u2019kamun from Qutar", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47749"}, {"umap_0": 9.327796936035156, "umap_1": 10.850570678710938, "region": "Eastern European", "recipe": "Guilt-Free Russian Tea", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100150"}, {"umap_0": 0.48706337809562683, "umap_1": 7.97437858581543, "region": "Eastern European", "recipe": "Sauteed Cabbage With Pork", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100844"}, {"umap_0": -0.5474689602851868, "umap_1": 10.905699729919434, "region": "Rest Africa", "recipe": "Green Beans and Shrimp - Saudi Arabia", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47934"}, {"umap_0": -0.7713521122932434, "umap_1": 9.198267936706543, "region": "UK", "recipe": "Lamb for Learners! Redcurrant and Honey Glazed Lamb (Crock Pot)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/103150"}, {"umap_0": -1.8276220560073853, "umap_1": 8.605207443237305, "region": "Japanese", "recipe": "Polenta Casserole With Sauteed Bell Peppers and Sausage", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/71730"}, {"umap_0": 1.187954306602478, "umap_1": 8.14775562286377, "region": "Irish", "recipe": "Crock Pot Irish Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/135960"}, {"umap_0": 2.542471408843994, "umap_1": 7.068464279174805, "region": "Italian", "recipe": "Chicago Style Deep Dish Sausage Pizza - Real Deep Dish", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/131952"}, {"umap_0": -0.49463245272636414, "umap_1": 6.42936897277832, "region": "Canadian", "recipe": "New Twist for Mushrooms on Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/143114"}, {"umap_0": -2.257624387741089, "umap_1": 8.200695991516113, "region": "Italian", "recipe": "Aglio e Olio alla Fremont", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/12242"}, {"umap_0": 10.195355415344238, "umap_1": 10.024937629699707, "region": "Indian Subcontinent", "recipe": "Lime Ice Cubes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/68374"}, {"umap_0": 2.4918410778045654, "umap_1": 5.456921100616455, "region": "South American", "recipe": "Awesome Beef or Chicken Taco Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/95643"}, {"umap_0": 2.157564640045166, "umap_1": 8.465614318847656, "region": "Australian", "recipe": "Pumpkin Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/5578"}, {"umap_0": 10.410820960998535, "umap_1": 8.73094654083252, "region": "Deutschland", "recipe": "Brischtner Nytlae (Dried Pears in Spice Wine)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118496"}, {"umap_0": -0.24130992591381073, "umap_1": 8.735085487365723, "region": "French", "recipe": "Roti De Porc Au Lait - Pork Loin With Whole Milk", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115620"}, {"umap_0": 0.6458545327186584, "umap_1": 12.06512451171875, "region": "Middle Eastern", "recipe": "Baked Sweet Potato Falafel", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3561"}, {"umap_0": 8.338778495788574, "umap_1": 6.122470378875732, "region": "Italian", "recipe": "Friselle (Little Pepper Nuggets)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123758"}, {"umap_0": -0.04856689274311066, "umap_1": 9.370747566223145, "region": "Italian", "recipe": "Flavorful Beef, Peppers, and Onions With White Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/127834"}, {"umap_0": -1.4204189777374268, "umap_1": 6.356353759765625, "region": "Italian", "recipe": "Tomato Feta Frittata", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123326"}, {"umap_0": -0.19540724158287048, "umap_1": 10.629534721374512, "region": "Mexican", "recipe": "Citrus Chicken and Pepper Fajitas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/89444"}, {"umap_0": 2.6694087982177734, "umap_1": 10.78990650177002, "region": "Thai", "recipe": "Big Bowl's Chicken Pad Thai (For Two)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/57985"}, {"umap_0": -0.7180554270744324, "umap_1": 9.044707298278809, "region": "Australian", "recipe": "Golden Carrot Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74572"}, {"umap_0": 1.76638662815094, "umap_1": 7.531803607940674, "region": "Deutschland", "recipe": "Simple Wiener Schnitzel", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137350"}, {"umap_0": 9.939409255981445, "umap_1": 6.940561771392822, "region": "Deutschland", "recipe": "German Cobbler Cake #RSC", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138201"}, {"umap_0": -2.582714557647705, "umap_1": 7.7991204261779785, "region": "Greek", "recipe": "Greek Salad With Pita Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/107675"}, {"umap_0": 0.10040132701396942, "umap_1": 5.899693489074707, "region": "French", "recipe": "Tartiflette", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115703"}, {"umap_0": -0.3396962285041809, "umap_1": 8.218035697937012, "region": "French", "recipe": "Hunters Chicken Chasseur", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114914"}, {"umap_0": 8.236907958984375, "umap_1": 6.314720153808594, "region": "US", "recipe": "Potato Bread from Idahoan\u00ae", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16555"}, {"umap_0": 11.791729927062988, "umap_1": 9.007614135742188, "region": "Irish", "recipe": "Creme de Menthe Cheesecake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134674"}, {"umap_0": 2.1584532260894775, "umap_1": 9.890329360961914, "region": "Chinese and Mongolian", "recipe": "Wilted Greens & Tofu Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/52934"}, {"umap_0": 1.5597060918807983, "umap_1": 4.754740238189697, "region": "Mexican", "recipe": "Mexican Fiesta Salad Pizza", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81915"}, {"umap_0": 1.7058980464935303, "umap_1": 7.181153297424316, "region": "French", "recipe": "Crock Pot French Dip Roast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115042"}, {"umap_0": 10.38370132446289, "umap_1": 8.518284797668457, "region": "Canadian", "recipe": "Liscombe Lodge Maple Syrup Cream", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147568"}, {"umap_0": 11.451323509216309, "umap_1": 7.367675304412842, "region": "French", "recipe": "Baked Cinnamon Sugar French Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115680"}, {"umap_0": 7.747557163238525, "umap_1": 6.774069786071777, "region": "Italian", "recipe": "Home Made Noodles", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/129859"}, {"umap_0": 1.3871736526489258, "umap_1": 8.233147621154785, "region": "Irish", "recipe": "Another Pork Chops and Beer Recipe", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134926"}, {"umap_0": 1.8537144660949707, "umap_1": 10.456645965576172, "region": "Thai", "recipe": "Thai Green Bean Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/59560"}, {"umap_0": 0.7565900683403015, "umap_1": 8.215730667114258, "region": "Eastern European", "recipe": "Hungarian Goulash (Gulas')", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105340"}, {"umap_0": 1.2058415412902832, "umap_1": 4.785986423492432, "region": "Middle Eastern", "recipe": "Oman Potato Chip Sandwich", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61203"}, {"umap_0": 10.282078742980957, "umap_1": 9.412310600280762, "region": "South American", "recipe": "Mazamorra Morada", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/93997"}, {"umap_0": -1.2957980632781982, "umap_1": 11.212735176086426, "region": "Caribbean", "recipe": "Cuban Mango Mojo", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92369"}, {"umap_0": -1.651509404182434, "umap_1": 12.028188705444336, "region": "Mexican", "recipe": "Guacamole. Avocado Cucumber Dip!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/78873"}, {"umap_0": 1.6591243743896484, "umap_1": 9.01375675201416, "region": "Canadian", "recipe": "Kindersely Road House Ribs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144213"}, {"umap_0": 8.850723266601562, "umap_1": 7.7457499504089355, "region": "Deutschland", "recipe": "Honig Brat Mandeln (Honey Roasted Almonds)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137419"}, {"umap_0": 3.3087291717529297, "umap_1": 9.057167053222656, "region": "Chinese and Mongolian", "recipe": "Pork and Squid Chinese Dumpling Filling", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53023"}, {"umap_0": 1.1993076801300049, "umap_1": 4.328829288482666, "region": "Mexican", "recipe": "Microwave Mexican Pizza", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87951"}, {"umap_0": 0.4797804057598114, "umap_1": 7.510035514831543, "region": "Spanish and Portuguese", "recipe": "Spanish Chicken Livers (Higados De Pollo a La Espaniola)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/140628"}, {"umap_0": -0.9859377145767212, "umap_1": 6.057549953460693, "region": "US", "recipe": "Steak 'n' Fries Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/13970"}, {"umap_0": -1.9234247207641602, "umap_1": 8.83180046081543, "region": "Italian", "recipe": "Caponata Authentic and Delicious", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132971"}, {"umap_0": -0.5151568651199341, "umap_1": 8.250602722167969, "region": "South American", "recipe": "Roast Prime Ribs of Beef With Cracked Pepper Crust", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/99643"}, {"umap_0": -2.306030035018921, "umap_1": 10.037104606628418, "region": "Canadian", "recipe": "Braised Fennel and Onion Pasta Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146503"}, {"umap_0": 10.015828132629395, "umap_1": 5.275490760803223, "region": "Scandinavian", "recipe": "Mom's Buttermilk Pancakes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/13414"}, {"umap_0": 0.207315593957901, "umap_1": 11.756802558898926, "region": "Eastern European", "recipe": "Polish Goulash With Kielbasa", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/133506"}, {"umap_0": -2.4116129875183105, "umap_1": 8.637063026428223, "region": "Italian", "recipe": "Cherry Tomato, Bocconcini and Basil Bruschetta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130554"}, {"umap_0": 9.35564136505127, "umap_1": 7.052667617797852, "region": "Greek", "recipe": "Tsoureki (Greek Easter Sweet Bread)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/107912"}, {"umap_0": -1.232099175453186, "umap_1": 7.777127265930176, "region": "Middle Eastern", "recipe": "Chicken Saute With Mozzarella Cheese (Kasarli Tavuk)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69813"}, {"umap_0": 0.16747550666332245, "umap_1": 11.451703071594238, "region": "Northern Africa", "recipe": "Moroccan-Style Lamb", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/50449"}, {"umap_0": 9.638171195983887, "umap_1": 6.198990821838379, "region": "Canadian", "recipe": "Carrot Pineapple Muffins", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144489"}, {"umap_0": 0.021898040547966957, "umap_1": 10.133394241333008, "region": "Mexican", "recipe": "Good for You Taco Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83005"}, {"umap_0": 10.530296325683594, "umap_1": 7.541575908660889, "region": "Italian", "recipe": "Lemon Basil Creme Brulee", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/121028"}, {"umap_0": -1.6048246622085571, "umap_1": 8.164427757263184, "region": "Italian", "recipe": "Meg's Red Sauce (Loaded With Tomatoes and Mushrooms)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/129552"}, {"umap_0": -0.12072480469942093, "umap_1": 5.19794225692749, "region": "Australian", "recipe": "Mini Egg & Bacon Pies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76449"}, {"umap_0": 0.8512495756149292, "umap_1": 9.65469741821289, "region": "Mexican", "recipe": "Mexican Sheppards Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79062"}, {"umap_0": -1.2206172943115234, "umap_1": 6.755017280578613, "region": "Italian", "recipe": "Beans, Greens, and Sausage Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/131547"}, {"umap_0": 10.606935501098633, "umap_1": 9.433394432067871, "region": "Canadian", "recipe": "Berry Blast Smoothie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/149177"}, {"umap_0": 4.049715995788574, "umap_1": 9.372949600219727, "region": "Japanese", "recipe": "Macrobiotic Oatmeal (Gluten-Free)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70555"}, {"umap_0": 1.9353752136230469, "umap_1": 10.66810131072998, "region": "Canadian", "recipe": "Apple Maple Beer Glazed Salmon", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146057"}, {"umap_0": 0.5410172939300537, "umap_1": 7.58200216293335, "region": "Italian", "recipe": "Buca Di Beppo Chicken With Lemon", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123277"}, {"umap_0": -1.5258145332336426, "umap_1": 5.550809860229492, "region": "Italian", "recipe": "Italian Chicken (or Shrimp) w-Tomato Cream Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/126663"}, {"umap_0": 0.28247714042663574, "umap_1": 12.702008247375488, "region": "Rest Africa", "recipe": "Pickled Okra", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48406"}, {"umap_0": -1.296913504600525, "umap_1": 9.81494426727295, "region": "Italian", "recipe": "Spaghetti & Lasagna Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/119340"}, {"umap_0": 1.5782115459442139, "umap_1": 7.235260963439941, "region": "French", "recipe": "Quickie French Onion Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/9892"}, {"umap_0": 0.6184023022651672, "umap_1": 6.855791091918945, "region": "UK", "recipe": "Yorkshire Pudding With Herbs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105029"}, {"umap_0": 9.358656883239746, "umap_1": 5.7030415534973145, "region": "Canadian", "recipe": "Aunt Helen's Buttermilk Pancakes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146876"}, {"umap_0": 1.7690497636795044, "umap_1": 5.804295539855957, "region": "Mexican", "recipe": "Bean & Charred Corn Nachos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81238"}, {"umap_0": -1.5968114137649536, "umap_1": 6.058291912078857, "region": "Italian", "recipe": "Italian Burgers With Salami & Mozzarella", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/121908"}, {"umap_0": 1.1434025764465332, "umap_1": 7.27559232711792, "region": "Caribbean", "recipe": "Beef Jerk Burgers ( Caribbean)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/90533"}, {"umap_0": -1.2217457294464111, "umap_1": 11.69527530670166, "region": "Mexican", "recipe": "Roasted Tomatillo and Garlic Salsa", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/7598"}, {"umap_0": 3.019717216491699, "umap_1": 9.367509841918945, "region": "Chinese and Mongolian", "recipe": "Chinese Long Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/52869"}, {"umap_0": 1.3353976011276245, "umap_1": 4.9188079833984375, "region": "Mexican", "recipe": "Old New Mexican Breakfast Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84308"}, {"umap_0": 9.346112251281738, "umap_1": 8.884907722473145, "region": "Australian", "recipe": "Grumichama or Brazil Cherry Ice Blocks", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73381"}, {"umap_0": 0.7967424988746643, "umap_1": 12.843717575073242, "region": "Indian Subcontinent", "recipe": "Imli Aur Dhaniye Ki Hari Chutney (Tamarind & Cilantro Dip)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/72208"}, {"umap_0": -1.6918190717697144, "umap_1": 8.513998031616211, "region": "Greek", "recipe": "Flamb\u00e9ed Shrimp With Tomatoes, Feta Cheese, and Ouzo", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/108153"}, {"umap_0": 9.802016258239746, "umap_1": 9.393402099609375, "region": "Thai", "recipe": "Coco - Limeade", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/57607"}, {"umap_0": -1.1158806085586548, "umap_1": 9.03155517578125, "region": "Greek", "recipe": "Greek Burgers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/9563"}, {"umap_0": -0.18470890820026398, "umap_1": 6.584038257598877, "region": "French", "recipe": "Fresh Cream of Tomato Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114368"}, {"umap_0": 2.9376025199890137, "umap_1": 10.095795631408691, "region": "Thai", "recipe": "Thai Veal Scaloppine", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/58080"}, {"umap_0": 0.14134319126605988, "umap_1": 10.777466773986816, "region": "Mexican", "recipe": "Chipotle Bean Burgers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80074"}, {"umap_0": -2.1879806518554688, "umap_1": 9.941044807434082, "region": "Australian", "recipe": "Maple Vinaigrette", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74171"}, {"umap_0": -0.09920617192983627, "umap_1": 8.322317123413086, "region": "Deutschland", "recipe": "German Potato Soup for the Crock Pot", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/139010"}, {"umap_0": 2.039147138595581, "umap_1": 6.8982768058776855, "region": "South American", "recipe": "Roast Beef with Mushroom & Onions", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/97203"}, {"umap_0": 1.362606406211853, "umap_1": 9.81152057647705, "region": "South American", "recipe": "Beef Curry for Slow Cooker", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/99419"}, {"umap_0": -0.49709126353263855, "umap_1": 9.022865295410156, "region": "French", "recipe": "French Lentil Soup With Sausage", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114554"}, {"umap_0": 10.13572883605957, "umap_1": 6.623961448669434, "region": "Canadian", "recipe": "My Kids Favourite Chocolate Chip Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/143329"}, {"umap_0": 2.0781054496765137, "umap_1": 9.4347505569458, "region": "Australian", "recipe": "Fruity Lamb Curry", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76607"}, {"umap_0": 9.623250007629395, "umap_1": 7.62224817276001, "region": "Eastern European", "recipe": "Russian Caramels", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100226"}, {"umap_0": 0.9148565530776978, "umap_1": 12.756828308105469, "region": "Indian Subcontinent", "recipe": "Hot and Sour Tomato Broth With Shrimp", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/65507"}, {"umap_0": 8.530837059020996, "umap_1": 6.678146839141846, "region": "Indian Subcontinent", "recipe": "Naan", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4566"}, {"umap_0": 1.6683013439178467, "umap_1": 7.894680976867676, "region": "Scandinavian", "recipe": "Porcupine Meatballs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/106142"}, {"umap_0": 9.491013526916504, "umap_1": 6.482408046722412, "region": "Italian", "recipe": "Italian Biscotti", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120667"}, {"umap_0": 2.738337516784668, "umap_1": 9.366826057434082, "region": "Chinese and Mongolian", "recipe": "Almond Chicken Appetizers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56157"}, {"umap_0": -2.153474807739258, "umap_1": 8.227680206298828, "region": "Greek", "recipe": "Paula Deen's Greek Dressing", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/108202"}, {"umap_0": 2.2133500576019287, "umap_1": 5.362441062927246, "region": "Mexican", "recipe": "Bob's Taco Soup With Pasta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87288"}, {"umap_0": 0.38845351338386536, "umap_1": 7.730276584625244, "region": "Irish", "recipe": "Irish Hotpot", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134797"}, {"umap_0": -1.2442249059677124, "umap_1": 4.64749002456665, "region": "Italian", "recipe": "Tri-Color Pasta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122311"}, {"umap_0": 1.9040604829788208, "umap_1": 7.023955345153809, "region": "Italian", "recipe": "Irresistible Italian Corn", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/10327"}, {"umap_0": -0.9400758147239685, "umap_1": 5.981141567230225, "region": "Italian", "recipe": "Speedy Gonzalez's Kielbasa Pasta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130375"}, {"umap_0": 0.44226670265197754, "umap_1": 5.752058506011963, "region": "Australian", "recipe": "Cheesy Chicken Dippers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76820"}, {"umap_0": 1.557762622833252, "umap_1": 5.61331844329834, "region": "Mexican", "recipe": "White Chicken Enchilada Slow-Cooker Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6857"}, {"umap_0": 1.1891599893569946, "umap_1": 5.942542552947998, "region": "Mexican", "recipe": "Saturday Night Chicken, Cheese and Refried Bean Enchiladas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87438"}, {"umap_0": 1.1769767999649048, "umap_1": 10.489023208618164, "region": "Indian Subcontinent", "recipe": "Indian Sweet Potato Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/66905"}, {"umap_0": 1.5091673135757446, "umap_1": 10.260404586791992, "region": "UK", "recipe": "Curried Apple and Leek Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/9010"}, {"umap_0": 2.6078097820281982, "umap_1": 9.342131614685059, "region": "Canadian", "recipe": "Chicken Linguine Soup - Crock Pot", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142937"}, {"umap_0": 2.086662769317627, "umap_1": 5.249919414520264, "region": "Mexican", "recipe": "Frijoles With Salsa", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84074"}, {"umap_0": -1.858019232749939, "umap_1": 7.242621898651123, "region": "Italian", "recipe": "Zucchini and Shells", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/12480"}, {"umap_0": -1.8012325763702393, "umap_1": 8.58883285522461, "region": "Middle Eastern", "recipe": "Couscous Salad (Vegan)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61866"}, {"umap_0": 0.4397864043712616, "umap_1": 7.415644645690918, "region": "Irish", "recipe": "Gaelic Steak Flambe", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134914"}, {"umap_0": -0.0687330961227417, "umap_1": 8.473615646362305, "region": "Spanish and Portuguese", "recipe": "Lomo Al Ajillo (Pork Loin in Garlic)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/140655"}, {"umap_0": -1.8862475156784058, "umap_1": 8.448264122009277, "region": "French", "recipe": "Vegan Pan Bagnat", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/111699"}, {"umap_0": -0.5002841353416443, "umap_1": 10.394060134887695, "region": "Mexican", "recipe": "Mayan Couscous", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6246"}, {"umap_0": -1.0137816667556763, "umap_1": 7.4154839515686035, "region": "South American", "recipe": "Beef and Lamb Meatball Kabobs With Individual Dipping Sauces", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96686"}, {"umap_0": 0.48926401138305664, "umap_1": 10.984363555908203, "region": "Mexican", "recipe": "Tacos from Scratch (Way Better Than a Packet and Just As Easy!)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79500"}, {"umap_0": 9.578376770019531, "umap_1": 8.592094421386719, "region": "Middle Eastern", "recipe": "Kirazli Dondurma - Cherry Ice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69981"}, {"umap_0": 11.283649444580078, "umap_1": 8.37243938446045, "region": "Scandinavian", "recipe": "Swedish Cream with Summer Berries", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/9160"}, {"umap_0": 11.302166938781738, "umap_1": 8.413507461547852, "region": "Irish", "recipe": "Holiday Cookie Pops", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134709"}, {"umap_0": 0.5016542077064514, "umap_1": 6.434261322021484, "region": "Indian Subcontinent", "recipe": "Ekuri - Spicy Scrambled Eggs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67896"}, {"umap_0": 1.8788880109786987, "umap_1": 8.74628734588623, "region": "Mexican", "recipe": "Mexican Pork", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81399"}, {"umap_0": -0.9979049563407898, "umap_1": 7.649424076080322, "region": "Italian", "recipe": "Primavera With Seared Seafood", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/127279"}, {"umap_0": 0.6275359392166138, "umap_1": 12.174811363220215, "region": "Southeast Asian", "recipe": "Malaysian Beef Curry", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69792"}, {"umap_0": -1.2578353881835938, "umap_1": 8.31895923614502, "region": "UK", "recipe": "Honeyed Winter Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/104865"}, {"umap_0": -1.9776275157928467, "umap_1": 7.977775573730469, "region": "Middle Eastern", "recipe": "Lebanese Fattoush", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3846"}, {"umap_0": 1.0413832664489746, "umap_1": 9.257974624633789, "region": "Indian Subcontinent", "recipe": "Kadai Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4079"}, {"umap_0": 2.988891124725342, "umap_1": 9.276805877685547, "region": "Chinese and Mongolian", "recipe": "Potstickers (Chinese Dumplings)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3089"}, {"umap_0": 0.3861425518989563, "umap_1": 10.429703712463379, "region": "Mexican", "recipe": "Chile Rojo", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/85757"}, {"umap_0": 9.798489570617676, "umap_1": 5.372229099273682, "region": "UK", "recipe": "Yorkshire Sausages", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/103358"}, {"umap_0": -1.0138651132583618, "umap_1": 4.760813236236572, "region": "Italian", "recipe": "Protein Packed Italian Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/133053"}, {"umap_0": 1.4162359237670898, "umap_1": 9.315413475036621, "region": "Eastern European", "recipe": "Mom's Hungarian Goulash", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105386"}, {"umap_0": -1.321197509765625, "umap_1": 4.770620346069336, "region": "Italian", "recipe": "Mobster's Manicotti", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123172"}, {"umap_0": 1.7008883953094482, "umap_1": 5.992887020111084, "region": "Mexican", "recipe": "Pupusas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/85632"}, {"umap_0": 2.7506191730499268, "umap_1": 8.600227355957031, "region": "Chinese and Mongolian", "recipe": "Chinese Fried Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53375"}, {"umap_0": 1.807955265045166, "umap_1": 7.862448692321777, "region": "Mexican", "recipe": "Mexicali Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79242"}, {"umap_0": 0.12790027260780334, "umap_1": 4.979955196380615, "region": "US", "recipe": "Asparagus Casserole I", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/14512"}, {"umap_0": 3.2846734523773193, "umap_1": 9.370888710021973, "region": "Chinese and Mongolian", "recipe": "Wonton Soup or Fried Wonton", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55510"}, {"umap_0": 10.378767967224121, "umap_1": 8.718915939331055, "region": "Canadian", "recipe": "Currant Jelly", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147718"}, {"umap_0": 10.641512870788574, "umap_1": 6.999699115753174, "region": "UK", "recipe": "Old-Fashioned Shortbread (4 Ingredients)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101711"}, {"umap_0": -0.40492239594459534, "umap_1": 9.244776725769043, "region": "Middle Eastern", "recipe": "Mujadarra and More", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61129"}, {"umap_0": 0.0029182357247918844, "umap_1": 13.750909805297852, "region": "Chinese and Mongolian", "recipe": "Chinese Take-Out: Chinese Five Spice Powder", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53214"}, {"umap_0": 7.668046951293945, "umap_1": 5.79879093170166, "region": "French", "recipe": "Food Processor French Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113358"}, {"umap_0": 10.3917236328125, "umap_1": 9.42120361328125, "region": "Rest Africa", "recipe": "African Dessert", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47655"}, {"umap_0": -0.43921467661857605, "umap_1": 12.259627342224121, "region": "Spanish and Portuguese", "recipe": "Spanish Rice Using Quinoa", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142031"}, {"umap_0": 9.913810729980469, "umap_1": 6.179925441741943, "region": "UK", "recipe": "Cacen Ddyrnu (Welsh Threshing Cake)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105088"}, {"umap_0": 0.05230466648936272, "umap_1": 8.382396697998047, "region": "Greek", "recipe": "Chicken Lemon Rice Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/109638"}, {"umap_0": 3.0586671829223633, "umap_1": 8.872909545898438, "region": "Japanese", "recipe": "Miso Mushrooms", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70882"}, {"umap_0": -1.5325583219528198, "umap_1": 9.906431198120117, "region": "South American", "recipe": "Marinated Herbed Beef in a Salt Crust", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96612"}, {"umap_0": 1.062806248664856, "umap_1": 7.800811767578125, "region": "South American", "recipe": "Heavenly Beef Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/99777"}, {"umap_0": 2.652691602706909, "umap_1": 9.47354793548584, "region": "Indian Subcontinent", "recipe": "Chinese Drumsticks Pakistani Style", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67743"}, {"umap_0": 10.367888450622559, "umap_1": 5.658212661743164, "region": "Deutschland", "recipe": "Easy Apple Kuchen", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137555"}, {"umap_0": 2.6496775150299072, "umap_1": 11.04352855682373, "region": "Thai", "recipe": "Thai Barbecue", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/57618"}, {"umap_0": 0.7284457087516785, "umap_1": 9.66073226928711, "region": "Mexican", "recipe": "Rollitos de Pollo en Salsa de Guajillo (Chicken Rolls in Guajillo Pepper Sauce)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6889"}, {"umap_0": 11.651995658874512, "umap_1": 7.62949275970459, "region": "French", "recipe": "Simple French Toast Bake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/116455"}, {"umap_0": -0.7817762494087219, "umap_1": 6.0642781257629395, "region": "Spanish and Portuguese", "recipe": "The Spanish Ranch Panini ! #RSC", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/140423"}, {"umap_0": 10.050749778747559, "umap_1": 7.220972061157227, "region": "UK", "recipe": "Raspberry Scottish Shortbread ( Vegan!)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101403"}, {"umap_0": -0.5603259801864624, "umap_1": 7.575573921203613, "region": "Italian", "recipe": "Fanny's Italian Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/11800"}, {"umap_0": -1.7217803001403809, "umap_1": 8.684728622436523, "region": "Irish", "recipe": "Garlic and Herb Roasted Potatoes and Squash", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/136310"}, {"umap_0": 9.430368423461914, "umap_1": 6.7747907638549805, "region": "Canadian", "recipe": "Strawberry Sourdough Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146982"}, {"umap_0": 3.0441465377807617, "umap_1": 9.833536148071289, "region": "Chinese and Mongolian", "recipe": "Xiao Long Bao (Little Buns)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56291"}, {"umap_0": 1.0489275455474854, "umap_1": 10.118488311767578, "region": "US", "recipe": "New England Bean Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/14433"}, {"umap_0": 10.32991886138916, "umap_1": 5.905421257019043, "region": "Canadian", "recipe": "Rhubarb Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144792"}, {"umap_0": -0.535754919052124, "umap_1": 5.8870368003845215, "region": "Deutschland", "recipe": "Swiss Potato and Mushroom Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/117540"}, {"umap_0": 2.0968968868255615, "umap_1": 6.599760055541992, "region": "UK", "recipe": "English Beer Batter", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/104541"}, {"umap_0": 10.33456802368164, "umap_1": 7.327070236206055, "region": "Spanish and Portuguese", "recipe": "Toucinho Do Ceu (Heavenly Fat)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118906"}, {"umap_0": 1.831363558769226, "umap_1": 4.865825653076172, "region": "Irish", "recipe": "Stuffed Banana Peppers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/135038"}, {"umap_0": 0.017885826528072357, "umap_1": 11.440414428710938, "region": "Middle Eastern", "recipe": "Fish in Persian Sweet-And-Sour Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61494"}, {"umap_0": 11.18381404876709, "umap_1": 7.685989856719971, "region": "French", "recipe": "Overnight Eggnog French Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113487"}, {"umap_0": 10.75781536102295, "umap_1": 10.99802017211914, "region": "Mexican", "recipe": "Frozen Mixed Berry Margarita", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/86800"}, {"umap_0": 1.2414777278900146, "umap_1": 8.073561668395996, "region": "US", "recipe": "Mauigirl's Loco Moco", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16732"}, {"umap_0": -2.1548430919647217, "umap_1": 8.517128944396973, "region": "Italian", "recipe": "Simple Caprese Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/10454"}, {"umap_0": 3.3709864616394043, "umap_1": 10.169971466064453, "region": "Korean", "recipe": "Korean Fried Chicken (Spicy Version)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69343"}, {"umap_0": 2.2434241771698, "umap_1": 10.606340408325195, "region": "Australian", "recipe": "Vegemite Asian Prawns With Green Slaw", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74959"}, {"umap_0": -1.783941626548767, "umap_1": 7.800165176391602, "region": "Middle Eastern", "recipe": "Fresh Herb and Tomato Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/60082"}, {"umap_0": -1.0681947469711304, "umap_1": 7.536027431488037, "region": "Italian", "recipe": "My Kickin' Pasta Fagioli Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/128615"}, {"umap_0": -0.25660020112991333, "umap_1": 7.814643383026123, "region": "French", "recipe": "Deconstructed Lobster Bisque", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/116291"}, {"umap_0": -0.10545535385608673, "umap_1": 11.115190505981445, "region": "Caribbean", "recipe": "Trini Doubles", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/90344"}, {"umap_0": 9.48012638092041, "umap_1": 6.869088172912598, "region": "Spanish and Portuguese", "recipe": "Portuguese Sweet Bread for Bread Machine", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118892"}, {"umap_0": -1.2693212032318115, "umap_1": 5.742815971374512, "region": "Australian", "recipe": "Pizza Topping - Smoked Salmon Pizza", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/72740"}, {"umap_0": 0.6392019391059875, "umap_1": 8.06462287902832, "region": "Deutschland", "recipe": "Pheasant with Sauerkraut", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138574"}, {"umap_0": -2.360288619995117, "umap_1": 8.828530311584473, "region": "Deutschland", "recipe": "My Mother's Chicken and Potatoes With Special Touches", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118452"}, {"umap_0": 0.08298793435096741, "umap_1": 12.085104942321777, "region": "Indian Subcontinent", "recipe": "Fish and Cabbage", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/72373"}, {"umap_0": -0.40015560388565063, "umap_1": 4.595405578613281, "region": "French", "recipe": "Pepperoni Souffle", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112428"}, {"umap_0": 1.0597927570343018, "umap_1": 9.302349090576172, "region": "Mexican", "recipe": "Leftover Steak Green Chili Burros Slow Cooker", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81532"}, {"umap_0": -1.2263686656951904, "umap_1": 11.830113410949707, "region": "Mexican", "recipe": "Pico de Gallo", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/7836"}, {"umap_0": -1.1378872394561768, "umap_1": 10.97275161743164, "region": "Australian", "recipe": "Onion Marmalade for New Zealand Meatloaf", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76975"}, {"umap_0": 10.368918418884277, "umap_1": 7.893019676208496, "region": "UK", "recipe": "Lemon--Cranberry Shortbread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101898"}, {"umap_0": 0.12785731256008148, "umap_1": 8.886496543884277, "region": "Greek", "recipe": "Beef Stifado", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/9449"}, {"umap_0": 2.873894214630127, "umap_1": 10.279242515563965, "region": "Japanese", "recipe": "Shrimp in Mild Tomato Chili Sauce (Ebi No Chiri So-Su)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70436"}, {"umap_0": 1.377915859222412, "umap_1": 10.808008193969727, "region": "Rest Africa", "recipe": "East African Curry", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48816"}, {"umap_0": -0.621149480342865, "umap_1": 7.715200424194336, "region": "Chinese and Mongolian", "recipe": "Chinese Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/51968"}, {"umap_0": -1.9091218709945679, "umap_1": 6.969133377075195, "region": "Italian", "recipe": "Genoese Minestrone", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/128503"}, {"umap_0": -0.13178449869155884, "umap_1": 10.678367614746094, "region": "Mexican", "recipe": "Chihuahua-Style Salsa Verde", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/7975"}, {"umap_0": 8.130681037902832, "umap_1": 6.629275798797607, "region": "Mexican", "recipe": "Soft Corn Tortilla Pancakes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/85070"}, {"umap_0": -1.1368415355682373, "umap_1": 5.316522121429443, "region": "Italian", "recipe": "Baked Butternut Squash Gratin - Giada De Laurentiis", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130588"}, {"umap_0": 0.16225770115852356, "umap_1": 9.77759838104248, "region": "Mexican", "recipe": "Chicken Enchiladas Verde", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/89214"}, {"umap_0": 0.8651372194290161, "umap_1": 5.820237159729004, "region": "Italian", "recipe": "Bacon, Sour Cream, Potato Manicotti With Gorgonzola Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/119679"}, {"umap_0": 8.680720329284668, "umap_1": 7.362706661224365, "region": "Australian", "recipe": "Gluten-Free All-Purpose Flour Mix #1", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75989"}, {"umap_0": -0.12426546961069107, "umap_1": 8.102157592773438, "region": "Belgian", "recipe": "Braised Belgian Endive", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/106612"}, {"umap_0": 10.735156059265137, "umap_1": 10.2648344039917, "region": "Caribbean", "recipe": "Bahama Lullaby", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/90409"}, {"umap_0": -1.5713587999343872, "umap_1": 5.383267402648926, "region": "Canadian", "recipe": "California Cauliflower", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145806"}, {"umap_0": -1.838204026222229, "umap_1": 9.752130508422852, "region": "Deutschland", "recipe": "Swiss Baked Tomatoes in Cream", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118292"}, {"umap_0": -1.9509501457214355, "umap_1": 9.508674621582031, "region": "Italian", "recipe": "Summer Tomato Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/126027"}, {"umap_0": 11.799275398254395, "umap_1": 8.082860946655273, "region": "Deutschland", "recipe": "German Chocolate Coconut Bars", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/139106"}, {"umap_0": 2.805629253387451, "umap_1": 9.534446716308594, "region": "Southeast Asian", "recipe": "Pancit", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63765"}, {"umap_0": 0.13560540974140167, "umap_1": 8.411050796508789, "region": "Canadian", "recipe": "Sauteed Potatoes and Leeks", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144021"}, {"umap_0": 1.5124220848083496, "umap_1": 9.755524635314941, "region": "Indian Subcontinent", "recipe": "Slowburn Goat Curry With Friend Roti", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/68442"}, {"umap_0": -2.026599884033203, "umap_1": 9.886940956115723, "region": "South American", "recipe": "Venezuelan Beef Roast Marinade", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/94059"}, {"umap_0": 2.2772741317749023, "umap_1": 7.4765849113464355, "region": "Italian", "recipe": "Aromatic Bread Dumplings", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/131601"}, {"umap_0": -0.10391520708799362, "umap_1": 4.592491626739502, "region": "Australian", "recipe": "Avocado, Ham and Cheese Melt", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76723"}, {"umap_0": 2.2713582515716553, "umap_1": 10.485796928405762, "region": "Southeast Asian", "recipe": "Indonesian Pork Satay", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3438"}, {"umap_0": 0.8210528492927551, "umap_1": 8.437171936035156, "region": "Italian", "recipe": "Ravioli Meat Filling", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/131151"}, {"umap_0": -0.986822247505188, "umap_1": 8.382224082946777, "region": "Italian", "recipe": "Mushroom Lovers' Turkey Cacciatore", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122536"}, {"umap_0": -1.4210366010665894, "umap_1": 10.303997993469238, "region": "Australian", "recipe": "Couscous With Ginger, Orange, Almond & Herbs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75558"}, {"umap_0": 1.4648970365524292, "umap_1": 5.342130184173584, "region": "Mexican", "recipe": "Southwest Baked Potatoes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/86325"}, {"umap_0": 0.2557952105998993, "umap_1": 9.102579116821289, "region": "Canadian", "recipe": "Apple Onion Sauce for Pork", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148338"}, {"umap_0": -2.27400803565979, "umap_1": 8.722634315490723, "region": "Italian", "recipe": "Braised Ligurian Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/126592"}, {"umap_0": 9.238080024719238, "umap_1": 6.174140930175781, "region": "South American", "recipe": "Banana Upside Cake (bolo De Banana)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/93454"}, {"umap_0": 2.551232099533081, "umap_1": 9.633914947509766, "region": "US", "recipe": "Five Spice Turkey Cheeseburgers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16752"}, {"umap_0": 1.4470648765563965, "umap_1": 8.176922798156738, "region": "Deutschland", "recipe": "Simply the Best Hot German Potato Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138865"}, {"umap_0": 1.2717951536178589, "umap_1": 12.364078521728516, "region": "Indian Subcontinent", "recipe": "Basmati Rice with Vegetables", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/66486"}, {"umap_0": -0.16624312102794647, "umap_1": 10.866996765136719, "region": "Northern Africa", "recipe": "Moroccan Braised Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/49660"}, {"umap_0": -0.4595973789691925, "umap_1": 5.337884902954102, "region": "Mexican", "recipe": "Poblano Queso Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79590"}, {"umap_0": 10.196186065673828, "umap_1": 6.824253559112549, "region": "Irish", "recipe": "Irish Apple Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/13101"}, {"umap_0": -0.4888237416744232, "umap_1": 9.748560905456543, "region": "Middle Eastern", "recipe": "Lentils With Wild Rice & Crispy Onions (Koshari)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47338"}, {"umap_0": 0.4378003478050232, "umap_1": 12.573949813842773, "region": "Mexican", "recipe": "Spaghetti Squash With Mexican Spices", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/78463"}, {"umap_0": -0.7579576969146729, "umap_1": 8.894984245300293, "region": "Italian", "recipe": "Sicilian Chicken With Lemon, Mint and Almonds", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122673"}, {"umap_0": 11.66150951385498, "umap_1": 7.368163585662842, "region": "Italian", "recipe": "Batista's Cappuccino", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/121239"}, {"umap_0": 1.0617879629135132, "umap_1": 4.742095947265625, "region": "US", "recipe": "Texas Stuffed Mushrooms", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/17405"}, {"umap_0": -1.9260987043380737, "umap_1": 8.716657638549805, "region": "Greek", "recipe": "Taramousalata (Greek Caviar Spread)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/9366"}, {"umap_0": 0.7939980626106262, "umap_1": 10.385493278503418, "region": "Indian Subcontinent", "recipe": "Grilled Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/72364"}, {"umap_0": -1.2129461765289307, "umap_1": 11.186966896057129, "region": "Mexican", "recipe": "Green Chili Salsa Dip (Beware Very Hot)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79195"}, {"umap_0": 0.44562482833862305, "umap_1": 11.186622619628906, "region": "Northern Africa", "recipe": "Couscous With Savory Caramelized Onion", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/49546"}, {"umap_0": 1.7255510091781616, "umap_1": 6.847947597503662, "region": "Italian", "recipe": "Italian Beef Brisket", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123914"}, {"umap_0": -2.6131300926208496, "umap_1": 8.673362731933594, "region": "French", "recipe": "Figs With Fennel, Goat Cheese and Green Peppercorn Vinaigrette", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114276"}, {"umap_0": -1.6937246322631836, "umap_1": 9.167866706848145, "region": "Australian", "recipe": "Sarah's Fabulous Summer Pasta Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/72916"}, {"umap_0": 1.787846326828003, "umap_1": 10.631842613220215, "region": "Chinese and Mongolian", "recipe": "Baked Curry Chicken With a Side of Coconut Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53905"}, {"umap_0": -0.8051272630691528, "umap_1": 10.017407417297363, "region": "Scandinavian", "recipe": "Danish Coleslaw - K\u00e5lsalat", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/140142"}, {"umap_0": 2.686178207397461, "umap_1": 7.480287551879883, "region": "Greek", "recipe": "Spinach Feta Pizza II", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110105"}, {"umap_0": 1.936732530593872, "umap_1": 9.649888038635254, "region": "Canadian", "recipe": "Canadian Pork Roast With Gravy", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146884"}, {"umap_0": 1.1046338081359863, "umap_1": 5.846712112426758, "region": "Mexican", "recipe": "Angela's Awesome Enchiladas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6836"}, {"umap_0": 2.3830513954162598, "umap_1": 10.378469467163086, "region": "Chinese and Mongolian", "recipe": "Curried Shrimp With Brown Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/54903"}, {"umap_0": -2.4874606132507324, "umap_1": 9.287787437438965, "region": "Italian", "recipe": "Rosemary-Scented, Extra-Crispy Fried Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/121889"}, {"umap_0": 10.922629356384277, "umap_1": 8.385458946228027, "region": "Canadian", "recipe": "Apple Bread Pudding With Maple Rum Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148779"}, {"umap_0": 3.0882670879364014, "umap_1": 9.804500579833984, "region": "Chinese and Mongolian", "recipe": "Emerald Dragon Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55971"}, {"umap_0": -1.9299217462539673, "umap_1": 7.339765548706055, "region": "French", "recipe": "Paves De Saumon Au Jambon De Bayonne (Salmon Steaks With Ham)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/116087"}, {"umap_0": -1.3202654123306274, "umap_1": 5.64713716506958, "region": "Italian", "recipe": "Spinach Stuffed Chicken Breast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130749"}, {"umap_0": 10.50543212890625, "umap_1": 7.773617744445801, "region": "Australian", "recipe": "Sugar Crust Sponge", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77431"}, {"umap_0": 2.072361707687378, "umap_1": 7.6413187980651855, "region": "Eastern European", "recipe": "Chicken Kiev", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/8560"}, {"umap_0": -1.7715682983398438, "umap_1": 7.237468242645264, "region": "Italian", "recipe": "Tuscan Cream Cheese Spread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132853"}, {"umap_0": 1.8808650970458984, "umap_1": 8.346580505371094, "region": "Chinese and Mongolian", "recipe": "Chinese Fried Beef and Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53365"}, {"umap_0": 3.478912591934204, "umap_1": 9.913973808288574, "region": "Japanese", "recipe": "Gyoza ( Pot Stickers)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70727"}, {"umap_0": 10.820918083190918, "umap_1": 6.653618812561035, "region": "Canadian", "recipe": "Gingered Chocolate Whipped Cream", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144010"}, {"umap_0": 7.882758140563965, "umap_1": 5.812241554260254, "region": "Mexican", "recipe": "' Fnky' Flour Tortillas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87691"}, {"umap_0": 3.675859212875366, "umap_1": 9.842616081237793, "region": "Japanese", "recipe": "Plum Salad Dressing", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/71114"}, {"umap_0": -1.7821314334869385, "umap_1": 8.905890464782715, "region": "Italian", "recipe": "Venus Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122175"}, {"umap_0": -1.0263582468032837, "umap_1": 4.592350959777832, "region": "Italian", "recipe": "Cheese and Nut Stuffed Shells", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/131057"}, {"umap_0": 0.7894139289855957, "umap_1": 7.219599723815918, "region": "South American", "recipe": "Marsala Creamed Beef With Noodles", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/99656"}, {"umap_0": 3.4995975494384766, "umap_1": 9.765250205993652, "region": "Chinese and Mongolian", "recipe": "Chinese Orange-Sesame Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55217"}, {"umap_0": 0.1961808055639267, "umap_1": 7.55633020401001, "region": "Middle Eastern", "recipe": "Terbiyeli Kereviz (Poached Celeriac)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69874"}, {"umap_0": 2.3259527683258057, "umap_1": 10.292511940002441, "region": "Southeast Asian", "recipe": "Vietnamese Warm Chicken Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/62422"}, {"umap_0": -0.9323740005493164, "umap_1": 11.338334083557129, "region": "Mexican", "recipe": "Mexican Low Fat Citrus Salad Dressing", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82408"}, {"umap_0": -0.8552679419517517, "umap_1": 4.24830961227417, "region": "Deutschland", "recipe": "Potato, Egg and Ham Bake (Bauern Fr\u00fchstuck)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137488"}, {"umap_0": 12.06760025024414, "umap_1": 7.778079032897949, "region": "Canadian", "recipe": "Chocolate-Peanut Crisp Bars", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148346"}, {"umap_0": 1.5701814889907837, "umap_1": 9.666003227233887, "region": "Rest Africa", "recipe": "Casbah Chicken with Orange Infused Basmati Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48872"}, {"umap_0": -0.60016930103302, "umap_1": 7.991176128387451, "region": "Middle Eastern", "recipe": "Grilled Chicken Skewers With Hummus-Yogurt Dipping Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61251"}, {"umap_0": 1.0263564586639404, "umap_1": 8.08423900604248, "region": "Middle Eastern", "recipe": "Middle Eastern Lamb and Bean Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61547"}, {"umap_0": 1.7628854513168335, "umap_1": 5.835239887237549, "region": "Mexican", "recipe": "Greg's Pinto Beans - Refried Beans", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77900"}, {"umap_0": 8.52304744720459, "umap_1": 6.319225788116455, "region": "French", "recipe": "Savarin With Berries", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113728"}, {"umap_0": -1.792480707168579, "umap_1": 7.952422618865967, "region": "Italian", "recipe": "Italian Marinade", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125218"}, {"umap_0": 0.8909968137741089, "umap_1": 11.691295623779297, "region": "Rest Africa", "recipe": "Doro Wat (Spicy Chicken Stew)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/49156"}, {"umap_0": 2.3138632774353027, "umap_1": 10.02312183380127, "region": "Southeast Asian", "recipe": "Eggplant (Aubergine) Adobo", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63753"}, {"umap_0": -1.6291037797927856, "umap_1": 7.161388397216797, "region": "Italian", "recipe": "Pasta Roma", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/127934"}, {"umap_0": 11.494688987731934, "umap_1": 6.804284572601318, "region": "US", "recipe": "Deb's Passover Brownies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/14643"}, {"umap_0": -0.6093863844871521, "umap_1": 11.441083908081055, "region": "South American", "recipe": "Oven-Roasted Tenderloin (Beef, Pork, Even Venison)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/97098"}, {"umap_0": -1.3691362142562866, "umap_1": 9.727387428283691, "region": "Italian", "recipe": "Rosemary Egg Frittata", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/12428"}, {"umap_0": 11.390667915344238, "umap_1": 6.852691650390625, "region": "UK", "recipe": "Peanut-Butter Flapjacks", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/103030"}, {"umap_0": 0.8971931338310242, "umap_1": 12.64441204071045, "region": "Indian Subcontinent", "recipe": "Indian Butter Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/65213"}, {"umap_0": 0.18060825765132904, "umap_1": 10.762374877929688, "region": "Mexican", "recipe": "Instant Pot\u00ae Charro (Refried Beans)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6186"}, {"umap_0": 0.9632858037948608, "umap_1": 7.276350021362305, "region": "Scandinavian", "recipe": "Easy Swedish Meatballs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/139910"}, {"umap_0": 10.606472969055176, "umap_1": 10.26840877532959, "region": "Australian", "recipe": "Lime Sunset Non-Alcoholic Cocktail", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75744"}, {"umap_0": 10.591907501220703, "umap_1": 7.810356616973877, "region": "French", "recipe": "Lavender Nougat", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112872"}, {"umap_0": 9.035015106201172, "umap_1": 5.901548385620117, "region": "Canadian", "recipe": "Most Tender Pie Crust", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/143104"}, {"umap_0": 0.38223251700401306, "umap_1": 5.967268943786621, "region": "Italian", "recipe": "Cjalzons - Friulian Pasta Filled With Savory Sweet Stuffing", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/124869"}, {"umap_0": 0.5889646410942078, "umap_1": 6.238109588623047, "region": "Canadian", "recipe": "Cheese Krispies Crackers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/143953"}, {"umap_0": -1.3035809993743896, "umap_1": 8.116023063659668, "region": "Italian", "recipe": "Fast Eddie's Hustlin' Eggplant", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120391"}, {"umap_0": -1.6137914657592773, "umap_1": 12.053178787231445, "region": "Central American", "recipe": "Salsa from Costa Rica!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92751"}, {"umap_0": 3.221585988998413, "umap_1": 10.252674102783203, "region": "Chinese and Mongolian", "recipe": "Xihongshi Jiang - Stir-Fried Shrimp in Tomato Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56397"}, {"umap_0": -2.6721746921539307, "umap_1": 7.969666481018066, "region": "South American", "recipe": "Heirloom Tomato Salad With Grilled Garlic Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100061"}, {"umap_0": 10.209290504455566, "umap_1": 8.166001319885254, "region": "Mexican", "recipe": "Flan De Cafe", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87743"}, {"umap_0": 0.6465972065925598, "umap_1": 5.177090644836426, "region": "South American", "recipe": "S.l. Hot Roast Beef Party Sandwiches", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/95785"}, {"umap_0": 9.115842819213867, "umap_1": 8.394359588623047, "region": "Indian Subcontinent", "recipe": "Rice Pudding (Kheer)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/5129"}, {"umap_0": 10.87574577331543, "umap_1": 7.493214130401611, "region": "Mexican", "recipe": "Simply the Best Mexican Flan", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81000"}, {"umap_0": 0.8154590725898743, "umap_1": 11.127267837524414, "region": "Irish", "recipe": "Baked Corned Beef Brisket", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/136547"}, {"umap_0": -1.821033239364624, "umap_1": 9.254093170166016, "region": "Italian", "recipe": "Drink from the Bowl Spaghetti Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/128890"}, {"umap_0": -1.8258922100067139, "umap_1": 9.031458854675293, "region": "Mexican", "recipe": "Black Beans and Rice(arroz Con Frijoles Negros)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/78257"}, {"umap_0": 10.204330444335938, "umap_1": 5.338412284851074, "region": "Italian", "recipe": "Italian Soft Dead Man's Bones", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/121147"}, {"umap_0": 2.3421366214752197, "umap_1": 8.676328659057617, "region": "US", "recipe": "Sizzling Steak Fajitas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/15352"}, {"umap_0": 9.618403434753418, "umap_1": 6.705162525177002, "region": "Canadian", "recipe": "Agave Lavender Muffins", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148948"}, {"umap_0": 2.175485134124756, "umap_1": 7.622127532958984, "region": "Spanish and Portuguese", "recipe": "Fried Calamari", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/141118"}, {"umap_0": 10.707467079162598, "umap_1": 10.320048332214355, "region": "US", "recipe": "Hawaii Five-O", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16759"}, {"umap_0": 10.739253044128418, "umap_1": 7.623933792114258, "region": "UK", "recipe": "Yummy Low Cal-Low Fat Pineapple Bread Pudding", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/103641"}, {"umap_0": 11.19957447052002, "umap_1": 7.613311767578125, "region": "US", "recipe": "Run For The Roses Pie II", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/18317"}, {"umap_0": -0.2407880425453186, "umap_1": 11.315374374389648, "region": "Mexican", "recipe": "Mexican Lentil Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/86849"}, {"umap_0": 0.09521909803152084, "umap_1": 9.362201690673828, "region": "Middle Eastern", "recipe": "Chickpea Patties in Pitas With Cilantro Yogurt", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/60474"}, {"umap_0": -0.47090598940849304, "umap_1": 6.503218650817871, "region": "Italian", "recipe": "Italian Breadcrumb-Crusted Tilapia W-Lemon", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/124448"}, {"umap_0": -1.6213449239730835, "umap_1": 7.207785606384277, "region": "Italian", "recipe": "Italian Snapper", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/121777"}, {"umap_0": 1.3110674619674683, "umap_1": 5.751152992248535, "region": "Mexican", "recipe": "Mexican 9-Layer Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84085"}, {"umap_0": 1.878241777420044, "umap_1": 8.753812789916992, "region": "South American", "recipe": "Meme's Calico Baked Beans", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96924"}, {"umap_0": -0.8955507278442383, "umap_1": 5.35370397567749, "region": "Italian", "recipe": "Lasagna in the Pressure Cooker", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/131117"}, {"umap_0": 11.097428321838379, "umap_1": 6.373406410217285, "region": "Deutschland", "recipe": "German Sour Cream Twists", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137808"}, {"umap_0": 0.007022353820502758, "umap_1": 11.734325408935547, "region": "Australian", "recipe": "Curried Pickled Onions", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76772"}, {"umap_0": 0.45874902606010437, "umap_1": 7.338892459869385, "region": "Eastern European", "recipe": "Frugal Gourmet's Polish Noodles and Cabbage", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/133360"}, {"umap_0": -0.1575111746788025, "umap_1": 5.806654453277588, "region": "US", "recipe": "Joelle's Famous Hot Crab and Artichoke Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16811"}, {"umap_0": 2.90606427192688, "umap_1": 7.009469985961914, "region": "Italian", "recipe": "Chewy Italian Batter Breadsticks", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/119751"}, {"umap_0": 9.997720718383789, "umap_1": 6.364442348480225, "region": "Scandinavian", "recipe": "The Ultimate Breakfast Cookie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/139209"}, {"umap_0": -0.500583827495575, "umap_1": 6.3571929931640625, "region": "Canadian", "recipe": "Lite Stuffed Mushrooms", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146603"}, {"umap_0": 9.942673683166504, "umap_1": 6.4778242111206055, "region": "Scandinavian", "recipe": "Gingersnaps (Pepparkakor)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105870"}, {"umap_0": 3.0555219650268555, "umap_1": 10.28598690032959, "region": "Korean", "recipe": "Korean Barbecue Wet Rub", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69136"}, {"umap_0": 11.022294044494629, "umap_1": 8.061348915100098, "region": "French", "recipe": "Millefeuille With Vanilla Cream and Chocolate Mousse", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112432"}, {"umap_0": -1.3980135917663574, "umap_1": 10.499991416931152, "region": "Rest Africa", "recipe": "Kele Wele", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48300"}, {"umap_0": 1.1709452867507935, "umap_1": 5.586130619049072, "region": "Mexican", "recipe": "Chile Con Queso (Chile-Cheese Dip)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83516"}, {"umap_0": -0.18024864792823792, "umap_1": 12.244661331176758, "region": "Indian Subcontinent", "recipe": "Masoor Dhal", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/65935"}, {"umap_0": 1.813773512840271, "umap_1": 8.55335521697998, "region": "Chinese and Mongolian", "recipe": "Southern Rice With Bacon Flavored Gravy", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53696"}, {"umap_0": -0.571422278881073, "umap_1": 8.44444751739502, "region": "Italian", "recipe": "Italian Baby Onions", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/119590"}, {"umap_0": 9.599403381347656, "umap_1": 9.754493713378906, "region": "UK", "recipe": "orange marmalade", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/104262"}, {"umap_0": 1.1669400930404663, "umap_1": 10.129842758178711, "region": "Middle Eastern", "recipe": "Duck Fesenjan", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/2855"}, {"umap_0": -0.6406524181365967, "umap_1": 11.46854305267334, "region": "Caribbean", "recipe": "Pique (Puerto Rican Style Hot Sauce)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92074"}, {"umap_0": -1.5321619510650635, "umap_1": 10.56371021270752, "region": "Greek", "recipe": "Chickpeas With Spinach (Greek)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110400"}, {"umap_0": -1.3721771240234375, "umap_1": 5.206984519958496, "region": "Italian", "recipe": "Wishbone Italian Grilled Chicken Sandwiches", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/126702"}, {"umap_0": -0.7962071299552917, "umap_1": 5.5524492263793945, "region": "Italian", "recipe": "Eggplant (Aubergine) Rollatini", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/131406"}, {"umap_0": -2.2322609424591064, "umap_1": 7.801762104034424, "region": "Greek", "recipe": "Brown Rice With Spinach and Feta Cheese", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/108296"}, {"umap_0": 1.2572479248046875, "umap_1": 9.441682815551758, "region": "US", "recipe": "Spiced Pumpkin Seeds", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/18420"}, {"umap_0": 1.802507758140564, "umap_1": 9.266167640686035, "region": "Indian Subcontinent", "recipe": "Broasted Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/72359"}, {"umap_0": -0.09042278677225113, "umap_1": 9.84847354888916, "region": "Rest Africa", "recipe": "Chickpea and Beef Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47588"}, {"umap_0": -1.0725185871124268, "umap_1": 6.658015251159668, "region": "Italian", "recipe": "Linguine With Bacon and Onions", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/127338"}, {"umap_0": 10.785246849060059, "umap_1": 9.027557373046875, "region": "Australian", "recipe": "Florentines With Berry Ice Cream", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73862"}, {"umap_0": -0.3742625415325165, "umap_1": 11.10119915008545, "region": "Rest Africa", "recipe": "Tunisian Fish Cakes With Lemon-Paprika A\u00efoli (Passover)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/49309"}, {"umap_0": 0.23900194466114044, "umap_1": 9.156368255615234, "region": "Deutschland", "recipe": "Swiss Pork and Mushrooms", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118228"}, {"umap_0": -0.03058946318924427, "umap_1": 6.014091491699219, "region": "Mexican", "recipe": "Cheese Soup With Jalape\u00f1o Pesto", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/88022"}, {"umap_0": 1.4410419464111328, "umap_1": 7.9549078941345215, "region": "Mexican", "recipe": "Spanish Rice Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82914"}, {"umap_0": 0.13814035058021545, "umap_1": 5.951913833618164, "region": "Italian", "recipe": "Chicken and Asparagus Fettuccine", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/11577"}, {"umap_0": 0.7318601012229919, "umap_1": 9.806900978088379, "region": "Mexican", "recipe": "Veggie Chili", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84548"}, {"umap_0": 1.459996223449707, "umap_1": 9.857269287109375, "region": "Caribbean", "recipe": "Curried Potato Chips", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91801"}, {"umap_0": 3.524404287338257, "umap_1": 9.201982498168945, "region": "Korean", "recipe": "Korean Soybean Noodles (Kong Kook Su)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4756"}, {"umap_0": -1.940906047821045, "umap_1": 6.084734916687012, "region": "Italian", "recipe": "Penne Pasta with Veggies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/12043"}, {"umap_0": -1.498612403869629, "umap_1": 8.07089614868164, "region": "Italian", "recipe": "Vegan Sausage Rigatoni", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125480"}, {"umap_0": 11.236673355102539, "umap_1": 6.95028829574585, "region": "French", "recipe": "Denny's-Style French Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115238"}, {"umap_0": 1.5257461071014404, "umap_1": 6.217804908752441, "region": "Mexican", "recipe": "Turkey Soft Tacos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/5743"}, {"umap_0": -0.5946857333183289, "umap_1": 6.078432559967041, "region": "Northern Africa", "recipe": "Tunisian Egg Briks", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/50064"}, {"umap_0": -0.23371565341949463, "umap_1": 12.626899719238281, "region": "Mexican", "recipe": "Lemon-Chili Rub", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79075"}, {"umap_0": 1.839859962463379, "umap_1": 6.068512439727783, "region": "Mexican", "recipe": "Sweet and Savory Black Bean Plaintain Burritos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/85725"}, {"umap_0": -2.038372039794922, "umap_1": 7.396195888519287, "region": "Italian", "recipe": "Pasta Ai Fiori Di Zucca (Pasta With Zucchini Blossoms)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/12210"}, {"umap_0": 10.95815658569336, "umap_1": 6.722874164581299, "region": "French", "recipe": "Nutella Brioche Rolls", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/117234"}, {"umap_0": -1.9898791313171387, "umap_1": 9.743003845214844, "region": "UK", "recipe": "Tomato Butter Tea Sandwiches", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/104630"}, {"umap_0": 3.3392016887664795, "umap_1": 10.062098503112793, "region": "Korean", "recipe": "My Auntie's Real Bulgogi", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4694"}, {"umap_0": -1.6173770427703857, "umap_1": 8.124360084533691, "region": "Italian", "recipe": "Aphrodisiac Tagliatelle with Blue Cheese Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/12274"}, {"umap_0": -1.9416553974151611, "umap_1": 7.549081325531006, "region": "Italian", "recipe": "Super Easy Italian Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/131858"}, {"umap_0": -0.26277557015419006, "umap_1": 7.222153186798096, "region": "Scandinavian", "recipe": "Strawberry Pasta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/106910"}, {"umap_0": 0.4316873848438263, "umap_1": 10.186958312988281, "region": "Mexican", "recipe": "Slow Cooker Pozole (Chicken and Pork)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/85566"}, {"umap_0": -1.8928779363632202, "umap_1": 9.587043762207031, "region": "Greek", "recipe": "Marinated Feta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/109586"}, {"umap_0": 1.2385129928588867, "umap_1": 5.460117340087891, "region": "Central American", "recipe": "South American Pizza With Chorizo and Chili Peppers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/93002"}, {"umap_0": -0.6707525253295898, "umap_1": 7.432048797607422, "region": "Australian", "recipe": "Light Smoked Fish Pie With Kumara Mash", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75118"}, {"umap_0": 0.7068323493003845, "umap_1": 5.762147426605225, "region": "Middle Eastern", "recipe": "Kurdish Kahdeh", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70069"}, {"umap_0": 1.5810576677322388, "umap_1": 5.0056962966918945, "region": "Mexican", "recipe": "Chorizo Sausage Chihuahua Dogs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87365"}, {"umap_0": 0.671999454498291, "umap_1": 12.363466262817383, "region": "Indian Subcontinent", "recipe": "Chicken in Gravy (Indian-Punjabi Style)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67385"}, {"umap_0": -0.8012382984161377, "umap_1": 9.176366806030273, "region": "South American", "recipe": "Feijao Na Pressao (Brazilian Black Beans in the Pressure Cooker)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/8314"}, {"umap_0": 1.0655608177185059, "umap_1": 8.46761703491211, "region": "South American", "recipe": "feijoada (brazilian black bean stew)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/93429"}, {"umap_0": 10.204320907592773, "umap_1": 8.843903541564941, "region": "French", "recipe": "Easy Chai Creme Caramel (Aka Chai Flan De Leche)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/111952"}, {"umap_0": 10.617517471313477, "umap_1": 6.73212194442749, "region": "Belgian", "recipe": "Dutch Vandermint Torte With Vandermint Coffee Frosting", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134010"}, {"umap_0": 1.1044844388961792, "umap_1": 9.912679672241211, "region": "US", "recipe": "Buffalo Shrimp", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/17622"}, {"umap_0": 0.8588863611221313, "umap_1": 7.437868118286133, "region": "French", "recipe": "My Mom's French Canadian Cretons", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113988"}, {"umap_0": 3.0241997241973877, "umap_1": 10.527693748474121, "region": "Mexican", "recipe": "Foley's Grilled Salmon With Soy Ginger", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79398"}, {"umap_0": -0.8556214570999146, "umap_1": 8.183527946472168, "region": "Italian", "recipe": "Pollo Alla Montanara (Chicken in Wine Sauce)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/129634"}, {"umap_0": 0.16890136897563934, "umap_1": 11.511482238769531, "region": "Indian Subcontinent", "recipe": "Indian Cauliflower and Kidney Bean Stew With Coconut Milk", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/66998"}, {"umap_0": 10.652979850769043, "umap_1": 10.26740550994873, "region": "Australian", "recipe": "Drunken Watermelon", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76384"}, {"umap_0": 3.737821102142334, "umap_1": 9.937808990478516, "region": "Japanese", "recipe": "Japanese Cabbage Salad with Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/71077"}, {"umap_0": 0.01138520147651434, "umap_1": 8.325850486755371, "region": "Scandinavian", "recipe": "Chicken Fricass\u00e9e With Creamy Sweet-And-Sour Dill Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/139682"}, {"umap_0": 2.902860403060913, "umap_1": 9.898431777954102, "region": "Chinese and Mongolian", "recipe": "Deb's General Tso's Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/2896"}, {"umap_0": 3.3006980419158936, "umap_1": 10.426973342895508, "region": "Australian", "recipe": "Chilli Plum Crabs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77413"}, {"umap_0": -1.1858551502227783, "umap_1": 7.470452785491943, "region": "Italian", "recipe": "Original Carrabba's Chicken Bryan (Not Copycat!)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/124919"}, {"umap_0": -1.8793965578079224, "umap_1": 5.698782444000244, "region": "Italian", "recipe": "Easy Italian Vegetable Packets", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125318"}, {"umap_0": -0.09685136377811432, "umap_1": 5.617732524871826, "region": "Chinese and Mongolian", "recipe": "Buttered Parmesan Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53803"}, {"umap_0": 10.380111694335938, "umap_1": 7.766465187072754, "region": "Canadian", "recipe": "Lemon Soymilk Pudding", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148979"}, {"umap_0": 9.107453346252441, "umap_1": 6.891109943389893, "region": "Scandinavian", "recipe": "Rosettes I", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/13419"}, {"umap_0": -0.004933270625770092, "umap_1": 4.822179317474365, "region": "Australian", "recipe": "Cheese & Vegemite Mini Quiches", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77559"}, {"umap_0": 0.6233452558517456, "umap_1": 10.268095970153809, "region": "Caribbean", "recipe": "Caribbean Vegetable Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91741"}, {"umap_0": -0.2816180884838104, "umap_1": 6.0629730224609375, "region": "Deutschland", "recipe": "Scallops in Swiss Cheese Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/117950"}, {"umap_0": -2.117828369140625, "umap_1": 8.800236701965332, "region": "Northern Africa", "recipe": "Red Pepper, Lemon and Mint Couscous", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/49548"}, {"umap_0": 0.9907320141792297, "umap_1": 4.8527021408081055, "region": "Mexican", "recipe": "Mexican Cheese Snacks", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80855"}, {"umap_0": 11.093069076538086, "umap_1": 7.582452297210693, "region": "Australian", "recipe": "Flourless Chocolate Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74499"}, {"umap_0": 2.122055768966675, "umap_1": 5.0107102394104, "region": "South American", "recipe": "Shredded Beef Enchiladas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96506"}, {"umap_0": -1.4233676195144653, "umap_1": 6.529354572296143, "region": "Italian", "recipe": "Spaghetti with Beef and Mushroom Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/127768"}, {"umap_0": 9.445223808288574, "umap_1": 6.677623748779297, "region": "Australian", "recipe": "Chocolate and Almond Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75575"}, {"umap_0": -1.8812910318374634, "umap_1": 10.176521301269531, "region": "Italian", "recipe": "Pasta With Garlic and Oil (Pasta Aglio E Olio)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/131484"}, {"umap_0": -1.4044510126113892, "umap_1": 9.174473762512207, "region": "French", "recipe": "Artichoke Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/111806"}, {"umap_0": -1.857147455215454, "umap_1": 9.701681137084961, "region": "French", "recipe": "Confit D'oignon - Onion Preserve", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112460"}, {"umap_0": 10.007903099060059, "umap_1": 5.882359981536865, "region": "Canadian", "recipe": "Mom,s Raisin Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144271"}, {"umap_0": 0.7440477013587952, "umap_1": 7.946354866027832, "region": "French", "recipe": "Chicken in a Pot", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113869"}, {"umap_0": -2.482712507247925, "umap_1": 8.086446762084961, "region": "Greek", "recipe": "Healthy Greek Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/107714"}, {"umap_0": -1.9129527807235718, "umap_1": 6.97475528717041, "region": "Italian", "recipe": "Appetizing Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/11344"}, {"umap_0": 0.7719407677650452, "umap_1": 5.481480598449707, "region": "Mexican", "recipe": "Jalapeno Popper Quesadillas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82203"}, {"umap_0": 3.3700122833251953, "umap_1": 10.080263137817383, "region": "Canadian", "recipe": "Orange-apricot Prawns", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144799"}, {"umap_0": 0.7927509546279907, "umap_1": 6.950196266174316, "region": "Belgian", "recipe": "Belgian Style Carrot Coins", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/106693"}, {"umap_0": 1.1569143533706665, "umap_1": 8.28869342803955, "region": "South American", "recipe": "Cheesy Ground Beef and Rice Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/94665"}, {"umap_0": -0.6531607508659363, "umap_1": 10.195749282836914, "region": "Indian Subcontinent", "recipe": "Chucumber (Indian Cucumber Salad)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64524"}, {"umap_0": 1.734744668006897, "umap_1": 7.619813919067383, "region": "Deutschland", "recipe": "Falscher Hase (False Hare German Meatballs)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138294"}, {"umap_0": 2.5987367630004883, "umap_1": 10.643059730529785, "region": "Southeast Asian", "recipe": "Indonesian Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/59860"}, {"umap_0": 2.723863124847412, "umap_1": 8.864019393920898, "region": "South American", "recipe": "Coconut Curry Beef Noodles", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/94858"}, {"umap_0": 0.9650956988334656, "umap_1": 4.880723476409912, "region": "US", "recipe": "Mexican Chicken Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/18074"}, {"umap_0": -1.263389229774475, "umap_1": 8.040308952331543, "region": "US", "recipe": "Killer Shrimp Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/17945"}, {"umap_0": 11.297856330871582, "umap_1": 7.8658447265625, "region": "French", "recipe": "Baked Cinnamon French Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115143"}, {"umap_0": 11.402894020080566, "umap_1": 8.030360221862793, "region": "Deutschland", "recipe": "Black Forest Cherry Cheesecake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137850"}, {"umap_0": 0.11632750183343887, "umap_1": 11.490843772888184, "region": "Middle Eastern", "recipe": "Tagine of Lamb with Quinces", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61662"}, {"umap_0": -1.4687013626098633, "umap_1": 8.50658130645752, "region": "Italian", "recipe": "Chicken Piccata (South Beach Phase 1)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/126525"}, {"umap_0": -1.2568435668945312, "umap_1": 7.199586391448975, "region": "Italian", "recipe": "Shaved Brussels Sprouts With Pancetta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/119915"}, {"umap_0": 0.09890953451395035, "umap_1": 9.473420143127441, "region": "Canadian", "recipe": "Pictou County Pizza Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144697"}, {"umap_0": -0.05035017803311348, "umap_1": 8.57482624053955, "region": "Deutschland", "recipe": "Simple Viennese Beef Goulash", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/107297"}, {"umap_0": 2.7068521976470947, "umap_1": 10.448904037475586, "region": "Japanese", "recipe": "Japanese Salmon Burger", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70943"}, {"umap_0": 10.349726676940918, "umap_1": 7.970216751098633, "region": "Deutschland", "recipe": "Zimtmakronen - Cinnamon Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137381"}, {"umap_0": 9.381885528564453, "umap_1": 6.707773208618164, "region": "Deutschland", "recipe": "Mom's Kuchen", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137283"}, {"umap_0": 0.9319941997528076, "umap_1": 8.81534481048584, "region": "Caribbean", "recipe": "Rice and Peas With Ham", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/90735"}, {"umap_0": 10.162126541137695, "umap_1": 5.602627277374268, "region": "Canadian", "recipe": "Maple Muffins", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147185"}, {"umap_0": 0.9786609411239624, "umap_1": 11.45162582397461, "region": "Mexican", "recipe": "Light Flour Tortillas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84775"}, {"umap_0": 10.572319030761719, "umap_1": 10.323277473449707, "region": "Mexican", "recipe": "Mango, Chilli and Lime Margarita", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83066"}, {"umap_0": 0.7196156978607178, "umap_1": 13.115609169006348, "region": "Indian Subcontinent", "recipe": "Shrimp in Coconut Gravy", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67691"}, {"umap_0": 2.4053750038146973, "umap_1": 9.922897338867188, "region": "Chinese and Mongolian", "recipe": "Stir-Fried Chicken With Pineapple and Peppers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/2934"}, {"umap_0": 3.3454458713531494, "umap_1": 9.315509796142578, "region": "Chinese and Mongolian", "recipe": "Chinese Beef With Anise Hyssop", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53004"}, {"umap_0": 10.13790225982666, "umap_1": 8.951178550720215, "region": "French", "recipe": "Honey-Soaked Goat Cheese", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113255"}, {"umap_0": 0.6283879280090332, "umap_1": 9.493538856506348, "region": "Mexican", "recipe": "Chicken and Black Bean Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6700"}, {"umap_0": 11.76770305633545, "umap_1": 8.455057144165039, "region": "Canadian", "recipe": "No Bake Cream Cheese Dessert", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145719"}, {"umap_0": 0.039625704288482666, "umap_1": 12.190072059631348, "region": "Indian Subcontinent", "recipe": "Chicken Tikka Mumbai", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/65204"}, {"umap_0": 0.9696589708328247, "umap_1": 10.34250545501709, "region": "Thai", "recipe": "Thai Red Curry With Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/58022"}, {"umap_0": 10.620315551757812, "umap_1": 10.249897003173828, "region": "Canadian", "recipe": "Tropical Strawberry Tea", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/143962"}, {"umap_0": 1.2627520561218262, "umap_1": 5.777937889099121, "region": "Mexican", "recipe": "Grilled Breakfast Burrito", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82869"}, {"umap_0": 0.7471975684165955, "umap_1": 7.868103504180908, "region": "Australian", "recipe": "Veal Birds", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75949"}, {"umap_0": 10.360438346862793, "umap_1": 8.682806015014648, "region": "Central American", "recipe": "South American Raisin Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92959"}, {"umap_0": 2.3578615188598633, "umap_1": 9.635660171508789, "region": "Australian", "recipe": "Cocktail Meatballs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75802"}, {"umap_0": -2.773643732070923, "umap_1": 8.544965744018555, "region": "Italian", "recipe": "Pan-Fried Garlic Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130407"}, {"umap_0": -0.48247095942497253, "umap_1": 8.675886154174805, "region": "French", "recipe": "Snails Sommeroise - Escargots a la Sommeroise", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113207"}, {"umap_0": 8.992899894714355, "umap_1": 6.524967670440674, "region": "Eastern European", "recipe": "Choereg (Armenian Easter Bread)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/13538"}, {"umap_0": 3.416114568710327, "umap_1": 9.989638328552246, "region": "Australian", "recipe": "Asian Lettuce Wraps", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/5308"}, {"umap_0": 8.348167419433594, "umap_1": 6.987048625946045, "region": "Rest Africa", "recipe": "Steamed Cornbread-Cakes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47557"}, {"umap_0": 9.833870887756348, "umap_1": 7.041590690612793, "region": "UK", "recipe": "Green Tea Shortbread Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101467"}, {"umap_0": 1.2901328802108765, "umap_1": 10.511434555053711, "region": "South American", "recipe": "Dr Pepper Beef Marinade", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/99886"}, {"umap_0": -0.23262551426887512, "umap_1": 10.578851699829102, "region": "Caribbean", "recipe": "Roasted Corn, Black Bean, and Mango Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91037"}, {"umap_0": 0.5840230584144592, "umap_1": 9.741433143615723, "region": "Mexican", "recipe": "Mom's Carne Guisada", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/7540"}, {"umap_0": 10.445120811462402, "umap_1": 8.04233169555664, "region": "Indian Subcontinent", "recipe": "Cheese Pudding With Raisins and Almonds", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/66517"}, {"umap_0": 0.48519623279571533, "umap_1": 8.37837028503418, "region": "Irish", "recipe": "Irish Pot Roast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134890"}, {"umap_0": -2.2729949951171875, "umap_1": 6.701333999633789, "region": "Middle Eastern", "recipe": "Falafel Pitas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/60903"}, {"umap_0": 0.4105159640312195, "umap_1": 10.130810737609863, "region": "Central American", "recipe": "American Women's Club of Luxembourg Chili", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92842"}, {"umap_0": 8.838973045349121, "umap_1": 6.7364182472229, "region": "Indian Subcontinent", "recipe": "Roti Canai_Paratha (Indian Pancake)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4609"}, {"umap_0": 0.05471676215529442, "umap_1": 7.252633094787598, "region": "Mexican", "recipe": "360 Cookware Chorizo Bean Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79989"}, {"umap_0": 2.023939847946167, "umap_1": 4.727809429168701, "region": "Mexican", "recipe": "Taco Casserole Surprise", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87725"}, {"umap_0": 1.1099916696548462, "umap_1": 12.706733703613281, "region": "Indian Subcontinent", "recipe": "Anjeeri Khumb with only 3 tsps. oil and maraschino cherries!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64894"}, {"umap_0": 1.1657395362854004, "umap_1": 8.06629467010498, "region": "Canadian", "recipe": "Smoked Pork Chops With Potatoes & Sauerkraut", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147740"}, {"umap_0": 12.081353187561035, "umap_1": 4.686682224273682, "region": "Deutschland", "recipe": "Spaetzle - German", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138779"}, {"umap_0": 0.2857591509819031, "umap_1": 6.614966869354248, "region": "Deutschland", "recipe": "German Potato Salad With Keilbasa #5FIX", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137184"}, {"umap_0": -0.37483659386634827, "umap_1": 6.65553617477417, "region": "French", "recipe": "French Onion Tomato Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113544"}, {"umap_0": 0.7989017367362976, "umap_1": 9.281834602355957, "region": "Mexican", "recipe": "Nopalitos Con Huevos Breakfast Tacos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/86660"}, {"umap_0": 0.7640136480331421, "umap_1": 12.481929779052734, "region": "Indian Subcontinent", "recipe": "Tuna Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64275"}, {"umap_0": -2.495041608810425, "umap_1": 9.036615371704102, "region": "Italian", "recipe": "Olive Oil, Garlic, and Crushed Red Pepper Pasta Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/119576"}, {"umap_0": -0.6572386622428894, "umap_1": 10.325284004211426, "region": "Middle Eastern", "recipe": "Iranian Sugar Pickled Garlic", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/60582"}, {"umap_0": 1.4814096689224243, "umap_1": 6.053394794464111, "region": "South American", "recipe": "Papas Huancaino", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/93837"}, {"umap_0": 10.918684959411621, "umap_1": 6.646834373474121, "region": "Deutschland", "recipe": "Chocolate Filled Almond Spritz Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138340"}, {"umap_0": -1.8504774570465088, "umap_1": 10.791175842285156, "region": "Australian", "recipe": "Succulent Prawns for the Barbie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75535"}, {"umap_0": -2.435455322265625, "umap_1": 6.750731945037842, "region": "Italian", "recipe": "Basil Butter Garlic Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132352"}, {"umap_0": 1.0257591009140015, "umap_1": 9.099783897399902, "region": "Greek", "recipe": "Dolma", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/9374"}, {"umap_0": 1.4252159595489502, "umap_1": 8.448905944824219, "region": "Chinese and Mongolian", "recipe": "Chicken With Szechuan Rice for 2", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/57164"}, {"umap_0": 1.1825228929519653, "umap_1": 10.686308860778809, "region": "Australian", "recipe": "Savoury Pumpkin Quiche", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74887"}, {"umap_0": 9.329658508300781, "umap_1": 6.513767242431641, "region": "Belgian", "recipe": "Liege Waffle Recipe - Li\u00e8ge Gaufre Recette", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/106568"}, {"umap_0": 1.5835986137390137, "umap_1": 6.910691261291504, "region": "South American", "recipe": "Easy Beef \u2018n\u2019 Pasta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/98468"}, {"umap_0": 0.8244311213493347, "umap_1": 8.260699272155762, "region": "Deutschland", "recipe": "Pork Chops and Pierogies for 2", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/136971"}, {"umap_0": 10.9827299118042, "umap_1": 8.54349136352539, "region": "UK", "recipe": "Traditional English Trifle", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/103800"}, {"umap_0": 0.7938772439956665, "umap_1": 12.604090690612793, "region": "Indian Subcontinent", "recipe": "Chicken or Lamb Biriyani", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64236"}, {"umap_0": 0.772128701210022, "umap_1": 12.36756706237793, "region": "Indian Subcontinent", "recipe": "Baked Fish Wrapped in Banana Leaves", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/68717"}, {"umap_0": 1.202843427658081, "umap_1": 11.409436225891113, "region": "Rest Africa", "recipe": "Sweet N' Spicy Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/51388"}, {"umap_0": -1.6273596286773682, "umap_1": 10.540791511535645, "region": "US", "recipe": "White Bean Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/18213"}, {"umap_0": -0.3158065974712372, "umap_1": 8.270655632019043, "region": "Canadian", "recipe": "Seared Pork Medallions With Saskatoon (Or Blueberry) and Rhubarb", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147201"}, {"umap_0": -0.035181835293769836, "umap_1": 9.522159576416016, "region": "Mexican", "recipe": "Two Bean Caserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/78596"}, {"umap_0": -0.2078840285539627, "umap_1": 5.976397514343262, "region": "Mexican", "recipe": "Spinach and Mushroom Quesadillas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79915"}, {"umap_0": 1.077321171760559, "umap_1": 8.21718692779541, "region": "French", "recipe": "Brasserie's Le Coze's French Onion Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114236"}, {"umap_0": 9.993802070617676, "umap_1": 5.464186668395996, "region": "South American", "recipe": "Heirloom Raisin Muffins", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100055"}, {"umap_0": 0.37413763999938965, "umap_1": 8.716294288635254, "region": "Belgian", "recipe": "Pennsylvania Dutch Potato Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134357"}, {"umap_0": 2.247965097427368, "umap_1": 11.000914573669434, "region": "Indian Subcontinent", "recipe": "Turkey Meatball Korma", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/68864"}, {"umap_0": 9.75698471069336, "umap_1": 7.453516006469727, "region": "Indian Subcontinent", "recipe": "Sandesh", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67002"}, {"umap_0": 2.091667652130127, "umap_1": 6.456871509552002, "region": "Mexican", "recipe": "Enchiladas Coloradas (Red Enchiladas)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80572"}, {"umap_0": 1.86276376247406, "umap_1": 10.717509269714355, "region": "Chinese and Mongolian", "recipe": "Asian Spicy Plum Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/51848"}, {"umap_0": 2.530447006225586, "umap_1": 10.041291236877441, "region": "Southeast Asian", "recipe": "Cheat n' Eat Vietnamese Chicken Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/62512"}, {"umap_0": 1.0116397142410278, "umap_1": 12.314139366149902, "region": "Indian Subcontinent", "recipe": "Aromatic Peas and Carrot Pilaf for one", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64705"}, {"umap_0": 1.7215689420700073, "umap_1": 10.256852149963379, "region": "Southeast Asian", "recipe": "Myrna's Curried Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63749"}, {"umap_0": -0.9524049162864685, "umap_1": 10.427093505859375, "region": "Mexican", "recipe": "Seafood Ceviche", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/7066"}, {"umap_0": -0.25578081607818604, "umap_1": 6.638718128204346, "region": "Caribbean", "recipe": "Trinidadian Macaroni Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91367"}, {"umap_0": -0.8399298787117004, "umap_1": 7.697590351104736, "region": "Deutschland", "recipe": "Easy German Potato Salad #5FIX", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137811"}, {"umap_0": -0.7990944385528564, "umap_1": 5.186559677124023, "region": "Italian", "recipe": "Asparagus Milanese", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132751"}, {"umap_0": -0.05589376762509346, "umap_1": 8.074045181274414, "region": "Deutschland", "recipe": "Veal Steaks", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137690"}, {"umap_0": 1.852655053138733, "umap_1": 10.20706558227539, "region": "Chinese and Mongolian", "recipe": "Steamed Sea Bass with Black Bean Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/57192"}, {"umap_0": -1.7756612300872803, "umap_1": 8.199274063110352, "region": "Italian", "recipe": "Michael Chiarello's Pickled Antipasto", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132715"}, {"umap_0": -2.453618049621582, "umap_1": 9.88633918762207, "region": "UK", "recipe": "Beetroot & Horseradish Puree", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/102512"}, {"umap_0": 0.4707120954990387, "umap_1": 6.374220371246338, "region": "Australian", "recipe": "Tassie Curry Scallop Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75158"}, {"umap_0": 1.3775466680526733, "umap_1": 10.290270805358887, "region": "South American", "recipe": "Prairie Fire Beef Brisket", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96182"}, {"umap_0": -0.4943050146102905, "umap_1": 8.376326560974121, "region": "Italian", "recipe": "Southern Italian Pasta Fagioli", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/127393"}, {"umap_0": -1.4104938507080078, "umap_1": 5.244559288024902, "region": "Italian", "recipe": "Zucchini Manicotti", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125556"}, {"umap_0": 0.49602025747299194, "umap_1": 6.53398323059082, "region": "Chinese and Mongolian", "recipe": "Cajun Quiche in a Rice Crust", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/54409"}, {"umap_0": 10.416463851928711, "umap_1": 7.738397598266602, "region": "Australian", "recipe": "Pancakes With Vanilla Banana (Using an Egg Replacer)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74010"}, {"umap_0": 1.4576456546783447, "umap_1": 5.499892711639404, "region": "Mexican", "recipe": "Cinco de Mayo", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80232"}, {"umap_0": 2.1327641010284424, "umap_1": 10.662544250488281, "region": "Australian", "recipe": "Rack of Lamb With Chilli-Mint Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77406"}, {"umap_0": -0.9710488319396973, "umap_1": 9.235594749450684, "region": "Chinese and Mongolian", "recipe": "Florida Beans and Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/54232"}, {"umap_0": 1.3386688232421875, "umap_1": 9.817499160766602, "region": "Rest Africa", "recipe": "Peanut (Groundnut) Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48987"}, {"umap_0": -0.7660301923751831, "umap_1": 9.261104583740234, "region": "Rest Africa", "recipe": "Preserved Lemons", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48174"}, {"umap_0": 0.6717744469642639, "umap_1": 5.91477108001709, "region": "Deutschland", "recipe": "Nudeln Mit Spinat Und Muskatnuss (Noodles W. Spinach and Nutmeg)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137013"}, {"umap_0": 0.5330303907394409, "umap_1": 6.743196964263916, "region": "Scandinavian", "recipe": "Dromskinka (Dream Ham)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/9153"}, {"umap_0": 9.152359962463379, "umap_1": 6.921017169952393, "region": "Scandinavian", "recipe": "Gluten Free Finnish (Hoito) Pancake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/139557"}, {"umap_0": 1.2150393724441528, "umap_1": 9.744861602783203, "region": "French", "recipe": "Onion Straws (French Fried Onions)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115865"}, {"umap_0": -1.9553046226501465, "umap_1": 9.343260765075684, "region": "Australian", "recipe": "Caramelised Onion & Goats Cheese Omelette", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73935"}, {"umap_0": 3.6354057788848877, "umap_1": 10.077268600463867, "region": "Korean", "recipe": "Wanjakuk (Korean Meatball Soup)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69292"}, {"umap_0": -1.2453991174697876, "umap_1": 5.132853031158447, "region": "Italian", "recipe": "Sausage Zucchini Boats", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123708"}, {"umap_0": 2.2950439453125, "umap_1": 9.934898376464844, "region": "Southeast Asian", "recipe": "Acar Campur (Pickled Vegetables)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/59795"}, {"umap_0": -1.4231547117233276, "umap_1": 7.371896743774414, "region": "Canadian", "recipe": "Bear Italiano - Bear Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145070"}, {"umap_0": -0.5152446627616882, "umap_1": 10.045548439025879, "region": "Mexican", "recipe": "Crock Pot Mexicali Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/78045"}, {"umap_0": 10.830865859985352, "umap_1": 7.895906925201416, "region": "French", "recipe": "Baked Blueberry Pecan French Toast With Blueberry Syrup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/111721"}, {"umap_0": -1.1581099033355713, "umap_1": 9.701723098754883, "region": "Italian", "recipe": "Bomba Calabrese (Spicy Calabrian Pepper Spread)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/11040"}, {"umap_0": -0.6526889204978943, "umap_1": 10.805870056152344, "region": "Chinese and Mongolian", "recipe": "Prawn Sang Choy Bow", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55309"}, {"umap_0": 0.6108986139297485, "umap_1": 4.784968852996826, "region": "Mexican", "recipe": "Oops Tex Mex Potatoes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/78434"}, {"umap_0": -1.1193559169769287, "umap_1": 5.877293109893799, "region": "Italian", "recipe": "Meatballs Ala Angela", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130922"}, {"umap_0": 10.286702156066895, "umap_1": 7.304640769958496, "region": "Spanish and Portuguese", "recipe": "Pastissets (Powdered Sugar Cookies from Spain)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/140546"}, {"umap_0": 0.4062589704990387, "umap_1": 10.26050090789795, "region": "Caribbean", "recipe": "Caribbean Chicken Curry", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/90497"}, {"umap_0": 0.033274564892053604, "umap_1": 8.684553146362305, "region": "Central American", "recipe": "Martha Stewart's All American Meatloaf", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92963"}, {"umap_0": 3.0481154918670654, "umap_1": 10.062190055847168, "region": "Japanese", "recipe": "Beef Kushiyaki", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4995"}, {"umap_0": -0.8106408715248108, "umap_1": 6.62211275100708, "region": "Italian", "recipe": "Egg Noodle Casserole With Italian Cheese", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/119647"}, {"umap_0": 1.5702959299087524, "umap_1": 6.314182281494141, "region": "Mexican", "recipe": "Mexican Vegetable Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87879"}, {"umap_0": 1.1275120973587036, "umap_1": 5.459662437438965, "region": "Mexican", "recipe": "Longhorn Chili Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84158"}, {"umap_0": -0.8691716194152832, "umap_1": 9.091316223144531, "region": "Italian", "recipe": "Italian Sausage, Sicilian Style", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130070"}, {"umap_0": 0.06120110675692558, "umap_1": 7.997251987457275, "region": "Japanese", "recipe": "Bacon Mushroom Burger", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70786"}, {"umap_0": 3.1422221660614014, "umap_1": 9.054335594177246, "region": "Chinese and Mongolian", "recipe": "Savory Chinese Beef (Crock Pot)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56049"}, {"umap_0": -1.2090941667556763, "umap_1": 8.22006607055664, "region": "Mexican", "recipe": "Mexican Night Burritos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81434"}, {"umap_0": -0.8484283685684204, "umap_1": 8.321549415588379, "region": "Australian", "recipe": "Sage and Macadamia Pork Roast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75037"}, {"umap_0": 10.7693510055542, "umap_1": 10.191994667053223, "region": "Australian", "recipe": "Vanilla Ginger Sour Cocktail", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/72676"}, {"umap_0": 0.10555657744407654, "umap_1": 9.530282974243164, "region": "Middle Eastern", "recipe": "Lamb and Bulgur Soup (Shorba Freek)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3689"}, {"umap_0": 2.9676406383514404, "umap_1": 10.062798500061035, "region": "Japanese", "recipe": "General Tso Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/71518"}, {"umap_0": 1.05437171459198, "umap_1": 6.2700581550598145, "region": "Mexican", "recipe": "Huevos Rancheros Sandwiches", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80098"}, {"umap_0": 10.907604217529297, "umap_1": 7.440410614013672, "region": "French", "recipe": "Almond French Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/116893"}, {"umap_0": -0.578080952167511, "umap_1": 7.900142192840576, "region": "Eastern European", "recipe": "Summer Borscht (Lower Fat)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100851"}, {"umap_0": -1.1572819948196411, "umap_1": 4.556168079376221, "region": "South American", "recipe": "Delicious Ground Beef Pizza Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/99097"}, {"umap_0": 11.268598556518555, "umap_1": 7.175631999969482, "region": "UK", "recipe": "Melt-In-Your-Mouth Mini Chocolate Chip Shortbread Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101554"}, {"umap_0": -0.17080117762088776, "umap_1": 9.19865608215332, "region": "Chinese and Mongolian", "recipe": "Rosemary Chicken With Wild Rice (Weight Watchers)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53898"}, {"umap_0": 0.8463926911354065, "umap_1": 12.083699226379395, "region": "Indian Subcontinent", "recipe": "Chicken and Vegetable Curry (Indian)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/66464"}, {"umap_0": 8.479124069213867, "umap_1": 7.198885440826416, "region": "Italian", "recipe": "Nick's Pizzelle Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/121131"}, {"umap_0": 0.6675624847412109, "umap_1": 12.89366626739502, "region": "Indian Subcontinent", "recipe": "Tamarind Chutney", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/66825"}, {"umap_0": 0.5457795262336731, "umap_1": 9.581137657165527, "region": "Mexican", "recipe": "Chilli Beans with Spicy Tortilla Crisps", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/85660"}, {"umap_0": 1.915384292602539, "umap_1": 4.656497001647949, "region": "Mexican", "recipe": "Jen's Nachos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/7425"}, {"umap_0": 2.7924530506134033, "umap_1": 10.67573070526123, "region": "Japanese", "recipe": "Green Beans with Peanut Dressing", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/71725"}, {"umap_0": 1.935951828956604, "umap_1": 4.967324733734131, "region": "Mexican", "recipe": "Mexican Dinner Pizza", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81746"}, {"umap_0": -1.4189534187316895, "umap_1": 6.698885440826416, "region": "Italian", "recipe": "Mozzarella Chicken Ciabatta Sandwiches", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/131675"}, {"umap_0": 10.237968444824219, "umap_1": 6.2917704582214355, "region": "Rest Africa", "recipe": "Banana Bread (from Africa!)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47812"}, {"umap_0": -0.3882516920566559, "umap_1": 9.124814987182617, "region": "Italian", "recipe": "Chicken Diablo", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/129719"}, {"umap_0": 0.5488468408584595, "umap_1": 7.219930648803711, "region": "UK", "recipe": "Hampshire Cream Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/104697"}, {"umap_0": 3.3690927028656006, "umap_1": 9.839742660522461, "region": "Chinese and Mongolian", "recipe": "Lillian's Spring Onion and Ginger Noodles", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/51974"}, {"umap_0": 10.2373685836792, "umap_1": 6.3332600593566895, "region": "Caribbean", "recipe": "Coconut Muffins", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/90845"}, {"umap_0": 10.785271644592285, "umap_1": 8.983062744140625, "region": "UK", "recipe": "Fizzy Jell-O", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101636"}, {"umap_0": -0.33945655822753906, "umap_1": 10.537605285644531, "region": "Greek", "recipe": "Mediterranean Veggie Burgers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/109473"}, {"umap_0": -0.36531534790992737, "umap_1": 8.661611557006836, "region": "Australian", "recipe": "Pumpkin, Sweet Potato, and Leek Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/5595"}, {"umap_0": -0.5688000321388245, "umap_1": 11.917841911315918, "region": "Indian Subcontinent", "recipe": "Minty Cucumber Raita", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4603"}, {"umap_0": 9.867973327636719, "umap_1": 6.5029191970825195, "region": "Irish", "recipe": "Parkin- The Gingerbread from England", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/135062"}, {"umap_0": 0.6897287964820862, "umap_1": 5.2665696144104, "region": "UK", "recipe": "Ham and Cheese Breakfast Quiche", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/8974"}, {"umap_0": -1.5464154481887817, "umap_1": 8.353484153747559, "region": "Deutschland", "recipe": "Truite a La Creme Zugoise (Trout in Herbed Cream Sauce)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118184"}, {"umap_0": -1.9634698629379272, "umap_1": 6.324359893798828, "region": "Greek", "recipe": "Baked Greek Chicken Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/107733"}, {"umap_0": -0.2915879487991333, "umap_1": 6.246881008148193, "region": "French", "recipe": "Alsatian Tart", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114885"}, {"umap_0": 10.76455307006836, "umap_1": 10.159624099731445, "region": "Australian", "recipe": "Cougar Kickoff Cocktail", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73552"}, {"umap_0": -0.6325548887252808, "umap_1": 8.991036415100098, "region": "Scandinavian", "recipe": "Pickled Herring Nana's Recipe (Or so Close)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/106272"}, {"umap_0": 10.551515579223633, "umap_1": 10.310701370239258, "region": "Australian", "recipe": "An Aussie Sol", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77241"}, {"umap_0": 0.6943299770355225, "umap_1": 9.899022102355957, "region": "US", "recipe": "Presidential Debate Chili", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16498"}, {"umap_0": -0.9291115999221802, "umap_1": 9.588019371032715, "region": "Indian Subcontinent", "recipe": "Bengali-Style Green Beans", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67246"}, {"umap_0": 1.3908172845840454, "umap_1": 7.886014938354492, "region": "Deutschland", "recipe": "Badenian Sour Liver (Badisches Saures Leberle)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137908"}, {"umap_0": 3.075787305831909, "umap_1": 9.263035774230957, "region": "South American", "recipe": "Hawaiian Teriyaki Beef", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/98417"}, {"umap_0": -2.2943882942199707, "umap_1": 6.853687286376953, "region": "Middle Eastern", "recipe": "Persian Herb and Cheese", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/2848"}, {"umap_0": -1.0580228567123413, "umap_1": 4.607542037963867, "region": "Italian", "recipe": "Low Carb Zucchini Lasagna (South Beach Friendly)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/128064"}, {"umap_0": 9.170491218566895, "umap_1": 5.9093403816223145, "region": "South American", "recipe": "Chilean Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/93789"}, {"umap_0": 3.9008381366729736, "umap_1": 10.0866060256958, "region": "Chinese and Mongolian", "recipe": "Betty Crocker Oriental Dressing", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55227"}, {"umap_0": 11.219620704650879, "umap_1": 8.545230865478516, "region": "French", "recipe": "Strawberry Mille Feuille", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/116827"}, {"umap_0": 10.95186710357666, "umap_1": 7.6603803634643555, "region": "Scandinavian", "recipe": "Danish Almond Ring", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100916"}, {"umap_0": 1.7908753156661987, "umap_1": 7.278170108795166, "region": "Scandinavian", "recipe": "Time-Life Swedish Meatballs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/106291"}, {"umap_0": -0.4508264362812042, "umap_1": 11.151329040527344, "region": "Italian", "recipe": "Zucchini Lentil Pasta Sauce (Vegetarian)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123242"}, {"umap_0": 11.427289962768555, "umap_1": 8.460942268371582, "region": "Australian", "recipe": "Pound Cake Truffles", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73847"}, {"umap_0": 10.072717666625977, "umap_1": 5.631075859069824, "region": "Canadian", "recipe": "Cinnamon Twist Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145556"}, {"umap_0": 1.6756099462509155, "umap_1": 6.191090106964111, "region": "Australian", "recipe": "Nachos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77134"}, {"umap_0": -0.1459924429655075, "umap_1": 9.162400245666504, "region": "Middle Eastern", "recipe": "Koshary", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/2619"}, {"umap_0": -1.4194878339767456, "umap_1": 10.445621490478516, "region": "Canadian", "recipe": "Lemon-Rosemary Grilled Pork Tenderloin", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147583"}, {"umap_0": -1.2383641004562378, "umap_1": 7.414096355438232, "region": "Italian", "recipe": "Vegan Lasagna I", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/12617"}, {"umap_0": 0.786368727684021, "umap_1": 7.645626068115234, "region": "Italian", "recipe": "Italian Ranch Shredded Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/133178"}, {"umap_0": 10.711524963378906, "umap_1": 10.80091381072998, "region": "Canadian", "recipe": "Tequila Grapefruit Splash", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146676"}, {"umap_0": 0.46166691184043884, "umap_1": 8.206416130065918, "region": "Deutschland", "recipe": "Kraut and Sausage in a Crockpot", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138219"}, {"umap_0": 1.073598861694336, "umap_1": 11.379616737365723, "region": "Mexican", "recipe": "Manchamanteles (Fruity Mole Stew)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/86979"}, {"umap_0": 0.06744198501110077, "umap_1": 10.287727355957031, "region": "Rest Africa", "recipe": "Curried Okra", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47995"}, {"umap_0": -1.7383971214294434, "umap_1": 10.345659255981445, "region": "Rest Africa", "recipe": "Marinated Baby Marrow (Courgette-Zucchini)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/51079"}, {"umap_0": -1.505161166191101, "umap_1": 5.65922737121582, "region": "Italian", "recipe": "Polenta With Italian Sausage and Vegetables", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125166"}, {"umap_0": 1.3676795959472656, "umap_1": 8.173250198364258, "region": "Central American", "recipe": "All American Hamburgers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/93098"}, {"umap_0": -1.4643367528915405, "umap_1": 9.460729598999023, "region": "Australian", "recipe": "Pasta With Tuna Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/5546"}, {"umap_0": 11.055620193481445, "umap_1": 6.838775634765625, "region": "French", "recipe": "Chocolate-Dipped Hazelnut Marbles", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115533"}, {"umap_0": -1.540805459022522, "umap_1": 8.47479248046875, "region": "Spanish and Portuguese", "recipe": "Broccoli, Cauliflower and Romanesco Cauliflower With Warm Ham Vi", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/140740"}, {"umap_0": 0.7387064695358276, "umap_1": 7.098805904388428, "region": "South American", "recipe": "Individual Beef Wellingtons II", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96313"}, {"umap_0": 1.9130972623825073, "umap_1": 5.743204593658447, "region": "Mexican", "recipe": "Salisbury Steak - Tex Mex Way", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/85636"}, {"umap_0": 11.582109451293945, "umap_1": 7.7360405921936035, "region": "French", "recipe": "French Waffles with Strawberries", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113980"}, {"umap_0": 11.66311264038086, "umap_1": 9.274120330810547, "region": "Rest Africa", "recipe": "South African Smoothie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47795"}, {"umap_0": -0.5895673632621765, "umap_1": 10.910447120666504, "region": "Mexican", "recipe": "Fish and Veggie Tacos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84844"}, {"umap_0": 9.877508163452148, "umap_1": 9.326733589172363, "region": "Canadian", "recipe": "Apple-Apricot Sauce for Pork", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148556"}, {"umap_0": 1.8734489679336548, "umap_1": 5.978754997253418, "region": "Mexican", "recipe": "Hearty Chicken Enchilada Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/88588"}, {"umap_0": -2.0421183109283447, "umap_1": 9.039802551269531, "region": "South American", "recipe": "Beef Adobo Salpicao", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96907"}, {"umap_0": 2.3681581020355225, "umap_1": 10.772686004638672, "region": "Southeast Asian", "recipe": "Vegetarian Pho (Vietnamese Noodle Soup)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3772"}, {"umap_0": -1.0620571374893188, "umap_1": 6.112938404083252, "region": "Italian", "recipe": "Zesty Fried Meatballs With Red Pepper Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132783"}, {"umap_0": 9.747696876525879, "umap_1": 7.595332622528076, "region": "Australian", "recipe": "Lemon or Lime and Macadamia Biscotti", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76870"}, {"umap_0": 10.19006061553955, "umap_1": 8.046283721923828, "region": "UK", "recipe": "Thai Baked Custard", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101321"}, {"umap_0": 9.616816520690918, "umap_1": 7.417548656463623, "region": "Scandinavian", "recipe": "Danish Pancakes W- Tart Strawberries", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101145"}, {"umap_0": -1.9307607412338257, "umap_1": 7.019047260284424, "region": "Italian", "recipe": "Italian Veggie Skillet", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120436"}, {"umap_0": 0.5598496198654175, "umap_1": 10.123669624328613, "region": "Mexican", "recipe": "Chicken Chili", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/88476"}, {"umap_0": 9.663139343261719, "umap_1": 7.648581504821777, "region": "UK", "recipe": "Scottish Tablet", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101615"}, {"umap_0": 2.9634034633636475, "umap_1": 9.608389854431152, "region": "Southeast Asian", "recipe": "Rumaki", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3929"}, {"umap_0": 0.2709687650203705, "umap_1": 12.72960376739502, "region": "Indian Subcontinent", "recipe": "Eggplant Bharta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67573"}, {"umap_0": 10.224851608276367, "umap_1": 9.328141212463379, "region": "Canadian", "recipe": "Nat's Peach Topping", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146305"}, {"umap_0": -1.7756894826889038, "umap_1": 9.381627082824707, "region": "Australian", "recipe": "5-Minute Low-Fat Garlic Prawns", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75100"}, {"umap_0": 1.8640124797821045, "umap_1": 4.824682235717773, "region": "Mexican", "recipe": "Texas Tortilla Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79996"}, {"umap_0": -2.374586343765259, "umap_1": 9.79255485534668, "region": "French", "recipe": "Classic Ravigote Dressing for Tossed Salads", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113239"}, {"umap_0": 10.879724502563477, "umap_1": 8.046968460083008, "region": "French", "recipe": "Amazing French Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113011"}, {"umap_0": -1.6272448301315308, "umap_1": 7.297032356262207, "region": "Spanish and Portuguese", "recipe": "Spanish Omelet With Potatoes and Chorizo", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/141445"}, {"umap_0": 7.513177871704102, "umap_1": 6.72554874420166, "region": "Italian", "recipe": "Basic Tortellini Pasta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122105"}, {"umap_0": 10.540383338928223, "umap_1": 7.636196136474609, "region": "UK", "recipe": "Perfect Lemon Curd", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/8778"}, {"umap_0": 0.3487512469291687, "umap_1": 10.458357810974121, "region": "Mexican", "recipe": "Mark's Low Fat Chicken Fajitas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/89434"}, {"umap_0": 11.746549606323242, "umap_1": 7.831028461456299, "region": "French", "recipe": "French Silk Fudge", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115854"}, {"umap_0": -0.45325809717178345, "umap_1": 8.007261276245117, "region": "Deutschland", "recipe": "Sp\u00e4tzle Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138781"}, {"umap_0": -1.7935446500778198, "umap_1": 10.381575584411621, "region": "Spanish and Portuguese", "recipe": "Shrimps Fried With Garlic", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/141178"}, {"umap_0": 11.02805233001709, "umap_1": 7.780513286590576, "region": "US", "recipe": "Quick Sticky Buns", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/14052"}, {"umap_0": -2.161686897277832, "umap_1": 10.18532943725586, "region": "Spanish and Portuguese", "recipe": "Cauliflower Al Ajoarriero - Spanish", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/141897"}, {"umap_0": -0.6048974394798279, "umap_1": 10.580102920532227, "region": "Mexican", "recipe": "Vince's Chicken Tortilla Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/88234"}, {"umap_0": 0.6900504231452942, "umap_1": 9.686701774597168, "region": "Mexican", "recipe": "Easy & Tasty Chicken Tortilla Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80075"}, {"umap_0": 0.21998491883277893, "umap_1": 8.772449493408203, "region": "Spanish and Portuguese", "recipe": "Spanish Turkey Meatballs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/140886"}, {"umap_0": -2.073589324951172, "umap_1": 8.879148483276367, "region": "Italian", "recipe": "Anchovy-Olive Pasta Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125951"}, {"umap_0": 9.847919464111328, "umap_1": 6.562987327575684, "region": "US", "recipe": "Apple Stack Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16304"}, {"umap_0": 9.165212631225586, "umap_1": 7.350872039794922, "region": "UK", "recipe": "Scottish Tablet II", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101877"}, {"umap_0": 10.443743705749512, "umap_1": 8.475082397460938, "region": "UK", "recipe": "Turkish Delight", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/8736"}, {"umap_0": 2.368593692779541, "umap_1": 9.768277168273926, "region": "Thai", "recipe": "Linda's Thai Sweet Chili Sauce for Dipping (Egg Rolls, Sushi)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/58370"}, {"umap_0": 10.211921691894531, "umap_1": 6.171392440795898, "region": "Scandinavian", "recipe": "Danish Brovst Dream Coffee Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101008"}, {"umap_0": -0.5999118685722351, "umap_1": 11.400858879089355, "region": "Caribbean", "recipe": "Jerk Marinade", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/90512"}, {"umap_0": -2.055128574371338, "umap_1": 7.81612491607666, "region": "Italian", "recipe": "Brent's Favorite Clam Linguine", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123806"}, {"umap_0": 0.3431191146373749, "umap_1": 5.240170955657959, "region": "South American", "recipe": "Beef and Macaroni Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/99207"}, {"umap_0": 0.5555034875869751, "umap_1": 9.143943786621094, "region": "Caribbean", "recipe": "Puerto Rican Macaroni Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91091"}, {"umap_0": 1.4609586000442505, "umap_1": 9.906042098999023, "region": "Deutschland", "recipe": "Vegan Octoberfest Weiners(Brats)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138985"}, {"umap_0": -0.4465193450450897, "umap_1": 8.947714805603027, "region": "US", "recipe": "Toddly Man's Big House Black-Eyed Peas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/14044"}, {"umap_0": 2.6515583992004395, "umap_1": 9.226421356201172, "region": "Chinese and Mongolian", "recipe": "Chow Yuk", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/57173"}, {"umap_0": 2.7805960178375244, "umap_1": 9.73937702178955, "region": "Thai", "recipe": "Peanut-Ginger Tofu", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/57570"}, {"umap_0": 1.560707926750183, "umap_1": 11.354384422302246, "region": "Japanese", "recipe": "Scallops with Wasabi and Ginger", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70728"}, {"umap_0": -1.5759351253509521, "umap_1": 11.272733688354492, "region": "Middle Eastern", "recipe": "Huh Huh Huh Huhmmos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/60752"}, {"umap_0": -0.34053176641464233, "umap_1": 5.331582546234131, "region": "Italian", "recipe": "Ham and Fresh Basil Pinwheels", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/12191"}, {"umap_0": 0.41087138652801514, "umap_1": 5.5249924659729, "region": "South American", "recipe": "Beef and Asparagus Rolls", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96293"}, {"umap_0": 1.48582923412323, "umap_1": 6.456732273101807, "region": "Mexican", "recipe": "Southwest Chicken Skillet", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/89464"}, {"umap_0": 0.139811173081398, "umap_1": 7.923862457275391, "region": "Spanish and Portuguese", "recipe": "Portuguese Chicken & Sausage", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/119123"}, {"umap_0": -0.508108377456665, "umap_1": 7.330385684967041, "region": "UK", "recipe": "English Garden Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/103962"}, {"umap_0": 9.731258392333984, "umap_1": 8.184741973876953, "region": "Caribbean", "recipe": "Sugar Cake (Trinidad)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91003"}, {"umap_0": -1.5692862272262573, "umap_1": 8.892705917358398, "region": "Canadian", "recipe": "Blueberry Mustard", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/149052"}, {"umap_0": -0.2067275047302246, "umap_1": 6.128017902374268, "region": "Mexican", "recipe": "Ultimate Meal Frittata", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87422"}, {"umap_0": 1.6260857582092285, "umap_1": 7.823522567749023, "region": "UK", "recipe": "Easy Shepherd's Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/104705"}, {"umap_0": 11.417586326599121, "umap_1": 8.337646484375, "region": "Australian", "recipe": "Nanaimo Bars", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77697"}, {"umap_0": 10.800504684448242, "umap_1": 9.343948364257812, "region": "Australian", "recipe": "Strawberry-Papaya Shake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74250"}, {"umap_0": 10.956401824951172, "umap_1": 6.908598899841309, "region": "Scandinavian", "recipe": "Danish Cream Cheese Wreath", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101146"}, {"umap_0": 1.3242301940917969, "umap_1": 12.063570976257324, "region": "Indian Subcontinent", "recipe": "Peanut Tikki", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/68247"}, {"umap_0": -0.25661998987197876, "umap_1": 6.924753665924072, "region": "Italian", "recipe": "Italian Fried Steak With Roasted Pepper Pesto", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/131500"}, {"umap_0": 1.110457181930542, "umap_1": 11.157255172729492, "region": "Indian Subcontinent", "recipe": "Littlemafia's Fish Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64941"}, {"umap_0": 11.470293998718262, "umap_1": 8.441516876220703, "region": "Mexican", "recipe": "Mexican Hot Fudge Sundae", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82498"}, {"umap_0": -1.3576542139053345, "umap_1": 11.660940170288086, "region": "Mexican", "recipe": "Sarah's Fresh Picante Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81688"}, {"umap_0": 10.915353775024414, "umap_1": 10.356585502624512, "region": "Australian", "recipe": "Lychee Champagne Cocktail", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73037"}, {"umap_0": 10.455739974975586, "umap_1": 8.930646896362305, "region": "UK", "recipe": "Low Fat Tropical Prawn and Carrot Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/102553"}, {"umap_0": 11.398619651794434, "umap_1": 7.977812767028809, "region": "Australian", "recipe": "Simple Vanilla Yoghurt Cream", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76844"}, {"umap_0": 0.4924359619617462, "umap_1": 5.446086883544922, "region": "South American", "recipe": "Quick Barbecue Beef Bake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/99811"}, {"umap_0": 1.6475183963775635, "umap_1": 8.434165000915527, "region": "South American", "recipe": "Slow-Roasted Beef(ATK)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/94847"}, {"umap_0": -0.15738041698932648, "umap_1": 8.916122436523438, "region": "Italian", "recipe": "Savory Italian Roast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125337"}, {"umap_0": -1.2619378566741943, "umap_1": 11.13453483581543, "region": "Middle Eastern", "recipe": "Lebanese Spiced Mushrooms", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63120"}, {"umap_0": 2.0212368965148926, "umap_1": 5.689796447753906, "region": "Mexican", "recipe": "Easy Mexican Layered Nacho Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/89868"}, {"umap_0": 1.2904988527297974, "umap_1": 5.878085613250732, "region": "Mexican", "recipe": "Creamy Green Chili, Chicken, & Corn Enchilada-Style Bake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/86697"}, {"umap_0": -0.8889918327331543, "umap_1": 5.327736854553223, "region": "Italian", "recipe": "Pasta House Pasta Con Broccoli (Actual Recipe)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120430"}, {"umap_0": 11.01464557647705, "umap_1": 6.211829662322998, "region": "UK", "recipe": "Traditional Buttermilk Cake (And Optional Frosting Recipe)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/103574"}, {"umap_0": -0.33717992901802063, "umap_1": 12.258980751037598, "region": "Indian Subcontinent", "recipe": "Indian Spiced Shrimp Wrap", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64408"}, {"umap_0": 1.343888521194458, "umap_1": 5.1833953857421875, "region": "Canadian", "recipe": "Brown Rice With Chiles for Two", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148172"}, {"umap_0": 1.3319039344787598, "umap_1": 8.557623863220215, "region": "Canadian", "recipe": "Layered Cabbage Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144599"}, {"umap_0": 2.9133336544036865, "umap_1": 9.388020515441895, "region": "Japanese", "recipe": "Asian \"Chicken\" Noodle Soup(Vegetarian)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70197"}, {"umap_0": -0.329262912273407, "umap_1": 10.784530639648438, "region": "Mexican", "recipe": "Mexican Beans-Frijoles", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/78614"}, {"umap_0": -0.19194583594799042, "umap_1": 7.180932998657227, "region": "French", "recipe": "Veal Forestier", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115404"}, {"umap_0": 9.63549518585205, "umap_1": 7.940674781799316, "region": "UK", "recipe": "Courting Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101532"}, {"umap_0": 10.337065696716309, "umap_1": 9.078323364257812, "region": "UK", "recipe": "Festive Sugar Plums - Old Fashioned Sweetmeats", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101530"}, {"umap_0": -0.7901566028594971, "umap_1": 10.480709075927734, "region": "Spanish and Portuguese", "recipe": "Cacoila (Portuguese Stewed Pork)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/119208"}, {"umap_0": 1.8778561353683472, "umap_1": 5.939470291137695, "region": "Mexican", "recipe": "Skillet Steak Fajitas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/85304"}, {"umap_0": 2.9359843730926514, "umap_1": 9.977510452270508, "region": "Chinese and Mongolian", "recipe": "Chinese Country Ribs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56381"}, {"umap_0": 1.198319673538208, "umap_1": 7.573212623596191, "region": "South American", "recipe": "Grammom's Beef Stroganoff", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/94261"}, {"umap_0": 10.64462661743164, "umap_1": 9.02371883392334, "region": "French", "recipe": "Strawberry Jam Essence De Provence", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112218"}, {"umap_0": -1.8625191450119019, "umap_1": 9.217657089233398, "region": "Italian", "recipe": "Italian Sausages With Cabbage and Onion", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125563"}, {"umap_0": 2.388711929321289, "umap_1": 10.993955612182617, "region": "Scandinavian", "recipe": "Creamy Horseradish Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/106001"}, {"umap_0": 0.7922235727310181, "umap_1": 13.021902084350586, "region": "Indian Subcontinent", "recipe": "Goan Beef Roast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/65178"}, {"umap_0": -2.024712085723877, "umap_1": 7.572224140167236, "region": "Greek", "recipe": "Greek Goddess Wrap-Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/107704"}, {"umap_0": 3.0079281330108643, "umap_1": 9.619030952453613, "region": "Chinese and Mongolian", "recipe": "Chinese Gu Lao Rou", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/52712"}, {"umap_0": -2.506399631500244, "umap_1": 7.299046039581299, "region": "Greek", "recipe": "Ouzo Shrimp", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/108886"}, {"umap_0": 10.597884178161621, "umap_1": 5.756188869476318, "region": "Canadian", "recipe": "Black and White Cheesecake Squares: It's a Martha Good Thing!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144639"}, {"umap_0": -0.9539880752563477, "umap_1": 7.705226898193359, "region": "Italian", "recipe": "Jumbo Shrimp and Zucchini Pasta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122971"}, {"umap_0": 10.44797420501709, "umap_1": 8.318530082702637, "region": "Italian", "recipe": "Risotto Al Cioccolato (Chocolate Risotto)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/121062"}, {"umap_0": 9.988883972167969, "umap_1": 9.451470375061035, "region": "Canadian", "recipe": "Orange Beets", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145411"}, {"umap_0": -1.718770980834961, "umap_1": 9.141714096069336, "region": "French", "recipe": "Restaurant Plaisir-Sante Bouillabaisse", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115152"}, {"umap_0": 10.750125885009766, "umap_1": 6.471128940582275, "region": "UK", "recipe": "Sponge Vannilla Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/103715"}, {"umap_0": 9.887571334838867, "umap_1": 6.101161003112793, "region": "Canadian", "recipe": "Country Cookies (Oatmeal-Blueberry)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148802"}, {"umap_0": -0.44785696268081665, "umap_1": 9.105504035949707, "region": "Scandinavian", "recipe": "Danish Rollmops", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101063"}, {"umap_0": 10.67367935180664, "umap_1": 10.827676773071289, "region": "Mexican", "recipe": "Mango Margaritas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81251"}, {"umap_0": 2.5616462230682373, "umap_1": 10.654887199401855, "region": "Thai", "recipe": "Tho Ruung Pad Thai", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/59377"}, {"umap_0": 1.7911100387573242, "umap_1": 10.399070739746094, "region": "Australian", "recipe": "French Dressing", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76360"}, {"umap_0": 2.9168143272399902, "umap_1": 9.998456954956055, "region": "Thai", "recipe": "Sweet Chili Chicken With Asian Vegetable Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/58869"}, {"umap_0": 0.14831365644931793, "umap_1": 11.140542984008789, "region": "Middle Eastern", "recipe": "Spicy Chicken Breasts With Tahini-Yogurt Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61977"}, {"umap_0": -0.19852854311466217, "umap_1": 11.588016510009766, "region": "Northern Africa", "recipe": "Moroccan Chicken Thighs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/50532"}, {"umap_0": 0.33052781224250793, "umap_1": 9.658503532409668, "region": "French", "recipe": "Oven Fried Chicken and French Fries", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/117202"}, {"umap_0": -0.28073740005493164, "umap_1": 11.500073432922363, "region": "Northern Africa", "recipe": "Moroccan-Spiced Crab Cakes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/50157"}, {"umap_0": -1.7667112350463867, "umap_1": 9.53663444519043, "region": "Italian", "recipe": "Fried Tomato, Onion, and Mushroom Ragout", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/10709"}, {"umap_0": -1.4612549543380737, "umap_1": 11.424036026000977, "region": "Middle Eastern", "recipe": "Claudia Roden's Hummus Bi Tahina (Chickpea and Sesame Dip)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63247"}, {"umap_0": 1.5612090826034546, "umap_1": 7.46037483215332, "region": "Scandinavian", "recipe": "Viking Meatball on a Stick - Copycat", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/107215"}, {"umap_0": -1.7705425024032593, "umap_1": 7.683483600616455, "region": "Italian", "recipe": "Sausage, Zucchini, Spinach and Tomato Pasta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/128289"}, {"umap_0": 10.590760231018066, "umap_1": 6.590651988983154, "region": "Rest Africa", "recipe": "South African Melktert or Milk Tart (Custard Pie)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48897"}, {"umap_0": 0.8370258212089539, "umap_1": 6.745672702789307, "region": "South American", "recipe": "Brazilian Corn and Shrimp Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/93479"}, {"umap_0": 10.38011360168457, "umap_1": 7.146824836730957, "region": "French", "recipe": "Bittersweet Chocolate Truffles Rolled in Spices", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112880"}, {"umap_0": 10.54295825958252, "umap_1": 9.112892150878906, "region": "Canadian", "recipe": "Snow Covered Apples", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/149151"}, {"umap_0": 11.463234901428223, "umap_1": 7.6804304122924805, "region": "Mexican", "recipe": "Sopapilla Cheesecake Dessert", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6263"}, {"umap_0": 0.7639448642730713, "umap_1": 12.973309516906738, "region": "Indian Subcontinent", "recipe": "Chaat Masala", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/72309"}, {"umap_0": -0.8754989504814148, "umap_1": 7.376551628112793, "region": "Scandinavian", "recipe": "Elisabeth's Garlic Dressing", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/140058"}, {"umap_0": 10.680970191955566, "umap_1": 6.97568941116333, "region": "UK", "recipe": "Traditional Bakewell Tart", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/8976"}, {"umap_0": 0.49108174443244934, "umap_1": 5.727354049682617, "region": "Canadian", "recipe": "Yummy Baked Potato Recipe", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142690"}, {"umap_0": 0.5761415362358093, "umap_1": 8.276139259338379, "region": "South American", "recipe": "Tender Brandied Beef", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/95496"}, {"umap_0": 0.8719810843467712, "umap_1": 7.818314075469971, "region": "Canadian", "recipe": "Meatballs Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148217"}, {"umap_0": 10.302268028259277, "umap_1": 8.12131118774414, "region": "Japanese", "recipe": "Green Tea Mousse", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70456"}, {"umap_0": 0.2910577058792114, "umap_1": 7.4747114181518555, "region": "Deutschland", "recipe": "Midwestern German Meatloaf", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138691"}, {"umap_0": 1.6556390523910522, "umap_1": 6.171474456787109, "region": "Mexican", "recipe": "Healthy Black Bean Enchiladas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82771"}, {"umap_0": -1.6506705284118652, "umap_1": 9.32905387878418, "region": "Italian", "recipe": "Italian Pepper Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120466"}, {"umap_0": -1.331217885017395, "umap_1": 11.124466896057129, "region": "Spanish and Portuguese", "recipe": "Saffron Butter", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/140316"}, {"umap_0": 0.39597684144973755, "umap_1": 10.759122848510742, "region": "Mexican", "recipe": "Crispy Slow Cooker Carnitas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82909"}, {"umap_0": 0.8575361371040344, "umap_1": 9.894878387451172, "region": "Indian Subcontinent", "recipe": "Tigua Indian Definitive Bowl of Red", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69042"}, {"umap_0": -2.281219959259033, "umap_1": 9.666858673095703, "region": "French", "recipe": "Classic French Potato Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/116490"}, {"umap_0": 11.849913597106934, "umap_1": 8.119468688964844, "region": "Canadian", "recipe": "Oreo Cookie Drops", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144981"}, {"umap_0": -0.9227136373519897, "umap_1": 7.5815348625183105, "region": "Caribbean", "recipe": "Crabmeat St. Barts", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91351"}, {"umap_0": 9.55331802368164, "umap_1": 9.761798858642578, "region": "Deutschland", "recipe": "Pickled Red Onions", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138042"}, {"umap_0": 0.2414015382528305, "umap_1": 10.88632583618164, "region": "Middle Eastern", "recipe": "Chicken with Bulgur", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61449"}, {"umap_0": 0.9229373335838318, "umap_1": 9.335219383239746, "region": "UK", "recipe": "Lorne Sausage", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101439"}, {"umap_0": -0.6003052592277527, "umap_1": 7.396515846252441, "region": "Caribbean", "recipe": "Ensalada De Camarones (Puerto Rican Shrimp Salad)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92180"}, {"umap_0": 2.4931068420410156, "umap_1": 8.570638656616211, "region": "Southeast Asian", "recipe": "KARI-KARE (Meat and Vegetable Stew in Peanut Sauce)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63602"}, {"umap_0": 2.6950314044952393, "umap_1": 9.49687671661377, "region": "Chinese and Mongolian", "recipe": "Pepper Steak", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53142"}, {"umap_0": 9.711673736572266, "umap_1": 7.068781852722168, "region": "Greek", "recipe": "Greek Honey Cookies (Melomakarona)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/107831"}, {"umap_0": 0.9879035353660583, "umap_1": 8.370538711547852, "region": "Australian", "recipe": "Steak Bolshio", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73170"}, {"umap_0": 2.9836626052856445, "umap_1": 8.801194190979004, "region": "Indian Subcontinent", "recipe": "Pigeon Pea Paste (Aka Arhar Dal or Toovar Dal)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67008"}, {"umap_0": -1.7543110847473145, "umap_1": 5.666971683502197, "region": "Italian", "recipe": "Italian Zucchini Skillet", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125406"}, {"umap_0": -0.6595043540000916, "umap_1": 11.750669479370117, "region": "Middle Eastern", "recipe": "Pistachio Quinoa Pilaf With Harissa", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61588"}, {"umap_0": 8.21139144897461, "umap_1": 6.102329254150391, "region": "Canadian", "recipe": "Pastry With No Trans Fat", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147422"}, {"umap_0": 1.2604190111160278, "umap_1": 12.577383041381836, "region": "Indian Subcontinent", "recipe": "Dal Maharani (The Queen of Indian Lentils!)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64178"}, {"umap_0": -0.9993788599967957, "umap_1": 8.276711463928223, "region": "Australian", "recipe": "Roast Potato Tortilla", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74008"}, {"umap_0": 9.758047103881836, "umap_1": 6.126584529876709, "region": "UK", "recipe": "Cornish Caramel Pudding", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/102915"}, {"umap_0": 0.9219141006469727, "umap_1": 8.323060035705566, "region": "Caribbean", "recipe": "Cuban-Greek Chicken and Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92689"}, {"umap_0": 9.570618629455566, "umap_1": 9.572281837463379, "region": "Mexican", "recipe": "Margaritas to Die For", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6604"}, {"umap_0": -2.5713889598846436, "umap_1": 8.20828914642334, "region": "Greek", "recipe": "Spiced Cheese Spread - (Tirokafteri)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110817"}, {"umap_0": -0.10510776191949844, "umap_1": 10.881714820861816, "region": "Canadian", "recipe": "Southern Style Greens", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148372"}, {"umap_0": 7.527230739593506, "umap_1": 6.731996059417725, "region": "Canadian", "recipe": "Sunny's Pizza Dough", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144229"}, {"umap_0": -0.736492395401001, "umap_1": 7.209438800811768, "region": "Italian", "recipe": "Risotto with Chicken and Asparagus", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/11636"}, {"umap_0": 1.2257952690124512, "umap_1": 5.957526206970215, "region": "Mexican", "recipe": "Bite-Size Taco Turnovers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84583"}, {"umap_0": 2.9348320960998535, "umap_1": 10.314735412597656, "region": "Thai", "recipe": "Thai Wonton Tacos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/59127"}, {"umap_0": 0.8653531074523926, "umap_1": 12.906578063964844, "region": "Indian Subcontinent", "recipe": "Best Potatoes Ever!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4454"}, {"umap_0": -1.2849581241607666, "umap_1": 8.195091247558594, "region": "Mexican", "recipe": "Anne's Calabacitas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6228"}, {"umap_0": 1.0773259401321411, "umap_1": 12.934423446655273, "region": "Indian Subcontinent", "recipe": "Baingan Ka Bharta (Indian-Punjabi Style)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67074"}, {"umap_0": 10.528319358825684, "umap_1": 8.996499061584473, "region": "Rest Africa", "recipe": "Banana Soup!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47881"}, {"umap_0": -0.8595709800720215, "umap_1": 11.71829891204834, "region": "Mexican", "recipe": "Smoky, Spicy Tomatillo Salsa Verde Aka Green Hell!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/85722"}, {"umap_0": 0.9189432263374329, "umap_1": 12.381942749023438, "region": "Indian Subcontinent", "recipe": "Veggie Delite Masala Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64750"}, {"umap_0": -1.2338111400604248, "umap_1": 5.3467559814453125, "region": "Greek", "recipe": "Spinach & Feta Baked 'Omelette'", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110374"}, {"umap_0": 1.4835739135742188, "umap_1": 12.297212600708008, "region": "Indian Subcontinent", "recipe": "Pilaf-Style Basmati Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63801"}, {"umap_0": 11.293014526367188, "umap_1": 8.827263832092285, "region": "Canadian", "recipe": "Sauteed Peaches with Vanilla Ice Cream", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147888"}, {"umap_0": 0.063170425593853, "umap_1": 11.672297477722168, "region": "Northern Africa", "recipe": "Eggplant (Aubergine) Tagine - Low Fat", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/50284"}, {"umap_0": 0.11022394150495529, "umap_1": 7.659482955932617, "region": "Canadian", "recipe": "Venison Chops With Mushroom Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145179"}, {"umap_0": -0.1398801952600479, "umap_1": 10.03643798828125, "region": "Mexican", "recipe": "Chicken Fajitas With Grilled Peppers and Onions", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/89478"}, {"umap_0": 2.0507731437683105, "umap_1": 11.173535346984863, "region": "Indian Subcontinent", "recipe": "Green Fish", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/72236"}, {"umap_0": 11.396681785583496, "umap_1": 10.151305198669434, "region": "Rest Africa", "recipe": "Slippery Nipple", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/51189"}, {"umap_0": -2.499584674835205, "umap_1": 7.4646430015563965, "region": "Greek", "recipe": "Crunchy Feta & Tomato Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110859"}, {"umap_0": -1.273516058921814, "umap_1": 6.4045233726501465, "region": "Italian", "recipe": "Dom's Linguine With Mushrooms & Peas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123886"}, {"umap_0": 9.12509822845459, "umap_1": 8.28995132446289, "region": "Thai", "recipe": "Quick Thai Tea For Two", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/58553"}, {"umap_0": 3.5569608211517334, "umap_1": 9.750225067138672, "region": "Chinese and Mongolian", "recipe": "Spicy Chinese Stir Fry Beef", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55307"}, {"umap_0": -1.1379667520523071, "umap_1": 7.447230815887451, "region": "Italian", "recipe": "Italian Chicken, Potatoes, and Squash Bake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120246"}, {"umap_0": 3.3748135566711426, "umap_1": 10.229393005371094, "region": "Chinese and Mongolian", "recipe": "Spicy Eggplant and Green Bean Stir Fry", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/52254"}, {"umap_0": 7.55553674697876, "umap_1": 6.746270656585693, "region": "Italian", "recipe": "THE Easiest Pizza Crust", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/129779"}, {"umap_0": 10.856467247009277, "umap_1": 7.206081867218018, "region": "Deutschland", "recipe": "German Baked Cheesecake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138267"}, {"umap_0": -1.17917799949646, "umap_1": 11.33971881866455, "region": "Northern Africa", "recipe": "Swordfish With Chermoula", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/50217"}, {"umap_0": 10.25863265991211, "umap_1": 7.950075149536133, "region": "Mexican", "recipe": "Margarita Mix", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80427"}, {"umap_0": 0.7936912178993225, "umap_1": 5.736952304840088, "region": "Indian Subcontinent", "recipe": "Mint and Cottage Cheese Samosas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/72110"}, {"umap_0": 0.012634641490876675, "umap_1": 8.352033615112305, "region": "Eastern European", "recipe": "Studzienina - Polish Head Cheese", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/133689"}, {"umap_0": -0.5981330275535583, "umap_1": 10.241686820983887, "region": "Mexican", "recipe": "Mexican Avocado and Hearts of Palm Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84875"}, {"umap_0": 9.99521541595459, "umap_1": 7.086462020874023, "region": "Caribbean", "recipe": "Jamaican Easter Bun", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92052"}, {"umap_0": 10.75131607055664, "umap_1": 10.151999473571777, "region": "Australian", "recipe": "Passion Fruit and Lychee Martini", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74195"}, {"umap_0": 0.18940070271492004, "umap_1": 5.097394943237305, "region": "Deutschland", "recipe": "Swiss and Ham Quiche", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/117435"}, {"umap_0": 11.024012565612793, "umap_1": 6.953031063079834, "region": "Canadian", "recipe": "Chocolate Butterscotch Ripple Squares", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145352"}, {"umap_0": 4.343148708343506, "umap_1": 9.620804786682129, "region": "Japanese", "recipe": "Godzilla Roll - Sushi", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/71954"}, {"umap_0": 0.998953640460968, "umap_1": 11.832167625427246, "region": "Indian Subcontinent", "recipe": "Tandoori Chicken Burgers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4119"}, {"umap_0": 3.1372594833374023, "umap_1": 9.517512321472168, "region": "Chinese and Mongolian", "recipe": "Moo Goo Gai Pan", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55899"}, {"umap_0": 2.5337212085723877, "umap_1": 9.578829765319824, "region": "Chinese and Mongolian", "recipe": "Foil-Wrapped Ginger Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56223"}, {"umap_0": 1.7920453548431396, "umap_1": 4.7065324783325195, "region": "Mexican", "recipe": "Ole' Chicken Enchilada Lovers Casserole ( Ww )", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/88902"}, {"umap_0": -1.2037229537963867, "umap_1": 4.891397953033447, "region": "Italian", "recipe": "Italian Parmesan Baked Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/133203"}, {"umap_0": 1.9315327405929565, "umap_1": 10.988516807556152, "region": "Southeast Asian", "recipe": "Dipping Sauce With Ginger (Nuoc Cham Gung)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/62463"}, {"umap_0": 1.1667430400848389, "umap_1": 7.870398044586182, "region": "UK", "recipe": "All Day Beef Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/102109"}, {"umap_0": 8.996176719665527, "umap_1": 7.8659186363220215, "region": "Indian Subcontinent", "recipe": "Besan Laddu", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4138"}, {"umap_0": -1.598083734512329, "umap_1": 6.080306053161621, "region": "Italian", "recipe": "Italian Savory Torte", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/133012"}, {"umap_0": -1.3958945274353027, "umap_1": 7.6432061195373535, "region": "Italian", "recipe": "Orzo With Lemon, Garlic, Parmigiano & Herbs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120145"}, {"umap_0": 3.0398051738739014, "umap_1": 10.739788055419922, "region": "Thai", "recipe": "Thai Chili Sauce Salmon", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/58266"}, {"umap_0": 1.2017189264297485, "umap_1": 6.279118061065674, "region": "South American", "recipe": "Cheesy Nacho's With Spicy Beef", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/97679"}, {"umap_0": 11.094701766967773, "umap_1": 8.38327407836914, "region": "Eastern European", "recipe": "Nesselrode Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100726"}, {"umap_0": -1.795520544052124, "umap_1": 6.056402683258057, "region": "Italian", "recipe": "Delicious and Simple Ricotta and Tomato Pasta Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/126934"}, {"umap_0": 10.636688232421875, "umap_1": 10.265210151672363, "region": "Australian", "recipe": "Mango Sorbet", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/5553"}, {"umap_0": 10.745750427246094, "umap_1": 7.198062419891357, "region": "French", "recipe": "Coconut French Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115081"}, {"umap_0": 8.843927383422852, "umap_1": 7.3433756828308105, "region": "Indian Subcontinent", "recipe": "How to Make 'tofu' - a Simple Homemade Recipe!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/68688"}, {"umap_0": 0.6295729279518127, "umap_1": 6.880488872528076, "region": "UK", "recipe": "Creamed SweetBreads", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/102836"}, {"umap_0": -2.3599414825439453, "umap_1": 8.011959075927734, "region": "Italian", "recipe": "Rigatoni With Red Pepper, Almonds and Bread Crumbs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125060"}, {"umap_0": -0.7407087683677673, "umap_1": 11.649407386779785, "region": "Rest Africa", "recipe": "Kenya Fish Baked With Tomatoes and Spices (Mtuzi Wa Samaki)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48668"}, {"umap_0": 10.723774909973145, "umap_1": 8.147116661071777, "region": "Caribbean", "recipe": "Mango Coconut Bread Pudding With Rum Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91904"}, {"umap_0": 0.31455355882644653, "umap_1": 5.593790531158447, "region": "South American", "recipe": "Horseradish Beef Strudel", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/98011"}, {"umap_0": -1.9179109334945679, "umap_1": 10.400378227233887, "region": "Middle Eastern", "recipe": "Dead Sea Babaganoush", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63220"}, {"umap_0": 3.466909885406494, "umap_1": 7.669651508331299, "region": "Mexican", "recipe": "Mexican Taquitos (Tuna)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79884"}, {"umap_0": 9.628279685974121, "umap_1": 8.461490631103516, "region": "Northern Africa", "recipe": "Mhalbi", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/50972"}, {"umap_0": 0.8521121144294739, "umap_1": 12.55677318572998, "region": "Indian Subcontinent", "recipe": "Indian Spiced Sweet Potato Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/68067"}, {"umap_0": 10.216424942016602, "umap_1": 5.989542484283447, "region": "Australian", "recipe": "Banana Slice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74703"}, {"umap_0": 2.761542797088623, "umap_1": 10.280957221984863, "region": "Thai", "recipe": "Amanda's Thai Peanut", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/58165"}, {"umap_0": 9.377599716186523, "umap_1": 7.761491298675537, "region": "Belgian", "recipe": "Appelflappen", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134008"}, {"umap_0": 11.440287590026855, "umap_1": 8.94237995147705, "region": "Irish", "recipe": "Cool Whip Jello", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/136515"}, {"umap_0": 11.266894340515137, "umap_1": 7.430263042449951, "region": "French", "recipe": "Streusel Topped French Toast Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114049"}, {"umap_0": -0.9124829173088074, "umap_1": 4.1500468254089355, "region": "Italian", "recipe": "Kat's Slow-Cooker Lasagna", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125045"}, {"umap_0": -0.5463264584541321, "umap_1": 10.847198486328125, "region": "Caribbean", "recipe": "Grilled Chicken and Plantains, Jamaican-Style", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91854"}, {"umap_0": 2.5161972045898438, "umap_1": 9.62346363067627, "region": "Indian Subcontinent", "recipe": "Chicken Broccoli", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/66718"}, {"umap_0": 0.3292330205440521, "umap_1": 10.66638469696045, "region": "Mexican", "recipe": "South Mexican Frijoles De Olla", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77808"}, {"umap_0": 0.8273971080780029, "umap_1": 7.926181316375732, "region": "Deutschland", "recipe": "Gypsy Schnitzel", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137117"}, {"umap_0": 0.7331476211547852, "umap_1": 4.986757278442383, "region": "Eastern European", "recipe": "Ham and Au Gratin Potatoes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/133873"}, {"umap_0": 9.699238777160645, "umap_1": 7.069442272186279, "region": "UK", "recipe": "Cranberry-Raisin Scones", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/103827"}, {"umap_0": 0.4987710416316986, "umap_1": 11.757622718811035, "region": "Australian", "recipe": "Kumera and Tuna Patties", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73908"}, {"umap_0": 0.42196187376976013, "umap_1": 10.087667465209961, "region": "Mexican", "recipe": "My Turkey Tortilla Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82631"}, {"umap_0": 11.472017288208008, "umap_1": 7.991462230682373, "region": "Australian", "recipe": "Chocolate and Ginger Tart", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73055"}, {"umap_0": -0.32733985781669617, "umap_1": 10.939979553222656, "region": "Mexican", "recipe": "Guacamole Cheese Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79129"}, {"umap_0": 10.394046783447266, "umap_1": 9.020578384399414, "region": "Canadian", "recipe": "Cranberry Orange and Honey Spread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/143435"}, {"umap_0": -1.6260554790496826, "umap_1": 7.08851432800293, "region": "Greek", "recipe": "BBQ Chicken With Greek Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/109161"}, {"umap_0": -0.000515283492859453, "umap_1": 12.56138801574707, "region": "Mexican", "recipe": "Fajita Steak Marinade", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84756"}, {"umap_0": -1.5862261056900024, "umap_1": 6.036340236663818, "region": "Italian", "recipe": "Italian Kale With Turkey Sausage and Penne", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130344"}, {"umap_0": 0.7508050203323364, "umap_1": 13.062902450561523, "region": "Indian Subcontinent", "recipe": "Chole Masala", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64892"}, {"umap_0": 2.606248617172241, "umap_1": 9.582758903503418, "region": "South American", "recipe": "Noodles With Honey-Balsamic Beef", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/94230"}, {"umap_0": 9.924560546875, "umap_1": 6.115597248077393, "region": "Rest Africa", "recipe": "Malva Pudding - Family's Favorite =p", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/51232"}, {"umap_0": 7.564727783203125, "umap_1": 6.725115776062012, "region": "South American", "recipe": "Pizza", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/93201"}, {"umap_0": -0.8886260390281677, "umap_1": 4.601931095123291, "region": "Italian", "recipe": "Crock Pot Fondue Italiano", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132796"}, {"umap_0": -0.3406410217285156, "umap_1": 11.568140983581543, "region": "Middle Eastern", "recipe": "Fooll Mudammes (Fava Bean Egyptian Breakfast)(\u0641\u0648\u0644 \u0645\u062f\u0645\u0633)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47273"}, {"umap_0": -0.9585955739021301, "umap_1": 9.413331985473633, "region": "Northern Africa", "recipe": "Moroccan Red Gazpacho", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/50366"}, {"umap_0": -1.5916132926940918, "umap_1": 9.849132537841797, "region": "Greek", "recipe": "Alternative Greek Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/107630"}, {"umap_0": -0.9777724742889404, "umap_1": 8.05307388305664, "region": "Italian", "recipe": "Risotto With Chicken and Caramelized Onions", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122922"}, {"umap_0": -0.07009800523519516, "umap_1": 4.914054870605469, "region": "Scandinavian", "recipe": "Cream Cheese and Salmon Smorrebrod", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/139892"}, {"umap_0": 2.257594347000122, "umap_1": 8.318817138671875, "region": "Rest Africa", "recipe": "South African Chicken - Inyama Yenkukhu", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/51251"}, {"umap_0": -1.3626586198806763, "umap_1": 7.3130784034729, "region": "Italian", "recipe": "Paul's Italian-Style Meatloaf", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122340"}, {"umap_0": 2.269575834274292, "umap_1": 7.972594738006592, "region": "French", "recipe": "Baked French Fries", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/111590"}, {"umap_0": 3.0306313037872314, "umap_1": 10.520716667175293, "region": "Chinese and Mongolian", "recipe": "P F Chang's Sichuan-Style Asparagus", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55447"}, {"umap_0": 1.5169289112091064, "umap_1": 9.936500549316406, "region": "Northern Africa", "recipe": "Exotic and Sweet Moroccan Chicken with Spicy Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/50955"}, {"umap_0": -0.9425987005233765, "umap_1": 10.629751205444336, "region": "Mexican", "recipe": "A+ Sweet & Savory Plantains (Or Banana) Appetizers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/85588"}, {"umap_0": -2.378746509552002, "umap_1": 7.114105224609375, "region": "Greek", "recipe": "Orzo Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110909"}, {"umap_0": -1.2278001308441162, "umap_1": 7.524376392364502, "region": "Italian", "recipe": "Plum Tomatoes and Artichokes With Penne", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/128086"}, {"umap_0": 3.5802395343780518, "umap_1": 9.519756317138672, "region": "Chinese and Mongolian", "recipe": "Stir-Fried Prawns with Noodles", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56583"}, {"umap_0": -0.5673277378082275, "umap_1": 9.488524436950684, "region": "Greek", "recipe": "Vegetable Orzo with Lemon & Herb Seasoning", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/108743"}, {"umap_0": 11.21760368347168, "umap_1": 7.592402935028076, "region": "Middle Eastern", "recipe": "Date Brownies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3490"}, {"umap_0": -1.5351697206497192, "umap_1": 9.6422758102417, "region": "Middle Eastern", "recipe": "Tabbouleh", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3518"}, {"umap_0": 0.2601361870765686, "umap_1": 8.095123291015625, "region": "Canadian", "recipe": "The Best Pork Chop Dinner - EVER!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142781"}, {"umap_0": 1.6744741201400757, "umap_1": 5.47749137878418, "region": "Mexican", "recipe": "Zesty Dip for Chips", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/7861"}, {"umap_0": 0.798533022403717, "umap_1": 8.00855541229248, "region": "Australian", "recipe": "Jennifer's Shepherd's Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74429"}, {"umap_0": -1.5483787059783936, "umap_1": 10.348699569702148, "region": "Spanish and Portuguese", "recipe": "Pollo en Mojo (well sort of)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/141287"}, {"umap_0": -1.224749207496643, "umap_1": 11.068684577941895, "region": "Mexican", "recipe": "Mexican Ceviche", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/78509"}, {"umap_0": 0.38385018706321716, "umap_1": 5.342156887054443, "region": "Canadian", "recipe": "Bacon and Egg Sandwich", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148197"}, {"umap_0": -1.0520628690719604, "umap_1": 10.406288146972656, "region": "Mexican", "recipe": "Guacamole Salad (Barefoot Contessa) Ina Garten", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82485"}, {"umap_0": 1.46034574508667, "umap_1": 9.320054054260254, "region": "Belgian", "recipe": "Pennsylvania Dutch Home Baked Beans", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134377"}, {"umap_0": 11.760978698730469, "umap_1": 7.804986953735352, "region": "Southeast Asian", "recipe": "Heavenly Chocomallows", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63587"}, {"umap_0": 3.2780463695526123, "umap_1": 9.204833030700684, "region": "Japanese", "recipe": "Shiitake Dashi", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70633"}, {"umap_0": -0.0033222923520952463, "umap_1": 10.11827278137207, "region": "US", "recipe": "Creamy Cilantro Salad Dressing", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/18041"}, {"umap_0": 1.1248903274536133, "umap_1": 9.54050064086914, "region": "Indian Subcontinent", "recipe": "Crazy Spicy Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4024"}, {"umap_0": 3.1560261249542236, "umap_1": 8.235814094543457, "region": "Chinese and Mongolian", "recipe": "Chow Mein Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55472"}, {"umap_0": -1.2940279245376587, "umap_1": 5.540240287780762, "region": "French", "recipe": "Baked Escargot in Mushroom Caps", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115033"}, {"umap_0": 3.2141611576080322, "umap_1": 10.50078010559082, "region": "Japanese", "recipe": "Bang Bang Shrimp", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70857"}, {"umap_0": -0.5370005369186401, "umap_1": 7.8642449378967285, "region": "French", "recipe": "Provencal Roast Lamb Stuffed With Figs, Goat's Cheese and Walnut", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112877"}, {"umap_0": 0.5719629526138306, "umap_1": 4.872244834899902, "region": "Chinese and Mongolian", "recipe": "Broccoli Casserole and Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53432"}, {"umap_0": 10.1602783203125, "umap_1": 6.847714900970459, "region": "Scandinavian", "recipe": "Cognac\u00e6bleskiver - Danish - Cognac Apple Fritters", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100933"}, {"umap_0": 1.0897228717803955, "umap_1": 6.974140167236328, "region": "Canadian", "recipe": "Creamy Lemon Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145347"}, {"umap_0": 0.6935108304023743, "umap_1": 8.633729934692383, "region": "South American", "recipe": "Kickin Vegetable Beef Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/98996"}, {"umap_0": 1.4681605100631714, "umap_1": 10.89324951171875, "region": "Middle Eastern", "recipe": "Saffron Couscous With Herbs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61577"}, {"umap_0": 9.679351806640625, "umap_1": 7.064289093017578, "region": "Belgian", "recipe": "Dutch Baby With Cranberry Orange Syrup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134415"}, {"umap_0": 0.4579998552799225, "umap_1": 5.721771240234375, "region": "Eastern European", "recipe": "Hungarian Noodle Side Dish", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/9061"}, {"umap_0": 0.6859077215194702, "umap_1": 4.895043849945068, "region": "South American", "recipe": "Rancher Beef Pita", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96889"}, {"umap_0": 9.46788215637207, "umap_1": 8.70071792602539, "region": "Mexican", "recipe": "How to Make Dulce de Leche", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6487"}, {"umap_0": 0.5781883597373962, "umap_1": 12.659963607788086, "region": "Indian Subcontinent", "recipe": "Cumin Scented Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/65315"}, {"umap_0": 11.278326034545898, "umap_1": 8.992044448852539, "region": "Irish", "recipe": "Irish Coffee from the Buena Vista San Francisco", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/136130"}, {"umap_0": 1.748248815536499, "umap_1": 6.023683071136475, "region": "Mexican", "recipe": "Shredded Chicken Tacos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/85050"}, {"umap_0": 11.584966659545898, "umap_1": 8.026214599609375, "region": "Italian", "recipe": "Gingerbread Latte", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130130"}, {"umap_0": 3.024116039276123, "umap_1": 9.615269660949707, "region": "Japanese", "recipe": "Miso Salmon Spaghetti", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/71938"}, {"umap_0": 2.7208845615386963, "umap_1": 10.148514747619629, "region": "Southeast Asian", "recipe": "Chicken in Lemongrass (Ga Xao Xa Ot)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/62435"}, {"umap_0": 2.4865505695343018, "umap_1": 8.89186954498291, "region": "Mexican", "recipe": "Easy Pototo Taquitos #5FIX", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80253"}, {"umap_0": 1.5574126243591309, "umap_1": 5.279350280761719, "region": "Mexican", "recipe": "Chicken Frito Enchiladas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/89212"}, {"umap_0": -1.0496069192886353, "umap_1": 6.808690547943115, "region": "Italian", "recipe": "Olive Garden Chicken Caprese", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/127473"}, {"umap_0": 1.634734034538269, "umap_1": 5.269521236419678, "region": "Mexican", "recipe": "Quesadilla Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81330"}, {"umap_0": -0.7381545305252075, "umap_1": 10.405523300170898, "region": "South American", "recipe": "Braised Beef and Onions", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/97146"}, {"umap_0": 11.534550666809082, "umap_1": 8.163215637207031, "region": "Deutschland", "recipe": "Upside-Down German Snack Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138452"}, {"umap_0": 0.3418410122394562, "umap_1": 7.589414119720459, "region": "Italian", "recipe": "Lazy Chicken Marsala", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125555"}, {"umap_0": 10.810623168945312, "umap_1": 9.988347053527832, "region": "Australian", "recipe": "Flying Kangaroo", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75647"}, {"umap_0": -0.06423194706439972, "umap_1": 8.653255462646484, "region": "Chinese and Mongolian", "recipe": "Slow-Cooked Harvest Vegetable and Rice Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/54143"}, {"umap_0": 2.9338090419769287, "umap_1": 9.77122688293457, "region": "Chinese and Mongolian", "recipe": "Crock Pot Oriental Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/52411"}, {"umap_0": 3.107837438583374, "umap_1": 9.255471229553223, "region": "Australian", "recipe": "Hot Potato Cakes With a Twist, and Fresh Tomato Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75079"}, {"umap_0": 0.19716471433639526, "umap_1": 11.994739532470703, "region": "Mexican", "recipe": "Hot Mexican Rub", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/86791"}, {"umap_0": 1.7486412525177002, "umap_1": 4.5669097900390625, "region": "South American", "recipe": "Cheesy Beef Noodles", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/98343"}, {"umap_0": -0.9900819063186646, "umap_1": 9.14884090423584, "region": "Caribbean", "recipe": "Low Fat Red Beans and Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/90654"}, {"umap_0": -1.199900507926941, "umap_1": 6.398742198944092, "region": "Italian", "recipe": "Italian Sausage and Spinach Quiche", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/127062"}, {"umap_0": 0.9132679104804993, "umap_1": 7.430976867675781, "region": "UK", "recipe": "English Sausage and Bean Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/104326"}, {"umap_0": -2.333700656890869, "umap_1": 6.373197078704834, "region": "Italian", "recipe": "Eggplant Pizza", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122171"}, {"umap_0": 1.5788544416427612, "umap_1": 7.845282554626465, "region": "Canadian", "recipe": "Tender and Tasty Roast Beef", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147232"}, {"umap_0": -0.7495318055152893, "umap_1": 5.995314598083496, "region": "Greek", "recipe": "Tomato-Feta-Greek Yogurt Phyllo Tart", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110319"}, {"umap_0": -0.5220938920974731, "umap_1": 5.3779377937316895, "region": "French", "recipe": "Brie and Red Currant Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112235"}, {"umap_0": -1.7691675424575806, "umap_1": 8.310100555419922, "region": "Australian", "recipe": "Pea, Feta and Mint Salad With Pistachios", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77192"}, {"umap_0": 2.1125428676605225, "umap_1": 6.313201427459717, "region": "Mexican", "recipe": "Tacos De Pollo", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/85813"}, {"umap_0": 1.1592556238174438, "umap_1": 9.418966293334961, "region": "Indian Subcontinent", "recipe": "Steve's Chicken Korma", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4128"}, {"umap_0": -1.6128437519073486, "umap_1": 9.288741111755371, "region": "Greek", "recipe": "Baked Cod with Greek Potatoes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/109566"}, {"umap_0": 3.8773720264434814, "umap_1": 9.406545639038086, "region": "Japanese", "recipe": "Japanese Scrambled Eggs with Pacific Saury", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/5071"}, {"umap_0": 3.343989372253418, "umap_1": 10.000374794006348, "region": "Chinese and Mongolian", "recipe": "Shun Lee's Szechuan Shrimp", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55363"}, {"umap_0": 1.3290810585021973, "umap_1": 6.70897912979126, "region": "Chinese and Mongolian", "recipe": "Chinese Curried Shrimp and Peas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/57082"}, {"umap_0": 0.2156497687101364, "umap_1": 12.363967895507812, "region": "Mexican", "recipe": "Super Fajita Marinade", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6160"}, {"umap_0": -0.010571273043751717, "umap_1": 7.808695316314697, "region": "Italian", "recipe": "Roasted Chicken With Lemons and Thyme", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125379"}, {"umap_0": 9.607107162475586, "umap_1": 7.821794509887695, "region": "Spanish and Portuguese", "recipe": "Aunt Fanny's Portuguese Rice Pudding", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118895"}, {"umap_0": 0.20657289028167725, "umap_1": 4.87691593170166, "region": "Irish", "recipe": "Shamrock Corned Beef Reuben Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/136315"}, {"umap_0": -0.4607025980949402, "umap_1": 11.211666107177734, "region": "Mexican", "recipe": "Mexicali Pork Chops", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80759"}, {"umap_0": -1.1594617366790771, "umap_1": 4.619128227233887, "region": "Italian", "recipe": "Sausage and Spinach Tortellini Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/128055"}, {"umap_0": 1.0305882692337036, "umap_1": 11.929807662963867, "region": "Middle Eastern", "recipe": "Stuffed Beets", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/72502"}, {"umap_0": 0.053588833659887314, "umap_1": 7.157907485961914, "region": "Irish", "recipe": "Irish Pub Soup (From 365 Easy One Dish Meals)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/136491"}, {"umap_0": 10.691167831420898, "umap_1": 6.999594688415527, "region": "Australian", "recipe": "Oven Caramel Corn", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77246"}, {"umap_0": 0.8105179071426392, "umap_1": 12.083481788635254, "region": "Indian Subcontinent", "recipe": "Coconut Butter Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67996"}, {"umap_0": 11.624321937561035, "umap_1": 8.709522247314453, "region": "Italian", "recipe": "Tiramisu (An Italian Delight!)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120662"}, {"umap_0": -1.0343867540359497, "umap_1": 9.783365249633789, "region": "Italian", "recipe": "Savory Green Beans", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/10310"}, {"umap_0": -1.4338454008102417, "umap_1": 5.912444114685059, "region": "Italian", "recipe": "Tuscan Bean, Chicken, and Italian Sausage Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/10233"}, {"umap_0": -0.9197416305541992, "umap_1": 6.257259845733643, "region": "Italian", "recipe": "Kim's Italian Meatballs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/121882"}, {"umap_0": 8.84247875213623, "umap_1": 7.164631366729736, "region": "Eastern European", "recipe": "Hungarian Poppy Seed Roll (Beigli)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105710"}, {"umap_0": 1.770277738571167, "umap_1": 11.02878189086914, "region": "Southeast Asian", "recipe": "Vietnamese Lettuce Rolls With Spicy Grilled Tofu", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/62082"}, {"umap_0": 10.831842422485352, "umap_1": 7.926901817321777, "region": "French", "recipe": "Walnut Raisin French Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113115"}, {"umap_0": 1.2650885581970215, "umap_1": 4.821526050567627, "region": "Mexican", "recipe": "Texas Taco Burgers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79787"}, {"umap_0": -0.12227872759103775, "umap_1": 10.868971824645996, "region": "South American", "recipe": "Peruvian Ceviche With Pickled Red Onions", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/93916"}, {"umap_0": 9.949121475219727, "umap_1": 6.6415534019470215, "region": "UK", "recipe": "Cranberry Pudding", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/8998"}, {"umap_0": -0.10735031217336655, "umap_1": 10.361869812011719, "region": "Mexican", "recipe": "Camarones Con Frijole Sopa", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/85277"}, {"umap_0": 9.936429023742676, "umap_1": 9.555929183959961, "region": "Italian", "recipe": "Iced Espresso Marvo", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130186"}, {"umap_0": -2.101750373840332, "umap_1": 9.796384811401367, "region": "Mexican", "recipe": "Jicama Salad (Mexico)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79600"}, {"umap_0": 1.458834171295166, "umap_1": 9.37569522857666, "region": "South American", "recipe": "Best Ever Beef Brisket", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/98374"}, {"umap_0": -1.0927454233169556, "umap_1": 5.387875556945801, "region": "Italian", "recipe": "Parmesan Tomatoes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/10372"}, {"umap_0": -1.071266770362854, "umap_1": 9.169951438903809, "region": "Italian", "recipe": "Garlic Polenta With Sausage", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/126903"}, {"umap_0": 10.816166877746582, "umap_1": 8.989754676818848, "region": "French", "recipe": "Creme Glacee Aux Myrtilles (Frozen Blueberry Cream)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115702"}, {"umap_0": -2.5517635345458984, "umap_1": 7.902929782867432, "region": "Italian", "recipe": "Grilled Veg and Almond Ricotta Crostinis", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/126803"}, {"umap_0": -1.1118669509887695, "umap_1": 9.731581687927246, "region": "UK", "recipe": "Ginger Duck and Orange Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/104493"}, {"umap_0": 1.6856554746627808, "umap_1": 11.480337142944336, "region": "Southeast Asian", "recipe": "Vietnamese Fish with Lemongrass and Chilli", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/62256"}, {"umap_0": -2.4938180446624756, "umap_1": 8.836197853088379, "region": "French", "recipe": "Grape Picker's Sausages With Grapes, Thyme and Wine", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115258"}, {"umap_0": -1.139853596687317, "umap_1": 5.236851692199707, "region": "Italian", "recipe": "Italian Marinated Chicken Breasts", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123054"}, {"umap_0": -1.1536849737167358, "umap_1": 11.75439167022705, "region": "Northern Africa", "recipe": "Charmoula Mayonnaise", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/49869"}, {"umap_0": -0.8700478076934814, "umap_1": 5.953568935394287, "region": "US", "recipe": "Tofu Creamed Spinach", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/15054"}, {"umap_0": -0.1698608547449112, "umap_1": 6.1382880210876465, "region": "Mexican", "recipe": "Mexican Corn Chili", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87201"}, {"umap_0": 10.885424613952637, "umap_1": 8.53498363494873, "region": "Irish", "recipe": "Irish Cream Almond Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/136769"}, {"umap_0": 1.6548129320144653, "umap_1": 9.861000061035156, "region": "South American", "recipe": "Beef Tenderloin With Henry Bain Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/95333"}, {"umap_0": 2.0236690044403076, "umap_1": 7.660715103149414, "region": "Mexican", "recipe": "Cactus Chicken Fried Steak", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/89453"}, {"umap_0": 1.4477132558822632, "umap_1": 5.137422561645508, "region": "Central American", "recipe": "Party Roll-ups: an American, an Englishman, and an Italian", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/93024"}, {"umap_0": 1.9531077146530151, "umap_1": 5.021805286407471, "region": "South American", "recipe": "Salsa Beef Skillet", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96475"}, {"umap_0": 0.28648433089256287, "umap_1": 9.895027160644531, "region": "South American", "recipe": "Spicy Beef Goulash", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96638"}, {"umap_0": 0.9185366034507751, "umap_1": 8.543752670288086, "region": "Irish", "recipe": "Veggie Guinness Stew (Vegan)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/135142"}, {"umap_0": 11.295226097106934, "umap_1": 7.38368558883667, "region": "French", "recipe": "Overnight Strawberry-Banana French Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112233"}, {"umap_0": -1.8786512613296509, "umap_1": 10.2505521774292, "region": "Australian", "recipe": "Healthy Grilled Herbed Fish", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75656"}, {"umap_0": -1.468809962272644, "umap_1": 9.261617660522461, "region": "Caribbean", "recipe": "Black Bean and Olive Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92548"}, {"umap_0": -1.3976020812988281, "umap_1": 11.138792991638184, "region": "Mexican", "recipe": "Rio Brava Salsa", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83716"}, {"umap_0": -0.7882421016693115, "umap_1": 8.978182792663574, "region": "Italian", "recipe": "Italian Pot Roast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125356"}, {"umap_0": 11.918304443359375, "umap_1": 10.068343162536621, "region": "Irish", "recipe": "Creme De Menthe Mousse", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/135088"}, {"umap_0": 10.849958419799805, "umap_1": 9.31883716583252, "region": "US", "recipe": "Ambrosia Salad II", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/17128"}, {"umap_0": -0.34674811363220215, "umap_1": 8.717296600341797, "region": "Irish", "recipe": "Irish Corned Beef With Cabbage", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/135074"}, {"umap_0": -1.522047758102417, "umap_1": 5.529359817504883, "region": "Australian", "recipe": "Amazing Stuffed Capsicum", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73560"}, {"umap_0": 1.1962745189666748, "umap_1": 6.49261999130249, "region": "Japanese", "recipe": "Crab Crisps - Kani Senbei", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70437"}, {"umap_0": 0.6921911835670471, "umap_1": 8.382219314575195, "region": "Canadian", "recipe": "Hamburger Macaroni Crock Pot Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145340"}, {"umap_0": 11.03760814666748, "umap_1": 8.769964218139648, "region": "UK", "recipe": "Nana's English Trifle", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/104800"}, {"umap_0": 1.1344938278198242, "umap_1": 12.94425106048584, "region": "Indian Subcontinent", "recipe": "Kabuli Chana Masala Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63875"}, {"umap_0": 1.4630522727966309, "umap_1": 9.666353225708008, "region": "Canadian", "recipe": "Oven Spareribs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142867"}, {"umap_0": 9.789596557617188, "umap_1": 8.079959869384766, "region": "Scandinavian", "recipe": "Danish Krasekager, Marzipan Cakes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100938"}, {"umap_0": -0.028178738430142403, "umap_1": 7.694163799285889, "region": "Italian", "recipe": "Chicken Piccata with Fettuccine", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/11454"}, {"umap_0": 11.998320579528809, "umap_1": 4.721621036529541, "region": "Eastern European", "recipe": "Rice Flour Crepes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/133465"}, {"umap_0": -1.1336603164672852, "umap_1": 7.587290287017822, "region": "US", "recipe": "Crab and Shrimp Louis", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/17935"}, {"umap_0": 9.57773494720459, "umap_1": 6.368839740753174, "region": "Canadian", "recipe": "Whole Wheat Waffles With Sauteed Apples and Cranberries", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148719"}, {"umap_0": 1.9391995668411255, "umap_1": 4.642899036407471, "region": "Mexican", "recipe": "Quesadillas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/78544"}, {"umap_0": -1.4901093244552612, "umap_1": 9.10964584350586, "region": "Greek", "recipe": "Greek Beef Kabobs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110249"}, {"umap_0": -0.9194230437278748, "umap_1": 4.757503032684326, "region": "Canadian", "recipe": "Canadian Bacon and Brie Quiche", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148708"}, {"umap_0": -0.8528251647949219, "umap_1": 8.821273803710938, "region": "Canadian", "recipe": "Creamy and Crunchy Tuna Salad Supreme", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/18785"}, {"umap_0": -1.6420037746429443, "umap_1": 11.2222900390625, "region": "Middle Eastern", "recipe": "Robin's Best Ever Hummus", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3649"}, {"umap_0": 1.3122022151947021, "umap_1": 8.742935180664062, "region": "Chinese and Mongolian", "recipe": "Mix Vegetable Pakoras (chinese style)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56971"}, {"umap_0": -1.571243166923523, "umap_1": 5.437544822692871, "region": "Italian", "recipe": "Easy Pizza Pasta Casserole (OAMC)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/131318"}, {"umap_0": 1.8441039323806763, "umap_1": 7.421917915344238, "region": "Greek", "recipe": "Chicken Avgolemono", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110091"}, {"umap_0": 2.304490327835083, "umap_1": 10.244935989379883, "region": "Thai", "recipe": "Grilled Thai Beef Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/58451"}, {"umap_0": 10.359602928161621, "umap_1": 6.390215873718262, "region": "Mexican", "recipe": "Mexican Hot Chocolate Snickerdoodles (Vegan)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/85053"}, {"umap_0": -0.16698792576789856, "umap_1": 9.321743965148926, "region": "Indian Subcontinent", "recipe": "West Indian Rum Stew Recipe", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64303"}, {"umap_0": -1.2580128908157349, "umap_1": 8.645570755004883, "region": "South American", "recipe": "Rosemary Steak", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/8512"}, {"umap_0": -0.11257972568273544, "umap_1": 5.336622714996338, "region": "Canadian", "recipe": "Cheezy Green Olive Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144906"}, {"umap_0": 9.351024627685547, "umap_1": 8.52212142944336, "region": "Central American", "recipe": "Honduras Torrejas ( Ladyfingers in Syrup)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92717"}, {"umap_0": -0.394025593996048, "umap_1": 8.105586051940918, "region": "Australian", "recipe": "Pineapple Cole Slaw With Apple & Marshmallows", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74931"}, {"umap_0": 2.607651948928833, "umap_1": 7.844747543334961, "region": "Indian Subcontinent", "recipe": "Curry Crumbed Chicken Schnitzels", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/68944"}, {"umap_0": 10.120142936706543, "umap_1": 7.455615043640137, "region": "Middle Eastern", "recipe": "Raw Vegan Nutella", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70023"}, {"umap_0": 10.536667823791504, "umap_1": 5.85667610168457, "region": "Chinese and Mongolian", "recipe": "Chinese Almond Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53002"}, {"umap_0": -0.7199134826660156, "umap_1": 9.058918952941895, "region": "South American", "recipe": "Grilled Prime Ribs of Beef With Garlic and Rosemary", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/94903"}, {"umap_0": 0.8016179203987122, "umap_1": 6.586182594299316, "region": "Canadian", "recipe": "Hamburger Quickie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146506"}, {"umap_0": 11.00777816772461, "umap_1": 6.966134071350098, "region": "Australian", "recipe": "Fun Mini Muffins -Almond Meal- Flourless", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76407"}, {"umap_0": 0.40706926584243774, "umap_1": 7.468785762786865, "region": "Irish", "recipe": "Garlic Potatoes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/135542"}, {"umap_0": 10.113068580627441, "umap_1": 7.425827980041504, "region": "Canadian", "recipe": "Acadian Cranberry Pie - Canada", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147068"}, {"umap_0": 10.305254936218262, "umap_1": 7.997673511505127, "region": "Greek", "recipe": "Baklava I", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/9433"}, {"umap_0": -2.232785224914551, "umap_1": 8.084171295166016, "region": "Italian", "recipe": "Italian Tuna Melts", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/131745"}, {"umap_0": 1.244853138923645, "umap_1": 8.72779655456543, "region": "Canadian", "recipe": "Simple Sweet and Sour Chops", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146990"}, {"umap_0": -0.6168350577354431, "umap_1": 12.034870147705078, "region": "Caribbean", "recipe": "Jamaican Jerk Pork", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91483"}, {"umap_0": 1.1446646451950073, "umap_1": 12.14500904083252, "region": "Southeast Asian", "recipe": "Kari Ayam Kelapa (Curried chicken with toasted coconut)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/59920"}, {"umap_0": -1.949479579925537, "umap_1": 10.577474594116211, "region": "Italian", "recipe": "Awesomely Easy Marinara Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/124644"}, {"umap_0": 2.1451356410980225, "umap_1": 9.919189453125, "region": "Chinese and Mongolian", "recipe": "Chinese Muslim Stir-Fried Beef and Celery (Qin Cai Chao Niu Rou)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56457"}, {"umap_0": -2.591780185699463, "umap_1": 6.8310041427612305, "region": "Italian", "recipe": "Walnut Pesto (Paula Deen)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/128283"}, {"umap_0": -0.7087075710296631, "umap_1": 6.0253400802612305, "region": "Italian", "recipe": "Vegan Gnocchi With Tomato Cream Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/129289"}, {"umap_0": 0.43849554657936096, "umap_1": 10.27269172668457, "region": "Indian Subcontinent", "recipe": "Chana Ko Tarkari", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/59647"}, {"umap_0": -0.42470529675483704, "umap_1": 7.816586017608643, "region": "Spanish and Portuguese", "recipe": "Portuguese Turkey Stuffing", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118697"}, {"umap_0": -0.7156092524528503, "umap_1": 6.06956672668457, "region": "Greek", "recipe": "Three-Cheese Phyllo Triangles With Onions and Yogurt", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110192"}, {"umap_0": 0.2427350878715515, "umap_1": 5.417876720428467, "region": "UK", "recipe": "English Muffins With Bacon Butter", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/104190"}, {"umap_0": -1.3072150945663452, "umap_1": 8.251768112182617, "region": "Canadian", "recipe": "Salmon Rillettes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147793"}, {"umap_0": -1.2602077722549438, "umap_1": 4.711234092712402, "region": "Italian", "recipe": "Stuffed Pasta Shells", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132738"}, {"umap_0": 10.495482444763184, "umap_1": 9.298541069030762, "region": "Southeast Asian", "recipe": "Cambodian Banana Dessert", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/62712"}, {"umap_0": 2.0359106063842773, "umap_1": 6.208338260650635, "region": "Mexican", "recipe": "Fixed up Spanish Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77974"}, {"umap_0": -0.6023274660110474, "umap_1": 5.456448078155518, "region": "UK", "recipe": "Love It or Hate It - Marmite and Cheese Straws With a Twist!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101992"}, {"umap_0": -0.40834954380989075, "umap_1": 8.52096939086914, "region": "Deutschland", "recipe": "Braised Wild Boar Back", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137573"}, {"umap_0": 0.24316124618053436, "umap_1": 9.96104907989502, "region": "Canadian", "recipe": "Mike's Sweet Chili Surprise", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147116"}, {"umap_0": 10.19580078125, "umap_1": 7.699525356292725, "region": "Italian", "recipe": "Amaretti", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/10953"}, {"umap_0": 11.090867042541504, "umap_1": 6.297987461090088, "region": "Scandinavian", "recipe": "Almond Butter Balls - Danish Mandelsm\u00f8rboller", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100894"}, {"umap_0": -0.7224007248878479, "umap_1": 6.452785968780518, "region": "Italian", "recipe": "Pasta Shrimp Toss", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125552"}, {"umap_0": 1.8311090469360352, "umap_1": 6.167548179626465, "region": "Mexican", "recipe": "Chicken Tortilla Soup With Shrimp", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84685"}, {"umap_0": 0.4322412610054016, "umap_1": 4.79233455657959, "region": "Canadian", "recipe": "Sweet & Salty Grilled Cheese Sandwich", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144591"}, {"umap_0": -1.3548874855041504, "umap_1": 10.589512825012207, "region": "Northern Africa", "recipe": "Spiced Eggplant (Aubergine) Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/50512"}, {"umap_0": 3.4463462829589844, "umap_1": 9.780030250549316, "region": "Chinese and Mongolian", "recipe": "Tangerine Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55226"}, {"umap_0": -1.6261612176895142, "umap_1": 10.35120964050293, "region": "US", "recipe": "Grilled Montana Trout", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/13731"}, {"umap_0": -0.503948986530304, "umap_1": 5.466320037841797, "region": "Italian", "recipe": "Baked Fennel with Parmesan", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/10787"}, {"umap_0": -1.7699774503707886, "umap_1": 5.705374240875244, "region": "Italian", "recipe": "Pretty Party Pasta Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122246"}, {"umap_0": -1.963655948638916, "umap_1": 7.469742774963379, "region": "Italian", "recipe": "Roman-Style Spaghetti With Garlic and Olive Oil", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122720"}, {"umap_0": -1.174747109413147, "umap_1": 6.197281837463379, "region": "Italian", "recipe": "Chicken Asiago Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125369"}, {"umap_0": 0.08443750441074371, "umap_1": 6.467732906341553, "region": "Eastern European", "recipe": "Hungarian Potato and Egg Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105795"}, {"umap_0": -0.8714216947555542, "umap_1": 5.548753261566162, "region": "Italian", "recipe": "Dandelion Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123763"}, {"umap_0": -1.8009405136108398, "umap_1": 8.431380271911621, "region": "Greek", "recipe": "Greek Caponata", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/109405"}, {"umap_0": 1.954458236694336, "umap_1": 8.671904563903809, "region": "Mexican", "recipe": "Pork Chops With Cumin Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/86419"}, {"umap_0": 1.7035311460494995, "umap_1": 11.042461395263672, "region": "Indian Subcontinent", "recipe": "Chicken Hariyali Tikka", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4051"}, {"umap_0": 10.80089282989502, "umap_1": 6.933441638946533, "region": "Eastern European", "recipe": "Jam Squares", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105549"}, {"umap_0": 11.060379028320312, "umap_1": 8.70517635345459, "region": "Italian", "recipe": "Strawberries & Mascarpone Cream With Amaretti Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/121323"}, {"umap_0": -1.6337313652038574, "umap_1": 6.649634838104248, "region": "Italian", "recipe": "Pasta Fagioli", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/127785"}, {"umap_0": 0.1645144820213318, "umap_1": 5.26685905456543, "region": "South American", "recipe": "Tater Tot, Beef & Cheese Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/98909"}, {"umap_0": 9.891934394836426, "umap_1": 7.50678825378418, "region": "Chinese and Mongolian", "recipe": "Milchreis (German Rice Pudding)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53801"}, {"umap_0": 11.150531768798828, "umap_1": 6.2199931144714355, "region": "Eastern European", "recipe": "Libbies Celestial Crusts", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142502"}, {"umap_0": -1.3617044687271118, "umap_1": 8.202807426452637, "region": "US", "recipe": "Dee's Sexy, Spicy, Shrimp, Sausage, and Peppers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/15336"}, {"umap_0": -1.248594880104065, "umap_1": 9.778515815734863, "region": "Spanish and Portuguese", "recipe": "Spanish White Bean Tortilla With Piri-Piri Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/141757"}, {"umap_0": 0.4271888732910156, "umap_1": 8.268725395202637, "region": "UK", "recipe": "Liver and Onions With Roast Veges", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/104890"}, {"umap_0": 0.8311628699302673, "umap_1": 5.722709655761719, "region": "Mexican", "recipe": "Freezer Sausage and Egg Breakfast Burritos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/85153"}, {"umap_0": 2.4494593143463135, "umap_1": 10.893613815307617, "region": "Thai", "recipe": "Spicy Devil's Tom Yum Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3179"}, {"umap_0": 10.68728256225586, "umap_1": 7.74041748046875, "region": "Scandinavian", "recipe": "Finnish Turnips", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/13684"}, {"umap_0": -0.9320008158683777, "umap_1": 7.229828834533691, "region": "Italian", "recipe": "Pasta With Prosciutto in a Lemon Cream Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/129941"}, {"umap_0": -0.26356375217437744, "umap_1": 10.286710739135742, "region": "Thai", "recipe": "Saus Prik Sticky Rice Sauce)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/58872"}, {"umap_0": -0.046355120837688446, "umap_1": 12.459877967834473, "region": "Canadian", "recipe": "Spiced Cauliflower With a Kick", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144204"}, {"umap_0": 2.823256731033325, "umap_1": 10.540130615234375, "region": "Chinese and Mongolian", "recipe": "Butter Lime Cilantro Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/54186"}, {"umap_0": 0.8476681113243103, "umap_1": 5.892983436584473, "region": "Canadian", "recipe": "Ham and Cheese Puffs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146500"}, {"umap_0": 10.916544914245605, "umap_1": 9.311678886413574, "region": "Mexican", "recipe": "Joe's Famous Michelada", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6517"}, {"umap_0": 0.2030342072248459, "umap_1": 8.892056465148926, "region": "South American", "recipe": "Mom's Pepper Steak", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96318"}, {"umap_0": 0.6628851890563965, "umap_1": 8.37923812866211, "region": "South American", "recipe": "Bistro Beef Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/98181"}, {"umap_0": -0.3064821660518646, "umap_1": 10.746016502380371, "region": "Middle Eastern", "recipe": "Middle Eastern Chicken Kebabs in Honey-Soy Marinade", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/60143"}, {"umap_0": -1.9981900453567505, "umap_1": 10.156318664550781, "region": "Middle Eastern", "recipe": "Classic Yogurt Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61945"}, {"umap_0": -1.644325852394104, "umap_1": 8.343690872192383, "region": "Rest Africa", "recipe": "Algerian Rice Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48679"}, {"umap_0": -1.5057601928710938, "umap_1": 8.401256561279297, "region": "French", "recipe": "French Bistro Steak and Tomatoes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113982"}, {"umap_0": 1.4272202253341675, "umap_1": 6.7758564949035645, "region": "US", "recipe": "Tennessee Eggs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/18183"}, {"umap_0": -0.4038572609424591, "umap_1": 5.603295803070068, "region": "French", "recipe": "Cauliflower Flan", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/117227"}, {"umap_0": -2.774646043777466, "umap_1": 7.75654935836792, "region": "Greek", "recipe": "Balsamic & Feta Cheese Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/109706"}, {"umap_0": 7.632309436798096, "umap_1": 6.748541831970215, "region": "French", "recipe": "French Honey Bread Abm", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112949"}, {"umap_0": 0.5723637342453003, "umap_1": 10.387426376342773, "region": "Mexican", "recipe": "Mexican Crock-Pot Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/88713"}, {"umap_0": 0.5806989073753357, "umap_1": 8.598536491394043, "region": "South American", "recipe": "Apple Cider Beef Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96290"}, {"umap_0": 1.000257134437561, "umap_1": 8.229677200317383, "region": "Deutschland", "recipe": "All Pumpkins' Night Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138408"}, {"umap_0": 3.3223419189453125, "umap_1": 10.342912673950195, "region": "Chinese and Mongolian", "recipe": "Chinese Barbecued Chicken Wings", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/57196"}, {"umap_0": -0.6928055286407471, "umap_1": 5.213754177093506, "region": "Italian", "recipe": "Spinach Tomato Tortellini", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/12494"}, {"umap_0": 9.983616828918457, "umap_1": 7.842149257659912, "region": "Chinese and Mongolian", "recipe": "Creamy Stove-Top Rice Pudding", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/54310"}, {"umap_0": -1.6628121137619019, "umap_1": 5.365706443786621, "region": "Italian", "recipe": "Al's Garlic Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122073"}, {"umap_0": 1.8710174560546875, "umap_1": 5.851068019866943, "region": "Mexican", "recipe": "Real Mexican Enchiladas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82751"}, {"umap_0": -2.5632143020629883, "umap_1": 9.503864288330078, "region": "Greek", "recipe": "Lemon Oregano Marinade", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110189"}, {"umap_0": 11.128646850585938, "umap_1": 8.859893798828125, "region": "Australian", "recipe": "Peaches and Ice Cream, Tempted yet ?", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77557"}, {"umap_0": -1.4949678182601929, "umap_1": 5.864278316497803, "region": "Italian", "recipe": "Winnipeg's Spicy Pasta & Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/127522"}, {"umap_0": 1.350890874862671, "umap_1": 6.048244953155518, "region": "Mexican", "recipe": "Mexican Rice Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/89676"}, {"umap_0": 0.037330262362957, "umap_1": 9.225337982177734, "region": "Deutschland", "recipe": "German Red Cabbage", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138707"}, {"umap_0": 10.962918281555176, "umap_1": 7.244486331939697, "region": "French", "recipe": "Julia Child's Mousseline Au Chocolat (Chocolate Mousse)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115760"}, {"umap_0": -0.7767975330352783, "umap_1": 4.922647953033447, "region": "Italian", "recipe": "Simple Italian Grilled Cheese", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/119267"}, {"umap_0": -0.5491448640823364, "umap_1": 6.249672889709473, "region": "Greek", "recipe": "Bourekakia Tiri - Cheese Rolls", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110772"}, {"umap_0": 9.880678176879883, "umap_1": 7.899832248687744, "region": "Australian", "recipe": "Apple and Golden Syrup Pudding (Australia)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74476"}, {"umap_0": -1.6649576425552368, "umap_1": 6.250842571258545, "region": "Italian", "recipe": "Manicotti", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125410"}, {"umap_0": 1.249767541885376, "umap_1": 8.422239303588867, "region": "UK", "recipe": "Scottish Meat Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/102204"}, {"umap_0": 0.7794864773750305, "umap_1": 9.746917724609375, "region": "Mexican", "recipe": "Mexican Rice Bean Veggie Thing", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/78491"}, {"umap_0": 0.9988527297973633, "umap_1": 10.760143280029297, "region": "Thai", "recipe": "Curry Chicken With Couscous and Acorn Squash", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/58081"}, {"umap_0": 9.439095497131348, "umap_1": 5.956291198730469, "region": "Mexican", "recipe": "Sopapillas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6369"}, {"umap_0": 0.055145878344774246, "umap_1": 9.339345932006836, "region": "Indian Subcontinent", "recipe": "Chilled cucumber soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64267"}, {"umap_0": 2.9634106159210205, "umap_1": 10.344860076904297, "region": "Canadian", "recipe": "Cumin Oysters", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148391"}, {"umap_0": 0.5340229868888855, "umap_1": 8.57981014251709, "region": "French", "recipe": "Marinated Beef Tenderloin-Caramelized Onions-Mushroom Ragout", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113940"}, {"umap_0": -1.1305686235427856, "umap_1": 5.919745445251465, "region": "Italian", "recipe": "Easy Baked Rigatoni With Ground Beef and Mushrooms", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130399"}, {"umap_0": -1.6870341300964355, "umap_1": 10.471819877624512, "region": "Greek", "recipe": "It's Greek to Me Chicken Breasts (Somersize Level 1)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110284"}, {"umap_0": 1.446755051612854, "umap_1": 11.534807205200195, "region": "Scandinavian", "recipe": "Andreas Viestad's Pork Meatballs With Prunes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/107118"}, {"umap_0": 3.281654119491577, "umap_1": 7.6903157234191895, "region": "French", "recipe": "Mean Chef's French Fries", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/116588"}, {"umap_0": 11.510458946228027, "umap_1": 7.283414840698242, "region": "Southeast Asian", "recipe": "Cassava Cake With Shredded Buco", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63564"}, {"umap_0": -0.24797332286834717, "umap_1": 11.071017265319824, "region": "Mexican", "recipe": "My Charra Bean Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82319"}, {"umap_0": 10.181310653686523, "umap_1": 8.254674911499023, "region": "Middle Eastern", "recipe": "Cream Kunafa", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61825"}, {"umap_0": -0.42767879366874695, "umap_1": 9.853402137756348, "region": "Mexican", "recipe": "Best Ever Cilantro Corn Salsa", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/7619"}, {"umap_0": 9.857704162597656, "umap_1": 5.650196075439453, "region": "US", "recipe": "Applesauce Cornbread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16058"}, {"umap_0": 0.8255650401115417, "umap_1": 9.900074005126953, "region": "US", "recipe": "Home-Style Buffalo Wings", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/17676"}, {"umap_0": 1.2974451780319214, "umap_1": 8.85756778717041, "region": "South American", "recipe": "Empanadas - Antioquia, Colombia", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/93640"}, {"umap_0": 2.7266793251037598, "umap_1": 9.715110778808594, "region": "Chinese and Mongolian", "recipe": "Foo Yung", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56304"}, {"umap_0": 0.9828050136566162, "umap_1": 7.126698970794678, "region": "Canadian", "recipe": "Vichyssoise Cream of Leek", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144540"}, {"umap_0": 2.73215913772583, "umap_1": 8.722335815429688, "region": "Caribbean", "recipe": "Slow-Cooker Jamaican Jerk BBQ Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91911"}, {"umap_0": -0.465935081243515, "umap_1": 7.947761058807373, "region": "Italian", "recipe": "Vegan Mushroom & Bechamel Lasagna", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/129543"}, {"umap_0": 1.0105150938034058, "umap_1": 9.142107963562012, "region": "Indian Subcontinent", "recipe": "Stuffed Chatamari (Nepali Stuffed Rice Crepes)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/59667"}, {"umap_0": 0.16232894361019135, "umap_1": 8.142657279968262, "region": "US", "recipe": "Emma's Clam Chowder", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/17688"}, {"umap_0": -1.5456469058990479, "umap_1": 8.884249687194824, "region": "Italian", "recipe": "Pasta and Peas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/12626"}, {"umap_0": 1.2549721002578735, "umap_1": 12.993866920471191, "region": "Indian Subcontinent", "recipe": "Cucumber Cutlet", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67416"}, {"umap_0": 1.59001886844635, "umap_1": 9.221657752990723, "region": "Belgian", "recipe": "Dutch Meat Loaf", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134186"}, {"umap_0": 0.3997994661331177, "umap_1": 6.454665184020996, "region": "UK", "recipe": "Cheddar Cheese Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/104940"}, {"umap_0": -1.2533832788467407, "umap_1": 10.593985557556152, "region": "Greek", "recipe": "Lamb Kebabs With Yoghurt Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/108899"}, {"umap_0": 2.177845001220703, "umap_1": 10.595561027526855, "region": "Spanish and Portuguese", "recipe": "Fruit Paella", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/140494"}, {"umap_0": 0.8273208737373352, "umap_1": 6.018863201141357, "region": "Eastern European", "recipe": "Anita's Polish Pierogies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/133373"}, {"umap_0": 0.7407148480415344, "umap_1": 5.560225963592529, "region": "Mexican", "recipe": "Mexican Grilled Corn on the Cob", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/86996"}, {"umap_0": 3.3007805347442627, "umap_1": 9.967154502868652, "region": "Chinese and Mongolian", "recipe": "Home-Made Saucy Oriental Burger", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/57219"}, {"umap_0": 0.31244710087776184, "umap_1": 11.449378967285156, "region": "Rest Africa", "recipe": "Tunisian Eggah With Sausages", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47642"}, {"umap_0": 0.8983188271522522, "umap_1": 6.985197067260742, "region": "French", "recipe": "(Potatoes) Pommes Lyonnaise", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/116109"}, {"umap_0": -0.3177778422832489, "umap_1": 5.548505783081055, "region": "Mexican", "recipe": "Santa Fe Salmon With Fresh Spinach Wild Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/85375"}, {"umap_0": 3.1425113677978516, "umap_1": 9.617280960083008, "region": "Korean", "recipe": "Spicy Tofu Casserole with Pork", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69120"}, {"umap_0": 1.70737624168396, "umap_1": 9.921626091003418, "region": "Canadian", "recipe": "Garlic Scape and Jalepeno Jelly", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142764"}, {"umap_0": -2.1506502628326416, "umap_1": 7.503776550292969, "region": "Italian", "recipe": "Olive Garden Pasta Salad Supremo", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125976"}, {"umap_0": 0.03127273544669151, "umap_1": 6.576362609863281, "region": "Mexican", "recipe": "Mexican Rice Skillet", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80970"}, {"umap_0": 3.0173182487487793, "umap_1": 9.560245513916016, "region": "Chinese and Mongolian", "recipe": "Pork and Vegetables in Black Bean Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/52215"}, {"umap_0": 0.7770051956176758, "umap_1": 11.703926086425781, "region": "UK", "recipe": "Bridget Jones's Turkey Buffet Curry in a Hurry!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101339"}, {"umap_0": -2.450244188308716, "umap_1": 7.627440452575684, "region": "Italian", "recipe": "Spaghetti W- Fresh Tomato Sauce W- Capers & Fresh Mozzarella", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130813"}, {"umap_0": 0.2627440094947815, "umap_1": 5.478451251983643, "region": "Deutschland", "recipe": "German Zwiebelkuchen (Onion Pie)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/13305"}, {"umap_0": 11.089301109313965, "umap_1": 6.686619758605957, "region": "Eastern European", "recipe": "Hungarian Cheese-Filled Coffee Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105288"}, {"umap_0": -0.3958199620246887, "umap_1": 7.195949077606201, "region": "Irish", "recipe": "Dublin Bay Shrimp Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/135374"}, {"umap_0": 0.08691467344760895, "umap_1": 4.500757694244385, "region": "Canadian", "recipe": "Cream Cheese Stuffed Mushroom caps", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148163"}, {"umap_0": 10.640205383300781, "umap_1": 7.689425468444824, "region": "Indian Subcontinent", "recipe": "Creme Caramels", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69003"}, {"umap_0": 0.7567131519317627, "umap_1": 9.595846176147461, "region": "Mexican", "recipe": "Handsome Jack's Red Hot Red Wine Chili", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83351"}, {"umap_0": 10.276200294494629, "umap_1": 5.612985610961914, "region": "Irish", "recipe": "Baileys Irish Cream Pancakes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/136096"}, {"umap_0": 2.251246213912964, "umap_1": 9.811243057250977, "region": "Chinese and Mongolian", "recipe": "Chinesey Chicken Wings", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56203"}, {"umap_0": 1.5477447509765625, "umap_1": 4.980820178985596, "region": "Mexican", "recipe": "Nachos Supreme", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83411"}, {"umap_0": -0.9134964346885681, "umap_1": 10.421812057495117, "region": "US", "recipe": "Texas Coleslaw", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/17495"}, {"umap_0": -1.0912203788757324, "umap_1": 5.120869159698486, "region": "Italian", "recipe": "Eggplant (Aubergine) Parmigiano", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123409"}, {"umap_0": 3.584340810775757, "umap_1": 9.676220893859863, "region": "Korean", "recipe": "Kimchi Jun (Kimchi Patty)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4785"}, {"umap_0": -1.1599665880203247, "umap_1": 9.975829124450684, "region": "Northern Africa", "recipe": "Moroccan Oven Roasted Sesame Potatoes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/49560"}, {"umap_0": -0.25800904631614685, "umap_1": 5.884183406829834, "region": "Canadian", "recipe": "Brussels Sprouts Gratin", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147828"}, {"umap_0": 8.855896949768066, "umap_1": 8.17015266418457, "region": "Australian", "recipe": "Carob Fudge", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73449"}, {"umap_0": 1.718493938446045, "umap_1": 7.4463887214660645, "region": "Scandinavian", "recipe": "Pressure Cooker Meatballs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/139688"}, {"umap_0": -0.054099734872579575, "umap_1": 8.034754753112793, "region": "US", "recipe": "Manhattan Filet with Pan Sauce Bordelaise", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/17641"}, {"umap_0": 8.088932037353516, "umap_1": 6.6288042068481445, "region": "Scandinavian", "recipe": "Knaakkebrod or Nakkileipa (Scandinavian-Style Rye Crisp Bread)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/13432"}, {"umap_0": -0.5568294525146484, "umap_1": 6.193646430969238, "region": "Italian", "recipe": "Meat and Spinach Ravioli Filling", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/11937"}, {"umap_0": 7.752982139587402, "umap_1": 6.848856449127197, "region": "Italian", "recipe": "Easy Maple-Proofed Pizza Dough for One", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125669"}, {"umap_0": 3.9718432426452637, "umap_1": 9.385099411010742, "region": "Japanese", "recipe": "Chilled Soba Noodles", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/71199"}, {"umap_0": 3.336444139480591, "umap_1": 9.949758529663086, "region": "Chinese and Mongolian", "recipe": "Baked Pork Ribs With Hoisin Barbecue Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56402"}, {"umap_0": -2.5576043128967285, "umap_1": 8.035008430480957, "region": "Italian", "recipe": "Tomato and Mozzarella Bites", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/11445"}, {"umap_0": 8.521719932556152, "umap_1": 6.278942108154297, "region": "Eastern European", "recipe": "Buckwheat Pancakes Russian Blini", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100774"}, {"umap_0": 1.4134681224822998, "umap_1": 5.7431840896606445, "region": "Mexican", "recipe": "Baked Mexican Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80325"}, {"umap_0": 10.530927658081055, "umap_1": 5.956060409545898, "region": "Belgian", "recipe": "The Best Almond Paste Bars", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/133978"}, {"umap_0": 10.893014907836914, "umap_1": 7.137414455413818, "region": "French", "recipe": "French Chocolate Cupcakes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113828"}, {"umap_0": 0.47363466024398804, "umap_1": 5.820273399353027, "region": "Irish", "recipe": "COLCANNON", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134767"}, {"umap_0": -1.0735938549041748, "umap_1": 6.248915672302246, "region": "Deutschland", "recipe": "Swiss Chard Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/117952"}, {"umap_0": 1.4559935331344604, "umap_1": 10.245786666870117, "region": "Thai", "recipe": "Coconut Curry Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/58030"}, {"umap_0": -1.971341609954834, "umap_1": 8.966514587402344, "region": "Rest Africa", "recipe": "Turkish Chicken Kebabs With Aleppo Pepper", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48375"}, {"umap_0": 1.8515671491622925, "umap_1": 4.967075824737549, "region": "Mexican", "recipe": "Leftover Steak Enchiladas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80079"}, {"umap_0": 1.4935951232910156, "umap_1": 9.735342979431152, "region": "Chinese and Mongolian", "recipe": "Chinese Plum Chicken Cutlets", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55948"}, {"umap_0": 10.910282135009766, "umap_1": 6.873297691345215, "region": "Canadian", "recipe": "Peanut Brittle Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144614"}, {"umap_0": -1.534580945968628, "umap_1": 7.149397850036621, "region": "Italian", "recipe": "Balsamic Tofu or Chicken and Bright Veggie Pasta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/124278"}, {"umap_0": -0.6063388586044312, "umap_1": 8.344342231750488, "region": "Chinese and Mongolian", "recipe": "Steamed Fish With Cabbage, Mushrooms and Chinese Black Beans", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56230"}, {"umap_0": -0.9128854274749756, "umap_1": 9.804506301879883, "region": "Mexican", "recipe": "Black Bean and Corn Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77955"}, {"umap_0": 4.03208065032959, "umap_1": 10.294976234436035, "region": "Japanese", "recipe": "Oshitashi (Japanese Spinach Salad With Roasted Sesame)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70662"}, {"umap_0": 10.753658294677734, "umap_1": 7.548896789550781, "region": "Canadian", "recipe": "Napoleons", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146919"}, {"umap_0": 10.334403038024902, "umap_1": 10.143391609191895, "region": "Australian", "recipe": "Applemint Iced Tea", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/72702"}, {"umap_0": 0.32953765988349915, "umap_1": 9.645954132080078, "region": "Central American", "recipe": "Dobladas(Guatemala)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/93144"}, {"umap_0": 0.535389244556427, "umap_1": 13.254276275634766, "region": "Rest Africa", "recipe": "Spicy African Preserved Limes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/49363"}, {"umap_0": -1.6463419198989868, "umap_1": 10.436721801757812, "region": "Irish", "recipe": "Terra's Colcannon (Courtesy of Spiral Path Farms Csa)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134671"}, {"umap_0": 10.580803871154785, "umap_1": 6.451938152313232, "region": "French", "recipe": "Fondant Aux Poires Et Au Gingembre (Choc Ginger Pear Fudge Cake)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112387"}, {"umap_0": 10.099893569946289, "umap_1": 6.042366027832031, "region": "Scandinavian", "recipe": "Brown Swedish Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105986"}, {"umap_0": -0.8276249170303345, "umap_1": 9.073336601257324, "region": "UK", "recipe": "Spicy Spaghetti With Garlic Mushrooms", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/102796"}, {"umap_0": 1.7465989589691162, "umap_1": 10.382780075073242, "region": "Southeast Asian", "recipe": "Filipino Beef Kabobs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63719"}, {"umap_0": 1.919236660003662, "umap_1": 9.967972755432129, "region": "Southeast Asian", "recipe": "Caramelized Pork Banh Mi", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/62129"}, {"umap_0": 11.071337699890137, "umap_1": 7.889893531799316, "region": "UK", "recipe": "Fresh Lime Pie (British Virgin Islands)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105061"}, {"umap_0": 0.3033906817436218, "umap_1": 7.623064041137695, "region": "Italian", "recipe": "My Best Chicken Piccata", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/11601"}, {"umap_0": 0.33403506875038147, "umap_1": 12.540398597717285, "region": "Indian Subcontinent", "recipe": "Indian Eggplant Curry", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67461"}, {"umap_0": 0.24190753698349, "umap_1": 11.79411506652832, "region": "Rest Africa", "recipe": "Vegetarian Fig, Olive and Chickpea Tagine", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47690"}, {"umap_0": 0.33403292298316956, "umap_1": 9.166858673095703, "region": "Middle Eastern", "recipe": "Egyptian Bamia", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/2612"}, {"umap_0": 1.044874906539917, "umap_1": 6.875057220458984, "region": "Canadian", "recipe": "Something Like Mashed Potatoes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147326"}, {"umap_0": -1.742253303527832, "umap_1": 7.737472057342529, "region": "Italian", "recipe": "Penne Rigate With Prosciutto, and Snow Peas in a Truffled Cream", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123314"}, {"umap_0": 1.1833767890930176, "umap_1": 7.128292560577393, "region": "Irish", "recipe": "Creamed Cabbage and Carrots", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/135907"}, {"umap_0": 0.009266161359846592, "umap_1": 8.048189163208008, "region": "South American", "recipe": "Danish Boiled Beef With Sweet and Sour Horseradish Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/95063"}, {"umap_0": 0.984284520149231, "umap_1": 12.958019256591797, "region": "Indian Subcontinent", "recipe": "Palak Panir (Saag Panir)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67577"}, {"umap_0": 11.241716384887695, "umap_1": 8.980339050292969, "region": "UK", "recipe": "Cranachan", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101641"}, {"umap_0": -0.7338122725486755, "umap_1": 6.916945457458496, "region": "Australian", "recipe": "Cheese, Onion, Leek & Potato Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76429"}, {"umap_0": 0.7410939931869507, "umap_1": 9.992947578430176, "region": "Indian Subcontinent", "recipe": "Chicken Thighs with Lime and Curry", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64429"}, {"umap_0": 2.165865182876587, "umap_1": 11.132843971252441, "region": "Southeast Asian", "recipe": "Fried Chilli Sambal", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/59739"}, {"umap_0": 11.67033576965332, "umap_1": 9.134739875793457, "region": "Mexican", "recipe": "Pound Cake With Dulce De Leche Filling", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83950"}, {"umap_0": -1.00088369846344, "umap_1": 10.995707511901855, "region": "Middle Eastern", "recipe": "Lime Soup With Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61810"}, {"umap_0": -2.7427170276641846, "umap_1": 9.340370178222656, "region": "Middle Eastern", "recipe": "Jungle Juice (Cucumber and Tomato Salad)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63246"}, {"umap_0": 1.8458852767944336, "umap_1": 6.870546817779541, "region": "Italian", "recipe": "Italian Roast Beef", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/124994"}, {"umap_0": -2.3552191257476807, "umap_1": 9.478193283081055, "region": "Indian Subcontinent", "recipe": "Indian Mayonnaise", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/68954"}, {"umap_0": 9.956003189086914, "umap_1": 7.380596160888672, "region": "French", "recipe": "Apple-Raspberry Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114179"}, {"umap_0": 0.6948102712631226, "umap_1": 9.551872253417969, "region": "Mexican", "recipe": "garlic shrimp", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81019"}, {"umap_0": -1.1323838233947754, "umap_1": 6.985578536987305, "region": "Italian", "recipe": "Quick Spaghetti", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123732"}, {"umap_0": -0.007444669492542744, "umap_1": 11.888574600219727, "region": "Indian Subcontinent", "recipe": "Pork Curry ( for the Ladies)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/65863"}, {"umap_0": 1.3530242443084717, "umap_1": 10.043692588806152, "region": "Mexican", "recipe": "Spicy Mexican Fish", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81094"}, {"umap_0": 10.996036529541016, "umap_1": 8.818633079528809, "region": "UK", "recipe": "Tipsy Jello Pudding Trifle", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101640"}, {"umap_0": 1.069703221321106, "umap_1": 8.941648483276367, "region": "US", "recipe": "Hopi Corn Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/17602"}, {"umap_0": 8.756756782531738, "umap_1": 7.521526336669922, "region": "Deutschland", "recipe": "Omelette (Pancakes-Crepes)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/117650"}, {"umap_0": 0.32673758268356323, "umap_1": 9.952874183654785, "region": "Mexican", "recipe": "Chipotle Chicken Taco Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/88862"}, {"umap_0": -0.43960681557655334, "umap_1": 12.580408096313477, "region": "Greek", "recipe": "Greek Blend Spice Mix", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/109732"}, {"umap_0": 9.864283561706543, "umap_1": 6.54950475692749, "region": "Canadian", "recipe": "Apple or Pear Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145981"}, {"umap_0": -1.075528860092163, "umap_1": 5.378075122833252, "region": "Italian", "recipe": "Easy Focaccia Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/11023"}, {"umap_0": -1.2162936925888062, "umap_1": 11.565125465393066, "region": "Mexican", "recipe": "Chunky Guacamole - Bobby Flay", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80217"}, {"umap_0": -1.6309967041015625, "umap_1": 12.115493774414062, "region": "Mexican", "recipe": "Elegant Guacamole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/78670"}, {"umap_0": 11.894551277160645, "umap_1": 10.133395195007324, "region": "Italian", "recipe": "Frangelico Chocolate Martini", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/124222"}, {"umap_0": 0.09613540023565292, "umap_1": 10.27182674407959, "region": "Caribbean", "recipe": "Fruity and Spicy Appetizers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/90082"}, {"umap_0": 12.214362144470215, "umap_1": 7.9051032066345215, "region": "Chinese and Mongolian", "recipe": "Rice Crispy Treats", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/54423"}, {"umap_0": 2.190314769744873, "umap_1": 6.638415336608887, "region": "South American", "recipe": "Jimmy's Cachapas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/94049"}, {"umap_0": 9.523773193359375, "umap_1": 7.86791467666626, "region": "Australian", "recipe": "Kumara & Corn Fritters", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76864"}, {"umap_0": 2.7804222106933594, "umap_1": 9.667583465576172, "region": "Chinese and Mongolian", "recipe": "Chicken Walnut Stir Fry", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/52861"}, {"umap_0": 11.62756061553955, "umap_1": 8.036343574523926, "region": "French", "recipe": "Chocolate Pudding French Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115504"}, {"umap_0": -1.7413356304168701, "umap_1": 8.746635437011719, "region": "French", "recipe": "All-In-One Ni\u00e7oise Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113381"}, {"umap_0": 0.9104582071304321, "umap_1": 8.765548706054688, "region": "South American", "recipe": "Fresh Spinach With Ground Beef", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/97525"}, {"umap_0": 10.223584175109863, "umap_1": 9.447748184204102, "region": "Italian", "recipe": "Italian Haroset-Charoset for Passover", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/126729"}, {"umap_0": 3.0466790199279785, "umap_1": 8.960543632507324, "region": "Spanish and Portuguese", "recipe": "The Lazy Cook's Spanish Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/141881"}, {"umap_0": -1.9119269847869873, "umap_1": 7.893063068389893, "region": "Greek", "recipe": "Couscous Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/108756"}, {"umap_0": -2.0197086334228516, "umap_1": 7.073923110961914, "region": "Italian", "recipe": "Carrabba's Cavatappi Amatriciana (Side Dish Pasta)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123626"}, {"umap_0": 1.7798981666564941, "umap_1": 8.77719783782959, "region": "Southeast Asian", "recipe": "Pickled Mustard Green (vietnamese Kimchi)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/62115"}, {"umap_0": 9.193370819091797, "umap_1": 6.022936820983887, "region": "Irish", "recipe": "Irish Soda Bread (Co.Cavan)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/135670"}, {"umap_0": 11.39769458770752, "umap_1": 8.023594856262207, "region": "UK", "recipe": "English Muffins Topped With Bananas and Cinnamon Sugar.", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/104176"}, {"umap_0": 1.29863440990448, "umap_1": 7.1696977615356445, "region": "Deutschland", "recipe": "Jaegerkohl (Hunter's Cabbage)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138382"}, {"umap_0": 0.5709402561187744, "umap_1": 12.530423164367676, "region": "Indian Subcontinent", "recipe": "Bombay Lamb Curry", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67238"}, {"umap_0": 0.7810654044151306, "umap_1": 8.148824691772461, "region": "Eastern European", "recipe": "Krupnik (Polish Vegetable Barley Soup)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100124"}, {"umap_0": 10.818602561950684, "umap_1": 7.5809855461120605, "region": "US", "recipe": "Mock Cherry Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/14407"}, {"umap_0": -2.6787431240081787, "umap_1": 6.866921424865723, "region": "Italian", "recipe": "The Classic Pesto", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132900"}, {"umap_0": 1.6391514539718628, "umap_1": 8.039920806884766, "region": "Scandinavian", "recipe": "Curried Eggs on Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/139525"}, {"umap_0": 0.5552326440811157, "umap_1": 8.1549072265625, "region": "Canadian", "recipe": "Maple Pork and Peach Skewers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146581"}, {"umap_0": 1.9352266788482666, "umap_1": 5.161035060882568, "region": "Italian", "recipe": "Low Fat Italian Chili Rellenos Wrap", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130299"}, {"umap_0": -1.4051463603973389, "umap_1": 4.84638786315918, "region": "Italian", "recipe": "Italian Sausage Florentine for the Crock Pot", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/128673"}, {"umap_0": -2.1275382041931152, "umap_1": 6.559417724609375, "region": "Italian", "recipe": "Baked Vegetable Gratin (Verdure Al Forno)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120365"}, {"umap_0": 2.1892921924591064, "umap_1": 10.958094596862793, "region": "Southeast Asian", "recipe": "Rice Noodle Salad With Vietnamese Shrimp", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/62374"}, {"umap_0": 11.588420867919922, "umap_1": 6.772088527679443, "region": "French", "recipe": "Speedy French Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113766"}, {"umap_0": -0.5309041142463684, "umap_1": 8.716485977172852, "region": "South American", "recipe": "Pressure Cooker Beef Barley Vegetable Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/97849"}, {"umap_0": 9.52021598815918, "umap_1": 6.072023391723633, "region": "Indian Subcontinent", "recipe": "Royal Cardamom Treats", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/68749"}, {"umap_0": -2.3790202140808105, "umap_1": 9.095721244812012, "region": "Italian", "recipe": "Green Olivida Crostini", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132323"}, {"umap_0": 11.441635131835938, "umap_1": 6.714810848236084, "region": "Deutschland", "recipe": "Coconut Pecan Frosting for German Chocolate Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137020"}, {"umap_0": 11.427209854125977, "umap_1": 8.777311325073242, "region": "Irish", "recipe": "Oreo Irish Liqueur Cheesecake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/136649"}, {"umap_0": 1.168131709098816, "umap_1": 5.304154396057129, "region": "Mexican", "recipe": "Healthier Chicken Enchiladas II", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6898"}, {"umap_0": -0.629272997379303, "umap_1": 10.622817993164062, "region": "Rest Africa", "recipe": "Veggie-Loaded Side Dish Bake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/51461"}, {"umap_0": -0.8927010893821716, "umap_1": 11.425787925720215, "region": "Northern Africa", "recipe": "Moroccan Chicken (Tagine) - Atk", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/49913"}, {"umap_0": 10.098462104797363, "umap_1": 7.098648548126221, "region": "Middle Eastern", "recipe": "Mandarin Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/60118"}, {"umap_0": 10.095542907714844, "umap_1": 9.283376693725586, "region": "Belgian", "recipe": "Dutch Apple Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134418"}, {"umap_0": 10.572176933288574, "umap_1": 8.129974365234375, "region": "Canadian", "recipe": "Cranberry Apple Tart", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/143296"}, {"umap_0": -0.6531105041503906, "umap_1": 6.455648899078369, "region": "Italian", "recipe": "Torta Di Pasta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122076"}, {"umap_0": 1.5893229246139526, "umap_1": 8.596124649047852, "region": "Middle Eastern", "recipe": "Persian Cutlet", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/60101"}, {"umap_0": -2.709214687347412, "umap_1": 7.584137916564941, "region": "Greek", "recipe": "Yummy Greek Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/107741"}, {"umap_0": -0.46193552017211914, "umap_1": 8.980504989624023, "region": "Mexican", "recipe": "Mexican Vegetable Caldo Verde Con Pollo", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/89042"}, {"umap_0": 3.207378625869751, "umap_1": 9.008267402648926, "region": "Chinese and Mongolian", "recipe": "Fat Free egg rolls", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/57168"}, {"umap_0": 10.267742156982422, "umap_1": 7.76490592956543, "region": "French", "recipe": "French Toast With Rum Bananas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114430"}, {"umap_0": -1.9979051351547241, "umap_1": 9.070948600769043, "region": "French", "recipe": "Creamy Saffron Mussels", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115667"}, {"umap_0": -2.2850003242492676, "umap_1": 8.51480770111084, "region": "Middle Eastern", "recipe": "Kisir", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69946"}, {"umap_0": -0.28104421496391296, "umap_1": 11.630274772644043, "region": "Indian Subcontinent", "recipe": "Coriander, Mint and Green Chilli Butter", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67713"}, {"umap_0": -0.7649892568588257, "umap_1": 12.151599884033203, "region": "Mexican", "recipe": "Jalapeno Spread-Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/78884"}, {"umap_0": 0.7143282294273376, "umap_1": 8.882909774780273, "region": "Middle Eastern", "recipe": "Greek Stuffed Zucchini (Halal)(Kolokithakia Yemista)(Gluten Free", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70129"}, {"umap_0": 0.7959996461868286, "umap_1": 5.863668441772461, "region": "Irish", "recipe": "Sheboygan Beer and Brat Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/136010"}, {"umap_0": -1.67689847946167, "umap_1": 6.733006477355957, "region": "Greek", "recipe": "Mediterranean Grilled Chicken Fingers #RSC", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/109749"}, {"umap_0": -0.688520073890686, "umap_1": 10.743539810180664, "region": "Greek", "recipe": "The Bean Soup Full of Choices", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/108434"}, {"umap_0": -0.9593788981437683, "umap_1": 10.908846855163574, "region": "Caribbean", "recipe": "Chickpea Fritters With Hot Pepper Mayonnaise", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/90192"}, {"umap_0": 8.29439926147461, "umap_1": 6.031138896942139, "region": "Scandinavian", "recipe": "Simple Swedish Pastry", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105883"}, {"umap_0": 1.8915190696716309, "umap_1": 5.487430572509766, "region": "Mexican", "recipe": "Enchiladas Mona Luisa", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84940"}, {"umap_0": 0.531986653804779, "umap_1": 12.960428237915039, "region": "Indian Subcontinent", "recipe": "Ontario Lamb Tikka Roast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64061"}, {"umap_0": -2.460339307785034, "umap_1": 8.003098487854004, "region": "Italian", "recipe": "Italian Salad With Balsamic Vinaigrette", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120487"}, {"umap_0": 10.026773452758789, "umap_1": 9.46152400970459, "region": "Deutschland", "recipe": "Summer Fruit Borscht", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138115"}, {"umap_0": -0.9145243167877197, "umap_1": 6.565636157989502, "region": "Italian", "recipe": "Rose's Parmesan-Breaded Fried Zucchini", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123618"}, {"umap_0": -0.12286669760942459, "umap_1": 11.758695602416992, "region": "Rest Africa", "recipe": "Doro Wat", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/51599"}, {"umap_0": -1.552089810371399, "umap_1": 8.917481422424316, "region": "Middle Eastern", "recipe": "Shawarma Djaj -- Chicken Shawarma (Lebanon -- Middle East)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63040"}, {"umap_0": 0.021580174565315247, "umap_1": 5.3114848136901855, "region": "French", "recipe": "Gratin Potatoes Dauphinois", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115316"}, {"umap_0": 11.945073127746582, "umap_1": 8.34962272644043, "region": "Mexican", "recipe": "S\u2019mores Quesadilla", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/85063"}, {"umap_0": 2.177293539047241, "umap_1": 6.099184989929199, "region": "Spanish and Portuguese", "recipe": "Mountain Rice (Arroz Da Serra) - Portuguese Brazil", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118679"}, {"umap_0": 10.135943412780762, "umap_1": 7.112623691558838, "region": "Eastern European", "recipe": "Hungarian Cherry Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105527"}, {"umap_0": 1.49203360080719, "umap_1": 9.381569862365723, "region": "Deutschland", "recipe": "Slow-Cooked German Short Ribs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137459"}, {"umap_0": 10.624743461608887, "umap_1": 9.374702453613281, "region": "Australian", "recipe": "Berry Watermelon Smoothie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76166"}, {"umap_0": -1.5848662853240967, "umap_1": 10.166808128356934, "region": "Mexican", "recipe": "Nopales Con Pico De Gallo", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83640"}, {"umap_0": -0.5579593181610107, "umap_1": 9.315838813781738, "region": "Spanish and Portuguese", "recipe": "El Bullitt ( Portuguese Vegetable Hot-Pot)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/119067"}, {"umap_0": -0.2012803554534912, "umap_1": 11.142373085021973, "region": "Middle Eastern", "recipe": "Baked Couscous with Tomatoes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61619"}, {"umap_0": 10.187808990478516, "umap_1": 6.482682704925537, "region": "UK", "recipe": "Gingerbread With Pecans and Raisins", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/104309"}, {"umap_0": 11.59180736541748, "umap_1": 7.891847610473633, "region": "Eastern European", "recipe": "Russian Cheese Piroshki", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100604"}, {"umap_0": -0.9312697052955627, "umap_1": 3.9964046478271484, "region": "Italian", "recipe": "My Favorite Easy Lasagna Recipe", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/129192"}, {"umap_0": 1.3099995851516724, "umap_1": 5.397132396697998, "region": "Mexican", "recipe": "La La La Bamba! Mexican Dip Ole'!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82140"}, {"umap_0": -1.265501856803894, "umap_1": 8.323101997375488, "region": "Italian", "recipe": "Costolette Di Maiale Con Salvia (Pork Chops With Sage)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/121782"}, {"umap_0": -0.1634191870689392, "umap_1": 9.486566543579102, "region": "Chinese and Mongolian", "recipe": "Dominican Moro De Habichuelas Negras ( Rice and Beans)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53424"}, {"umap_0": -0.3582545816898346, "umap_1": 5.137890338897705, "region": "Italian", "recipe": "Cream of Mushroom Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/129270"}, {"umap_0": 0.18689262866973877, "umap_1": 7.478733539581299, "region": "French", "recipe": "French Chicken [with Linguine]", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113907"}, {"umap_0": 2.126091241836548, "umap_1": 10.938815116882324, "region": "Thai", "recipe": "Thai-Style Grapefruit and Prawn", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3356"}, {"umap_0": -0.8398703336715698, "umap_1": 7.191639423370361, "region": "Australian", "recipe": "Toadstool Salad (For Kids!)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74859"}, {"umap_0": -1.4928706884384155, "umap_1": 8.687613487243652, "region": "Italian", "recipe": "Vegan Eggplant Rollatini", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123182"}, {"umap_0": 1.1508342027664185, "umap_1": 6.171228885650635, "region": "Mexican", "recipe": "Pico de gallo shrimp salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81349"}, {"umap_0": 0.9417232871055603, "umap_1": 12.73490047454834, "region": "Indian Subcontinent", "recipe": "Chicken in Yogurt and Almond Curry", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/65418"}, {"umap_0": 0.8187896609306335, "umap_1": 5.6959028244018555, "region": "Italian", "recipe": "Best Italian Alfredo Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123689"}, {"umap_0": 9.684968948364258, "umap_1": 8.2518892288208, "region": "Mexican", "recipe": "Pan De Meurete (Bread of the Dead) or Sugar Skull Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87849"}, {"umap_0": -1.1702262163162231, "umap_1": 11.809029579162598, "region": "Mexican", "recipe": "Pico De Gallo Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83470"}, {"umap_0": 10.294347763061523, "umap_1": 9.280075073242188, "region": "Canadian", "recipe": "Plum and Apple Fool", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144624"}, {"umap_0": 10.91801643371582, "umap_1": 10.622156143188477, "region": "Mexican", "recipe": "Ginger Margaritas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84748"}, {"umap_0": -1.1414788961410522, "umap_1": 6.660133361816406, "region": "Italian", "recipe": "Adriana's Pasta With Sausage, Cannellini Bean, and Broccoli Rabe", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/126469"}, {"umap_0": 1.0549054145812988, "umap_1": 8.457744598388672, "region": "Mexican", "recipe": "Red Bean Chili", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82930"}, {"umap_0": 1.85953688621521, "umap_1": 10.063806533813477, "region": "Chinese and Mongolian", "recipe": "Chinese Flank Steak", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53244"}, {"umap_0": 0.11703982949256897, "umap_1": 4.702688217163086, "region": "Canadian", "recipe": "Mom's Cheesy Potatoe Caserole #5FIX", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/143349"}, {"umap_0": 2.488203525543213, "umap_1": 10.506277084350586, "region": "Thai", "recipe": "Thai Braised Pork Ribs (Pressure Cooker)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/57705"}, {"umap_0": 1.4033921957015991, "umap_1": 12.588260650634766, "region": "Indian Subcontinent", "recipe": "Akki Rotti", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4639"}, {"umap_0": -1.7084037065505981, "umap_1": 10.002152442932129, "region": "Scandinavian", "recipe": "Mustard Dill Sauce - to Serve With Salmon", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/139638"}, {"umap_0": 0.48281338810920715, "umap_1": 5.531712055206299, "region": "Deutschland", "recipe": "Krautburger", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/13377"}, {"umap_0": 2.268494129180908, "umap_1": 10.031625747680664, "region": "Rest Africa", "recipe": "Cornflake-crumbed fish with spinach", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/49303"}, {"umap_0": 1.3866162300109863, "umap_1": 9.900384902954102, "region": "Chinese and Mongolian", "recipe": "Waldorf Brown Rice Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53991"}, {"umap_0": 10.918259620666504, "umap_1": 7.958308219909668, "region": "Deutschland", "recipe": "Boysenberry-Filled Sandwich Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118593"}, {"umap_0": 11.057143211364746, "umap_1": 9.138713836669922, "region": "French", "recipe": "French Chocolate Bark", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112089"}, {"umap_0": 0.7429876327514648, "umap_1": 12.343132972717285, "region": "Indian Subcontinent", "recipe": "Chicken Korma - Takeaway Style!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64071"}, {"umap_0": 1.3051496744155884, "umap_1": 7.397836685180664, "region": "South American", "recipe": "Beef Stroganoff Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96858"}, {"umap_0": -1.5075063705444336, "umap_1": 12.006537437438965, "region": "Mexican", "recipe": "Creamy Mexican Green Salsa-Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/89791"}, {"umap_0": 3.148944854736328, "umap_1": 8.9029541015625, "region": "Chinese and Mongolian", "recipe": "Sue Gow", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/52557"}, {"umap_0": -0.12715567648410797, "umap_1": 10.932998657226562, "region": "Indian Subcontinent", "recipe": "Garlic Mushrooms With Spinach Raita", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/68770"}, {"umap_0": 3.5829391479492188, "umap_1": 9.868836402893066, "region": "Australian", "recipe": "Sesame Pasta Chicken Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/5296"}, {"umap_0": -1.289717674255371, "umap_1": 5.662283897399902, "region": "US", "recipe": "Creamy Jambalaya Pasta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/14973"}, {"umap_0": 1.046501636505127, "umap_1": 12.69597053527832, "region": "Indian Subcontinent", "recipe": "Smoked Seekh Kababs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64135"}, {"umap_0": 9.486129760742188, "umap_1": 7.297597885131836, "region": "Indian Subcontinent", "recipe": "Apple Jalebi", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/66925"}, {"umap_0": -0.9925557374954224, "umap_1": 9.947272300720215, "region": "Canadian", "recipe": "Cabbage-Zucchini Stir Fry", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146163"}, {"umap_0": 0.3792119026184082, "umap_1": 4.707038879394531, "region": "Deutschland", "recipe": "Easy German Lasagna", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138392"}]}};
var embedOpt = {"mode": "vega-lite"};
function showError(el, error){
el.innerHTML = ('<div class="error" style="color:red;">'
+ '<p>JavaScript Error: ' + error.message + '</p>'
+ "<p>This usually means there's a typo in your chart specification. "
+ "See the javascript console for the full traceback.</p>"
+ '</div>');
throw error;
}
const el = document.getElementById('vis-1');
vegaEmbed("#vis-1", spec, embedOpt)
.catch(error => showError(el, error));
})(vegaEmbed);
</script>
<p>Remember, the closer two recipes are, the more similar they <em>should</em> be. It looks like it. Notice how recipes from the same region tend to form groups. This makes sense: recipes of the same region use similar sets of ingredients. </p>
<h2 id="i-dont-like-spinach">I don't like spinach</h2>
<p>While studying recommendation systems. I <a href="http://charuaggarwal.net/Recommender-Systems.htm">came across</a> a <em>particularly</em> interesting technique for building recommender systems. </p>
<p>The first step is to create a network of items (recipes in our case). This includes the recipes that you like, and recipes that you don't like. Using pandas, let's define that:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># let's define some polarising ingredients</span>
<span class="n">liked_ingredients</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"cheese"</span><span class="p">,</span> <span class="s2">"pizza"</span><span class="p">,</span> <span class="s2">"avocado"</span><span class="p">,</span> <span class="s2">"olive oil"</span><span class="p">]</span>
<span class="n">hated_ingredients</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"spinach"</span><span class="p">,</span> <span class="s2">"mushroom"</span><span class="p">,</span> <span class="s2">"olive"</span><span class="p">,</span> <span class="s2">"beef"</span><span class="p">,</span> <span class="s2">"truffle"</span><span class="p">,</span> <span class="s2">"blue cheese"</span><span class="p">]</span>
<span class="c1"># let's add a "like" property</span>
<span class="n">df</span><span class="p">[</span><span class="s2">"like"</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
<span class="c1"># and populate our data </span>
<span class="n">df</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="n">df</span><span class="o">.</span><span class="n">ingredient_string</span><span class="o">.</span><span class="n">str</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span><span class="o">.</span><span class="n">str</span><span class="o">.</span><span class="n">contains</span><span class="p">(</span><span class="s2">"|"</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">hated_ingredients</span><span class="p">)),</span> <span class="s2">"like"</span><span class="p">]</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span>
<span class="n">df</span><span class="o">.</span><span class="n">loc</span><span class="p">[</span><span class="n">df</span><span class="o">.</span><span class="n">ingredient_string</span><span class="o">.</span><span class="n">str</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span><span class="o">.</span><span class="n">str</span><span class="o">.</span><span class="n">contains</span><span class="p">(</span><span class="s2">"|"</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">liked_ingredients</span><span class="p">)),</span> <span class="s2">"like"</span><span class="p">]</span> <span class="o">=</span> <span class="o">+</span><span class="mi">1</span>
</code></pre></div>
<p>Yeah, I don't like spinach. Let me be. </p>
<p>Once I've defined what recipes I like, and what recipes I don't, we can use our leverage our embeddings again, to visualise <em>my own</em> network of recipes. Here's a sample of 500:</p>
<div id="vis"></div>
<script>
(function(vegaEmbed) {
var spec = {"config": {"view": {"continuousWidth": 400, "continuousHeight": 300}}, "data": {"name": "data-a48bde4a404c70bcc159550b325d9243"}, "mark": "point", "encoding": {"color": {"field": "like", "scale": {"domain": [0.0, 1.0, -1.0], "range": ["gray", "green", "red"]}, "type": "nominal"}, "tooltip": [{"field": "recipe", "type": "nominal"}, {"field": "region", "type": "nominal"}, {"field": "url", "type": "nominal"}], "x": {"field": "umap_0", "type": "quantitative"}, "y": {"field": "umap_1", "type": "quantitative"}}, "height": 500, "selection": {"selector002": {"type": "interval", "bind": "scales", "encodings": ["x", "y"]}}, "title": "Visualizing 500 recipes", "width": 500, "$schema": "https://vega.github.io/schema/vega-lite/v4.17.0.json", "datasets": {"data-a48bde4a404c70bcc159550b325d9243": [{"umap_0": -1.1850786209106445, "umap_1": 6.134487152099609, "region": "Italian", "recipe": "Crock Pot Spaghetti", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/129855", "like": -1}, {"umap_0": -1.1895201206207275, "umap_1": 8.653212547302246, "region": "Eastern European", "recipe": "Pate Iz Shchuki -Baked Salmon Mousse", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100310", "like": 0}, {"umap_0": -0.5190680027008057, "umap_1": 6.319146156311035, "region": "Canadian", "recipe": "Spanish stuffed meatloaf", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148887", "like": 1}, {"umap_0": 9.447676658630371, "umap_1": 6.079851150512695, "region": "Canadian", "recipe": "Kefir Jam Muffins", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145871", "like": 0}, {"umap_0": -2.2245516777038574, "umap_1": 8.895587921142578, "region": "Australian", "recipe": "Red Wine Steak and Mushrooms", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75932", "like": 1}, {"umap_0": 1.0995079278945923, "umap_1": 5.980602741241455, "region": "South American", "recipe": "Hot Mexican Beef Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96342", "like": 1}, {"umap_0": -0.22713147103786469, "umap_1": 8.200007438659668, "region": "Canadian", "recipe": "Apple, Carrot Pineapple Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148164", "like": 0}, {"umap_0": 3.311671257019043, "umap_1": 9.73155403137207, "region": "Korean", "recipe": "Japchae", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4723", "like": -1}, {"umap_0": 10.302436828613281, "umap_1": 10.304679870605469, "region": "US", "recipe": "Fresh Raspberry Mojito", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/17745", "like": 0}, {"umap_0": 3.8760950565338135, "umap_1": 10.024311065673828, "region": "Southeast Asian", "recipe": "Sesame Eggplant (Aubergine) Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/59850", "like": 0}, {"umap_0": 0.3885427713394165, "umap_1": 8.351722717285156, "region": "Australian", "recipe": "Lemon Scented Lamb", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75969", "like": 0}, {"umap_0": 1.5670115947723389, "umap_1": 10.798117637634277, "region": "Australian", "recipe": "Spicy Apricot Lamb Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76663", "like": 0}, {"umap_0": 9.558920860290527, "umap_1": 6.659140110015869, "region": "Indian Subcontinent", "recipe": "Kashmiri Naan", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/65649", "like": 0}, {"umap_0": 1.9093105792999268, "umap_1": 5.1884894371032715, "region": "Mexican", "recipe": "Lailani's Taco Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/78878", "like": 1}, {"umap_0": 9.506790161132812, "umap_1": 6.551031112670898, "region": "Canadian", "recipe": "Healthy Oatmeal Yogurt Bran Muffins", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147918", "like": 0}, {"umap_0": 8.961240768432617, "umap_1": 7.516850471496582, "region": "Middle Eastern", "recipe": "Megli Popsicles (Lebanese)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63118", "like": 0}, {"umap_0": 2.4023356437683105, "umap_1": 10.893607139587402, "region": "Thai", "recipe": "Khao Soi Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3176", "like": 0}, {"umap_0": -1.3299518823623657, "umap_1": 9.10419750213623, "region": "Middle Eastern", "recipe": "Bazella (Middle Eastern-Style Beef Casserole)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61623", "like": 1}, {"umap_0": -1.29935884475708, "umap_1": 7.717833042144775, "region": "Italian", "recipe": "Fast 'n Easy FLIPPIN GOOD CHICKEN!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122078", "like": 1}, {"umap_0": 1.114492416381836, "umap_1": 8.263710975646973, "region": "Rest Africa", "recipe": "Egyptian Yellow Lentil Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47717", "like": -1}, {"umap_0": 8.602962493896484, "umap_1": 8.177571296691895, "region": "Deutschland", "recipe": "Blancmanger (Chicken and Rice Casserole)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138725", "like": 0}, {"umap_0": -1.606046199798584, "umap_1": 6.272897720336914, "region": "Italian", "recipe": "Sunday Sauce With Meatballs, Sausages, and Pork Chops", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123843", "like": 1}, {"umap_0": 10.657774925231934, "umap_1": 8.120484352111816, "region": "Canadian", "recipe": "Canadian Bacon Stack-Ups", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147941", "like": 0}, {"umap_0": -0.6598324775695801, "umap_1": 8.080796241760254, "region": "French", "recipe": "Cassoulet", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112343", "like": 0}, {"umap_0": 10.475963592529297, "umap_1": 5.699642658233643, "region": "French", "recipe": "Breadless French Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115247", "like": 0}, {"umap_0": 0.818125307559967, "umap_1": 9.986652374267578, "region": "Northern Africa", "recipe": "Moroccan Flavored Pork Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/50289", "like": 1}, {"umap_0": 1.3073502779006958, "umap_1": 6.508403301239014, "region": "Indian Subcontinent", "recipe": "Easy Microwave Potato and Corn Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64400", "like": 1}, {"umap_0": 0.4339883327484131, "umap_1": 7.10546875, "region": "Australian", "recipe": "Breadfruit and Lamb Liver", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76512", "like": 1}, {"umap_0": 10.413260459899902, "umap_1": 7.858121871948242, "region": "Middle Eastern", "recipe": "Omm 'Ali (Egyptian Bread and Butter Pudding)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47477", "like": 0}, {"umap_0": -0.6674445867538452, "umap_1": 5.123907566070557, "region": "US", "recipe": "Broccoli and Artichoke Bake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/14820", "like": 1}, {"umap_0": -0.21166661381721497, "umap_1": 11.940535545349121, "region": "Indian Subcontinent", "recipe": "Indian Tomato Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4086", "like": 1}, {"umap_0": 2.3027584552764893, "umap_1": 10.956110954284668, "region": "Thai", "recipe": "Coconut, Lime and Chilli Baked Fish With Thai Potato Wedges", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/59450", "like": 1}, {"umap_0": 10.223357200622559, "umap_1": 8.356406211853027, "region": "Korean", "recipe": "Lemon Sweet & Sour Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69229", "like": 0}, {"umap_0": -1.7379339933395386, "umap_1": 5.8034749031066895, "region": "Greek", "recipe": "Joe's Tasty Bruschetta Pizza!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110324", "like": 1}, {"umap_0": 0.2126130759716034, "umap_1": 7.719091892242432, "region": "French", "recipe": "Les Supremes De Volaile Saint Sylvestre", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112943", "like": 0}, {"umap_0": 2.5439085960388184, "umap_1": 10.184285163879395, "region": "Chinese and Mongolian", "recipe": "Marinated Chinese Chicken Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53252", "like": 0}, {"umap_0": 1.618972659111023, "umap_1": 7.0421013832092285, "region": "US", "recipe": "Cranberry Brisket", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/18716", "like": -1}, {"umap_0": 0.4893477261066437, "umap_1": 10.455350875854492, "region": "Mexican", "recipe": "Chipotle Tilapia Tacos with Mango-Cilantro Salsa", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6134", "like": 0}, {"umap_0": 2.007398843765259, "umap_1": 4.715290546417236, "region": "Mexican", "recipe": "Mexican-Style Beefy Tortellini", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82398", "like": 1}, {"umap_0": -0.35907480120658875, "umap_1": 10.42431640625, "region": "Mexican", "recipe": "Mexican Cabbage Salad-Taco Filling", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77801", "like": 0}, {"umap_0": 1.94753897190094, "umap_1": 11.03625202178955, "region": "Thai", "recipe": "Chicken Salad With Thai-Flavored Dressing", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3384", "like": 0}, {"umap_0": 1.6027430295944214, "umap_1": 6.762001991271973, "region": "US", "recipe": "Aunt Fanny's Squash", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16132", "like": 0}, {"umap_0": -0.5982398390769958, "umap_1": 8.583219528198242, "region": "Canadian", "recipe": "Canadian Mary Pickford's University Avenue Potage", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/143813", "like": 0}, {"umap_0": 2.6169447898864746, "umap_1": 10.519927978515625, "region": "Japanese", "recipe": "Dr. Andrew Weil\u2019s Grilled or Broiled Salmon", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/71842", "like": 0}, {"umap_0": 11.396207809448242, "umap_1": 8.511942863464355, "region": "French", "recipe": "Almond Cream With Fruit", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113134", "like": 0}, {"umap_0": 10.781975746154785, "umap_1": 8.984734535217285, "region": "UK", "recipe": "Strawberry-Lemon Angel Food Trifle", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/103951", "like": 0}, {"umap_0": 0.7907938957214355, "umap_1": 10.293313026428223, "region": "Middle Eastern", "recipe": "Egyptian Koshary Pasta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47308", "like": 0}, {"umap_0": -1.2615807056427002, "umap_1": 8.718500137329102, "region": "Caribbean", "recipe": "Rabo Encendido(Cuban Oxtail Stew)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92674", "like": 1}, {"umap_0": 1.245664358139038, "umap_1": 4.96910285949707, "region": "Indian Subcontinent", "recipe": "Fuss-Free Biryani Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64086", "like": 0}, {"umap_0": -0.3872736990451813, "umap_1": 11.4719877243042, "region": "Middle Eastern", "recipe": "Spicy Dilly Beans", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/72524", "like": 0}, {"umap_0": -0.10169387608766556, "umap_1": 8.22164249420166, "region": "Canadian", "recipe": "Maple Ham Peachies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144208", "like": 0}, {"umap_0": 10.378604888916016, "umap_1": 6.253831386566162, "region": "UK", "recipe": "Mixed Nut Shortbread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101649", "like": 0}, {"umap_0": -1.3679935932159424, "umap_1": 6.473010540008545, "region": "Italian", "recipe": "Spaghetti (With Mushroom Soup?!)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125094", "like": -1}, {"umap_0": 0.8709162473678589, "umap_1": 12.464061737060547, "region": "Indian Subcontinent", "recipe": "Pathani Chicken Biryani", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/72390", "like": 0}, {"umap_0": 2.7814364433288574, "umap_1": 9.63673210144043, "region": "Chinese and Mongolian", "recipe": "Szechuan Vegetable Stir-Fry", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55902", "like": 0}, {"umap_0": -0.6416953206062317, "umap_1": 6.175542831420898, "region": "Canadian", "recipe": "Deluxe Mac and Cheese", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142968", "like": 1}, {"umap_0": 0.022139783948659897, "umap_1": 10.70101261138916, "region": "South American", "recipe": "Tequila-Marinated Beef Fajitas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/97772", "like": 0}, {"umap_0": 10.462568283081055, "umap_1": 9.70547103881836, "region": "Mexican", "recipe": "Monkey Shake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81498", "like": 0}, {"umap_0": 0.9298517107963562, "umap_1": 12.21575927734375, "region": "Indian Subcontinent", "recipe": "Coconut Beet Samosas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67831", "like": 1}, {"umap_0": -0.6186256408691406, "umap_1": 7.069271087646484, "region": "Italian", "recipe": "Pollo Capri - Adapted from Bella's Italian Cafe, Tampa, Florida", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123308", "like": 1}, {"umap_0": 0.7549301385879517, "umap_1": 7.419032096862793, "region": "Italian", "recipe": "Light Veal Marsala", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/127832", "like": -1}, {"umap_0": 10.337684631347656, "umap_1": 7.999570846557617, "region": "Rest Africa", "recipe": "Sauteed Bananas With Caramel Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48955", "like": 0}, {"umap_0": 0.7815414071083069, "umap_1": 9.64523696899414, "region": "Mexican", "recipe": "Mexican Black Bean Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81016", "like": 0}, {"umap_0": -0.6640657186508179, "umap_1": 5.883609294891357, "region": "Indian Subcontinent", "recipe": "Low Carb Meatballs a La Parmigiana", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/66347", "like": 1}, {"umap_0": 1.2964386940002441, "umap_1": 5.1462273597717285, "region": "UK", "recipe": "Stilton and Grape Avocados Recipe", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/104465", "like": 1}, {"umap_0": -0.7768697738647461, "umap_1": 6.05380916595459, "region": "Italian", "recipe": "Pesto Filled Spiral Meatloaf", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123793", "like": 1}, {"umap_0": 3.0572879314422607, "umap_1": 7.49185848236084, "region": "French", "recipe": "French Fried Onions (Gluten-Free)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/111785", "like": 0}, {"umap_0": -0.3980916142463684, "umap_1": 12.852380752563477, "region": "Caribbean", "recipe": "Jammin' Jamaican Spice Blend", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92043", "like": 0}, {"umap_0": 0.5679068565368652, "umap_1": 7.683577060699463, "region": "US", "recipe": "Creamy Sweet Potato Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/15184", "like": 0}, {"umap_0": 10.96013069152832, "umap_1": 7.587233543395996, "region": "UK", "recipe": "English Walnut Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/103763", "like": 0}, {"umap_0": -0.47361117601394653, "umap_1": 8.561030387878418, "region": "UK", "recipe": "Easy Chicken Stock", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/102053", "like": 0}, {"umap_0": 8.828392028808594, "umap_1": 8.148130416870117, "region": "Middle Eastern", "recipe": "Iranian Saffron Rice Pudding (Sholeh Zard) (Dairy Free & Glu", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/60933", "like": 0}, {"umap_0": 0.44980233907699585, "umap_1": 9.950838088989258, "region": "Mexican", "recipe": "Pork and Apple Burritos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84247", "like": 1}, {"umap_0": -0.2053876519203186, "umap_1": 6.008750915527344, "region": "South American", "recipe": "Tessa Kiros Beef and Potato Croquettes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/95917", "like": 1}, {"umap_0": 2.67214298248291, "umap_1": 10.572834968566895, "region": "Thai", "recipe": "Thai Shrimp and Broccoli Pasta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/58511", "like": 0}, {"umap_0": -0.1595761477947235, "umap_1": 5.343988418579102, "region": "Mexican", "recipe": "Baked Chorizo Cheesy Mac", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84522", "like": 1}, {"umap_0": -1.598894476890564, "umap_1": 11.995153427124023, "region": "Mexican", "recipe": "Chipotle Mexican Grill Guacamole Copycat", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87336", "like": 1}, {"umap_0": 0.052441176027059555, "umap_1": 5.2800493240356445, "region": "French", "recipe": "Creamy French Onion Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113902", "like": 1}, {"umap_0": 1.6097749471664429, "umap_1": 7.684686183929443, "region": "Eastern European", "recipe": "Beef Stroganoff with Noodles", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/8597", "like": -1}, {"umap_0": 0.5770699977874756, "umap_1": 6.024519920349121, "region": "French", "recipe": "French Onion Biscuits", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114084", "like": 0}, {"umap_0": 9.463890075683594, "umap_1": 9.363100051879883, "region": "Italian", "recipe": "Granita De Limone (Sicilian Lemon Ice)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120780", "like": 0}, {"umap_0": -0.5556496977806091, "umap_1": 9.402655601501465, "region": "Chinese and Mongolian", "recipe": "White Beans & Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/54234", "like": 0}, {"umap_0": -1.6857001781463623, "umap_1": 7.512906074523926, "region": "Deutschland", "recipe": "German Salat Fix", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137251", "like": 1}, {"umap_0": 1.2722601890563965, "umap_1": 10.944067001342773, "region": "Australian", "recipe": "Cranberry Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73556", "like": 0}, {"umap_0": 0.4704318940639496, "umap_1": 4.850879669189453, "region": "South American", "recipe": "Beef and Blue Sandwich", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96044", "like": 1}, {"umap_0": 11.64326000213623, "umap_1": 7.896361351013184, "region": "Mexican", "recipe": "Mexican Coffee Balls", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82205", "like": 0}, {"umap_0": -0.5871949791908264, "umap_1": 4.973294258117676, "region": "Italian", "recipe": "Crispy Eggplant with Spicy Tomato Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/12376", "like": 1}, {"umap_0": 10.561944007873535, "umap_1": 8.81438159942627, "region": "Italian", "recipe": "Limoncello Panna Cotta With Black Cherry Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/121274", "like": 0}, {"umap_0": 10.184091567993164, "umap_1": 7.238198757171631, "region": "Italian", "recipe": "Michele's Spiced Almond Biscotti", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122057", "like": 0}, {"umap_0": 2.5322582721710205, "umap_1": 10.279123306274414, "region": "Thai", "recipe": "Mango Summer Rolls & Thai Dipping Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/58648", "like": 0}, {"umap_0": 0.7151965498924255, "umap_1": 9.91037654876709, "region": "Mexican", "recipe": "Pueblo Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82618", "like": 0}, {"umap_0": 3.6300299167633057, "umap_1": 9.259065628051758, "region": "Japanese", "recipe": "Japanese Vegetable Pancakes (Okonomiyaki)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/71890", "like": -1}, {"umap_0": 1.4382530450820923, "umap_1": 7.865445613861084, "region": "Chinese and Mongolian", "recipe": "Oven-Cooked Rice Pilaf", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/54403", "like": 0}, {"umap_0": -0.5371537208557129, "umap_1": 4.815740585327148, "region": "South American", "recipe": "Cheesy Beef Noodle Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/99597", "like": 1}, {"umap_0": 10.231728553771973, "umap_1": 7.1652445793151855, "region": "Rest Africa", "recipe": "Khobz Tunis - Algerian Helouwa - My Family Recipe", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47972", "like": 0}, {"umap_0": 0.24582378566265106, "umap_1": 10.788599967956543, "region": "Mexican", "recipe": "Tacos al Pastor", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/7006", "like": 0}, {"umap_0": 1.425007700920105, "umap_1": 8.345734596252441, "region": "South American", "recipe": "Believe It or Not Roast Beef", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/98284", "like": -1}, {"umap_0": 0.8389599323272705, "umap_1": 8.373648643493652, "region": "South American", "recipe": "Broedlaewend (Romanian Beef Soup)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96275", "like": 1}, {"umap_0": -2.4443905353546143, "umap_1": 9.003817558288574, "region": "Italian", "recipe": "Italian Orange Slices", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125157", "like": 1}, {"umap_0": 9.854039192199707, "umap_1": 7.419904708862305, "region": "Chinese and Mongolian", "recipe": "(Leftover) Rice Pudding", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53456", "like": 0}, {"umap_0": 2.2491025924682617, "umap_1": 8.778008460998535, "region": "Belgian", "recipe": "Belgian Mayonnaise to Serve With Frites", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/106602", "like": 0}, {"umap_0": 0.44109848141670227, "umap_1": 4.630356788635254, "region": "US", "recipe": "Frankly Super Supper", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/18001", "like": 1}, {"umap_0": -0.32183316349983215, "umap_1": 11.799098014831543, "region": "US", "recipe": "Chef John's Buttermilk Fried Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/14487", "like": 0}, {"umap_0": -1.290636658668518, "umap_1": 8.649124145507812, "region": "Rest Africa", "recipe": "Safari Steak for the Hunter", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48084", "like": 0}, {"umap_0": -0.6573124527931213, "umap_1": 10.916947364807129, "region": "Northern Africa", "recipe": "Moroccan Spiced Preserved Lemons", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/49826", "like": 0}, {"umap_0": -0.929466187953949, "umap_1": 4.51997184753418, "region": "Italian", "recipe": "Italian Hoagie Delight", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132631", "like": 1}, {"umap_0": -0.9419817328453064, "umap_1": 8.130386352539062, "region": "Indian Subcontinent", "recipe": "Caramelized Cumin-Roasted Carrots", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63951", "like": 1}, {"umap_0": 0.8741731643676758, "umap_1": 11.66552734375, "region": "Middle Eastern", "recipe": "A Baqliyya of Zirlab's", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61589", "like": 0}, {"umap_0": -2.3510994911193848, "umap_1": 7.491191387176514, "region": "Italian", "recipe": "\"Good Carb\" Fettuccine Witih Fresh Tomatoes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/119308", "like": 1}, {"umap_0": 9.6798734664917, "umap_1": 6.823861598968506, "region": "Greek", "recipe": "Greek Yogurt Strawberry Banana Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110060", "like": 0}, {"umap_0": -0.6030805706977844, "umap_1": 7.98883581161499, "region": "French", "recipe": "Burgundy Pork Tenderloin", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113354", "like": 0}, {"umap_0": 11.5413236618042, "umap_1": 6.94635534286499, "region": "Mexican", "recipe": "Ninfa's Flan", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80019", "like": 1}, {"umap_0": 10.419769287109375, "umap_1": 9.615630149841309, "region": "South American", "recipe": "My Mom's Cranberry Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100008", "like": 0}, {"umap_0": 0.20882202684879303, "umap_1": 8.077316284179688, "region": "South American", "recipe": "Heinz 57 Beef Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/98809", "like": -1}, {"umap_0": -1.8444103002548218, "umap_1": 7.516116619110107, "region": "Italian", "recipe": "Melon, Prosciutto & Mozzarella Salad With Mint Vinaigrette", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/127989", "like": 1}, {"umap_0": 0.8042580485343933, "umap_1": 6.945413589477539, "region": "Irish", "recipe": "Colcannon(Mashed Potato & Cabbage)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134644", "like": 0}, {"umap_0": 10.007749557495117, "umap_1": 5.933751583099365, "region": "Australian", "recipe": "Spelt Soda Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76365", "like": 0}, {"umap_0": 0.564936637878418, "umap_1": 6.081768035888672, "region": "Canadian", "recipe": "Microwave Poached Eggs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147710", "like": 1}, {"umap_0": 11.158587455749512, "umap_1": 7.070868015289307, "region": "French", "recipe": "Peach Cobbler French Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/116263", "like": 0}, {"umap_0": -0.11201471090316772, "umap_1": 11.078572273254395, "region": "US", "recipe": "Cranberry Pork Chops I", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/18696", "like": 0}, {"umap_0": 1.7187167406082153, "umap_1": 7.4296555519104, "region": "Deutschland", "recipe": "Helen's Creamy Garlic String - Green Beans", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137904", "like": 0}, {"umap_0": -2.461521625518799, "umap_1": 8.884740829467773, "region": "Italian", "recipe": "Chef John's Bagna Cauda", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/11365", "like": 1}, {"umap_0": 2.537705183029175, "umap_1": 9.78603458404541, "region": "Chinese and Mongolian", "recipe": "Pei Wei Asian Diner Shanghai Pork Ribs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56756", "like": 0}, {"umap_0": 0.5408082604408264, "umap_1": 12.35210132598877, "region": "Indian Subcontinent", "recipe": "Banana Dahl", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/65926", "like": 0}, {"umap_0": 1.1257686614990234, "umap_1": 8.981525421142578, "region": "Middle Eastern", "recipe": "Makhlouta 2 - Vegetarian Hearty Lebanese Lentil & Bean Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63063", "like": 0}, {"umap_0": -0.8881869316101074, "umap_1": 4.514981746673584, "region": "Italian", "recipe": "Bob's Awesome Lasagna", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/11872", "like": 1}, {"umap_0": 0.3362944424152374, "umap_1": 7.0383429527282715, "region": "Irish", "recipe": "Corned Beef and Cabbage for 2", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/136261", "like": -1}, {"umap_0": 1.5462255477905273, "umap_1": 11.949945449829102, "region": "Indian Subcontinent", "recipe": "Sweet and Sour Fish Khatti Meethi Macchi", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64984", "like": 0}, {"umap_0": -0.9165903925895691, "umap_1": 8.658659934997559, "region": "Scandinavian", "recipe": "Karrysalat - Danish Curried Macaroni and Herring Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101212", "like": 1}, {"umap_0": 2.67948317527771, "umap_1": 7.135268211364746, "region": "Italian", "recipe": "Potato, Parmesan and Anchovy Focaccia", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132249", "like": 1}, {"umap_0": -0.3302302956581116, "umap_1": 7.245589733123779, "region": "Mexican", "recipe": "Sopa De Calabacin Y Guajolote (Zucchini and Turkey Soup)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82599", "like": 0}, {"umap_0": 10.758835792541504, "umap_1": 6.664599418640137, "region": "Canadian", "recipe": "A Different Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147627", "like": 0}, {"umap_0": 10.548820495605469, "umap_1": 7.828482151031494, "region": "French", "recipe": "Apple Cinnamon French Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112177", "like": 0}, {"umap_0": 1.1214299201965332, "umap_1": 11.835747718811035, "region": "Indian Subcontinent", "recipe": "Restaurant Style Indian Butter Chicken (Chicken Makhani)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64597", "like": 1}, {"umap_0": -0.49632641673088074, "umap_1": 10.749210357666016, "region": "Middle Eastern", "recipe": "Chicken Shawarma", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63045", "like": 1}, {"umap_0": -0.6656883358955383, "umap_1": 5.413561820983887, "region": "Italian", "recipe": "Baked Mashed Potatoes Italian", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/119844", "like": 1}, {"umap_0": -0.8973937630653381, "umap_1": 8.444534301757812, "region": "Caribbean", "recipe": "Caribbean Potato and Eggs Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/90588", "like": 0}, {"umap_0": -2.2734081745147705, "umap_1": 8.599804878234863, "region": "Italian", "recipe": "Spicy Linguine With Clams", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125636", "like": 1}, {"umap_0": 9.773694038391113, "umap_1": 6.301175117492676, "region": "Canadian", "recipe": "Parkin Drops", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/143090", "like": 0}, {"umap_0": 3.7195725440979004, "umap_1": 9.354264259338379, "region": "Japanese", "recipe": "Japanese Wok-Fried Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/71206", "like": 0}, {"umap_0": -2.3354671001434326, "umap_1": 8.990545272827148, "region": "Italian", "recipe": "Trota Alle Erbette (Trout with Herbs)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/10512", "like": 1}, {"umap_0": 3.0256967544555664, "umap_1": 9.340682983398438, "region": "Chinese and Mongolian", "recipe": "Beef and Mushroom Stir-Fry Korean Style", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56776", "like": -1}, {"umap_0": 0.21639230847358704, "umap_1": 5.183401107788086, "region": "UK", "recipe": "Collier\u2019s Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/102743", "like": 1}, {"umap_0": -1.54658842086792, "umap_1": 9.06863784790039, "region": "US", "recipe": "Cowboy Kale", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/17345", "like": 1}, {"umap_0": 0.5320228934288025, "umap_1": 8.11629867553711, "region": "South American", "recipe": "Beef & Portabellas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/99143", "like": 1}, {"umap_0": 2.7491660118103027, "umap_1": 10.60092544555664, "region": "Southeast Asian", "recipe": "Spicy Peanut Dipping Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/62230", "like": 0}, {"umap_0": -0.06501508504152298, "umap_1": 10.493794441223145, "region": "Deutschland", "recipe": "German Geraucherte Forelle Nach Art Des Hauses (Smoked Trout)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138182", "like": 0}, {"umap_0": 4.006468772888184, "umap_1": 10.27139949798584, "region": "Japanese", "recipe": "Spinach with Sesame Dressing (from Japanese Home Cooking)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/71731", "like": -1}, {"umap_0": 11.346846580505371, "umap_1": 6.1185808181762695, "region": "Scandinavian", "recipe": "Copy-Cat Hoito Finnish Pancakes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142221", "like": 0}, {"umap_0": 0.5280241370201111, "umap_1": 7.505107402801514, "region": "South American", "recipe": "Cornbread Beef Liver Patties", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/95957", "like": 0}, {"umap_0": 2.9683446884155273, "umap_1": 9.626852035522461, "region": "Thai", "recipe": "Thai-style Salmon Potato", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/59548", "like": -1}, {"umap_0": -2.0645203590393066, "umap_1": 8.43727970123291, "region": "French", "recipe": "Salade Gruy\u00e8re De Comt\u00e8 Pour Deux", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/111594", "like": 1}, {"umap_0": 11.384322166442871, "umap_1": 7.0832085609436035, "region": "Australian", "recipe": "Malted Nightcap", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74725", "like": 0}, {"umap_0": 0.9112706184387207, "umap_1": 12.757550239562988, "region": "Indian Subcontinent", "recipe": "Tofu & Potato Stuffed Bell Peppers in a Spicy Indian Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/65998", "like": 0}, {"umap_0": -0.4696824550628662, "umap_1": 12.515528678894043, "region": "Caribbean", "recipe": "Caribbean Jerk Seasoning & Rub", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/90998", "like": 0}, {"umap_0": -2.077889919281006, "umap_1": 8.809181213378906, "region": "Canadian", "recipe": "Stuffed Zucchini - Chilled", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142717", "like": 0}, {"umap_0": 2.6803553104400635, "umap_1": 7.0498199462890625, "region": "UK", "recipe": "Potato Skins and Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101388", "like": 0}, {"umap_0": 9.966638565063477, "umap_1": 9.367307662963867, "region": "Irish", "recipe": "Caribbean Ginger Beer", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/135837", "like": 0}, {"umap_0": -1.4631023406982422, "umap_1": 6.109340190887451, "region": "Italian", "recipe": "Tomato Cream Pasta.", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/126644", "like": 1}, {"umap_0": 0.9024763703346252, "umap_1": 11.940484046936035, "region": "Indian Subcontinent", "recipe": "Takkali Payam Opma", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/66263", "like": 0}, {"umap_0": 1.197152018547058, "umap_1": 7.201746463775635, "region": "South American", "recipe": "Oven (Or Slow Cooker) Barbecued Beef", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/99428", "like": -1}, {"umap_0": 10.89644718170166, "umap_1": 6.839352607727051, "region": "Chinese and Mongolian", "recipe": "Chinese Chip Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53135", "like": 0}, {"umap_0": -0.5381951928138733, "umap_1": 5.4431586265563965, "region": "Rest Africa", "recipe": "Watermelon Salad With Celery-Nut Dressing", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48565", "like": 1}, {"umap_0": 0.26075559854507446, "umap_1": 5.338015556335449, "region": "Canadian", "recipe": "Best 5 Minutes Sandwich", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147855", "like": -1}, {"umap_0": 10.12112045288086, "umap_1": 9.393574714660645, "region": "UK", "recipe": "Fluffy Orange Syllabub", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/102368", "like": 0}, {"umap_0": 1.4043314456939697, "umap_1": 7.761448860168457, "region": "Greek", "recipe": "Avegolemono (Greek Lemon Chicken Soup)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/109512", "like": 0}, {"umap_0": 1.7731153964996338, "umap_1": 5.481025695800781, "region": "Mexican", "recipe": "Turkey Enchiladas---A Little Lighter Version", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/86341", "like": 1}, {"umap_0": 1.898542881011963, "umap_1": 11.419892311096191, "region": "Thai", "recipe": "Larb Gai - Thai Chicken Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/58776", "like": 0}, {"umap_0": 10.133990287780762, "umap_1": 5.9880876541137695, "region": "French", "recipe": "Cinnamon Espresso Cream Sables", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114568", "like": 0}, {"umap_0": -0.7373630404472351, "umap_1": 7.718879222869873, "region": "Italian", "recipe": "Pear Parmesan Risotto With Hazelnuts", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120373", "like": 1}, {"umap_0": 8.82620906829834, "umap_1": 7.235421657562256, "region": "Deutschland", "recipe": "Mohnstriezel -- Poppy Seed Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138842", "like": 0}, {"umap_0": -0.813057005405426, "umap_1": 8.23116683959961, "region": "French", "recipe": "Grilled Chicken Dijonnaise", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/116372", "like": 0}, {"umap_0": 0.09704425930976868, "umap_1": 7.571213722229004, "region": "French", "recipe": "Lila's Favourite Chicken With Creamy Mushroom Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114057", "like": 1}, {"umap_0": 1.2712476253509521, "umap_1": 9.035685539245605, "region": "Irish", "recipe": "Glazed Corned Beef (Silver Palate)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/136167", "like": -1}, {"umap_0": 3.203937530517578, "umap_1": 9.78446102142334, "region": "US", "recipe": "Cedar Planked Salmon", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/17247", "like": 0}, {"umap_0": -0.41177719831466675, "umap_1": 13.591712951660156, "region": "Australian", "recipe": "HOMEMADE Holiday Seasoning and SPICE", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73001", "like": 0}, {"umap_0": 8.251080513000488, "umap_1": 6.563953876495361, "region": "Deutschland", "recipe": "Bavarian Pretzels- Pretzel Rolls (Laugenbrezeln)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137458", "like": 0}, {"umap_0": 0.8185259699821472, "umap_1": 8.256429672241211, "region": "South American", "recipe": "Onion-Smothered Beef", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/99472", "like": 1}, {"umap_0": 1.339928388595581, "umap_1": 9.5243501663208, "region": "Eastern European", "recipe": "Beef & Chickpea Paprikash", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105495", "like": -1}, {"umap_0": 10.011178016662598, "umap_1": 6.347383499145508, "region": "Italian", "recipe": "Italian Chocolate Chip Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/11230", "like": 0}, {"umap_0": 10.13790225982666, "umap_1": 8.951178550720215, "region": "French", "recipe": "Honey-Soaked Goat Cheese", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113255", "like": 1}, {"umap_0": 0.8377261161804199, "umap_1": 10.998503684997559, "region": "Chinese and Mongolian", "recipe": "Ginger Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/52851", "like": 0}, {"umap_0": 10.175458908081055, "umap_1": 7.586801052093506, "region": "Middle Eastern", "recipe": "Gluten Free Mandarin & Almond Syrup Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/60470", "like": 0}, {"umap_0": 9.692200660705566, "umap_1": 8.407427787780762, "region": "Indian Subcontinent", "recipe": "Banana Burfi", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67407", "like": 0}, {"umap_0": -2.0898938179016113, "umap_1": 9.530020713806152, "region": "Italian", "recipe": "Italian Barbecued Steak", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123012", "like": 1}, {"umap_0": -1.5693659782409668, "umap_1": 9.3914213180542, "region": "Deutschland", "recipe": "Bratwurst-Potato Skillet Dinner", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137369", "like": 1}, {"umap_0": -1.116334080696106, "umap_1": 9.287352561950684, "region": "UK", "recipe": "English Mustard", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/102369", "like": 0}, {"umap_0": -0.8204387426376343, "umap_1": 10.038043022155762, "region": "Greek", "recipe": "Iman Bayaldi (Greek Eggplant Layers)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110275", "like": 1}, {"umap_0": 0.38013556599617004, "umap_1": 9.571761131286621, "region": "Mexican", "recipe": "Becky's Gourmet Southwestern Taco Salad or Nachos With Steak", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82723", "like": 1}, {"umap_0": 10.460600852966309, "umap_1": 5.786361217498779, "region": "Belgian", "recipe": "Oma's Boterkoek (Dutch Buttercake)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134046", "like": 0}, {"umap_0": 10.43691635131836, "umap_1": 9.140484809875488, "region": "Australian", "recipe": "Tangy Citrus Pots", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73504", "like": 0}, {"umap_0": -1.8791556358337402, "umap_1": 9.904389381408691, "region": "Rest Africa", "recipe": "Arabian Pickled Onions", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47878", "like": 0}, {"umap_0": 0.5187867283821106, "umap_1": 12.717525482177734, "region": "Indian Subcontinent", "recipe": "Kheema Matar", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/65666", "like": -1}, {"umap_0": 0.5754416584968567, "umap_1": 9.46481990814209, "region": "Caribbean", "recipe": "Fidel's Revolutionary Chili", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91717", "like": -1}, {"umap_0": 3.005664110183716, "umap_1": 10.086755752563477, "region": "Korean", "recipe": "Pasta with Korean Sesame Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69271", "like": 0}, {"umap_0": -2.39272403717041, "umap_1": 7.180198669433594, "region": "Greek", "recipe": "Ww 5 Points - Greek Pizza", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110304", "like": 1}, {"umap_0": 0.7749611139297485, "umap_1": 7.597709655761719, "region": "Canadian", "recipe": "Quebec Meat Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144798", "like": 0}, {"umap_0": -1.7026762962341309, "umap_1": 9.14134407043457, "region": "Italian", "recipe": "Warm Green Bean Salad with Pine Nuts and Basil", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/119950", "like": 1}, {"umap_0": -0.7000232338905334, "umap_1": 6.579843997955322, "region": "Italian", "recipe": "Risotto Alla Milanese", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125993", "like": 1}, {"umap_0": 7.717833042144775, "umap_1": 6.442302227020264, "region": "Eastern European", "recipe": "Grandma Reilkoff's Authentic Russian Blintze", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100378", "like": 0}, {"umap_0": 0.5022920966148376, "umap_1": 6.842819690704346, "region": "Eastern European", "recipe": "Polish Kapusta Kielbasa", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/133705", "like": 0}, {"umap_0": 1.6971757411956787, "umap_1": 11.688207626342773, "region": "Southeast Asian", "recipe": "Cambodian Fish Amok", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/62694", "like": 0}, {"umap_0": -1.6330304145812988, "umap_1": 9.885078430175781, "region": "Rest Africa", "recipe": "Rice Salad With Mint", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48392", "like": 0}, {"umap_0": -0.5844018459320068, "umap_1": 11.074140548706055, "region": "Caribbean", "recipe": "Bahama Shrimp Skewers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91517", "like": 1}, {"umap_0": 9.613204002380371, "umap_1": 8.623011589050293, "region": "Middle Eastern", "recipe": "Lokum ( Turkish Delight )", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61228", "like": 0}, {"umap_0": -0.7855482697486877, "umap_1": 11.475994110107422, "region": "Spanish and Portuguese", "recipe": "Grilled Pork Threads", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/141185", "like": 1}, {"umap_0": 10.437041282653809, "umap_1": 7.87003231048584, "region": "Australian", "recipe": "Nashi Pear Puds", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73076", "like": 0}, {"umap_0": -0.5804792642593384, "umap_1": 7.825493335723877, "region": "Italian", "recipe": "Veal Scaloppine Saltimbocca", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130084", "like": 1}, {"umap_0": 0.35925719141960144, "umap_1": 8.358013153076172, "region": "Irish", "recipe": "Irish Stew With Guinness", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134570", "like": 1}, {"umap_0": 0.021180037409067154, "umap_1": 10.130359649658203, "region": "Mexican", "recipe": "Breakfast Egg and Avocado Tostada", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84551", "like": 1}, {"umap_0": 0.27298417687416077, "umap_1": 8.719152450561523, "region": "Canadian", "recipe": "Pork Chops in Mushroom Soup (Aka Pork Chop Dinner)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145507", "like": -1}, {"umap_0": 0.6827617287635803, "umap_1": 9.6076078414917, "region": "Mexican", "recipe": "Chili Con Carne With Veggies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79866", "like": 1}, {"umap_0": 2.017608880996704, "umap_1": 5.731778621673584, "region": "Mexican", "recipe": "Layered Mexican Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/88539", "like": 1}, {"umap_0": 1.4073379039764404, "umap_1": 7.631011486053467, "region": "Scandinavian", "recipe": "Microwave Swedish Meatballs for 2", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/106383", "like": -1}, {"umap_0": -0.4583122432231903, "umap_1": 8.868474960327148, "region": "UK", "recipe": "English Spiced Beef", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/103982", "like": -1}, {"umap_0": -1.6112645864486694, "umap_1": 12.072936058044434, "region": "Mexican", "recipe": "Tostitos Rica Mango Salsa", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/81432", "like": 0}, {"umap_0": 11.519378662109375, "umap_1": 7.874290466308594, "region": "French", "recipe": "Blintz Stuffed French Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112924", "like": 1}, {"umap_0": 0.22269786894321442, "umap_1": 6.97373104095459, "region": "Canadian", "recipe": "Cauliflower With Mushroom Cheese Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142947", "like": 1}, {"umap_0": 9.784527778625488, "umap_1": 6.597893238067627, "region": "UK", "recipe": "Chocolate Surprise Cupcakes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/8946", "like": 1}, {"umap_0": 9.102849960327148, "umap_1": 6.40867280960083, "region": "Canadian", "recipe": "Poppy Seed Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144384", "like": 0}, {"umap_0": -2.1560158729553223, "umap_1": 9.51371955871582, "region": "Canadian", "recipe": "Mustard Chive Vinaigrette", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/143588", "like": 1}, {"umap_0": 1.1569068431854248, "umap_1": 9.489564895629883, "region": "Italian", "recipe": "Italian Sausage Sweet #2", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/121288", "like": 0}, {"umap_0": 10.355172157287598, "umap_1": 8.300712585449219, "region": "Canadian", "recipe": "Maple Candied Sweet Potatoes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142712", "like": 0}, {"umap_0": 10.1763334274292, "umap_1": 5.847024917602539, "region": "Canadian", "recipe": "Maple Squares", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/143156", "like": 0}, {"umap_0": 0.36425596475601196, "umap_1": 9.473384857177734, "region": "Spanish and Portuguese", "recipe": "Skillet Linguica With Pasta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/118791", "like": 1}, {"umap_0": 7.525515556335449, "umap_1": 7.143021583557129, "region": "Italian", "recipe": "Homemade Pasta Sheets", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130426", "like": 1}, {"umap_0": 1.1162711381912231, "umap_1": 8.146279335021973, "region": "South American", "recipe": "Vegetable Beef Soup (Crockpot)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/94531", "like": -1}, {"umap_0": -1.3993396759033203, "umap_1": 5.5542683601379395, "region": "Canadian", "recipe": "Spinach Chicken Breast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145842", "like": 1}, {"umap_0": 1.387834906578064, "umap_1": 10.809419631958008, "region": "Scandinavian", "recipe": "Not so Universal Dipping Sauce (Iceland)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/139836", "like": 0}, {"umap_0": -1.0863066911697388, "umap_1": 4.289551734924316, "region": "Italian", "recipe": "Pesto Snack Pizza", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122403", "like": 1}, {"umap_0": 10.452999114990234, "umap_1": 7.272473335266113, "region": "Scandinavian", "recipe": "Scandinavian Rice Pudding", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/139310", "like": 0}, {"umap_0": -0.5004931688308716, "umap_1": 7.338395118713379, "region": "Eastern European", "recipe": "Catfish in Sauerkraut", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105709", "like": 0}, {"umap_0": 10.01169490814209, "umap_1": 7.774265766143799, "region": "Indian Subcontinent", "recipe": "Baklava - An Indian Milk Sweet In Sugar Syrup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/66702", "like": 0}, {"umap_0": 0.15904690325260162, "umap_1": 8.337121963500977, "region": "South American", "recipe": "Tender Braised Beef Short Ribs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/98623", "like": -1}, {"umap_0": -0.9758134484291077, "umap_1": 11.048715591430664, "region": "Middle Eastern", "recipe": "Turkish Marinade (Beef & Lamb Kabobs)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70190", "like": 1}, {"umap_0": -1.8655471801757812, "umap_1": 7.9572038650512695, "region": "Indian Subcontinent", "recipe": "Romaine Salad with Grilled Vegetables", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/66478", "like": 1}, {"umap_0": 3.9817955493927, "umap_1": 9.785297393798828, "region": "Japanese", "recipe": "Inari Zushi", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70458", "like": 0}, {"umap_0": 9.90712833404541, "umap_1": 7.746610641479492, "region": "Northern Africa", "recipe": "Bourtaka Muhallabieh (Orange Custard With Caramel)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/50980", "like": 0}, {"umap_0": 0.7801458835601807, "umap_1": 11.89452075958252, "region": "Indian Subcontinent", "recipe": "Cottage Cheese (paneer) Cutlets", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67039", "like": 1}, {"umap_0": 0.9591661691665649, "umap_1": 10.184574127197266, "region": "Spanish and Portuguese", "recipe": "Battered Grouper Bites With Jalapeno Tartar Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/140789", "like": 0}, {"umap_0": 0.8904129862785339, "umap_1": 12.776399612426758, "region": "Indian Subcontinent", "recipe": "Easy Spicy Curried Peas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/65218", "like": 0}, {"umap_0": -0.12338791787624359, "umap_1": 8.361936569213867, "region": "Eastern European", "recipe": "Lecho", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105764", "like": -1}, {"umap_0": 0.033274564892053604, "umap_1": 8.684553146362305, "region": "Central American", "recipe": "Martha Stewart's All American Meatloaf", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92963", "like": 1}, {"umap_0": 0.04600761458277702, "umap_1": 9.539316177368164, "region": "US", "recipe": "Cajun Roasted Pork Loin", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/15695", "like": 1}, {"umap_0": -1.588865041732788, "umap_1": 9.696952819824219, "region": "French", "recipe": "Ratatouille from the Ritz", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/111645", "like": 1}, {"umap_0": -1.7829601764678955, "umap_1": 7.490671634674072, "region": "Italian", "recipe": "Healthy Eggplant Parmesan (No Frying Required)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/12364", "like": 1}, {"umap_0": 0.31522831320762634, "umap_1": 5.601083278656006, "region": "Southeast Asian", "recipe": "Embutido", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3943", "like": 1}, {"umap_0": 10.354706764221191, "umap_1": 8.461705207824707, "region": "Spanish and Portuguese", "recipe": "Fig Jam Sweet Spanish Temptation!", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/141665", "like": 0}, {"umap_0": -0.5451114773750305, "umap_1": 5.423852443695068, "region": "Italian", "recipe": "Olive Garden Baked Pasta Romana", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130632", "like": 1}, {"umap_0": 1.9135979413986206, "umap_1": 5.672440528869629, "region": "South American", "recipe": "Beef and Kasha Mexicana", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/98509", "like": 1}, {"umap_0": -1.2617789506912231, "umap_1": 6.856207847595215, "region": "UK", "recipe": "Roasted Stuffed Onions - the Naked Chef, Jamie Oliver", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/103997", "like": 1}, {"umap_0": 0.22626058757305145, "umap_1": 7.87052059173584, "region": "Italian", "recipe": "Chicken Breast With Lemon Sage Butter", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130529", "like": 0}, {"umap_0": 1.2216589450836182, "umap_1": 9.630709648132324, "region": "French", "recipe": "Crock Pot -Slow Cooker French Canadian Beans", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112915", "like": 0}, {"umap_0": -0.8544538021087646, "umap_1": 8.88943099975586, "region": "Eastern European", "recipe": "Walleye Hungarian Style (S\u00fcll\u00f6szelet Magyarosan)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105622", "like": 0}, {"umap_0": 3.954008102416992, "umap_1": 9.858881950378418, "region": "Japanese", "recipe": "Sweet Potatoes Simmered With Hijiki", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/71093", "like": 0}, {"umap_0": 1.4343724250793457, "umap_1": 7.680675983428955, "region": "Scandinavian", "recipe": "Swedish Spareribs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/106075", "like": -1}, {"umap_0": 0.7790343165397644, "umap_1": 9.638144493103027, "region": "US", "recipe": "Texas New Mexico Chili", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/18626", "like": -1}, {"umap_0": 1.2660120725631714, "umap_1": 10.12723445892334, "region": "US", "recipe": "Southern-Style Buttermilk Fried Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16229", "like": 0}, {"umap_0": 1.881528377532959, "umap_1": 7.698709011077881, "region": "Canadian", "recipe": "Porcupine Balls", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144062", "like": -1}, {"umap_0": -0.9288707375526428, "umap_1": 11.16751480102539, "region": "Spanish and Portuguese", "recipe": "Sofrito sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/141155", "like": 1}, {"umap_0": -1.4165360927581787, "umap_1": 6.273860454559326, "region": "Italian", "recipe": "Sinatra's Meatball Sandwich", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125423", "like": 1}, {"umap_0": 0.9488803148269653, "umap_1": 11.570879936218262, "region": "Indian Subcontinent", "recipe": "Biriyani", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4127", "like": 1}, {"umap_0": 8.909699440002441, "umap_1": 5.620061874389648, "region": "Deutschland", "recipe": "How to Make Quark Cheese", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137255", "like": 0}, {"umap_0": 0.017823049798607826, "umap_1": 7.319319725036621, "region": "Middle Eastern", "recipe": "Lachmajou (Middle-Eastern Lamb Dish)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61611", "like": 1}, {"umap_0": 8.319412231445312, "umap_1": 7.170512676239014, "region": "French", "recipe": "Bread Machine Sesame French Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/116408", "like": 0}, {"umap_0": -1.2656375169754028, "umap_1": 10.194904327392578, "region": "Italian", "recipe": "Carrot Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/124794", "like": 0}, {"umap_0": 0.015035233460366726, "umap_1": 10.506610870361328, "region": "Middle Eastern", "recipe": "Stuffed Eggplants With Meat (Karniyarik)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70078", "like": -1}, {"umap_0": -1.7405555248260498, "umap_1": 6.960663318634033, "region": "Italian", "recipe": "Sausage & Peppers Etc: 2 Quick Meals", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/127565", "like": 1}, {"umap_0": 9.68491268157959, "umap_1": 7.133563041687012, "region": "Mexican", "recipe": "Double Chocolate Cupcakes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/87963", "like": 0}, {"umap_0": 0.7470725178718567, "umap_1": 7.653170585632324, "region": "South American", "recipe": "Magyar Beef Paprikash", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/94614", "like": -1}, {"umap_0": 9.491979598999023, "umap_1": 8.344870567321777, "region": "UK", "recipe": "Coconut Ice - No Cook Easy Version", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/103620", "like": 0}, {"umap_0": 10.71562671661377, "umap_1": 7.951128005981445, "region": "US", "recipe": "Maple Syrup Tarts", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16410", "like": 0}, {"umap_0": 1.3340120315551758, "umap_1": 12.653389930725098, "region": "Indian Subcontinent", "recipe": "Chachchari ( Mixed Vegetables - Bengali)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/66098", "like": -1}, {"umap_0": 0.12013180553913116, "umap_1": 6.423801422119141, "region": "Indian Subcontinent", "recipe": "Hunza Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/59615", "like": 1}, {"umap_0": -1.8127301931381226, "umap_1": 9.250195503234863, "region": "Rest Africa", "recipe": "Moroccan Style Chickpea Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48159", "like": 1}, {"umap_0": -2.540347099304199, "umap_1": 8.002099990844727, "region": "Greek", "recipe": "Greek Inspired London Broil", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110617", "like": 1}, {"umap_0": -1.625109076499939, "umap_1": 5.669013500213623, "region": "Italian", "recipe": "Contadina\u00ae Italian Chili", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/12005", "like": 1}, {"umap_0": 2.9198195934295654, "umap_1": 9.796874046325684, "region": "Chinese and Mongolian", "recipe": "Light Chinese Chicken Salad With Hoisin Vinaigrette", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53172", "like": 0}, {"umap_0": 0.1132591962814331, "umap_1": 5.34034538269043, "region": "French", "recipe": "Camembert Parcel With Rhubarb and Cranberry Coulis", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/111655", "like": 1}, {"umap_0": 11.730826377868652, "umap_1": 7.70757532119751, "region": "Italian", "recipe": "A New Yorker's Real Italian Cheesecake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120660", "like": 1}, {"umap_0": -0.03750184178352356, "umap_1": 4.46916389465332, "region": "US", "recipe": "Bethany's Frito\u00ae Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/17324", "like": 1}, {"umap_0": -1.0414122343063354, "umap_1": 5.6872148513793945, "region": "US", "recipe": "Penne with Italian Sausage, Mushrooms, and Pumpkin Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/18734", "like": 1}, {"umap_0": -1.836037039756775, "umap_1": 8.983660697937012, "region": "Italian", "recipe": "Eggplant Relish", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132233", "like": 1}, {"umap_0": 0.8373492360115051, "umap_1": 11.240327835083008, "region": "Mexican", "recipe": "Mexican Enchilada Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83038", "like": 0}, {"umap_0": 10.626126289367676, "umap_1": 10.718032836914062, "region": "Mexican", "recipe": "Prickly Pear Margaritas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82898", "like": 0}, {"umap_0": -2.404245376586914, "umap_1": 8.472664833068848, "region": "Italian", "recipe": "Prosciutto Wrapped Grilled Prawns", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132078", "like": 1}, {"umap_0": -0.475350558757782, "umap_1": 11.476449966430664, "region": "Middle Eastern", "recipe": "Orange Chicken Koresh Iranian", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61911", "like": 0}, {"umap_0": 1.1926896572113037, "umap_1": 8.951848983764648, "region": "South American", "recipe": "Beef Curry With Apples and Raisins", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/98853", "like": -1}, {"umap_0": -2.483853578567505, "umap_1": 7.934386730194092, "region": "Italian", "recipe": "Penne Tricolore", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120255", "like": 1}, {"umap_0": 0.7254524827003479, "umap_1": 8.167946815490723, "region": "Eastern European", "recipe": "Hungarian Meatball Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105639", "like": 1}, {"umap_0": 10.114264488220215, "umap_1": 9.311877250671387, "region": "Spanish and Portuguese", "recipe": "Compota De Peras (Pear Compote)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/140332", "like": 0}, {"umap_0": -0.5089557766914368, "umap_1": 9.376617431640625, "region": "Caribbean", "recipe": "Jamaican Rice and Peas (Baked)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91614", "like": 0}, {"umap_0": 1.7959222793579102, "umap_1": 10.138152122497559, "region": "South American", "recipe": "My Beef Marinade and Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/94151", "like": -1}, {"umap_0": 1.5806632041931152, "umap_1": 11.400876998901367, "region": "Chinese and Mongolian", "recipe": "Elegant Shrimp on Chinese Spoons", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/52172", "like": 0}, {"umap_0": 10.686570167541504, "umap_1": 10.334814071655273, "region": "Irish", "recipe": "Irish Spring", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134755", "like": 0}, {"umap_0": 9.512006759643555, "umap_1": 6.218499183654785, "region": "Irish", "recipe": "Traditional Irish Brown Soda Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134961", "like": 0}, {"umap_0": -1.5781458616256714, "umap_1": 7.750732898712158, "region": "Italian", "recipe": "Barbecued Italian Sausage and Bean Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/130397", "like": 1}, {"umap_0": 0.4757559597492218, "umap_1": 12.604691505432129, "region": "Indian Subcontinent", "recipe": "Aloo Gobi", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64579", "like": 0}, {"umap_0": -0.22424258291721344, "umap_1": 11.056602478027344, "region": "Canadian", "recipe": "Canadian Day Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/144191", "like": 0}, {"umap_0": -0.17222923040390015, "umap_1": 9.497633934020996, "region": "Caribbean", "recipe": "Colorful Caribbean Sweet Potato Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/7986", "like": 0}, {"umap_0": -0.24111458659172058, "umap_1": 10.542080879211426, "region": "Rest Africa", "recipe": "Moroccan Chickpea Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48060", "like": 1}, {"umap_0": 11.142991065979004, "umap_1": 8.3550443649292, "region": "Mexican", "recipe": "Mexican Trifle", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84027", "like": 0}, {"umap_0": 9.90172004699707, "umap_1": 6.256960391998291, "region": "Canadian", "recipe": "Date Cake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146324", "like": 0}, {"umap_0": 9.844709396362305, "umap_1": 9.310951232910156, "region": "Deutschland", "recipe": "Hippocras (Non-Alcoholic)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138492", "like": 0}, {"umap_0": 1.7144811153411865, "umap_1": 7.089815139770508, "region": "South American", "recipe": "Ground Beef & Vegetable Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/94449", "like": -1}, {"umap_0": 10.07182502746582, "umap_1": 8.341670036315918, "region": "Caribbean", "recipe": "Coquito (Puerto Rican Eggnog)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92177", "like": 0}, {"umap_0": 0.5005300045013428, "umap_1": 12.809632301330566, "region": "Indian Subcontinent", "recipe": "Butternut Squash Coconut Curry", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4304", "like": 1}, {"umap_0": -0.4200623333454132, "umap_1": 5.337055206298828, "region": "Canadian", "recipe": "Seafood Stuffed Mushrooms", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148600", "like": 1}, {"umap_0": 11.81010913848877, "umap_1": 7.760477542877197, "region": "UK", "recipe": "Almond Roca (English Toffee)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/102568", "like": 0}, {"umap_0": 9.832840919494629, "umap_1": 7.890415668487549, "region": "Australian", "recipe": "Pikelets With Cinnamon Apple Slices", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73346", "like": 0}, {"umap_0": -1.7133979797363281, "umap_1": 6.6384172439575195, "region": "French", "recipe": "Green Bean Salad With Radishes and Prosciutto", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114693", "like": 1}, {"umap_0": 0.749729335308075, "umap_1": 5.082089900970459, "region": "French", "recipe": "French Onion Potato Casserole #5FIX", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112868", "like": 1}, {"umap_0": -1.7115132808685303, "umap_1": 9.044116973876953, "region": "Australian", "recipe": "Bubble & Squeak Patties With Tomato Salsa", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75956", "like": 1}, {"umap_0": 1.373085856437683, "umap_1": 9.704680442810059, "region": "Rest Africa", "recipe": "West African Peanut Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48277", "like": 0}, {"umap_0": 1.4935951232910156, "umap_1": 9.735342979431152, "region": "Chinese and Mongolian", "recipe": "Chinese Plum Chicken Cutlets", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55948", "like": 0}, {"umap_0": -1.5976577997207642, "umap_1": 11.886408805847168, "region": "Mexican", "recipe": "Traditional Guacamole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84631", "like": 1}, {"umap_0": -1.9662648439407349, "umap_1": 8.760674476623535, "region": "Canadian", "recipe": "Braised Cannellini Beans With Onions and Arugula", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/146341", "like": 1}, {"umap_0": -0.6250852942466736, "umap_1": 6.701230525970459, "region": "French", "recipe": "Vincent Price Soupe \u00e0 L'oignon - Onion Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112895", "like": 1}, {"umap_0": -1.2206172943115234, "umap_1": 6.755017280578613, "region": "Italian", "recipe": "Beans, Greens, and Sausage Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/131547", "like": 1}, {"umap_0": 1.0188153982162476, "umap_1": 5.508022785186768, "region": "Mexican", "recipe": "Mexi-Corn Lasagna by Dei Fratelli", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83021", "like": 1}, {"umap_0": -1.432366967201233, "umap_1": 9.989920616149902, "region": "Australian", "recipe": "My French Dressing\t2", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/75266", "like": 1}, {"umap_0": 0.4453372061252594, "umap_1": 9.032065391540527, "region": "US", "recipe": "Sausage and Shrimp Gumbo", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/14548", "like": 0}, {"umap_0": -1.2803369760513306, "umap_1": 10.824132919311523, "region": "South American", "recipe": "Citrus Chilean Sea Bass W- Pineapple Mango Salsa", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/93749", "like": 1}, {"umap_0": -2.219860792160034, "umap_1": 8.985672950744629, "region": "Spanish and Portuguese", "recipe": "Ensaladilla Tasca", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/141658", "like": 1}, {"umap_0": 10.401158332824707, "umap_1": 8.364279747009277, "region": "Indian Subcontinent", "recipe": "Shahi Tukre With Peaches and Melba", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67778", "like": 0}, {"umap_0": 3.145146369934082, "umap_1": 10.443859100341797, "region": "Korean", "recipe": "Bulgogi \"fire Meat\" With Leafy Green Vegetables and Sw", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69603", "like": -1}, {"umap_0": 0.1614750176668167, "umap_1": 12.734733581542969, "region": "Australian", "recipe": "Cauliflower With Sesame Seeds", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77711", "like": 0}, {"umap_0": -0.07009800523519516, "umap_1": 4.914054870605469, "region": "Scandinavian", "recipe": "Cream Cheese and Salmon Smorrebrod", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/139892", "like": 1}, {"umap_0": 10.870918273925781, "umap_1": 7.694238185882568, "region": "Deutschland", "recipe": "Frankfurt-Style Chocolate Pudding (Frankfurter Pudding)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/137396", "like": 0}, {"umap_0": 8.278300285339355, "umap_1": 7.1392903327941895, "region": "French", "recipe": "French Health Rolls", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115897", "like": 0}, {"umap_0": 8.452439308166504, "umap_1": 7.092415809631348, "region": "Northern Africa", "recipe": "Moroccan Semolina Soup with Milk, Anise Seeds, and Honey", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/2696", "like": 0}, {"umap_0": -1.2895585298538208, "umap_1": 11.647132873535156, "region": "Mexican", "recipe": "Guacamole: a Basic Recipe", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80240", "like": 1}, {"umap_0": 3.1594626903533936, "umap_1": 9.679027557373047, "region": "Chinese and Mongolian", "recipe": "Steamed Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55509", "like": 0}, {"umap_0": 9.92365550994873, "umap_1": 6.91334867477417, "region": "UK", "recipe": "Damp Jamaican Gingerbread (English Recipe)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/102531", "like": 0}, {"umap_0": 0.14099453389644623, "umap_1": 11.822744369506836, "region": "Indian Subcontinent", "recipe": "Baked Samosas (From the New Revised Edition Moosewood Cookbook)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64126", "like": 0}, {"umap_0": 10.13015079498291, "umap_1": 9.819299697875977, "region": "Australian", "recipe": "Lemon, Lime and Bitters Crush", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77203", "like": 0}, {"umap_0": 0.7510555386543274, "umap_1": 13.056574821472168, "region": "Canadian", "recipe": "Montreal Steak Spice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147612", "like": 0}, {"umap_0": 0.2103879153728485, "umap_1": 7.211034297943115, "region": "Belgian", "recipe": "Bloemkool Met Versche Wurst - Cauliflower With Sausage", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134251", "like": 0}, {"umap_0": -1.9002048969268799, "umap_1": 6.193087100982666, "region": "South American", "recipe": "One-Pot Macaroni With Beef and Tomatoes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/99967", "like": 1}, {"umap_0": -2.3340203762054443, "umap_1": 7.4687018394470215, "region": "Italian", "recipe": "Spaghetti with Roasted Tomatoes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125098", "like": 1}, {"umap_0": 0.5050579309463501, "umap_1": 9.32116413116455, "region": "US", "recipe": "Super Easy Sloppy Joes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/14574", "like": -1}, {"umap_0": 2.9883620738983154, "umap_1": 9.80622386932373, "region": "Chinese and Mongolian", "recipe": "Salmon with Ginger and Black Bean", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56437", "like": 0}, {"umap_0": 12.078207969665527, "umap_1": 4.6823248863220215, "region": "South American", "recipe": "Brazilian Cheese Puffs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/93321", "like": 1}, {"umap_0": 0.8912193179130554, "umap_1": 7.144341468811035, "region": "Irish", "recipe": "Chicken Pot Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/135735", "like": -1}, {"umap_0": -2.593534231185913, "umap_1": 7.8842878341674805, "region": "South American", "recipe": "Colorful Heirloom Bruschetta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100045", "like": 1}, {"umap_0": 10.912936210632324, "umap_1": 7.592945098876953, "region": "Eastern European", "recipe": "Kolache Raisin Cottage Cheese Filling", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142394", "like": 1}, {"umap_0": -0.21122437715530396, "umap_1": 7.659480571746826, "region": "French", "recipe": "Crock Pot Chicken With Mushrooms and Leeks (Low Carb)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/117175", "like": -1}, {"umap_0": -2.0493929386138916, "umap_1": 7.6341552734375, "region": "Italian", "recipe": "Goat Cheese and Artichoke Pizza", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/127680", "like": 1}, {"umap_0": -2.528930187225342, "umap_1": 7.982789039611816, "region": "Canadian", "recipe": "Broccoli and Feta Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147990", "like": 1}, {"umap_0": 11.443806648254395, "umap_1": 8.00767707824707, "region": "Scandinavian", "recipe": "Super Easy Fruit Danish", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101226", "like": 1}, {"umap_0": -1.2563352584838867, "umap_1": 10.434575080871582, "region": "Northern Africa", "recipe": "Moroccan Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/50376", "like": 1}, {"umap_0": -0.5071907043457031, "umap_1": 6.496397972106934, "region": "Canadian", "recipe": "Mediterranean Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/148402", "like": 1}, {"umap_0": 0.06120110675692558, "umap_1": 7.997251987457275, "region": "Japanese", "recipe": "Bacon Mushroom Burger", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70786", "like": -1}, {"umap_0": 0.6496170163154602, "umap_1": 9.024492263793945, "region": "Scandinavian", "recipe": "Danish Fruit Stuffed Pork Roast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101204", "like": 0}, {"umap_0": 1.8443557024002075, "umap_1": 10.97974681854248, "region": "Thai", "recipe": "Fiery Thai Beef Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/59045", "like": 0}, {"umap_0": -1.7164322137832642, "umap_1": 8.89891529083252, "region": "Italian", "recipe": "Italian Marinated Vegetables", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/120351", "like": 1}, {"umap_0": 1.1932616233825684, "umap_1": 12.024711608886719, "region": "Indian Subcontinent", "recipe": "Tandoori Grilled Chicken", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4080", "like": 0}, {"umap_0": 10.764182090759277, "umap_1": 10.989800453186035, "region": "Deutschland", "recipe": "Spezi for Grown Ups", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/107433", "like": 0}, {"umap_0": 1.3912837505340576, "umap_1": 5.971057415008545, "region": "Mexican", "recipe": "Make-Ahead Mexican Lasagna", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/84255", "like": 1}, {"umap_0": 12.073341369628906, "umap_1": 8.225969314575195, "region": "Canadian", "recipe": "Peanut Butter Crunchers 2007", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145033", "like": 0}, {"umap_0": -1.5111716985702515, "umap_1": 9.223572731018066, "region": "Italian", "recipe": "Sicilian Tuna Steaks in Onion Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122877", "like": 1}, {"umap_0": 2.3548498153686523, "umap_1": 10.851354598999023, "region": "Central American", "recipe": "Honduran Coconut Seafood Soup (Sopa Catratcha De Mariscos Con Un", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/92710", "like": 1}, {"umap_0": 1.2219387292861938, "umap_1": 12.110342025756836, "region": "Indian Subcontinent", "recipe": "Sweet Corn Biryani !", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64376", "like": 0}, {"umap_0": -1.9334834814071655, "umap_1": 6.069193363189697, "region": "Italian", "recipe": "Italian Pasta Veggie Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/10386", "like": -1}, {"umap_0": 2.841202974319458, "umap_1": 10.765084266662598, "region": "Southeast Asian", "recipe": "Chili Hot Sauce Recipe - Sriracha Style", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/62072", "like": 0}, {"umap_0": 3.505317449569702, "umap_1": 9.640971183776855, "region": "Chinese and Mongolian", "recipe": "Easy Fried Rice for Two", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53288", "like": 0}, {"umap_0": 8.23872184753418, "umap_1": 6.855097770690918, "region": "Indian Subcontinent", "recipe": "Indian Naan II", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4617", "like": 0}, {"umap_0": -1.2070578336715698, "umap_1": 11.195632934570312, "region": "Mexican", "recipe": "The Fires of Hades - Hellish Relish", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/7593", "like": 1}, {"umap_0": -1.3469449281692505, "umap_1": 8.995787620544434, "region": "Middle Eastern", "recipe": "Ghormeh Sabzi (Persian Herb Stew)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/2872", "like": -1}, {"umap_0": 11.741819381713867, "umap_1": 8.536918640136719, "region": "Irish", "recipe": "Paris Peppermint Topping", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134908", "like": 0}, {"umap_0": 3.7550482749938965, "umap_1": 10.522557258605957, "region": "Japanese", "recipe": "Japanese Potsticker Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/5001", "like": 0}, {"umap_0": -2.072842597961426, "umap_1": 8.675630569458008, "region": "Greek", "recipe": "Fat-Free Tzatziki", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/108172", "like": 1}, {"umap_0": 1.7465989589691162, "umap_1": 10.382780075073242, "region": "Southeast Asian", "recipe": "Filipino Beef Kabobs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/63719", "like": 0}, {"umap_0": -1.587270975112915, "umap_1": 11.241811752319336, "region": "Middle Eastern", "recipe": "Quick & Easy Tahini Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/62823", "like": 0}, {"umap_0": 1.2939603328704834, "umap_1": 8.155804634094238, "region": "Canadian", "recipe": "Traditional Christmas Meat Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145128", "like": -1}, {"umap_0": 0.850754976272583, "umap_1": 9.974328994750977, "region": "Australian", "recipe": "Baby Back Ribs (Slow Cooker)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73702", "like": 0}, {"umap_0": 10.84080696105957, "umap_1": 6.465611934661865, "region": "Mexican", "recipe": "Chocolate Allspice Dessert Nachos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6289", "like": 0}, {"umap_0": 1.6355795860290527, "umap_1": 9.453885078430176, "region": "Thai", "recipe": "Chili-Mushroom Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/58687", "like": 1}, {"umap_0": 11.0742769241333, "umap_1": 10.460848808288574, "region": "US", "recipe": "Vieux Carre", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16926", "like": 0}, {"umap_0": -0.011873293668031693, "umap_1": 5.467948913574219, "region": "South American", "recipe": "Cottage Cheesy Beef Bake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/97014", "like": 1}, {"umap_0": 0.707388162612915, "umap_1": 12.20598316192627, "region": "Indian Subcontinent", "recipe": "Slow Cooker Chicken Tikka Masala - Weight Watchers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/65216", "like": 0}, {"umap_0": -2.0839784145355225, "umap_1": 9.767499923706055, "region": "Canadian", "recipe": "Grilled Lemon-Basil Halibut", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142844", "like": 1}, {"umap_0": -1.3928797245025635, "umap_1": 7.954107761383057, "region": "Italian", "recipe": "Baked Orecchiette With Pork Sugo", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/128724", "like": 1}, {"umap_0": 0.37006673216819763, "umap_1": 11.647196769714355, "region": "Northern Africa", "recipe": "Fish Couscous W-Onion T'faya (ZWT-9 \u2013 Morocco)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/50404", "like": 1}, {"umap_0": -1.4682801961898804, "umap_1": 10.121813774108887, "region": "Mexican", "recipe": "Grilled Portabella Mushrooms and Veggie Fajitas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80416", "like": 1}, {"umap_0": -1.665097713470459, "umap_1": 9.799483299255371, "region": "Middle Eastern", "recipe": "Marinated Mushrooms", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/60612", "like": -1}, {"umap_0": 7.448425769805908, "umap_1": 6.933340072631836, "region": "Australian", "recipe": "Wattleseed Pasta", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77472", "like": 1}, {"umap_0": 3.251059055328369, "umap_1": 9.023836135864258, "region": "Chinese and Mongolian", "recipe": "Easy Chicken Stir-Fry With Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/53890", "like": 0}, {"umap_0": 2.5244975090026855, "umap_1": 11.083739280700684, "region": "Southeast Asian", "recipe": "Java Style Beef Sate", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3443", "like": -1}, {"umap_0": -0.5707054734230042, "umap_1": 7.356980800628662, "region": "UK", "recipe": "Poached Lobster, Scallops and Vegetables with Vermouth", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/102216", "like": 0}, {"umap_0": 0.9268041849136353, "umap_1": 5.902054309844971, "region": "Mexican", "recipe": "South of the Border Steak", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/80384", "like": 1}, {"umap_0": 0.9334036707878113, "umap_1": 8.925015449523926, "region": "Mexican", "recipe": "My Mother's Delicious Chicken Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/89480", "like": -1}, {"umap_0": -1.6990082263946533, "umap_1": 7.760260105133057, "region": "Italian", "recipe": "Spicy Seafood and Penne", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/124721", "like": 1}, {"umap_0": -2.514467477798462, "umap_1": 7.685223579406738, "region": "Italian", "recipe": "Tomato Basil Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/129930", "like": 1}, {"umap_0": 3.0204155445098877, "umap_1": 9.322197914123535, "region": "Canadian", "recipe": "Sweet & Sour Pork Crepes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147652", "like": 0}, {"umap_0": 10.36502742767334, "umap_1": 6.631762504577637, "region": "Canadian", "recipe": "Sassy's Awesome Banana Bread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145548", "like": 0}, {"umap_0": 11.079668045043945, "umap_1": 8.859467506408691, "region": "US", "recipe": "Billy's Fro-Yo Doggy Treats", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/17984", "like": 0}, {"umap_0": 0.6927990317344666, "umap_1": 6.8058271408081055, "region": "Irish", "recipe": "Southern Colcannon", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/136192", "like": 0}, {"umap_0": -0.9374880790710449, "umap_1": 9.93418025970459, "region": "US", "recipe": "Bahamian Baked Grouper", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/18507", "like": 0}, {"umap_0": 0.48706337809562683, "umap_1": 7.97437858581543, "region": "Eastern European", "recipe": "Sauteed Cabbage With Pork", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/100844", "like": 0}, {"umap_0": 11.322461128234863, "umap_1": 8.1932373046875, "region": "Middle Eastern", "recipe": "Fruit & Nut Chocolate Fudge", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/60581", "like": 0}, {"umap_0": 0.5671481490135193, "umap_1": 10.565378189086914, "region": "Northern Africa", "recipe": "Moroccan Peanut Couscous With Peas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/49699", "like": 0}, {"umap_0": 3.1680703163146973, "umap_1": 9.956693649291992, "region": "Chinese and Mongolian", "recipe": "Chinese Steamed Fish in Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/56838", "like": 0}, {"umap_0": -2.275972604751587, "umap_1": 6.432253837585449, "region": "Italian", "recipe": "Easy Bruschetta Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/132308", "like": 1}, {"umap_0": 10.261940956115723, "umap_1": 7.815501689910889, "region": "Australian", "recipe": "Pavlova With a Passionfruit Curd", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/73817", "like": 0}, {"umap_0": 0.1922290325164795, "umap_1": 11.985663414001465, "region": "Australian", "recipe": "Ainsley's Barbecue Spice Rub", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/74235", "like": 0}, {"umap_0": 1.6508421897888184, "umap_1": 11.269798278808594, "region": "Thai", "recipe": "Thai Mango Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/57597", "like": 0}, {"umap_0": -1.129408597946167, "umap_1": 5.371294021606445, "region": "Italian", "recipe": "Four Cheese Fettuccini with Prosciutto and Artichoke Hearts", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/129038", "like": 1}, {"umap_0": 3.825429677963257, "umap_1": 10.303936958312988, "region": "Korean", "recipe": "Korean Tofu & Leek BBQ", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/69583", "like": 0}, {"umap_0": 0.7130230665206909, "umap_1": 9.434370994567871, "region": "Rest Africa", "recipe": "Riz Gras - Fat Rice (Burkina Faso)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/48626", "like": -1}, {"umap_0": -0.3255823254585266, "umap_1": 11.150347709655762, "region": "Caribbean", "recipe": "Grilled Jamaican Pork Tenderloin Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91688", "like": 1}, {"umap_0": 1.8708499670028687, "umap_1": 8.618474006652832, "region": "Eastern European", "recipe": "Sultszalonnas Krumplisalata (Hot Bacon Potato Salad)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105730", "like": 0}, {"umap_0": -1.586853265762329, "umap_1": 8.754724502563477, "region": "South American", "recipe": "Brazilian Christmas Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/8332", "like": 1}, {"umap_0": 2.263772964477539, "umap_1": 10.496352195739746, "region": "Southeast Asian", "recipe": "Pickled Daikon Radish and Carrot", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3736", "like": 0}, {"umap_0": 10.011534690856934, "umap_1": 7.102960109710693, "region": "UK", "recipe": "Lily Vanilli\u2019s Bacon and Fairtrade Banana Cupcakes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/103759", "like": 0}, {"umap_0": 1.1060556173324585, "umap_1": 12.75713062286377, "region": "Australian", "recipe": "Chilli King Prawns (Shrimp) Skewers With Pistachio Coriander Rub", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/77309", "like": 0}, {"umap_0": 1.9740351438522339, "umap_1": 10.085070610046387, "region": "Indian Subcontinent", "recipe": "Chicken in Garlic Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/72231", "like": 0}, {"umap_0": 9.495906829833984, "umap_1": 5.442904472351074, "region": "UK", "recipe": "Shortbread", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/101689", "like": 0}, {"umap_0": -1.821033239364624, "umap_1": 9.254093170166016, "region": "Italian", "recipe": "Drink from the Bowl Spaghetti Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/128890", "like": 1}, {"umap_0": 3.1372594833374023, "umap_1": 9.517512321472168, "region": "Chinese and Mongolian", "recipe": "Moo Goo Gai Pan", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/55899", "like": -1}, {"umap_0": -1.1487171649932861, "umap_1": 9.068509101867676, "region": "Thai", "recipe": "Thai Fish Cakes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/59527", "like": 0}, {"umap_0": 10.898775100708008, "umap_1": 6.431585311889648, "region": "Eastern European", "recipe": "Czech Chocolate Pecan Cookies", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/142513", "like": 0}, {"umap_0": 10.298615455627441, "umap_1": 10.19249153137207, "region": "Italian", "recipe": "Jefes Grand Granita", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/121594", "like": 0}, {"umap_0": 10.321759223937988, "umap_1": 7.565423965454102, "region": "Italian", "recipe": "Easiest Amaretti Cookies Ever", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/121047", "like": 0}, {"umap_0": 3.104684352874756, "umap_1": 10.503979682922363, "region": "Indian Subcontinent", "recipe": "Superb Satay Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/68310", "like": 0}, {"umap_0": 1.2906321287155151, "umap_1": 6.730407238006592, "region": "US", "recipe": "New Mexico Green Chile Breakfast Burritos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/18614", "like": 1}, {"umap_0": 10.791954040527344, "umap_1": 8.142362594604492, "region": "Middle Eastern", "recipe": "Egyptian Palace Bread (Dessert)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/47482", "like": 0}, {"umap_0": -0.23186954855918884, "umap_1": 12.196702003479004, "region": "US", "recipe": "Southern Texas-Style Beef Barbacoa", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/17442", "like": -1}, {"umap_0": 1.8301336765289307, "umap_1": 7.218275547027588, "region": "French", "recipe": "French Dip Burgers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/116491", "like": -1}, {"umap_0": -0.21403299272060394, "umap_1": 6.477816104888916, "region": "Italian", "recipe": "Healthy Kale Breakfast Frittata", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/122174", "like": 1}, {"umap_0": -0.9929534196853638, "umap_1": 5.950178623199463, "region": "Mexican", "recipe": "Dan's Chicken Enchiladas", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79395", "like": 1}, {"umap_0": 2.2955150604248047, "umap_1": 10.812288284301758, "region": "Southeast Asian", "recipe": "Vietnamese Grilled Catfish with Noodles (Cha Ca)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/62119", "like": 0}, {"umap_0": -2.085153579711914, "umap_1": 8.688108444213867, "region": "Italian", "recipe": "Neapolitan Seafood Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125781", "like": 1}, {"umap_0": 2.82283353805542, "umap_1": 10.811625480651855, "region": "Japanese", "recipe": "The Best Salmon Marinade", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/70475", "like": 1}, {"umap_0": 10.06797981262207, "umap_1": 8.157014846801758, "region": "Italian", "recipe": "Chocolate Torrone", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/121096", "like": 0}, {"umap_0": 2.264511823654175, "umap_1": 6.063222885131836, "region": "Mexican", "recipe": "Salsa Verde Pork Burrito Bowls", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/86036", "like": 0}, {"umap_0": -0.2860279977321625, "umap_1": 5.8170294761657715, "region": "US", "recipe": "Jim's Special Cajun Scallops", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16194", "like": 1}, {"umap_0": 0.17413212358951569, "umap_1": 10.479493141174316, "region": "Mexican", "recipe": "Poached Huevos Rancheros", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83725", "like": 1}, {"umap_0": 1.1284825801849365, "umap_1": 8.573590278625488, "region": "South American", "recipe": "Island Beef Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/96824", "like": -1}, {"umap_0": 0.02151194028556347, "umap_1": 12.289113998413086, "region": "Mexican", "recipe": "Adobo De Chile", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/79278", "like": 0}, {"umap_0": -1.7122970819473267, "umap_1": 9.194269180297852, "region": "Rest Africa", "recipe": "Ethiopian Potato Salad", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/51570", "like": 0}, {"umap_0": 10.568939208984375, "umap_1": 6.90299654006958, "region": "French", "recipe": "Gingerbread French Toast", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/115028", "like": 0}, {"umap_0": -0.23653945326805115, "umap_1": 6.094488620758057, "region": "Italian", "recipe": "Italian Dressing Croutons", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/124750", "like": 0}, {"umap_0": 1.2102420330047607, "umap_1": 10.195693969726562, "region": "US", "recipe": "Cajun Baked French Fries", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/15675", "like": 1}, {"umap_0": -0.9183633923530579, "umap_1": 7.708144187927246, "region": "South American", "recipe": "Mexican Stuffed Beef Fillets", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/95756", "like": 1}, {"umap_0": 0.7877466082572937, "umap_1": 13.033647537231445, "region": "Indian Subcontinent", "recipe": "Mattar Paneer", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/65461", "like": 0}, {"umap_0": 10.983002662658691, "umap_1": 7.451921463012695, "region": "French", "recipe": "Frenchy Toast Casserole (French Toast Casserole) Ala the Cassero", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/113201", "like": 0}, {"umap_0": -1.8542791604995728, "umap_1": 5.826737403869629, "region": "Italian", "recipe": "Pasta With Lentils and Arugula (Martha Stewart)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/125029", "like": 1}, {"umap_0": -1.293904185295105, "umap_1": 7.929196357727051, "region": "Canadian", "recipe": "Mustard & Herb Grilled Pork Chops", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145858", "like": 1}, {"umap_0": -0.5371036529541016, "umap_1": 7.5515828132629395, "region": "Middle Eastern", "recipe": "Rice Seasoning Mix", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61720", "like": 0}, {"umap_0": 1.5072715282440186, "umap_1": 9.702645301818848, "region": "US", "recipe": "Barbequed Country Ribs", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16254", "like": 0}, {"umap_0": 11.291780471801758, "umap_1": 6.740469932556152, "region": "Eastern European", "recipe": "Authentic Hungarian Pastries", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105459", "like": 1}, {"umap_0": -2.1887266635894775, "umap_1": 9.002697944641113, "region": "French", "recipe": "Thon En Chartreuse (Tuna With Vegetables and Wine)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/112440", "like": 1}, {"umap_0": -0.9483489990234375, "umap_1": 9.490569114685059, "region": "Southeast Asian", "recipe": "Atsara (Papaya Relish)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/3917", "like": 0}, {"umap_0": 11.806905746459961, "umap_1": 8.421477317810059, "region": "Italian", "recipe": "Fruit and Mascarpone Italian Cheesecake-Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/121506", "like": 1}, {"umap_0": 7.4960174560546875, "umap_1": 7.033345699310303, "region": "Indian Subcontinent", "recipe": "PIAZ PARATHA (Scallion Bread)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/66793", "like": 0}, {"umap_0": 0.6915923953056335, "umap_1": 8.512727737426758, "region": "Canadian", "recipe": "Yummy Crock Pot Pork Tenderloin", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/143692", "like": 0}, {"umap_0": -1.2377650737762451, "umap_1": 5.134418487548828, "region": "Italian", "recipe": "Crock Pot Italian Bow Tie Supper", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/124648", "like": 1}, {"umap_0": -1.131126046180725, "umap_1": 5.786356449127197, "region": "South American", "recipe": "Freezer Veggie, Beef and Pasta Bake", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/94606", "like": 1}, {"umap_0": 9.31960391998291, "umap_1": 8.406059265136719, "region": "Caribbean", "recipe": "Nutmeg Syrup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91068", "like": 0}, {"umap_0": 1.755436658859253, "umap_1": 5.431872367858887, "region": "Mexican", "recipe": "Pork Tacos", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/6951", "like": 0}, {"umap_0": 0.925565242767334, "umap_1": 6.156373977661133, "region": "South American", "recipe": "Sierra Beef & Rice Supper", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/94679", "like": -1}, {"umap_0": 0.6192034482955933, "umap_1": 6.268477439880371, "region": "Mexican", "recipe": "Mexican Fiesta Casserole", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/83285", "like": 1}, {"umap_0": 2.120532751083374, "umap_1": 5.495871067047119, "region": "Mexican", "recipe": "Latin-Inspired Spicy Cream Chicken Stew", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/7142", "like": 1}, {"umap_0": -1.962687373161316, "umap_1": 10.653576850891113, "region": "French", "recipe": "Asparagus With Lemon and Tarragon", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/116117", "like": 1}, {"umap_0": 10.724434852600098, "umap_1": 9.489255905151367, "region": "Australian", "recipe": "Very Berry Fruit Terrine With Maple Custard", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76460", "like": 0}, {"umap_0": -0.3602024018764496, "umap_1": 6.830756664276123, "region": "Italian", "recipe": "Rich Italian Sausage and Potato Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/10279", "like": 0}, {"umap_0": 2.144357204437256, "umap_1": 10.131176948547363, "region": "Thai", "recipe": "Thai Yellow Curry - Vegan", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/58072", "like": -1}, {"umap_0": -0.45959705114364624, "umap_1": 8.560117721557617, "region": "Canadian", "recipe": "Slow Cooker Vegetable Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/147845", "like": 0}, {"umap_0": 0.5746748447418213, "umap_1": 6.756824970245361, "region": "French", "recipe": "Creamy Seafood Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/114655", "like": 0}, {"umap_0": 2.560509204864502, "umap_1": 9.790608406066895, "region": "Indian Subcontinent", "recipe": "Beets With Tropical Flavours", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/64534", "like": 0}, {"umap_0": 0.7873938679695129, "umap_1": 8.498421669006348, "region": "US", "recipe": "Cindi's Jambalaya Cajun Pot Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/14549", "like": 0}, {"umap_0": 0.8876485228538513, "umap_1": 5.796229362487793, "region": "US", "recipe": "Alaskan Spicy Spinach Dip", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/17288", "like": 1}, {"umap_0": 0.12840768694877625, "umap_1": 5.337678909301758, "region": "South American", "recipe": "Sopa De Pan En Cazuela (Columbian Bread Pot Soup)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/93660", "like": 1}, {"umap_0": 1.5170148611068726, "umap_1": 4.559617519378662, "region": "Mexican", "recipe": "Taco Burgers", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/78789", "like": 1}, {"umap_0": -0.2012803554534912, "umap_1": 11.142373085021973, "region": "Middle Eastern", "recipe": "Baked Couscous with Tomatoes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/61619", "like": 1}, {"umap_0": -2.366230010986328, "umap_1": 9.31108570098877, "region": "Italian", "recipe": "Sicilian Style Pasta Sauce W-Meat or Not", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/123166", "like": 1}, {"umap_0": -2.0142886638641357, "umap_1": 7.254846096038818, "region": "Italian", "recipe": "Artichoke,fresh Mozzarella Salami Sandwiches (Panini)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/129260", "like": 1}, {"umap_0": 9.940065383911133, "umap_1": 6.373366832733154, "region": "Scandinavian", "recipe": "Mom's Pepparkakor (Gingerbread Cookies)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/105879", "like": 0}, {"umap_0": 9.190016746520996, "umap_1": 8.331125259399414, "region": "Canadian", "recipe": "Blueberry Wild Rice", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145393", "like": 0}, {"umap_0": 8.31847095489502, "umap_1": 7.207501411437988, "region": "Indian Subcontinent", "recipe": "Whole Wheat Bread With Ginger & Cashews for ABM", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/67936", "like": 0}, {"umap_0": -2.2441775798797607, "umap_1": 9.45218276977539, "region": "Belgian", "recipe": "Warm Potato Salad With Lemon and Chive Vinaigrette", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/134528", "like": 1}, {"umap_0": -1.4820746183395386, "umap_1": 6.55026912689209, "region": "Italian", "recipe": "Italian Tuna Panini", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/129035", "like": 1}, {"umap_0": 10.330740928649902, "umap_1": 7.4398393630981445, "region": "French", "recipe": "French Vanilla Slices (Mille-feuilles)", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/9736", "like": 0}, {"umap_0": -2.349660873413086, "umap_1": 9.312090873718262, "region": "Spanish and Portuguese", "recipe": "Winter Gazpacho", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/13673", "like": 1}, {"umap_0": -0.73268061876297, "umap_1": 4.771425724029541, "region": "Italian", "recipe": "Spinach Calzone", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/131662", "like": 1}, {"umap_0": 1.6492486000061035, "umap_1": 7.56981897354126, "region": "Australian", "recipe": "GRPA's Best Homemade Turkey Gravy", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/76297", "like": 0}, {"umap_0": -0.5097493529319763, "umap_1": 7.268265724182129, "region": "US", "recipe": "Bonnie's Crab Cakes", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/16800", "like": 0}, {"umap_0": 11.181482315063477, "umap_1": 6.232764720916748, "region": "Eastern European", "recipe": "Raised Polish Doughnuts Paczki", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/133510", "like": 0}, {"umap_0": 10.606070518493652, "umap_1": 6.4818501472473145, "region": "Mexican", "recipe": "Mexican Almond Hot Chocolate", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82431", "like": 0}, {"umap_0": 2.331252098083496, "umap_1": 6.2352399826049805, "region": "Mexican", "recipe": "Bean and Beef Shaloupias", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/7429", "like": 1}, {"umap_0": 0.6237757205963135, "umap_1": 8.454628944396973, "region": "Canadian", "recipe": "BBQ & Garlic Crusted Roast Sirloin W- Wine Gravy", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/145066", "like": -1}, {"umap_0": -1.0780130624771118, "umap_1": 11.72840404510498, "region": "Indian Subcontinent", "recipe": "Spicy Yogurt Dressing", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/4666", "like": 0}, {"umap_0": 11.454381942749023, "umap_1": 8.859098434448242, "region": "Caribbean", "recipe": "Jamaica No Mistake Mon Coffee", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/91618", "like": 0}, {"umap_0": -1.110107183456421, "umap_1": 5.792154312133789, "region": "Italian", "recipe": "Italian Style Turkey Meatloaf", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/12654", "like": 0}, {"umap_0": 2.2700493335723877, "umap_1": 7.130560874938965, "region": "Greek", "recipe": "Kalasouna - Cheese and Onion Pie", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/110763", "like": 1}, {"umap_0": -0.15274086594581604, "umap_1": 10.90386962890625, "region": "Mexican", "recipe": "Spicy Posole Soup", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/82680", "like": 0}, {"umap_0": -1.0216495990753174, "umap_1": 8.602620124816895, "region": "Irish", "recipe": "Kenmare Bay Mussels With Wine-Cream Sauce", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/135065", "like": 0}, {"umap_0": 9.59228801727295, "umap_1": 5.764557361602783, "region": "Deutschland", "recipe": "Chocolate Hearts", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/138807", "like": 0}, {"umap_0": 10.613481521606445, "umap_1": 6.488113880157471, "region": "US", "recipe": "Mississippi Mud Cake I", "url": "https://cosylab.iiitd.edu.in/recipedb/search_recipeInfo/13791", "like": 0}]}};
var embedOpt = {"mode": "vega-lite"};
function showError(el, error){
el.innerHTML = ('<div class="error" style="color:red;">'
+ '<p>JavaScript Error: ' + error.message + '</p>'
+ "<p>This usually means there's a typo in your chart specification. "
+ "See the javascript console for the full traceback.</p>"
+ '</div>');
throw error;
}
const el = document.getElementById('vis');
vegaEmbed("#vis", spec, embedOpt)
.catch(error => showError(el, error));
})(vegaEmbed);
</script>
<h2 id="scandinavia-who-wouldve-thought">Scandinavia, who would've thought</h2>
<p>The second step is to score each "unseen" item (e.g., recipes that I don't know if I will like or not). To do so - we need to look at its neighbours. Remember, we're talking about vectors, so neighbours in this context means similar vectors. Let's take the <a href="https://en.wikipedia.org/wiki/Cosine_similarity">cosine similarity</a> of two vectors as the measure of their similarity. </p>
<p>The process to score an "unseen" recipe is then:
1. Identify its K (e.g., 10) closest neighbours
2. Calculate the average score of the neighbours (e.g., <code>+1</code> if we like, <code>-1</code> if we don't)
3. If we want to get fancy, we can weight that average with the distance to the unseen item</p>
<p>If you're the visual kind: </p>
<p><img alt="agarwall" style="border-radius: 5px;" src="https://duarteocarmo.com/images/40/agarwall.png"/></p>
<p>With the above methodology, we can score every single "unseen" recipe. We scored every liked and disliked recipe as a <code>-1</code> or a <code>+1</code>. Therefore, every unlabelled recipe will have a score between these two numbers. If that score is above <code>0</code>, I am more likely to <em>like</em> the recipe, if not, I'm more likely to <em>dislike</em> it. </p>
<p>But wait. This sounds computationally expensive.</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># count the likes and dislikes</span>
<span class="n">df</span><span class="o">.</span><span class="n">like</span><span class="o">.</span><span class="n">value_counts</span><span class="p">(</span><span class="n">normalize</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="c1"># 0 54905</span>
<span class="c1"># 1 48661</span>
<span class="c1">#-1 12091</span>
</code></pre></div>
<p>This means that for each one of the 55.000 unseen recipes, we need to calculate the distance to each one of the 60.752 seen recipes. And only then determine which are the K closest neighbours. Yeah that could take a long time. </p>
<h2 id="quick-maths-literally">Quick maths - literally</h2>
<p>Fortunately - Facebook's AI team has tackled this challenge. Not only that, they've shared it as an <a href="https://github.com/facebookresearch/faiss">open-source package</a>. Faiss, is an open -source library that does exactly what we need. It finds the most similar K vectors to the one(s) you're searching for. </p>
<p>We're not talking about 116.000 recipes anymore. That will take less than 2 seconds on my machine:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># start by taking the labeled and unlabelled embeddings</span>
<span class="n">labeled_embeddings</span> <span class="o">=</span> <span class="n">embedding_matrix</span><span class="p">[</span><span class="n">labeled_indices</span><span class="p">,</span> <span class="p">:]</span>
<span class="n">unlabeled_embeddings</span> <span class="o">=</span> <span class="n">embedding_matrix</span><span class="p">[</span><span class="n">unlabeled_indices</span><span class="p">,</span> <span class="p">:]</span>
<span class="c1"># create our index </span>
<span class="n">d</span> <span class="o">=</span> <span class="n">labeled_embeddings</span><span class="o">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="n">index</span> <span class="o">=</span> <span class="n">faiss</span><span class="o">.</span><span class="n">IndexFlatIP</span><span class="p">(</span><span class="n">d</span><span class="p">)</span>
<span class="c1"># normalize and add our labeled recipes</span>
<span class="n">faiss</span><span class="o">.</span><span class="n">normalize_L2</span><span class="p">(</span><span class="n">labeled_embeddings</span><span class="p">)</span>
<span class="n">index</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">labeled_embeddings</span><span class="p">)</span>
<span class="c1"># normalize and query for our unlabelled recipes </span>
<span class="n">faiss</span><span class="o">.</span><span class="n">normalize_L2</span><span class="p">(</span><span class="n">unlabeled_embeddings</span><span class="p">)</span>
<span class="n">r_distances</span><span class="p">,</span> <span class="n">r_indexes</span> <span class="o">=</span> <span class="n">index</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">unlabeled_embeddings</span><span class="p">,</span> <span class="n">k</span><span class="o">=</span><span class="mi">6</span><span class="p">)</span>
</code></pre></div>
<p>On larger datasets (we're talking 1M+ vectors) the exact neighbour search can be very computationally expensive. </p>
<p>With FAISS, we able to speed that up. We can do <em>approximate</em> searches to save time, we can make these calculations on GPUs. It's an awesome tool, with a great <a href="https://github.com/facebookresearch/faiss/">wiki</a>. </p>
<h2 id="icelandic-caramel-potatoes">Icelandic Caramel Potatoes</h2>
<p>Yup - back to food. </p>
<p>After some data wrangling, I was able to give a weighted recommendation to every recipe in the network:</p>
<p><img alt="recommendations" style="border-radius: 5px;" src="https://duarteocarmo.com/images/40/recommendations.png"/></p>
<ul>
<li><code>distances</code>: the distances that each one of the 10 neighbours has to the recipe in the row</li>
<li><code>scores</code>: the scores of the 10 closest neighbours to the recipe (+1 if I like, -1 if I dislike)</li>
<li><code>score_normal</code>: The average score of the 10 neighbours </li>
<li><code>score_weighted</code>: <code>score_normal</code>, weighted by <code>distance</code></li>
</ul>
<p>As you can see above - I don't think I would like that <em>Suya</em> recipe. But both French recipes on the table have perfect 1.0 scores - I should like them. In principle of course. <em>Pear Brandy Souffle</em> looks like a party I wouldn't like to get into - but hey, you only know if you try it. </p>
<p>There's another interesting question we can explore: What's my most recommended region? What is the region that suits my tastes the most? Pandas to the rescue:</p>
<p><img alt="recipe_regions" style="border-radius: 5px;" src="https://duarteocarmo.com/images/40/regions.png"/></p>
<p>Looks like French cuisine has the highest average recipe score. But Scandinavia is a close second! Who would've thought that? Maybe I do belong in Scandinavia.</p>
<h2 id="the-return-of-simple-tools">The return of simple tools</h2>
<p>Transparency is one of the biggest advantages of this method. By looking at the closest neighbours column - we are able to know <em>how</em> a certain recommendation was made. With so many ML algorithms and transformers out there - interpretability <em>is not an easy thing to land</em>. </p>
<p>Machine learning has made incredible advancements in the last 3/5 years. We have transformers, deep architectures, massive multi-billion parameter models serving users. Amidst all the advancements it's easy to get lost in adopting always the new shiny thing. Even if we don't understand how that shiny thing works. </p>
<p>There's a certain beauty to simple tools. Simple, explainable, and interpretable algorithms are a joy. And if <a href="/blog/simple-software.html">simple is good</a> - why complicate? </p>Serving models with FastAPI: It's not just about the speed2022-06-10T11:00:00+02:002022-06-10T11:00:00+02:00Duarte O.Carmotag:duarteocarmo.com,2022-06-10:/blog/serving-ml-models-fastapi.html<p><em>Disclaimer: This post was originally published in the <a href="http://blog.amplemarket.com/">Amplemarket blog</a></em></p>
<p>Serving and deploying Machine Learning models is a topic that can get complicated quite fast. At Amplemarket, my team and I, like to keep things simple. </p>
<p>Let's talk about it.</p>
<h2 id="simplicity-is-key">Simplicity is key</h2>
<p>At <a href="https://amplemarket.com/">Amplemarket</a>, we’re big fans of …</p><p><em>Disclaimer: This post was originally published in the <a href="http://blog.amplemarket.com/">Amplemarket blog</a></em></p>
<p>Serving and deploying Machine Learning models is a topic that can get complicated quite fast. At Amplemarket, my team and I, like to keep things simple. </p>
<p>Let's talk about it.</p>
<h2 id="simplicity-is-key">Simplicity is key</h2>
<p>At <a href="https://amplemarket.com/">Amplemarket</a>, we’re big fans of simplifying. We know that the less code we have to write, the fewer bugs we're likely to introduce. <a href="https://fastapi.tiangolo.com/">FastAPI</a> allows us to take a trained model and create an API for it, in less than 10 lines of code! That’s pretty incredible.</p>
<p>Let’s say you are creating a model that is trained on the Iris data set that predicts the species of a plant given some information about it. Previously, we would have saved our model to a <code>pickle</code> file, and sent it to our engineering team; perhaps we would have even scheduled a meeting with them to discuss how to use this model. We would also have sent some documentation on how to use that model and how it can inference on some data. </p>
<p>But the likelihood that something will go wrong in one of those steps is greater than we’d like.
Every time the model gets updated, we would need to have another discussion, about how the model has changed, and what gets improved - documentation would get outdated, etc.</p>
<p>To avoid dealing with that house of cards, we at Amplemarket have settled on a process that significantly reduces the complexity of deploying the machine learning models we develop.</p>
<p>As an example, the following snippet trains a classifier and saves it to the model.joblib file:</p>
<p><em>Note: To run the snippets, make sure to <code>python -m pip install scikit-learn fastapi "uvicorn[standard]"</code></em></p>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span> <span class="nn">sklearn</span> <span class="kn">import</span> <span class="n">svm</span>
<span class="kn">from</span> <span class="nn">sklearn</span> <span class="kn">import</span> <span class="n">datasets</span>
<span class="kn">import</span> <span class="nn">joblib</span>
<span class="c1"># create model</span>
<span class="n">clf</span> <span class="o">=</span> <span class="n">svm</span><span class="o">.</span><span class="n">SVC</span><span class="p">(</span><span class="n">probability</span><span class="o">=</span><span class="n">true</span><span class="p">)</span>
<span class="n">X</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">datasets</span><span class="o">.</span><span class="n">load_iris</span><span class="p">(</span><span class="n">return_X_y</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">clf</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span>
<span class="c1"># save model</span>
<span class="n">joblib</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">clf</span><span class="p">,</span> <span class="s1">'model.joblib'</span><span class="p">)</span>
</code></pre></div>
<p>With <a href="https://fastapi.tiangolo.com/">FastAPI</a>, serving your model is as simple as creating an <code>app.py</code> file with the following contents:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># app.py</span>
<span class="kn">from</span> <span class="nn">typing</span> <span class="kn">import</span> <span class="n">Optional</span>
<span class="kn">from</span> <span class="nn">fastapi</span> <span class="kn">import</span> <span class="n">FastAPI</span>
<span class="kn">import</span> <span class="nn">joblib</span>
<span class="c1"># create FastAPI app and load model</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">FastAPI</span><span class="p">()</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">joblib</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="s2">"model.joblib"</span><span class="p">)</span>
<span class="c1"># create an endpoint that receives POST requests</span>
<span class="c1"># and returns predictions</span>
<span class="nd">@app</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s2">"/predict/"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">predict</span><span class="p">(</span><span class="n">features</span><span class="p">):</span>
<span class="n">predictions</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">predict</span><span class="p">([</span><span class="nb">eval</span><span class="p">(</span><span class="n">features</span><span class="p">)])</span><span class="o">.</span><span class="n">tolist</span><span class="p">()</span>
<span class="k">return</span> <span class="n">predictions</span>
</code></pre></div>
<p>You can then launch the API with <code>uvicorn app:app --reload</code>.</p>
<p>Such a simple setup to launch an API ensures that our Machine Learning team is not limited to creating these models, but also responsible for making them available to our development team, or even directly to our users.</p>
<p><em>“You built it? You ship it”</em></p>
<h2 id="reduce-the-need-for-coordination">Reduce the need for coordination</h2>
<p>As a remote, distributed, and asynchronous team, documentation is huge for us. We don’t want to have a meeting with 5 other departments every time we build or ship a new model. We want to document as best we can, with the least effort possible.</p>
<p>With the script described above, if you visit <code>localhost:8000/docs</code> you’ll notice that your API includes some documentation out of the box:</p>
<p><img alt="API-screenshot-1" src="https://duarteocarmo.com/images/39/1.png" /></p>
<p>These docs already tell a lot about the application: what endpoints it has, what type of queries the user can send, etc. We love FastAPI because it takes little work to enrich the documentation further and minimize the need for future coordination.</p>
<p>Let’s add a couple of things to our <code>app.py</code> script:</p>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span> <span class="nn">fastapi</span> <span class="kn">import</span> <span class="n">FastAPI</span>
<span class="kn">import</span> <span class="nn">joblib</span>
<span class="c1"># some documentation in markdown</span>
<span class="n">description</span> <span class="o">=</span> <span class="s2">"""</span>
<span class="s2">## Documentation</span>
<span class="s2">**ℹ️ Read carefully before using**</span>
<span class="s2">This api allows you to predict the type of Iris plant given a list of features.</span>
<span class="s2">The features should be:</span>
<span class="s2">* sepal length in cm</span>
<span class="s2">* sepal width in cm</span>
<span class="s2">* petal length in cm</span>
<span class="s2">* petal width in cm</span>
<span class="s2">_Build by:_</span>
<span class="s2">![logo](<https://amplemarket.com/_next/image?url=</span><span class="si">%2F</span><span class="s2">svg</span><span class="si">%2F</span><span class="s2">logo.svg&w=384&q=75>)</span>
<span class="s2">"""</span>
<span class="c1"># create FastAPI app and load model</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">FastAPI</span><span class="p">(</span>
<span class="n">title</span><span class="o">=</span><span class="s2">"IRIS Classification"</span><span class="p">,</span>
<span class="n">description</span><span class="o">=</span><span class="n">description</span><span class="p">,</span>
<span class="n">version</span><span class="o">=</span><span class="s2">"0.1"</span><span class="p">,</span>
<span class="n">contact</span><span class="o">=</span><span class="p">{</span>
<span class="s2">"name"</span><span class="p">:</span> <span class="s2">"Amplemarket"</span><span class="p">,</span>
<span class="s2">"url"</span><span class="p">:</span> <span class="s2">"<https://amplemarket.com>"</span><span class="p">,</span>
<span class="s2">"email"</span><span class="p">:</span> <span class="s2">"support@yourcompany.com"</span><span class="p">,</span>
<span class="p">},</span>
<span class="p">)</span>
<span class="c1"># ... rest of the file ....</span>
</code></pre></div>
<p>If we now turn back to our docs, we see that the markdown we've added has been rendered at the top of the page. Now, when someone needs to check some details about this model, all the information that person might need is neatly described - and we even provide a support email if they run into trouble!</p>
<p><img alt="API-screenshot-2" src="https://duarteocarmo.com/images/39/2.png" /></p>
<p>But FastAPI doesn’t stop there. </p>
<p>With a couple more lines of code, and thanks to a small library called <a href="https://pydantic-docs.helpmanual.io/">Pydantic</a>, we can also add data validation to our model’s API. By doing so, API users will know what kind of data it expects to receive and what kind of data the API will respond back with.</p>
<p>We start by creating two classes, one to handle requests, and the other for responses:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># We'll take this in:</span>
<span class="k">class</span> <span class="nc">Features</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
<span class="n">sepal_length</span><span class="p">:</span> <span class="n">confloat</span><span class="p">(</span><span class="n">ge</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">le</span><span class="o">=</span><span class="mf">1.0</span><span class="p">)</span> <span class="c1"># ensures values are between 0 and 1 </span>
<span class="n">sepal_width</span><span class="p">:</span> <span class="n">confloat</span><span class="p">(</span><span class="n">ge</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">le</span><span class="o">=</span><span class="mf">1.0</span><span class="p">)</span>
<span class="n">petal_length</span><span class="p">:</span> <span class="n">confloat</span><span class="p">(</span><span class="n">ge</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">le</span><span class="o">=</span><span class="mf">1.0</span><span class="p">)</span>
<span class="n">petal_width</span><span class="p">:</span> <span class="n">confloat</span><span class="p">(</span><span class="n">ge</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">le</span><span class="o">=</span><span class="mf">1.0</span><span class="p">)</span>
<span class="c1"># with an example </span>
<span class="k">class</span> <span class="nc">Config</span><span class="p">:</span>
<span class="n">schema_extra</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">"example"</span><span class="p">:</span> <span class="p">{</span>
<span class="s2">"sepal_length"</span><span class="p">:</span> <span class="mf">0.2</span><span class="p">,</span>
<span class="s2">"sepal_width"</span><span class="p">:</span> <span class="mf">0.5</span><span class="p">,</span>
<span class="s2">"petal_length"</span><span class="p">:</span> <span class="mf">0.8</span><span class="p">,</span>
<span class="s2">"petal_width"</span><span class="p">:</span> <span class="mf">1.0</span><span class="p">,</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1"># We'll respond something like this:</span>
<span class="k">class</span> <span class="nc">Response</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
<span class="n">setosa_probability</span><span class="p">:</span> <span class="n">confloat</span><span class="p">(</span><span class="n">ge</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">le</span><span class="o">=</span><span class="mf">1.0</span><span class="p">)</span>
<span class="n">versicolor_probability</span><span class="p">:</span> <span class="n">confloat</span><span class="p">(</span><span class="n">ge</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">le</span><span class="o">=</span><span class="mf">1.0</span><span class="p">)</span>
<span class="n">virginica_probability</span><span class="p">:</span> <span class="n">confloat</span><span class="p">(</span><span class="n">ge</span><span class="o">=</span><span class="mf">0.0</span><span class="p">,</span> <span class="n">le</span><span class="o">=</span><span class="mf">1.0</span><span class="p">)</span>
<span class="c1"># with an example</span>
<span class="k">class</span> <span class="nc">Config</span><span class="p">:</span>
<span class="n">schema_extra</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">"example"</span><span class="p">:</span> <span class="p">{</span>
<span class="s2">"setosa_probability"</span><span class="p">:</span> <span class="mf">0.7</span><span class="p">,</span>
<span class="s2">"versicolor_probability"</span><span class="p">:</span> <span class="mf">0.1</span><span class="p">,</span>
<span class="s2">"virginica_probability"</span><span class="p">:</span> <span class="mf">0.2</span><span class="p">,</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>And we tweak our endpoint code:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># the endpoint</span>
<span class="nd">@app</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s2">"/predict/"</span><span class="p">,</span> <span class="n">response_model</span><span class="o">=</span><span class="n">Response</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">predict</span><span class="p">(</span><span class="n">features</span><span class="p">:</span> <span class="n">Features</span><span class="p">):</span>
<span class="n">feature_list</span> <span class="o">=</span> <span class="p">[</span>
<span class="n">features</span><span class="o">.</span><span class="n">sepal_length</span><span class="p">,</span>
<span class="n">features</span><span class="o">.</span><span class="n">sepal_width</span><span class="p">,</span>
<span class="n">features</span><span class="o">.</span><span class="n">petal_length</span><span class="p">,</span>
<span class="n">features</span><span class="o">.</span><span class="n">sepal_width</span><span class="p">,</span>
<span class="p">]</span>
<span class="n">predictions</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">predict_proba</span><span class="p">([</span><span class="n">feature_list</span><span class="p">])[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="n">predictions_clean</span> <span class="o">=</span> <span class="n">Response</span><span class="p">(</span>
<span class="n">setosa_probability</span><span class="o">=</span><span class="n">predictions</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>
<span class="n">versicolor_probability</span><span class="o">=</span><span class="n">predictions</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span>
<span class="n">virginica_probability</span><span class="o">=</span><span class="n">predictions</span><span class="p">[</span><span class="mi">2</span><span class="p">],</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">predictions_clean</span>
</code></pre></div>
<p>The two classes above are particularly strict about what our API can receive and what it will respond back with. Suppose a developer tries to query the API with a <code>petal_width</code> of 1.3. Because we’ve specified that petal width must be a number between 0.0 and 1.1, our API will reject the query and reply back with:</p>
<div class="codehilite"><pre><span></span><code><span class="c1">## request </span>
<span class="n">curl</span> <span class="o">-</span><span class="n">X</span> <span class="s1">'POST'</span> \\
<span class="s1">'<http://localhost:8000/predict/>'</span> \\
<span class="o">-</span><span class="n">H</span> <span class="s1">'accept: application/json'</span> \\
<span class="o">-</span><span class="n">H</span> <span class="s1">'Content-Type: application/json'</span> \\
<span class="o">-</span><span class="n">d</span> <span class="s1">'{</span>
<span class="s2">"sepal_length"</span><span class="p">:</span> <span class="mf">0.2</span><span class="p">,</span>
<span class="s2">"sepal_width"</span><span class="p">:</span> <span class="mf">0.5</span><span class="p">,</span>
<span class="s2">"petal_length"</span><span class="p">:</span> <span class="mf">0.8</span><span class="p">,</span>
<span class="s2">"petal_width"</span><span class="p">:</span> <span class="mf">1.1</span>
<span class="p">}</span><span class="s1">'</span>
<span class="c1">## response </span>
<span class="p">{</span>
<span class="s2">"detail"</span><span class="p">:</span> <span class="p">[</span>
<span class="p">{</span>
<span class="s2">"loc"</span><span class="p">:</span> <span class="p">[</span>
<span class="s2">"body"</span><span class="p">,</span>
<span class="s2">"petal_width"</span>
<span class="p">],</span>
<span class="s2">"msg"</span><span class="p">:</span> <span class="s2">"ensure this value is less than or equal to 1.0"</span><span class="p">,</span>
<span class="s2">"type"</span><span class="p">:</span> <span class="s2">"value_error.number.not_le"</span><span class="p">,</span>
<span class="s2">"ctx"</span><span class="p">:</span> <span class="p">{</span>
<span class="s2">"limit_value"</span><span class="p">:</span> <span class="mi">1</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">]</span>
<span class="p">}</span>
</code></pre></div>
<p>As an added bonus, the model Config classes also help provide developers with an example request and response:</p>
<p><img alt="API-screenshot-3" src="https://duarteocarmo.com/images/39/3.png" /></p>
<p>With this documentation page at hand, our users know exactly what our API is, what it <em>expects</em>, and what it will <em>reply back</em>.</p>
<p>All of this comes without us having to invest much time and effort into ensuring the documentation has all the information that future developers might need. And notice how we didn’t have to write any extra documentation. </p>
<p>Our documentation <em>is</em> our code.</p>
<h2 id="make-it-fast-enough">Make it fast (enough)</h2>
<p>Python is far from the fastest language out there, nor does it claim to be. We don’t use Python for its speed, but for its ecosystem, especially as it relates to data science and its many needs. </p>
<p>Even with <a href="https://andrewbrookins.com/python/is-fastapi-a-fad/">several</a> <a href="https://fastapi.tiangolo.com/benchmarks/">claims</a> that FastAPI is a very performant web framework, we know we’re not using the <a href="https://www.techempower.com/benchmarks/">fastest web framework</a> out there. </p>
<p>However, even if FastAPI was slower than it currently is, we would still be willing to compromise that speed for time-to-market, documentation, and ease of use.</p>
<p>When deploying, <a href="https://tiangolo.com/">Sebastián Ramírez</a> offers a <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker">FastAPI/uvicorn high-performance docker image</a> with auto-tuning. Allowing the app to scale according to the number of available CPU cores on the machine it's running on:</p>
<div class="codehilite"><pre><span></span><code><span class="k">FROM</span><span class="w"> </span><span class="s">tiangolo/uvicorn-gunicorn-fastapi:python3.9</span>
<span class="k">COPY</span><span class="w"> </span>./requirements.txt<span class="w"> </span>/app/requirements.txt
<span class="k">RUN</span><span class="w"> </span>pip<span class="w"> </span>install<span class="w"> </span>--no-cache-dir<span class="w"> </span>--upgrade<span class="w"> </span>-r<span class="w"> </span>/app/requirements.txt
<span class="k">COPY</span><span class="w"> </span>./app<span class="w"> </span>/app
</code></pre></div>
<p>If you’re running on Kubernetes or something like that, you <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker#-warning-you-probably-dont-need-this-docker-image">probably don’t need this image</a> - but if you have a simpler setup, this image will come very in handy!</p>
<h2 id="deploy-with-confidence">Deploy with confidence</h2>
<p>At <a href="https://amplemarket.com/">Amplemarket</a> we like to adopt best practices from Software Development and apply them to our Machine Learning projects. That means every model we develop and deploy is version controlled, tested, and continuously deployed.</p>
<p>Using CI/CD automation, we can continuously deploy our model and code to several targets (e.g., staging and production). Allowing us to serve different versions of our model in different endpoints, and roll back with ease. </p>
<p>FastAPI also allows us to <a href="https://fastapi.tiangolo.com/tutorial/testing/">easily test</a> our code. This is especially important when we are inferencing. What if we receive a different set of numbers? Will we make a prediction? What if the user sends us a string, and it gets evaluated as a float? How do we account for that? Testing matters. And FastAPI allows us to do it with ease.</p>
<h2 id="closing-thoughts">Closing thoughts</h2>
<p>FastAPI has been particularly valuable when serving our Machine Learning models. Our development team is especially happy with the high level of documentation and data validation that our APIs offer and our users also get those benefits.</p>
<p>Thanks to FastAPI, we’ve been able to predict with confidence, and I hope you got some inspiration from this post to gain confidence as well.</p>
<p><em>Note: This is also a show of appreciation to the incredible work of FastAPI’s lead developer <a href="https://tiangolo.com/">Sebastián Ramírez</a>.</em></p>Mac apps you didn't know you needed2022-04-12T09:30:00+02:002022-04-12T09:30:00+02:00Duarte O.Carmotag:duarteocarmo.com,2022-04-12:/blog/incredible-mac-apps.html<p>I'm a bit of an <a href="https://www.urbandictionary.com/define.php?term=iSheep">iSheep</a>. I didn't even know that term existed until a colleague used it on me a couple of years ago. But this is not an Apple vs. Windows (vs. Linux) post. I like my Mac, you might prefer your Windows or Linux machine - that's fine …</p><p>I'm a bit of an <a href="https://www.urbandictionary.com/define.php?term=iSheep">iSheep</a>. I didn't even know that term existed until a colleague used it on me a couple of years ago. But this is not an Apple vs. Windows (vs. Linux) post. I like my Mac, you might prefer your Windows or Linux machine - that's fine. This post focuses on Mac apps.</p>
<p>I've worked remotely for almost 3 years now - and the importance of little things starts showing. Those things that make my day easier, more pleasant, more productive. From the <a href="/blog/how-to-work-from-home-revisited">desk I sit at</a>, to the <a href="/blog/vim-for-python-development-and-not-only">editor</a> I use, these things <em>matter</em>.</p>
<p>There's a certain <em>magic</em> to software that makes everyday work just a <em>little</em> more enjoyable and productive. Here's a list of apps that help me achieve just that. </p>
<h3 id="meetingbar"><a target="_blank" href="https://meetingbar.onrender.com/">MeetingBar</a></h3>
<p>There are few things in life I hate more than an Outlook notification 10 minutes before my next meeting. Especially in a remote setting. Yes, I want to know when the next meeting will take place - but without everything buzzing all the time. MeetinBar does just that. Your next meeting in your menu bar. When it's time - hit your shortcut, hit it, and you're there. </p>
<h3 id="itsycal"><a target="_blank" href="https://www.mowglii.com/itsycal/">Itsycal</a></h3>
<p>I like Apple's Calendar app (yeah, iSheep - I told you) - but during a workday, often, you just want to check a simple date. "Are you available on the 5th of July?", "What are you doing on week #34?". These are though questions. Itsycal answers all those, right in your menu bar, in a couple of clicks.</p>
<h3 id="maestral"><a target="_blank" href="https://maestral.app/">Maestral</a></h3>
<p>I still use Dropbox. It's not the best Cloud service, but it was the first I used. There's one thing I can't stand though- their Mac app - always trying to push the next big Dropbox thing on me, eating my RAM, or annoying me with pop ups. I <em>just</em> want file sync. Maestral is a lightweight and open source alternative client that does Dropbox file sync - and nothing more - without annoying me or eating my RAM. 100% open-source - what an app. </p>
<h3 id="clocker"><a target="_blank" href="https://abhishekbanthia.com/clocker/">Clocker</a></h3>
<p>Who likes dealing with time zones? I certainly don't. 8AM in Copenhagen, it's 7AM in Lisbon, which in Singapore means...? I have no clue. Clocker solves just that. In a few clicks I can select a time, see what it corresponds to in other time zones, and copy all those to my clipboard. Done. No more timezone hell. </p>
<h3 id="raycast"><a target="_blank" href="https://www.raycast.com/">Raycast</a></h3>
<p>For years Spotlight search was good enough. Then I started using <a href="https://www.alfredapp.com/">Alfred</a>, which was pretty awesome. Now I use Raycast, which is even better. I think of it as Spotlight on steroids (I really hate that expression). I can find files super fast, access my clipboard history, search messages on Slack, search my Google Drive, tweet, check my schedule.. You get my point - go give it a shot. </p>
<h3 id="podcastmenu"><a target="_blank" href="https://github.com/insidegui/PodcastMenu">PodcastMenu</a></h3>
<p><a href="https://overcast.fm/">Overcast</a> is my favourite podcast app. When working at my desk - I listen to podcasts sometimes, <em>especially</em> if I'm doing something repetitive (e.g., bookkeeping for example). PodcastMenu puts Overcast right in my menu bar. I also syncs perfectly with the mobile version - so that I can keep listening my pods when I leave my place.</p>
<h3 id="textsniper"><a target="_blank" href="https://textsniper.app/">TextSniper</a></h3>
<p>Someone sends me a bad scan of a document and there's a number I need to copy from it. There's a weird pdf that I need to copy a reference from. What do I do? I used to look at them one-by-one and copy them over. Now.. I just hit CMD+Shift+2 and this uses OCR for me to copy the text from it. This has saved me <em>at least</em> an hour of my life. </p>
<h3 id="rectangle"><a target="_blank" href="https://rectangleapp.com/">Rectangle</a></h3>
<p>We agree. Windows management in MacOS is.. Lacking to say the least. For a long time, I used <a href="https://www.spectacleapp.com/">Spectacle</a> to manage my windows, and I really liked it. Now that Spectacle is not in active development anymore, the predecessor seems to be Rectangle. A free and open-source option, which has served me very well, and I can definetly recommend. </p>
<h3 id="stats"><a target="_blank" href="https://github.com/exelban/stats">Stats</a></h3>
<p>OK, you don't exactly <em>need</em> this one. But I like to glance at my menu bar app to see my RAM, SSD, and CPU stats. Particularly if I'm doing something in the <em>heavier</em> side. Stats is a free and open source alternative to the popular <a href="https://bjango.com/mac/istatmenus/">iStat Menus</a> - that sticks to the basics. It allows me to customize whatever I want to see in my menu bar and keep an eye on the state of my Mac. </p>
<h2 id="final-thoughts">Final thoughts</h2>
<p>You'll notice that <em>at least</em> 7 out 9 applications I mentioned are free <em>and</em> open source. Not only that, but the developers are also regularly pushing updates and making these apps better every day. It's incredible how good a product of passion can become. This post is my way of thanking them for their awsome work. Don't forget to also support them.</p>A simple system to stay in touch with people2022-03-21T14:30:00+01:002022-03-21T14:30:00+01:00Duarte O.Carmotag:duarteocarmo.com,2022-03-21:/blog/infrequent-tiny-crm.html<p><img src="https://duarteocarmo.com/images/37/infrequent_screenshot.png" alt="Embeddings" style="max-width:100%;"></p>
<p>Someone once told me that my professional network is one of the most important things I'll build throughout my career. For years I've struggled to find a system that would help me stay in touch with my network. So I decided to build my own - let me show you how …</p><p><img src="https://duarteocarmo.com/images/37/infrequent_screenshot.png" alt="Embeddings" style="max-width:100%;"></p>
<p>Someone once told me that my professional network is one of the most important things I'll build throughout my career. For years I've struggled to find a system that would help me stay in touch with my network. So I decided to build my own - let me show you how it works. </p>
<h2 id="the-idea">The idea</h2>
<p>The idea is pretty simple, you want to stay in touch with a group of people, by talking to them every X days/months/years. Let's say you want to keep up with Jane every two months. If two months have passed and you haven't talked, you should get nudged into doing it. </p>
<p>To solve this, I started with a recurring item in my to-do list, but it quickly got messy. I tested <a href="https://getdex.com/">Dex</a>, but they would only allow me to keep tabs on 15 people. <a href="https://www.monicahq.com/">Monica</a> looks like a fun deployment challenge - that's not what I'm looking for. </p>
<p>What I really wanted was something <em>simple</em>. Something like other <a href="https://kindle-highlights.email/">small things</a> I've built before? I bet I could build something simple using a bit of Python. </p>
<h2 id="how-it-works">How it works</h2>
<p>At the core of the tool is a simple folder. In it, every person that I want to stay in touch with, gets their own markdown file:</p>
<div class="codehilite"><pre><span></span><code>├──<span class="w"> </span>infrequent.py
└──<span class="w"> </span>people
<span class="w"> </span>├──<span class="w"> </span>john-snow.md
<span class="w"> </span>├──<span class="w"> </span>arya-stark.md
<span class="w"> </span>├──<span class="w"> </span>...
<span class="w"> </span>└──<span class="w"> </span>sansa-stark.md
</code></pre></div>
<p>At the top of the file: the person's name, our relationship, and the frequency at which we should keep in touch. After that, every entry is a header with a date of contact, and some notes about what happened in that date. Here's an example:</p>
<div class="codehilite"><pre><span></span><code>Name: John Snow
Relationship: Idol
Interval(every): 2 months
<span class="gu">## 21-03-2022</span>
<span class="k">-</span><span class="w"> </span>Was recruiting for more troops
<span class="k">-</span><span class="w"> </span>Dead walkers in the wall
<span class="gu">## 13-03-2022</span>
<span class="k">-</span><span class="w"> </span>Had to go to the wall
<span class="k">-</span><span class="w"> </span>He was starting to notice something changing in the weahter
</code></pre></div>
<p>Using a small script I call <code>infrequent.py</code>, I parse all the files in the <code>people</code> folder. The script retrieves the person's details and dates of interactions. Using some datetime logic, I then identify the people I'm late reaching out to:</p>
<div class="codehilite"><pre><span></span><code><span class="o">...</span>
<span class="n">interaction_dates</span><span class="o">.</span><span class="n">sort</span><span class="p">()</span>
<span class="n">last_interaction_date</span> <span class="o">=</span> <span class="n">interaction_dates</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="n">next_interaction_date</span> <span class="o">=</span> <span class="n">last_interaction_date</span> <span class="o">+</span> <span class="n">time_delta</span>
<span class="n">message</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2"> - </span><span class="si">{</span><span class="n">relation</span><span class="si">}</span><span class="s2"> - (Cadency: every </span><span class="si">{</span><span class="n">contact_frequency</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">delay_in_days</span><span class="si">}</span><span class="s2"> days passed since last contact)"</span>
<span class="k">if</span> <span class="n">next_interaction_date</span> <span class="o"><</span> <span class="n">today</span><span class="p">:</span>
<span class="n">to_contact</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
<span class="o">...</span>
</code></pre></div>
<p>Once every person is processed, the same script sends me an email with the people I'm late reaching out to, using <a href="https://aws.amazon.com/ses/">SES</a>. </p>
<h2 id="how-i-use-it">How I use it</h2>
<p>I store the <code>people</code> folder and the <code>infrequent.py</code> script in a GitHub repository - <a href="https://github.com/duarteocarmo/tiny-crm-demo">similar to this one</a>. Thanks to GitHub actions, the script runs every Friday morning. When it does, I receive an email with the names of people I'm late reaching out to. </p>
<p>Every time I interact with someone in the folder, I update their file, and push the changes back to GitHub. It's simple, and works surprisingly well. </p>
<p><a href="https://github.com/duarteocarmo/tiny-crm-demo">Here's a copy of my repo</a> in case you want to play around with the script. Feel free to <a href="mailto:me@duarteocarmo.com">email me</a> if you have problems getting it to run. </p>
<p><em>This post was inspired by <a href="https://sive.rs/hundreds">this</a> article</em></p>Visualizing every job in the world2022-02-10T09:00:00+01:002022-02-10T09:00:00+01:00Duarte O.Carmotag:duarteocarmo.com,2022-02-10:/blog/every-job-world.html<p><a href="https://projector.tensorflow.org/?config=https://raw.githubusercontent.com/duarteocarmo/esco-visualizations/master/projector_config.json">
<img src="https://duarteocarmo.com/images/36/every-job-world.png" alt="Embeddings" style="max-width:100%;">
</a></p>
<p>Imagine you have to classify <em>every single job title</em> in the world into 10 categories, how would you go about it? </p>
<p>This is a <em>fairly hard</em> problem to solve. However, the European Union has actually taken it on. They named it: <a href="https://ec.europa.eu/esco/portal/occupation">the ESCO project.</a> (ESCO stands for European Skills, Competences …</p><p><a href="https://projector.tensorflow.org/?config=https://raw.githubusercontent.com/duarteocarmo/esco-visualizations/master/projector_config.json">
<img src="https://duarteocarmo.com/images/36/every-job-world.png" alt="Embeddings" style="max-width:100%;">
</a></p>
<p>Imagine you have to classify <em>every single job title</em> in the world into 10 categories, how would you go about it? </p>
<p>This is a <em>fairly hard</em> problem to solve. However, the European Union has actually taken it on. They named it: <a href="https://ec.europa.eu/esco/portal/occupation">the ESCO project.</a> (ESCO stands for European Skills, Competences, Qualifications and Occupations) </p>
<p>Damn I love the EU. </p>
<p>What if we scraped their database of 3001 occupations and ran them through the famous <a href="https://en.wikipedia.org/wiki/BERT_(language_model)">BERT</a> model? We could look at all the <a href="https://ec.europa.eu/esco/portal/occupation?uri=http%3A%2F%2Fdata.europa.eu%2Fesco%2Fisco%2FC821&conceptLanguage=en&full=true#&uri=http://data.europa.eu/esco/isco/C821">alternative names</a> for each title/occupation, and build a network of jobs.</p>
<p>The result is <a href="https://projector.tensorflow.org/?config=https://raw.githubusercontent.com/duarteocarmo/esco-visualizations/master/projector_config.json">this projection</a>: a network of every job in the world, that clusters titles by similarity.</p>
<p>You can also run the PCA or t-SNE algorithms through it. These will cluster the jobs in slightly different ways. Go ahead and look for your job title on the right pane, and see the most similar jobs out there (at least according to BERT).</p>Simple software2022-01-06T00:00:00+01:002022-01-06T00:00:00+01:00Duarte O.Carmotag:duarteocarmo.com,2022-01-06:/blog/simple-software.html<p>In the summer of 2017 I wrote one of my very first programs: an algorithm that ranked leads. It would help our sales team to target the best potential customers in Boston and surrounding areas. </p>
<p>We (me and my manager at the time) were making a short trip to the …</p><p>In the summer of 2017 I wrote one of my very first programs: an algorithm that ranked leads. It would help our sales team to target the best potential customers in Boston and surrounding areas. </p>
<p>We (me and my manager at the time) were making a short trip to the local <a href="https://goo.gl/maps/8nRDzKo9VUaBxXe56">Dunkin' Donuts</a>, and I remember talking to him about what I was building. In the midst of talking about all the edge cases I had in mind, he cut me off, and said: "Duarte, <em>first</em> make it work. <em>then</em> make it pretty". He became one of my mentors.</p>
<p>At the time I didn't really get it. But this was one of <em>the</em> best pieces of advice I was ever given. </p>
<p>Don't make a "robust" plan for that weird edge case. That edge case will probably never happen. Which means you will be writing code for something that will most likely not happen (i.e. useless code). Why should you write useless code? You shouldn't. Handle that edge case when it happens, and only <em>if</em> it happens. </p>
<p>Even though words like Agile, SAFe, and LEAN have become nothing short of <em>buzzwords</em>, there's one lesson from the Agile Manifesto that I try to keep in mind: "Responding to change over following a plan". Iterate quickly, and then change your software only when required. </p>
<p>Writing complex code is not a way of demonstrating technical ability. It has the exact opposite effect. Startups and large Businesses value programs that solve problems. Of course they also value reliability and speed, but do they prefer something slow that works, or something fast that doesn't exist? </p>
<p>Scheduler, State Machine, Abstract, Controller, Operator. These words always make my complexity alarm go off. Yes, under certain circumstances they're needed, but when you have a technical discussion and these come up, it's time to take a step back and make sure that you know what you're getting into. By the time you do, it might be too late to make things simple again. </p>
<p>Some people think great software is complicated. <a href="https://instagram-engineering.com/types-for-python-http-apis-an-instagram-story-d3c3a207fdb7">Instagram</a> is a Python monolith with a few thousand Django endpoints. And even if <a href="/photos">I don't use it anymore</a>, it's great software. What makes software great is the ability to provide high value to users in a <a href="https://www.gkogan.co/blog/simple-systems/">reliable</a> and upgradable way. </p>
<p>I think of great software like I think about great architecture. There is a way of adding complexity without adding rigidity, maintaining flexibility, and breathability. And I don't think I've mastered that yet. Because great is simple, but it's also <a href="https://bigseventravel.com/how-long-to-build-the-pyramids/">hard</a>. </p>NFTs are dumb. Let's make some2021-12-26T00:00:00+01:002021-12-26T00:00:00+01:00Duarte O.Carmotag:duarteocarmo.com,2021-12-26:/blog/nftuga-nft-experimentation.html<p><a href="/blog/nftuga-nft-experimentation">English</a> | <a href="/nftuga-nft-experimentation-pt">Português</a> </p>
<p>Old people don't like new ideas. We see it everywhere around us. Our parents still don't understand most of today's tech trends. Even my dad still <em>doesn't trust</em> online shopping. Which I find hilarious.</p>
<p>The rise of <a href="https://www.theverge.com/22310188/nft-explainer-what-is-blockchain-crypto-art-faq">NFTs</a> is the first time I <em>really</em> felt old when talking …</p><p><a href="/blog/nftuga-nft-experimentation">English</a> | <a href="/nftuga-nft-experimentation-pt">Português</a> </p>
<p>Old people don't like new ideas. We see it everywhere around us. Our parents still don't understand most of today's tech trends. Even my dad still <em>doesn't trust</em> online shopping. Which I find hilarious.</p>
<p>The rise of <a href="https://www.theverge.com/22310188/nft-explainer-what-is-blockchain-crypto-art-faq">NFTs</a> is the first time I <em>really</em> felt old when talking tech. Why the hell would someone pay for a photo when you can just right-click it? It makes no sense. </p>
<p>But there's a reason I work with technology - I have a natural tendency to be curious about things like this. And I also know, that the best way to learn about something - is to build it. </p>
<p>So I decided to built some NFTs. I called them: <em>NFTugas</em>.</p>
<p><img alt="training-nftuga-gif" src="https://duarteocarmo.com/images/nftuga/nftuga-gif.gif" /></p>
<h2 id="artificially-generated-faces-of-portuguese-politicians">Artificially generated faces of Portuguese politicians</h2>
<p>From what I've noticed, most NFTs look pretty similar. Their usually a collection of pixelated avatars. Each one having different combinations of certain attributes (e.g., like <a href="https://opensea.io/collection/boredapeyachtclub">these</a> or <a href="https://www.larvalabs.com/cryptopunks">these</a>). The look all the same - and we're making art over here - so we'll take another route.</p>
<p>For a long time I've been pondering on the idea of making artificially generated faces of Portuguese politicians. Stupid right? I know - but in my head it does sound kind of artistic. </p>
<p><a href="https://en.wikipedia.org/wiki/Generative_adversarial_network">GANs</a> (Generative Adversarial Networks) are what's usually used for this type of project. On a high level, you create a <em>generator</em> (e.g., make faces) and a <em>discriminator</em> (e.g., tells if faces are fake or real). <em>Training</em> a GAN means battling the generator against the discriminator for a long period of time. As the generator tries to trick the discriminator more and more, it starts coming up with some pretty weird faces.</p>
<p><center>
<img alt="raw-dataset" src="https://duarteocarmo.com/images/nftuga/raw-images.png" />
</center></p>
<h2 id="teaching-a-model-how-to-make-faces">Teaching a model how to make faces</h2>
<p>The premise was set - I <a href="https://github.com/duarteocarmo/nftuga/blob/master/download_images.py">downloaded</a> 1500 photos of past and present members of the Portuguese Parliament (here's the <a href="https://www.kaggle.com/duarteocarmo/diplomatas-download">Kaggle dataset</a>). After some data wrangling, 8.5 hours of model training, and being blocked for using too many GPU resources, I finally got to some satisfactory results. I used an implementation of GAN in which cropped the images to the facial boundaries. If you're interested in diving deeper into the technical stuff, <a href="https://www.kaggle.com/duarteocarmo/nftuga-training">here's the Kaggle notebook</a>. </p>
<p>It was now time to take the face generator and create some NFTugas. From a pool of 100 randomly generated images, I selected 20 that I believe were <em>interesting</em>. Some look like a mix of male and female (and the latter are rare, <em>especially</em> in Portuguese Parliament), others look a bit like aliens, or not humans at all. I didn't want to give them boring names such as "BORED APE #007". So I scrapped names of Portuguese villages from the web, and assigned them to the 20 selected images (names like <em>fanhais</em>, or <em>charneca</em>). </p>
<p><center>
<img alt="model-results" src="https://duarteocarmo.com/images/nftuga/model-results.png" />
</center></p>
<h2 id="from-pngs-to-nfts-a-bumpy-road">From PNGs to NFTs: A bumpy road</h2>
<p>I'm familiar with Ethereum and Bitcoin. Recently, I've been hearing a lot about <em><a href="https://solana.com">Solana</a></em> as well. <em>Supposedly</em>, Solana is faster, better for the environment, NFT friendly, and cheaper to operate on. I like cheap, and I would also say I'm a pretty big fan of our Planet - so these NFTs would be <a href="https://www.sofi.com/learn/content/what-is-nft-minting/">minted</a> on Solana. </p>
<p>I investigated how the hell one is supposed to create NFTs on Solana. The easiest way would be to use things like <a href="https://opensea.io">Opensea</a> or <a href="https://solsea.io/">Solsea</a>. These basically let you upload an image, and automatically create NFTs from it. That sounds too easy, and not very educational, at least for me.</p>
<p>While researching, I came accross <a href="https://github.com/metaplex-foundation/metaplex">Metaplex</a>, a "protocol built for developers to create NFTs on Solana" - that's what they call it. It's just like a tool to conduct NFT operations on Solana. I started by creating a <a href="https://docs.metaplex.com/create-store/init-store">Storefront</a> for NFTuga - but it ended up being incredibly slow and laggy. After that, I decided I would be happy to simply put the NFTugas on the chain. To do it, I used something called the <em>Candy-Machine</em>. Candy-machines allow you to take <code>png</code> files and mint them into the block-chain, without having to create a whole storefront for it.</p>
<h2 id="nftugas-on-the-solana-blockchain">NFTugas on the Solana blockchain</h2>
<p>After some trial and a lot of error, I did managed to mint all 20 unique NFTugas into the Solana blockchain. I'm surprised by how immature some of the developer tooling is - at least on Solana. Also, transactions on the chain seem to be <em>very</em> expensive. I spent about ~30 EUR to mint (e.g., create) about 20 NFTs (we are talking no more than 2MB). </p>
<p>So are NFTs stupid? Yeah. As stupid as a <a href="https://news.artnet.com/market/maurizio-cattelan-banana-art-basel-miami-beach-1722516">banana on a wall selling for 120.000 USD</a>. The value of objects is only determined by what individuals are willing to pay for them. If people believe that a digital token on Ethereum is worth a million dollars, who the hell am I to prove them wrong? </p>
<p>I <em>did</em> learn a lot during the process, which was my main goal. And even though I wasn't totally sold on the concept, I did end up with 20 unique items in a database that might exist for a long time. Bobino already asked me for one, and I'll give a couple away to friends as well. </p>
<p>If you, dear reader are interested in any of these, leave me an email with your public key address on Solana, or fill out <a href="https://forms.gle/q9NeyfQdwbFBaSbc8">this</a> form, and I'll send you one as well. </p>
<p>Here's the list to all 20 NFTugas, with links to their location on the Solana blockchain:</p>
<ul>
<li><a href="https://explorer.solana.com/address/EmfVGHYqTa76x82jh8133Hp6iQvE43e8NSimfm4jXywq">gasparões</a> - <em>Sold</em></li>
<li><a href="https://explorer.solana.com/address/HLugPDkBNZfgFhvuHeYxP5W9LEYbQi2BmPaYkyek7vKm">cetos</a> - <em>Reserved</em></li>
<li><a href="https://explorer.solana.com/address/BU1ZcT5xthBfiF9tgSKUACVKdCEvvZppbST2Eh7gHz9H">cumieira</a> </li>
<li><a href="https://explorer.solana.com/address/">ameais</a></li>
<li><a href="https://explorer.solana.com/address/GG2wNV2gJTgnsfNbryc3Eb7pKHvxr1hEMU192y6pxtUY">fanhais</a></li>
<li><a href="https://explorer.solana.com/address/391L2c8ZDHZExvfN6joy36Pna4K1pLEPBYz6Ay7wo5zM">sernelha</a></li>
<li><a href="https://explorer.solana.com/address/8hf2UiWPtpmuE7gPFu3D2cU3b4z2PRNHG9BxSUVwvkaR">charneca</a></li>
<li><a href="https://explorer.solana.com/address/85Cm9f2XUWSEsCWwHibce2miitcrz2ajCvx6AQ2ACmpd">albarraque</a></li>
<li><a href="https://explorer.solana.com/address/F7ni1Qa9iSiVK8yLr4ZwPUKbAriRzaNUjeTcHUqgW1bQ">cernadela</a></li>
<li><a href="https://explorer.solana.com/address/6pxqLQs9w4c2tyKJ4jRnpFcdi1G5Zo31McnqzihmNSxp">cavada_nova</a></li>
<li><a href="https://explorer.solana.com/address/7niUipVkr58B6zfdx92VUNak1CBWxMfEaAu3MJ5xy8Zv">moita_redonda</a></li>
<li><a href="https://explorer.solana.com/address/GSaAtwFjja979nSYeK7jYJ5rF5teDKGHyie2MPjV7KXG">gradissimo</a></li>
<li><a href="https://explorer.solana.com/address/Caiv1ZKkqxg4x2tKK422ny51MDuvCqkSgnX8jbkRYspj">senhor_da_serra</a> - <em>Reserved</em></li>
<li><a href="https://explorer.solana.com/address/ESRtgAmNRaxupepvuFD61JFDS85j9YRfc6cDJX633Uw6">torre_dos_namorados</a></li>
<li><a href="https://explorer.solana.com/address/AntpwziEwHw9SaSAUF1cpXysDbVrfnZfzbB61jSC6DP1">santana</a></li>
<li><a href="https://explorer.solana.com/address/HiRHzSe8CCjTqdGTtojKiKf45t3WJsPieu54Vd2XAEJP">cacela_velha</a></li>
<li><a href="https://explorer.solana.com/address/gNZ6g1jn1QRmSNuaHLaLSqpZebZT4fEgfy8R14rTBHS">arrota_da_moita</a></li>
<li><a href="https://explorer.solana.com/address/CYDXjb7D4rkTt1JWvc7DSRtf5pRWADFTiNJGRuUMi3kQ">ribolhos</a></li>
<li><a href="https://explorer.solana.com/address/7LQ2r5p7cQrabyWK8hgHEcHnasMkqabwyrpY2ikPrDqW">quintas da torre</a></li>
<li><a href="https://explorer.solana.com/address/GiB3Goa2nEBFKLdZjNxrXGjBfNasEXopCR18NaUTR2fc">helenos</a></li>
</ul>Os NFTs são estúpidos. Bora fazer uns2021-12-26T00:00:00+01:002021-12-26T00:00:00+01:00Duarte O.Carmotag:duarteocarmo.com,2021-12-26:/nftuga-nft-experimentation-pt.html<p><a href="/blog/nftuga-nft-experimentation">English</a> | <a href="/nftuga-nft-experimentation-pt">Português</a> </p>
<p>As pessoas mais velhas não gostam de ideias novas. Os nossos pais e avós não percebem a maior parte das novidades de tecnologia que estão a nossa volta. Até o meu pai às vezes diz que <em>não confia</em> em shopping online. Cago-me a rir. </p>
<p>A primeira vez que …</p><p><a href="/blog/nftuga-nft-experimentation">English</a> | <a href="/nftuga-nft-experimentation-pt">Português</a> </p>
<p>As pessoas mais velhas não gostam de ideias novas. Os nossos pais e avós não percebem a maior parte das novidades de tecnologia que estão a nossa volta. Até o meu pai às vezes diz que <em>não confia</em> em shopping online. Cago-me a rir. </p>
<p>A primeira vez que eu me senti velho no mundo da tecnologia foi com o aparecimento dos <a href="https://www.theverge.com/22310188/nft-explainer-what-is-blockchain-crypto-art-faq">NFTs</a>. Porque é que eu havia de pagar por uma fotografia na internet sabendo que posso simplesmente fazer um screenshot? Não faz sentido nenhum. </p>
<p>Mas se há uma razão pela qual eu trabalho em tecnologia é porque estas coisas me deixam curioso. E a melhor matar a curiosidade, é meter as mãos na massa. </p>
<p>Decidi fazer uns NFTs. Chamei-lhes: <em>NFTugas</em>. </p>
<p><img alt="training-nftuga-gif" src="https://duarteocarmo.com/images/nftuga/nftuga-gif.gif" /></p>
<h2 id="caras-deputados-geradas-artificialmente">Caras deputados geradas artificialmente</h2>
<p>Todos os NFTs que eu vejo na Internet são um bocado iguais. Uma colecção de avatares com diferentes combinações de certas características (e.g., tipo <a href="https://opensea.io/collection/boredapeyachtclub">estes</a>, ou <a href="https://www.larvalabs.com/cryptopunks">estes</a>). Mas nós estamos aqui para fazer arte - portanto decidi fazer uma coisa ligeiramente diferente..</p>
<p>Há muito tempo que tenho uma ideia na minha cabeça: Gerar caras de deputados Portugueses só com inteligência artificial. Estúpido não é? Completamente - mas pode ser divertido. E isso é o que interessa. </p>
<p>Para este tipo de projecto, costumam-se usar <a href="https://en.wikipedia.org/wiki/Generative_adversarial_network">GANs</a> (Generative Adversarial Networks). Em resumo, cria-se um modelo <em>generator</em> (e.g., cria novas caras) e um modelo <em>discriminator</em> (e.g., detecta se as caras são falsas ou não). "Treinar" este modelo significa por o nosso gerador contra o nosso discriminador durante um longo período de tempo. Quanto mais a batalha se prolonga, mais o <em>generator</em> começa a tentar enganar o nosso <em>discriminator</em>, e acaba por criar umas caras bem estranhas. </p>
<p><center>
<img alt="raw-dataset" src="https://duarteocarmo.com/images/nftuga/raw-images.png" />
</center></p>
<h2 id="ensinar-um-modelo-a-criar-caras">Ensinar um modelo a criar caras</h2>
<p>Ideia decidida, era hora de criar o nosso dataset. Consegui <a href="https://github.com/duarteocarmo/nftuga/blob/master/download_images.py">scrappar</a> do site do parlamento cerca de 1500 caras de deputados (<a href="https://www.kaggle.com/duarteocarmo/diplomatas-download">dataset final</a>) - alguns em funções, outros reformados. Depois de alguma ginastica, e de treinar os nossos modelos durante ~8 horas, finalmente consegui uns resultados interessantes. Além disso, usei deteção facial para reduzir as fotografias só ás caras em questão e melhorar os resultados. Deixo o link do <a href="https://www.kaggle.com/duarteocarmo/nftuga-training">notebook</a> para os mais curiosos. </p>
<p>Era hora de criar uns NFTs. Com o nosso <em>generator</em> criado, gerei cerca de 100 caras de deputados. Destas, selecionei 20 que achei mais <em>interessantes</em>. Algumas parecem uma mistura de homens e mulheres (não há muitas), umas parecem extra-terrestres, outras, parece que fizeram uma cirurgia plástica que correu mal. Não lhes queria dar um nome qualquer (<em>tipo NFTuga #004</em>) - portanto decidi dar um nome de uma aldeia portuguesa a cada um deles. Há um chamado <em>Gasparões</em>, outro chamado <em>Quintas da Torre</em>, etc. (lista completa em baixo do post)</p>
<p><center>
<img alt="model-results" src="https://duarteocarmo.com/images/nftuga/model-results.png" />
</center></p>
<h2 id="de-pngs-a-nfts-nada-facil">De PNGs a NFTs: Nada fácil</h2>
<p>Conheço razoavelmente os mundos do Ethereum e Bitcoin, mas recentemente tenho ouvido falar bastante de <em><a href="https://solana.com">Solana</a></em>. Supostamente é mais rápida, melhor para o nosso ambiente, e mais propicia para NFTs. Ora, eu gosto de coisas baratas, principalmente se fazem bem a nosso ambiente. Estava escolhida a blockchain então - estes NFTs iam ser <a href="https://www.sofi.com/learn/content/what-is-nft-minting/">criados</a> na Solana. </p>
<p>Comecei a investigar o que é que queria dizer <em>criar</em> um NFT. A maneira mais fácil claro, seria usar coisas como o <a href="https://opensea.io">OpenSea</a> ou no nosso caso, o <a href="https://solsea.io/">Solsea</a> onde podemos fazer o upload de um <code>png</code>, e deixar que eles criem automaticamente um NFT. Fácil? Sim. Demasiado até. Não estou interessado em coisas fáceis. Estou mais interessado em perceber como é que isto funciona. </p>
<p>Enquanto estava a estudar a assunto, descobri uma framework chamada <a href="https://github.com/metaplex-foundation/metaplex">Metaplex</a>. Eles descrevem-se como "a protocol built for developers to create NFTs on Solana". Parece ser o que eu estava a procura. Comecei por criar uma loja online para os meus NFTs viverem, mas a loja era super lenta e nada estável. Finalmente, acabei por descobrir um conceito chamado "<a href="https://docs.metaplex.com/create-candy/introduction">Candy-machine"</a>. É basicamente uma ferramenta que nos permite transformar todos as nossas caras em NFTs seguindo uma data de instruções e comandos específicos definidos na documentação. </p>
<h2 id="nftugas-na-blockchain-solana">NFTugas na blockchain Solana</h2>
<p>Depois de muitas tentativas falhadas, la acabei por conseguir criar os 20 NFTugas na blockchain. Fiquei surpreendido pela qualidade das ferramentas que existem no espaço (pelo menos no espaço Solana) que deixam um pouco a desejar. Além de que as transações na blockchain parecem ser <em>bastante</em> caras. No total, acabei por gastar a volta de 30 EUR só para os criar (não estamos a falar de mais de 2 MB de imagens).</p>
<p>Também acabei por aprender bastante durante o processo - o meu objectivo principal. Fico feliz também por ter 20 itens "únicos", criados por mim (or por um AI que eu criei) numa blockchain. Se calhar ficarão lá muito tempo. Se calhar isto é tudo uma bolha e rebenta amanhã. Segue jogo. </p>
<p>Continuam a ser estúpidos? Sim, tão estúpidos quanto <a href="https://news.artnet.com/market/maurizio-cattelan-banana-art-basel-miami-beach-1722516">uma banana numa parede por 120.000 USD</a>. Ou seja, a arte, e o valor dos objectos é proporcional ao valor que nós lhe atribuímos. Se existem pessoas que acreditam que o valor de um token digital é superior a um milhão de euros, quem sou eu para as desmentir? </p>
<p>A Bobino já me pediu um dos NFTugas, e outros dois amigos também me pediram para lhes enviar um. Se estiveres interessado/a manda -me um email com a tua public key, ou preenche <a href="https://forms.gle/q9NeyfQdwbFBaSbc8">este</a> formulário e eu mando-te um também. </p>
<p>Deixo aqui a lista completa dos 20 NFTugas com links para os poderes ver na blockchain:</p>
<ul>
<li><a href="https://explorer.solana.com/address/EmfVGHYqTa76x82jh8133Hp6iQvE43e8NSimfm4jXywq">gasparões</a> - <em>Vendido</em></li>
<li><a href="https://explorer.solana.com/address/HLugPDkBNZfgFhvuHeYxP5W9LEYbQi2BmPaYkyek7vKm">cetos</a> - <em>Reservado</em></li>
<li><a href="https://explorer.solana.com/address/BU1ZcT5xthBfiF9tgSKUACVKdCEvvZppbST2Eh7gHz9H">cumieira</a> </li>
<li><a href="https://explorer.solana.com/address/">ameais</a></li>
<li><a href="https://explorer.solana.com/address/GG2wNV2gJTgnsfNbryc3Eb7pKHvxr1hEMU192y6pxtUY">fanhais</a></li>
<li><a href="https://explorer.solana.com/address/391L2c8ZDHZExvfN6joy36Pna4K1pLEPBYz6Ay7wo5zM">sernelha</a></li>
<li><a href="https://explorer.solana.com/address/8hf2UiWPtpmuE7gPFu3D2cU3b4z2PRNHG9BxSUVwvkaR">charneca</a></li>
<li><a href="https://explorer.solana.com/address/85Cm9f2XUWSEsCWwHibce2miitcrz2ajCvx6AQ2ACmpd">albarraque</a></li>
<li><a href="https://explorer.solana.com/address/F7ni1Qa9iSiVK8yLr4ZwPUKbAriRzaNUjeTcHUqgW1bQ">cernadela</a></li>
<li><a href="https://explorer.solana.com/address/6pxqLQs9w4c2tyKJ4jRnpFcdi1G5Zo31McnqzihmNSxp">cavada_nova</a></li>
<li><a href="https://explorer.solana.com/address/7niUipVkr58B6zfdx92VUNak1CBWxMfEaAu3MJ5xy8Zv">moita_redonda</a></li>
<li><a href="https://explorer.solana.com/address/GSaAtwFjja979nSYeK7jYJ5rF5teDKGHyie2MPjV7KXG">gradissimo</a></li>
<li><a href="https://explorer.solana.com/address/Caiv1ZKkqxg4x2tKK422ny51MDuvCqkSgnX8jbkRYspj">senhor_da_serra</a> - <em>Reservado</em></li>
<li><a href="https://explorer.solana.com/address/ESRtgAmNRaxupepvuFD61JFDS85j9YRfc6cDJX633Uw6">torre_dos_namorados</a></li>
<li><a href="https://explorer.solana.com/address/AntpwziEwHw9SaSAUF1cpXysDbVrfnZfzbB61jSC6DP1">santana</a></li>
<li><a href="https://explorer.solana.com/address/HiRHzSe8CCjTqdGTtojKiKf45t3WJsPieu54Vd2XAEJP">cacela_velha</a></li>
<li><a href="https://explorer.solana.com/address/gNZ6g1jn1QRmSNuaHLaLSqpZebZT4fEgfy8R14rTBHS">arrota_da_moita</a></li>
<li><a href="https://explorer.solana.com/address/CYDXjb7D4rkTt1JWvc7DSRtf5pRWADFTiNJGRuUMi3kQ">ribolhos</a></li>
<li><a href="https://explorer.solana.com/address/7LQ2r5p7cQrabyWK8hgHEcHnasMkqabwyrpY2ikPrDqW">quintas da torre</a></li>
<li><a href="https://explorer.solana.com/address/GiB3Goa2nEBFKLdZjNxrXGjBfNasEXopCR18NaUTR2fc">helenos</a></li>
</ul>How to work from home - revisited2021-11-21T00:00:00+01:002021-11-21T00:00:00+01:00Duarte O.Carmotag:duarteocarmo.com,2021-11-21:/blog/how-to-work-from-home-revisited.html<p><img alt="setup-image-perspective" src="https://duarteocarmo.com/images/setup_post_2_alternate.jpeg" /> </p>
<h3 id="revisiting">Revisiting</h3>
<p>Back in March last year, <a href="/blog/how-to-work-from-home">I wrote</a> about how I was keeping sane while working from home. From then to now, a lot of things have changed. New house, new job, new habits. Not all has changed though. COVID is, and will be for some time, a reality. And …</p><p><img alt="setup-image-perspective" src="https://duarteocarmo.com/images/setup_post_2_alternate.jpeg" /> </p>
<h3 id="revisiting">Revisiting</h3>
<p>Back in March last year, <a href="/blog/how-to-work-from-home">I wrote</a> about how I was keeping sane while working from home. From then to now, a lot of things have changed. New house, new job, new habits. Not all has changed though. COVID is, and will be for some time, a reality. And with it, work-from-home is here to stay. While some people hate working from home, I for another hand, find it to be something very close to "the future of work". Whatever that is.</p>
<h3 id="setup">Setup</h3>
<p><a href="/blog/how-to-work-from-home#have-a-setup">On a previous post</a>, I talked about the importance of having a home setup. And argued that you should aim to have a better one than in your office. Some of these devices might seem like some stupidly expensive objects. But saving in your home setup will cost you a lot of money (and health) in the long term. Save a lot of money by not buying a chair - and complain about your back after working for 2 weeks on it. I value my health - so I invest in it.</p>
<p>I've upgraded to a <a href="https://www.lg.com/uk/monitors/lg-35wn75c">larger curved monitor</a> with a VISMA mount. In combination with a <a href="https://www.amazon.de/-/en/gp/product/B08BYJ5BCF/ref=ppx_od_dt_b_asin_title_s05?ie=UTF8&psc=1">monitor arm</a> really wins me back a lot of desk real estate. I do live in Denmark, where it gets dark especially early (~3/4 pm). So I decided to get this <a href="https://www.amazon.de/gp/product/B08W2C5W59/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1">great monitor light bar</a> - which I have been really enjoying for the past couple of weeks.</p>
<p>I am completely sold on <a href="https://www.keychron.com/products/keychron-k2-wireless-mechanical-keyboard">Keychron</a> - I've been trying to upgrade to the <a href="https://www.keychron.com/collections/keyboard/products/keychron-k3-wireless-mechanical-keyboard?variant=32220198535257">K3</a>, but it seems impossible to buy one right now. The mouse, is still the mighty <a href="https://www.logitech.com/en-roeu/products/mice/mx-master-3-mac-wireless-mouse.910-005696.html">MX Master 3</a> - which is ridiculously expensive, but such a joy to use.</p>
<p><img alt="setup-image-front" src="https://duarteocarmo.com/images/setup_post_2_cover.jpeg" /> </p>
<h3 id="habits">Habits</h3>
<p>I'm still trying to keep <a href="/blog/how-to-work-from-home#start-the-day-right">good habits</a> while working - especially now that my default mode is working from home. I still <a href="/blog/run-every-day">run everyday</a>, always get dressed before starting to work. I still try to read the news in the morning using my <a href="https://reederapp.com/">RSS reader</a>.</p>
<p>I started to develop a taste for coffee other then <a href="https://www.amazon.de/dp/B003SG5XP0/ref=sr_1_7?keywords=nescafe+gold&qid=1585059650&sr=8-7">Nescafe</a>. I know - I'm turning a bit posh. I now order Portuguese or Italian coffee (Bobino still thinks the latter is better - I disagree). Every morning I grind it, and get the moka going.</p>
<p>When working, now more then ever, I default to turning off all my notifications. Except for a couple of contacts in my favorites. We already receive too many notifications. Apps, emails, slack, calendar - it's just too much. I decided that I don't need any of them - and that they only distract me from getting something done.</p>
<h3 id="apps-and-music">Apps and Music</h3>
<p>When working I rely on a set of highly programmable, albeit <a href="/blog/vim-for-python-development-and-not-only">archaic</a> tools - but that's a post for another time. When I'm not working with code, I use a core set of applications that help me get work done. Instead of standing in my way when I'm trying to. This includes an app that <a href="https://github.com/leits/MeetingBar">shows my next meeting</a> in my menu bar instead of sending me annoying reminders. An <a href="https://textsniper.app/">app that uses OCR</a> to copy text from any screenshot I take, and an app to <a href="https://apps.apple.com/us/app/hidden-bar/id1452453066?mt=12">keep things clean</a>.</p>
<p>Even though the amount of meetings I am involved in has been steadily increasing - I still shamelessly block my calendar for long periods of time. I reserve this time to do focused work. If you don't claim your time, nobody else will claim it for you. So block that slot.</p>
<p>For those enjoyable moments of focused work, I normally listen to some podcasts or music. For Podcasts, I highly recommend the <a href="https://changelog.com/podcasts">Changelog</a> network, for those of you in tech. For music, I'm still a big fan of those long mixes, that are actually curated by professionals, and not some AI (looking at you Spotify). <a href="https://soulection.com/tracklists/">Joe Kay</a>, <a href="https://sashamarie.co/radio">Sasha Marie</a> and <a href="https://soundcloud.com/complexion">Complexion</a> are some of the biggest "sponsors" of my work.</p>Four years of Python2021-10-06T00:00:00+02:002021-10-06T00:00:00+02:00Duarte O.Carmotag:duarteocarmo.com,2021-10-06:/blog/four-years-python.html<p>The other day I realized: I've been programming in Python for about 4 years now. I do get paid to write code, but for some reason still don't consider myself a <em>pro.</em> I did learn some valuable lessons though.</p>
<p>For those who just got started with Python, you'll hopefully take …</p><p>The other day I realized: I've been programming in Python for about 4 years now. I do get paid to write code, but for some reason still don't consider myself a <em>pro.</em> I did learn some valuable lessons though.</p>
<p>For those who just got started with Python, you'll hopefully take something out of these lessons. For the experienced, see this as a celebration of our beloved language.</p>
<h3 id="reading-is-better-than-googling">Reading is better than Googling</h3>
<p>A couple of years ago, something changed in my workflow: When learning a new library (e.g,. transformers), instead of recklessly googling for how to do things, I actually started reading the library's documentation. I've noticed that reading documentation actually gives me a much better understanding of the library and the features I want to use. Also, when doing so, I actually understand better the full power of every external dependency I add to my project, which is much more fulfilling then Googling and forgetting.</p>
<p>What led me to read more docs, was the sheer trouble in setting up Vim's auto complete. Now that I don't have it - I must say I don't miss it. (<a href="https://github.com/duarteocarmo/dotfiles/blob/38a7343b56dddc7bcd3a1625bd729d826da268b0/.config/nvim/init.vim#L36">supertab</a> is just fine, and makes me study docs when I don't know what I'm doing)</p>
<h3 id="explicit-is-better-than-implicit">Explicit is better than implicit</h3>
<p>As you get more experienced writing code, you'll start making your code more and more concise. As you optimize (e.g., list comprehensions, case matching), your code will become harder to read.</p>
<p>And I believe Python was (and <em>is</em>) designed this way. <a href="https://www.python.org/dev/peps/pep-0020/#id2">Explicit is better than implicit</a>, so be careful when mastering the full power of Python. Brandon Rhode's talk below summarizes this phenomenon perfectly:</p>
<p><center></p>
<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" src="https://www.youtube-nocookie.com/embed/S0No2zSJmks?start=869" title="YouTube video player" width="95%" height="330" frameborder="0"></iframe>
<p></center></p>
<h3 id="first-make-it-work-then-make-it-pretty">First make it work then make it pretty</h3>
<p>When all of those repos start pilling up, you'll notice that you'll start thinking of all of the smallest details your project needs to accomplish from the start. How will I test this? How will I package it? What type of abstractions will I build?</p>
<p>I still remember one of my first managers telling me <em>"first make it work, THEN make it pretty".</em> Damn that was good advice. Keep things super simple from the start, and add complexity as you come across it. You might notice some things start being duplicated, or convoluted, that's when it's time to abstract them.</p>
<h3 id="test-early-and-test-often">Test early, and test often</h3>
<p>Writing code can be an unrewarding feat. Often, you'll develop features in your code that do not directly benefit your end-users or business owners. An end-user does not care if you've used Heroku or Elastic Beanstalk or a certain class. Worse: end-users don't <em>even</em> notice it.</p>
<p>Testing is often downplayed by management. "Why are you spending a week on something that does not benefit our customers directly? That seems low priority."</p>
<p>Remember to <em>not only</em> start testing early, but to communicate to your stakeholders the importance, and benefit of testing (e.g., reliability, robustness, ability to develop faster in the future, up time..).</p>
<h3 id="continuously-learn">Continuously learn</h3>
<p>Dad's a doctor - and from a very young age I've seen him studying every weekend for a couple of hours. He also regularly goes to conferences, and learns whatever there was new to learn in his field.</p>
<p>We're not doctors, but <a href="https://www.calnewport.com/blog/2011/08/11/the-career-craftsman-manifesto/">our craft</a> lies in creating reliable, fast, and scalable systems; in this case, by leveraging Python.</p>
<p><img alt="alt-text-2" src="https://duarteocarmo.com/images/python-books.png" /></p>
<p>Whether it's contributing to open-source, going to <a href="https://pycon.org/">PyCon</a> or <a href="https://pydata.org/">PyData</a>, or answering questions in Stack Overflow - we should strive to get continuously better in our craft. Recently, <a href="https://www.manning.com/books/practices-of-the-python-pro">Practices of the Python Pro by Dane Hillard</a>, and The <a href="https://scaling-python.com/">Hacker's Guide to Scaling Python by Julien Danjou</a> have been incredibly useful in further developing my knowledge of the language.</p>
<p>The more I work with Python (and other languages), the more I fall in love with our craft. On the surface, it's pretty easy to get a small script running, and doing something simple.</p>
<p>However, as your work evolves, and you grow, things start getting complicated, convoluted, and challenging. And that's where these principles can make a difference.</p>
<p>See you out there, fellow Pythonista.</p>Self-hosting my Instagram profile2021-09-20T00:00:00+02:002021-09-20T00:00:00+02:00Duarte O.Carmotag:duarteocarmo.com,2021-09-20:/blog/self-hosting-instagram-python.html<p>After more than 5 years using Instagram, I decided it's time to move out. This "turning" point for me, is when I start loosing control and influence over the platform I'm using. This happens in a multitude of ways: Loosing control of what we consume/see (a) by means of …</p><p>After more than 5 years using Instagram, I decided it's time to move out. This "turning" point for me, is when I start loosing control and influence over the platform I'm using. This happens in a multitude of ways: Loosing control of what we consume/see (a) by means of a completely algorithmic feed, being served a multitude of ads (b), and being pushed to consume, rather then share (c).</p>
<p>So I created <a href="https://duarteocarmo.com/photos">/photos</a></p>
<p>Bulk downloading them was quite straightforward. Using Python and <a href="https://instaloader.github.com">Instaloader</a>, I was able to retrieve all of my +300 posts from Instagram, including albums. Since I'm using <a href="https://docs.getpelican.com/en/latest/">Pelican</a> for this static blog, I had to create a "page" for every one of these photos. Which is, albeit, a bit of a hack. But hey, Python is great to automate this type of thing.</p>
<p>The actual photos are now stored in a (probably insecure) S3 bucket, which I sync to a local folder. To keep things fast, I have both Cloudfront (for the photos) and Cloudflare (for the actual blog) sitting on top of them. I'm also using <a href="https://pillow.readthedocs.io/en/stable/">Pillow</a> to generate thumbnails in <code>.webp</code> format, just to ensure the <a href="https://duarteocarmo.com/photos">/photos</a> page loads relatively fast.</p>
<p>Uploading is by no means as simple as opening an app and snapping a picture. But I've created a small python script that processes a photo, generates a thumbnail, asks some questions about it, and uploads it to S3 and my blog. And that's good enough. </p>
<p>For those wondering, I still have my <a href="https://www.instagram.com/duarteoc/">Instagram profile</a> up, which now just serves to redirect people back to my website via a <a href="https://tinyurl.com/duarteintheinterwebs/">landing page</a>. Instagram blocked my url a long time ago - reasons unknown. </p>
<p>Vittoria suggested I should also email my close friends and family automatically when I upload a photo, I think that's a great idea - but probably a story for another day. </p>The short tale of an online scam2021-06-24T00:00:00+02:002021-06-24T00:00:00+02:00Duarte O.Carmotag:duarteocarmo.com,2021-06-24:/blog/tale-online-scammer-python.html<p>I'm moving places soon. I absolutely hate moving - but hey, it's like everything else in life: you push through. This time, there was a nice plot twist: someone tried to scam me online. This made things... interesting. Let's talk about it. </p>
<h2 id="when-it-sounds-too-good-to-be-true-its-because">When it sounds too good to be true it's …</h2><p>I'm moving places soon. I absolutely hate moving - but hey, it's like everything else in life: you push through. This time, there was a nice plot twist: someone tried to scam me online. This made things... interesting. Let's talk about it. </p>
<h2 id="when-it-sounds-too-good-to-be-true-its-because">When it sounds too good to be true it's because...</h2>
<p>As usual, like everyone in Denmark, I put up my old bed for sale in <a href="https://www.dba.dk/">DBA.dk</a>. It's the Danish version of Craigslist, I don't use it that much but has served useful in the past. After posting it, two days went by and nobody replied. But then I received an interesting WhatsApp message: </p>
<p><img alt="alt-text-1" src="https://duarteocarmo.com/images/30/whatsapp_screenshot.png" /> </p>
<p>Check <a href="https://github.com/duarteocarmo/dba_scam/tree/master/screenshots">this</a> link for screenshots of the whole conversation. </p>
<p>For those not fluent in Danish, "Dimitriy" (the name on his WhatsApp account) is telling me that he'll purchase the bed I'm selling. He also suggests that we should use a <em>very</em> convenient service by <a href="https://www.postnord.dk/en">PostNord</a> (the danish post company). This service supposedly arrives at my place, packages everything up, and brings it to him. Sounds super convenient. Right?</p>
<p><img alt="alt-text-1" src="https://duarteocarmo.com/images/30/whatsapp_screenshot_2.png" /> </p>
<p>He has set everything up via PostNord so that I only have to confirm receiving the money by going to the link. He even sent me a link to where I can confirm everything. Now, my Danish is certainly lacking (e.g., non-existent) - but when someone sends me a link like: </p>
<div class="codehilite"><pre><span></span><code>https://postnord-dk.delivery-85367.icu/andet-unoliving-ikea-ja-id-10807800110
</code></pre></div>
<p>My radar starts beeping - and yours should too. The page looks pretty nice - and perfectly emulates <a href="https://www.postnord.dk/en">PostNord</a>'s website. It has my name and everything - looks pretty legit:</p>
<p><img alt="alt-text-1" src="https://duarteocarmo.com/images/30/home_page.png" /> </p>
<p>After clicking the big yellow button to "confirm the transaction", I'm brought (surprising!) to a page to input my credit card details. I decided to start filling all of the credit card forms while monitoring the <code>POST</code> requests the website might be sending. </p>
<p><img alt="alt-text-1" src="https://duarteocarmo.com/images/30/card_confirmation.png" /> </p>
<ol>
<li>First I'm asked to input a credit card number and last name</li>
<li>It then asks for an expiration date and a CVC number </li>
<li>Once that is done, it prompts the user to input his/her <a href="https://en.wikipedia.org/wiki/NemID">NemID</a> username and password (e.g., the login solution used for most state services in Denmark - e.g., banks, digital post)</li>
<li>And finally - it asks for a confirmation of my bank account's balance - just to ensure they retrieve the right amount. </li>
</ol>
<p>If I had put all of this information correctly, Dimitriy would pretty much own me at this point. </p>
<p>You can check all of the web pages I went through in <a href="https://github.com/duarteocarmo/dba_scam/">this</a> repo. </p>
<h2 id="sending-some-surprises">Sending some surprises</h2>
<p>I'm pretty well versioned in Python - I know it can serve me well when trying to get back at Dimitriy. While going through the forms in his scam website, I noticed a <code>POST</code> request firing from my browser with the following information:</p>
<div class="codehilite"><pre><span></span><code><span class="nf">POST</span> <span class="nn">/</span> <span class="kr">HTTP</span><span class="o">/</span><span class="m">1.1</span>
<span class="na">Host</span><span class="o">:</span> <span class="l">postnord-dk.delivery-85367.icu</span>
<span class="na">User-Agent</span><span class="o">:</span> <span class="l">Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:89.0) Gecko/20100101 Firefox/89.0</span>
<span class="na">Accept</span><span class="o">:</span> <span class="l">text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8</span>
<span class="na">Accept-Language</span><span class="o">:</span> <span class="l">en</span>
<span class="na">Accept-Encoding</span><span class="o">:</span> <span class="l">gzip, deflate, br</span>
<span class="na">Content-Type</span><span class="o">:</span> <span class="l">application/x-www-form-urlencoded</span>
<span class="na">Content-Length</span><span class="o">:</span> <span class="l">81</span>
<span class="na">Origin</span><span class="o">:</span> <span class="l">https://postnord-dk.delivery-85367.icu</span>
<span class="na">DNT</span><span class="o">:</span> <span class="l">1</span>
<span class="na">Connection</span><span class="o">:</span> <span class="l">keep-alive</span>
<span class="na">Referer</span><span class="o">:</span> <span class="l">https://postnord-dk.delivery-85367.icu/andet-unoliving-ikea-ja-id-10807800110</span>
<span class="na">Cookie</span><span class="o">:</span> <span class="l">ssupp.vid=viKziAQroXxx; ssupp.visits=1</span>
<span class="na">Upgrade-Insecure-Requests</span><span class="o">:</span> <span class="l">1</span>
<span class="na">Sec-GPC</span><span class="o">:</span> <span class="l">1</span>
<span class="nt">Body:card_number</span><span class="o">=</span><span class="s">5156+1542+2403+1977</span><span class="p">&</span><span class="nt">page</span><span class="o">=</span><span class="s">nemidnotif</span><span class="p">&</span><span class="nt">nemlogin</span><span class="o">=</span><span class="s">9999999</span><span class="p">&</span><span class="nt">nempassword</span><span class="o">=</span><span class="s">1876</span>
</code></pre></div>
<p>The last line of the snippet shows all the information Dimitriy would get straight from my browser. (e.g., <code>card_number</code>, <code>nemlogin</code>, <code>nempassword</code>)</p>
<p>In an attempt to add some confusion to his operation, I decided to create a little script. This little script would send him about 5000 different combinations of the above parameters in a completely random fashion. Fun. </p>
<p>My hope is that Dimitriy is storing the information about all his victims in the same database (or even spreadsheet). By sending him 5000 fake combinations of victim details, he'll have a hard time finding the <em>actual</em> victims. Yes, this could be a long shot - Dimitriy could have a more sophisticated setup, and I suspect he does. </p>
<p>But for the kicks, let's just use some python to piss him off:</p>
<div class="codehilite"><pre><span></span><code><span class="kn">import</span> <span class="nn">asyncio</span>
<span class="kn">import</span> <span class="nn">concurrent.futures</span>
<span class="kn">import</span> <span class="nn">requests</span>
<span class="kn">import</span> <span class="nn">random</span>
<span class="c1"># create some fake data</span>
<span class="n">URL</span> <span class="o">=</span> <span class="s2">"https://postnord-dk.delivery-85367.icu/andet-unoliving-ikea-ja-id-10807800110#"</span>
<span class="n">totals</span> <span class="o">=</span> <span class="mi">5000</span>
<span class="n">card_numbers</span> <span class="o">=</span> <span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">5156000000000000</span><span class="p">,</span> <span class="mi">9999999999999999</span><span class="p">))</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">totals</span><span class="p">)]</span>
<span class="n">card_number_list</span> <span class="o">=</span> <span class="p">[</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">x</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">4</span><span class="p">]</span><span class="si">}</span><span class="s2">+</span><span class="si">{</span><span class="n">x</span><span class="p">[</span><span class="mi">4</span><span class="p">:</span><span class="mi">8</span><span class="p">]</span><span class="si">}</span><span class="s2">+</span><span class="si">{</span><span class="n">x</span><span class="p">[</span><span class="mi">8</span><span class="p">:</span><span class="mi">12</span><span class="p">]</span><span class="si">}</span><span class="s2">+</span><span class="si">{</span><span class="n">x</span><span class="p">[</span><span class="mi">12</span><span class="p">:</span><span class="mi">16</span><span class="p">]</span><span class="si">}</span><span class="s2">"</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">card_numbers</span><span class="p">]</span>
<span class="n">page</span> <span class="o">=</span> <span class="s2">"nemidnotif"</span>
<span class="n">nemlogin_list</span> <span class="o">=</span> <span class="p">[</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">111111</span><span class="p">,</span><span class="w"> </span><span class="mi">999999</span><span class="p">)</span><span class="si">}</span><span class="s2">-</span><span class="si">{</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">1111</span><span class="p">,</span><span class="w"> </span><span class="mi">9999</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">totals</span><span class="p">)]</span>
<span class="n">nempassword_array</span> <span class="o">=</span> <span class="p">[</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">1111</span><span class="p">,</span> <span class="mi">9999</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">totals</span><span class="p">)]</span>
<span class="c1"># send a request to Dimitriy</span>
<span class="k">def</span> <span class="nf">send_data</span><span class="p">():</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">params</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">"card_number"</span><span class="p">:</span> <span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">card_number_list</span><span class="p">),</span>
<span class="s2">"page"</span><span class="p">:</span> <span class="n">page</span><span class="p">,</span>
<span class="s2">"nemlogin"</span><span class="p">:</span> <span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">nemlogin_list</span><span class="p">),</span>
<span class="s2">"nempassword"</span><span class="p">:</span> <span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">(</span><span class="n">nempassword_array</span><span class="p">),</span>
<span class="p">}</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="n">URL</span><span class="p">,</span> <span class="n">params</span><span class="o">=</span><span class="n">params</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Sent data."</span><span class="p">)</span>
<span class="k">return</span> <span class="n">response</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="c1"># parallelize requests using asyncio</span>
<span class="k">async</span> <span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="k">with</span> <span class="n">concurrent</span><span class="o">.</span><span class="n">futures</span><span class="o">.</span><span class="n">ThreadPoolExecutor</span><span class="p">(</span><span class="n">max_workers</span><span class="o">=</span><span class="mi">20</span><span class="p">)</span> <span class="k">as</span> <span class="n">executor</span><span class="p">:</span>
<span class="n">loop</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">get_event_loop</span><span class="p">()</span>
<span class="n">futures</span> <span class="o">=</span> <span class="p">[</span>
<span class="n">loop</span><span class="o">.</span><span class="n">run_in_executor</span><span class="p">(</span><span class="n">executor</span><span class="p">,</span> <span class="n">send_data</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">totals</span><span class="p">)</span>
<span class="p">]</span>
<span class="k">for</span> <span class="n">r</span> <span class="ow">in</span> <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">gather</span><span class="p">(</span><span class="o">*</span><span class="n">futures</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="n">r</span><span class="p">)</span>
<span class="n">loop</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">get_event_loop</span><span class="p">()</span>
<span class="n">loop</span><span class="o">.</span><span class="n">run_until_complete</span><span class="p">(</span><span class="n">main</span><span class="p">())</span>
</code></pre></div>
<p>When running this, I successfully submitted about 4000 <code>POST</code> requests. After that, the website started denying my requests. Dimitriy probably noticed that we were up to no good. </p>
<p>Now that we've served our cold dish. Let's try to find a bit more about this scam. </p>
<h2 id="looking-closer">Looking closer</h2>
<p>When looking closer at the link (<code>https://postnord-dk.delivery-85367.icu</code>) it looks like that the attacker is automatically generating specific delivery links for each victim. Actually, I received another link from him the previous day (<code>https://postnord-dk.delivery-94512.icu</code>). It looks like when the attacker selects a victim he quickly generates a link. Once he has the information, he then kills the link and brings the website offline. It's actually pretty smart, for us to completely block his operation, we would have to continuously scan every <code>postnord-dk.delivery-XXXXX.icu</code> url. This can be done of course but requires much more effort. </p>
<p>I also managed to retrieve all of the <code>whois</code> information. I <a href="https://gist.github.com/duarteocarmo/f83c47e6512593a971d7c4198c28ca51">saved the results in this gist</a>. I'm not an expert in reading <code>whois</code> outputs, but it appears that our attacker <em>could</em> be based in Iceland. I doubt it. But If you're an expert in reading these outputs, do reach out! (<a href="mailto:me@duarteocarmo.com">email</a> is best)</p>
<p>Finally, I also downloaded all of the web pages as I navigated through the scammer's website (<a href="https://github.com/duarteocarmo/dba_scam">check this repo</a>). When looking at their source code, I came across a file called <code>cpg_waiter.js</code> (link <a href="https://github.com/duarteocarmo/dba_scam/blob/master/html_pages/card_prompt_1/Modtag%20pengene_files/cpg_waiter.js">here</a>). This file contains a lot of source code comments in Russian. This makes me think this scammer was probably leveraging some Russian-built tool to scam out DBA re-sellers. I also found <a href="https://github.com/dzubchik/fake-olx/blob/2dde01b22bfea6e8af294e09ccb742ee5c877662/%D0%9E%D1%82%D1%80%D0%B8%D0%BC%D0%B0%D0%BD%D0%BD%D1%8F%20%D0%BD%D0%B0%20%D0%B1%D0%B0%D0%BD%D0%BA%D1%96%D0%B2%D1%81%D1%8C%D0%BA%D1%83%20%D0%BA%D0%B0%D1%80%D1%82%D1%83_files/cpg_waiter.js">another GitHub user</a> that came across this file. Maybe he purchases the whole engine from someone? Maybe he/she is in fact Russian? I don't know.</p>
<h2 id="i-know-that-i-know-nothing">I know that I know nothing</h2>
<p>It's been fun getting some revenge from this scammer. But I have to admit that I'm still super intrigued about who this person is and what tools they are using. </p>
<p>I did learn a couple of valuable lessons in the process. (1) That these types of scams are getting more and more sophisticated - and leveraging social engineering to make them more believable. Also, (2) if you want to protect other people from falling victims to scams like these: tell them to <u>always</u> look at the url bar. <u>Always</u>. </p>
<p><em>If you have some valuable information/experience with these types of scams, do <a href="mailto:me@duarteocarmo.com">reach out</a>, and I'll include it in this post.</em> </p>
<hr>
<h4 id="updates-notes">Updates & notes</h4>
<ul>
<li>A nice reddit user by the name of Sungod23 took the time to dive a bit deeper into the scam. One of the name <a href="https://www.ip-adress.com/website/ns2.nameserverflux.be">servers points to Russia</a>. And another name server <a href="https://www.ip-adress.com/website/ns1.well-wall.to">points to an IP in Ukraine</a>. It looks like my suspicion from Russia appears accurate. </li>
<li>Another user by the name of Julian, suggested I report the scam to namecheap, and to the Danish authorities. I have informed the Danish authorities prior to writing this post. And I just sent an email to namecheap reporting it as well. </li>
</ul>Run every day2021-05-24T00:00:00+02:002021-05-24T00:00:00+02:00Duarte O.Carmotag:duarteocarmo.com,2021-05-24:/blog/run-every-day.html<p>Something fun happened the other day. While at dinner - I asked a co-worker if he did any sports. He answered, "Yeah, I run <em>one mile every day</em>, exactly the same route, around my building". The whole table started laughing. Thinking "here's Duarte running half marathons, he must think this guy …</p><p>Something fun happened the other day. While at dinner - I asked a co-worker if he did any sports. He answered, "Yeah, I run <em>one mile every day</em>, exactly the same route, around my building". The whole table started laughing. Thinking "here's Duarte running half marathons, he must think this guy is ridiculous". I didn't laugh for a second. In fact, I think the One-mile-a-day guy is probably the smartest of the bunch. Here's why.</p>
<p>For about two years, I’ve been running every day. I’m not a professional athlete, or am I training to run a big marathon. I have found that running every day, consistently, vastly improves my mental and physical well-being.</p>
<p>Everyone is busy. “I don’t have <em>time</em>”, “It’s <em>impossible</em>”, I’ve heard it all - I don’t buy it. If this was the case, you wouldn’t have time to do your laundry, watch that TV show, or even read this rant. If you want to do something, you make time for it. Often, people will come up with excuses as to why they can't do something. The truth is if it's prioritized enough - it gets done.</p>
<p>Nothing matters more than time - that's your most valuable resource. If someone tries to block your time with something that doesn't contribute to your end goal, the answer is simple: no thanks. Running allows you to get your time back. Every minute you run is <em>your</em> minute, and no one else's. And it feels good to allocate time to yourself every day. But not all days are easy.</p>
<p>It's raining. It's cold. My leg hurts. My head hurts. It's too early. There are a thousand reasons why you <em>shouldn't</em> go out for a run. But there are a thousand and one reasons why you should. When you think about why you can't do it - think of how much better you'll feel once you've gone out for that run. Once you've done it for long enough - you won't be able to sleep without it.</p>
<p>1 mile? 10K? 5K? 21K? Nobody cares. It doesn't matter. Really, for the first years of running, I didn't wear a smartwatch, measured my pace, or paid attention to my breathing (still don't do the last). Why? Cause it's not about competing with others, it's about claiming <em>your</em> time back. People get overly concerned about times, paces, and distances. Trying to use some external motivator so they can get their ass out of bed. Motivation comes from within.</p>
<p>One-mile-a-day guy gets it - the rest of the table doesn't. </p>
<p><img alt="alt-text-1" src="https://duarteocarmo.com/images/29-app-screenshots.png" /> </p>
<p>Two apps I love to use for running. <a href="https://apps.apple.com/us/app/trail-router/id1500479574">Trail router</a> allows you to discover new running routes, wherever you are in the world. <a href="https://apps.apple.com/us/app/zones-for-training/id1139688415">Zones</a>, allows you to visualize running stats in ways Apple doesn't.</p>How to build a newsletter using Python and FastAPI2021-04-11T00:00:00+02:002021-04-11T00:00:00+02:00Duarte O.Carmotag:duarteocarmo.com,2021-04-11:/blog/how-to-build-a-newsletter-using-python-and-fastapi.html<p><center>
<img src="https://duarteocarmo.com/images/newsletter-cover.jpg" alt="Digital library" style="max-width:100%;">
</center></p>
<p>My favorite way of learning is by reading extensively about a topic. For this, nothing better then my Kindle. But I have been growing increasingly envious of the large bookshelves of scratched and highlighted books that I see in older generations. </p>
<p>I mean, who doesn't dream about having their own …</p><p><center>
<img src="https://duarteocarmo.com/images/newsletter-cover.jpg" alt="Digital library" style="max-width:100%;">
</center></p>
<p>My favorite way of learning is by reading extensively about a topic. For this, nothing better then my Kindle. But I have been growing increasingly envious of the large bookshelves of scratched and highlighted books that I see in older generations. </p>
<p>I mean, who doesn't dream about having their own private library of knowledge they can just jump into at any time? So I have been relentlessly building ways of storing the knowledge from my readings. Building my <a href="https://duarteocarmo.com/blog/managing-kindle-highlights-with-python-and-github.html">highlight library</a> was the first attempt.</p>
<p>But what else can we build to keep us connected to what we read? How can we guarantee we get reminded of important pieces of knowledge that feed into our brains?</p>
<p>This is how I did it. </p>
<h2 id="ah-shit-another-newsletter">Ah shit, another newsletter</h2>
<p>So the solution that I wanted to build had some high-level requirements:</p>
<ul>
<li>It needs to parse all of the highlights in my <code>My Clippings.txt</code> file stored on my Kindle</li>
<li>It should store them somewhere in the Cloud</li>
<li>It should send me, on a regularly basis, a single passage that I have highlighted in the past</li>
</ul>
<p>Well, that sounds pretty much like a newsletter to me! I know, I know, the world is full of newsletters. But hey, I certainly don't want to receive a Telegram message of something I highlighted on my Kindle. Email sounds like a "slower" medium to consume knowledge. </p>
<p>So the premise was set, we are going to build a newsletter service. </p>
<p>For reference, here's the high-level architecture of what I've built. Don't panic! We'll dive deeper into the details step by step. This is just for reference:</p>
<p><center>
<img src="https://duarteocarmo.com/images/kindle-highlights-architecture.png" alt="Kindle higlights architecture diagram" style="max-width:100%;">
</center></p>
<h2 id="the-backbone-fastapi">The backbone: FastAPI</h2>
<p>In the past I have experimented with a lot of different Python based web frameworks (e.g., Django, Flask, Pyramid). But recently, I have been hearing a lot of rage about <a href="https://fastapi.tiangolo.com/">FastAPI</a>. Word on the street is that its super fast, and async out of the box. This sounded pretty exciting, so I decided to give it a shot. (Note: If you are building something serious, do some research first)</p>
<p>The <a href="https://github.com/duarteocarmo/kindle-highlights-newsletter/blob/master/app/main.py#L23">web app</a> is made of four simple endpoints:</p>
<ul>
<li>A home page that should display a form for users to sign up to the newsletter (<a href="https://github.com/duarteocarmo/kindle-highlights-newsletter/blob/c6830513bbb0da05613f221102a47d3fe38409f7/app/main.py#L23">link</a>)</li>
<li>A way of handling submitted form data from users (<a href="https://github.com/duarteocarmo/kindle-highlights-newsletter/blob/c6830513bbb0da05613f221102a47d3fe38409f7/app/main.py#L28">link</a>)</li>
<li>An endpoint to confirm subscriptions to the newsletter (<a href="https://github.com/duarteocarmo/kindle-highlights-newsletter/blob/c6830513bbb0da05613f221102a47d3fe38409f7/app/main.py#L54">link</a>)</li>
<li>An endpoint to unsubscribe from the newsletter (<a href="https://github.com/duarteocarmo/kindle-highlights-newsletter/blob/c6830513bbb0da05613f221102a47d3fe38409f7/app/main.py#L65">link</a>)</li>
</ul>
<p>One interesting thing I noticed, is that every time I wanted to send an email or register a user in a database, things could get pretty long . This where I started to leverage some of the async capabilities of FastAPI. <code>Async</code> methods and <code>background_tasks</code> became super useful to handle user requests. </p>
<p>Let's look at some example code (from <a href="https://github.com/duarteocarmo/kindle-highlights-newsletter/blob/master/app/main.py">here</a>):</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># full code: https://github.com/duarteocarmo/kindle-highlights-newsletter/blob/master/app/main.py</span>
<span class="nd">@app</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s2">"/"</span><span class="p">)</span>
<span class="k">async</span> <span class="k">def</span> <span class="nf">sign_up</span><span class="p">(</span>
<span class="n">request</span><span class="p">:</span> <span class="n">Request</span><span class="p">,</span>
<span class="n">background_tasks</span><span class="p">:</span> <span class="n">BackgroundTasks</span><span class="p">,</span>
<span class="n">file</span><span class="p">:</span> <span class="n">UploadFile</span> <span class="o">=</span> <span class="n">File</span><span class="p">(</span><span class="o">...</span><span class="p">),</span>
<span class="n">email</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="n">Form</span><span class="p">(</span><span class="o">...</span><span class="p">),</span>
<span class="p">):</span>
<span class="n">highlights</span> <span class="o">=</span> <span class="k">await</span> <span class="n">parse_highlights_file</span><span class="p">(</span><span class="n">file</span><span class="p">)</span> <span class="c1"># Parse highlights from user</span>
<span class="n">email_valid</span> <span class="o">=</span> <span class="k">await</span> <span class="n">email_is_valid</span><span class="p">(</span><span class="n">email</span><span class="p">)</span> <span class="c1"># Check if email is valid</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">highlights</span> <span class="ow">or</span> <span class="n">email_valid</span> <span class="ow">is</span> <span class="kc">False</span><span class="p">:</span>
<span class="k">return</span> <span class="n">FileResponse</span><span class="p">(</span><span class="s2">"static/error.html"</span><span class="p">)</span>
<span class="n">subscribed_status</span> <span class="o">=</span> <span class="k">await</span> <span class="n">check_user_subscribed</span><span class="p">(</span><span class="n">email</span><span class="p">)</span> <span class="c1"># Check if user is subscribed</span>
<span class="k">if</span> <span class="n">subscribed_status</span> <span class="ow">is</span> <span class="kc">False</span><span class="p">:</span>
<span class="c1"># Note: none of these background tasks block our webpage. Pretty awesome.</span>
<span class="n">background_tasks</span><span class="o">.</span><span class="n">add_task</span><span class="p">(</span><span class="n">register_user</span><span class="p">,</span> <span class="n">email</span><span class="p">)</span>
<span class="n">background_tasks</span><span class="o">.</span><span class="n">add_task</span><span class="p">(</span><span class="n">send_confirmation_to</span><span class="p">,</span> <span class="n">email</span><span class="p">)</span>
<span class="n">background_tasks</span><span class="o">.</span><span class="n">add_task</span><span class="p">(</span><span class="n">upload_highlights</span><span class="p">,</span> <span class="n">highlights</span><span class="p">,</span> <span class="n">email</span><span class="p">)</span>
<span class="k">return</span> <span class="n">templates</span><span class="o">.</span><span class="n">TemplateResponse</span><span class="p">(</span><span class="s2">"sign_up.html"</span><span class="p">,</span> <span class="p">{</span><span class="s2">"request"</span><span class="p">:</span> <span class="n">request</span><span class="p">})</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="n">templates</span><span class="o">.</span><span class="n">TemplateResponse</span><span class="p">(</span><span class="s2">"success.html"</span><span class="p">,</span> <span class="p">{</span><span class="s2">"request"</span><span class="p">:</span> <span class="n">request</span><span class="p">})</span>
</code></pre></div>
<h2 id="data-layer-so-cloud-much-native">Data layer: So Cloud, much native</h2>
<p>Databases are a pain. I can't even begin to tell you how much I hate database migrations. Yes, I understand transforming python to SQL code can be insanely hard. But I mean, I just want to store something. So how hard can this possibly be? The premise was set: I was not going to use something like <a href="https://www.sqlalchemy.org/">SQLAlchemy</a>, even though FastAPI <a href="https://fastapi.tiangolo.com/tutorial/sql-databases/">recommends it</a>. </p>
<p>So I thought of storing everything in a <a href="https://www.sqlite.org/index.html">SQLite</a> database - that sounded like a good idea at first. But I also don't want to store a database file in the middle of my source code. I know, I know, I have serious issues. </p>
<p>One thing that came to mind was <a href="https://www.mongodb.com/">mongoDB</a> - a documented oriented database is pretty simple to get up and running. But I have moved to the dark side, I must admit. And have been putting everything in AWS whenever I can. So what does AWS offer as a mongo clone? Let me introduce you to <a href="https://aws.amazon.com/dynamodb/">DynamoDB</a>!</p>
<p>In the process, I found a very handy utility called <a href="https://pynamodb.readthedocs.io/en/latest/">PynamoDB</a>, which allows you to interface with your DynamoDB through your python code. All I needed to do was to define some models, and I could pretty quickly get to storing and retrieving data from my database. </p>
<p>So I created a <code>models.py</code> file, which I could query from anywhere within my application - here's an example of my database model for a highlight (something the user highlighted in their kindle):</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># full code: https://github.com/duarteocarmo/kindle-highlights-newsletter/blob/master/app/models.py</span>
<span class="kn">from</span> <span class="nn">pynamodb.models</span> <span class="kn">import</span> <span class="n">Model</span>
<span class="kn">from</span> <span class="nn">pynamodb.attributes</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">UnicodeAttribute</span><span class="p">,</span>
<span class="n">UTCDateTimeAttribute</span><span class="p">,</span>
<span class="n">BooleanAttribute</span><span class="p">,</span>
<span class="n">NumberAttribute</span><span class="p">,</span>
<span class="p">)</span>
<span class="k">class</span> <span class="nc">HighlightModel</span><span class="p">(</span><span class="n">Model</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> Kindle highlight</span>
<span class="sd"> """</span>
<span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
<span class="n">table_name</span> <span class="o">=</span> <span class="s2">"kindle-highlights-contents"</span>
<span class="n">region</span> <span class="o">=</span> <span class="s2">"eu-west-1"</span>
<span class="n">email</span> <span class="o">=</span> <span class="n">UnicodeAttribute</span><span class="p">(</span><span class="n">hash_key</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">null</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">author</span> <span class="o">=</span> <span class="n">UnicodeAttribute</span><span class="p">(</span><span class="n">null</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">book</span> <span class="o">=</span> <span class="n">UnicodeAttribute</span><span class="p">(</span><span class="n">null</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">content</span> <span class="o">=</span> <span class="n">UnicodeAttribute</span><span class="p">(</span><span class="n">null</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">date_string</span> <span class="o">=</span> <span class="n">UnicodeAttribute</span><span class="p">(</span><span class="n">null</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">highlight_index</span> <span class="o">=</span> <span class="n">NumberAttribute</span><span class="p">(</span><span class="n">range_key</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">null</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</code></pre></div>
<p>Great you have a web service, you are storing some data on the Cloud. How do we deploy this? </p>
<h2 id="deployment-elastic-beanstalk-thank-you-for-existing">Deployment: Elastic Beanstalk, thank you for existing</h2>
<p>FastAPI <a href="https://fastapi.tiangolo.com/deployment/docker/">recommends</a> Docker to deploy your applications. To do so, all I needed to do was to create a <a href="https://github.com/duarteocarmo/kindle-highlights-newsletter/blob/master/Dockerfile">Dockerfile</a> and a <a href="https://github.com/duarteocarmo/kindle-highlights-newsletter/blob/master/docker-compose.yml"><code>docker-compose.yml</code> file</a>. Also, by using this image, you supposedly get <a href="https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker">automatic performance scaling</a> which sounded pretty appealing (for when someone decided to DDoS my website)</p>
<p>For me, by far the easiest way to deploy a docker-based application nowadays is <a href="https://aws.amazon.com/elasticbeanstalk/">AWS Elastic Beanstalk</a>. In short, AWS takes a .zip file with your application, together with a <code>docker-compose.yml</code> file, and automatically runs it in EC2 instances. Additionally, you can integrate this process into your workflow with <a href="https://github.com/features/actions">GitHub actions</a> - but we'll get deeper into that in a second. </p>
<p>To send all my emails, I use Amazon's <a href="https://aws.amazon.com/ses/">SES (Simple Email Service)</a>. I was much cheaper than other solutions e.g., SendGrid. And it allowed me to keep everything in AWS (user lock-in? Yes. 200%)</p>
<p>One thing to note, is that my application should not only receive some highlights and an email from the users, and store them on a database. My application actually needs to send out emails with individual users every week. To do this, I needed some sort of scheduled task running every Friday. I started with <a href="https://github.com/tiangolo/fastapi/issues/520#issuecomment-716969948">APScheduler</a> as advised in a shady GitHub issue. But I noticed that whenever I had more than 1 worker running my application, the jobs would run unreliably, our twice instead of once. In fact, I quickly discovered I was <a href="https://apscheduler.readthedocs.io/en/stable/faq.html#how-do-i-share-a-single-job-store-among-one-or-more-worker-processes">screwed</a>.</p>
<p>So where can I run scheduled tasks to send regular emails to my users? Cron? No, we are in the Cloud native era. </p>
<h2 id="cicd-github-abusing-github-actions">CI/CD: GitHub - (ab)using GitHub actions</h2>
<p>In the final application, I managed to use GitHub actions for two, pretty critical tasks:</p>
<ul>
<li><strong>To automatically upgrade/update my application</strong>(<a href="https://github.com/duarteocarmo/kindle-highlights-newsletter/blob/master/.github/workflows/elastic_beanstalk.yml">action file</a>): Every time I commit to my repository's master branch, GitHub automatically takes my application, and re-deploys it to Elastic Beanstalk. Taking all of my environment variables and secrets, zipping everything, and deploying </li>
<li><strong>To automatically send the newsletter to all my users</strong>(<a href="https://github.com/duarteocarmo/kindle-highlights-newsletter/blob/master/.github/workflows/send_newsletter.yml">action file</a>): I created a GitHub action that runs my <code>send_email.py</code> (<a href="https://github.com/duarteocarmo/kindle-highlights-newsletter/blob/master/send_email.py">link</a>) script, every Friday morning. The job is a bit flaky, and doesn't run quite on time. But hey, it runs. </li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>This took much more time than I expected to build. I gained a renewed respect for all the different newsletter services out there (at least the ones built from scratch). Through building my own newsletter platform I got to discover and learn a bunch of new technologies that will for sure serve me well in the future. </p>
<p>So what was the end result for this project? </p>
<p><a href="https://kindle-highlights.email/">Kindle-highlights.email</a>, a free and open-source project where any user can upload their highlights file, and receive one highlighted passage every Friday morning. This allows me to keep track of important pieces of knowledge I want to remember in the future, and hopefully help a couple of folks out there looking to build something similar!</p>
<p><center>
<img src="https://duarteocarmo.com/images/kindle-highlights.png" alt="Kindle higlights architecture diagram" style="max-width:100%;">
</center></p>
<p>Have comments? Questions? Features? Just create an issue in the <a href="https://github.com/duarteocarmo/kindle-highlights-newsletter">GitHub repo</a>.</p>Kindle highlights as a (free) service2021-03-21T00:00:00+01:002021-03-21T00:00:00+01:00Duarte O.Carmotag:kindle-highlights.email,2021-03-21:/Hacking on my finances (Part 2: Beancount on Beanstalk)2021-01-15T00:00:00+01:002021-01-15T00:00:00+01:00Duarte O.Carmotag:duarteocarmo.com,2021-01-15:/blog/hacking-on-my-finances-part-2-beancount-on-beanstalk.html<p><em>In <a href="/blog/hacking-on-my-finances.html">part 1</a> of this series, I talked about the setup that I'm using to manage my finances and investments. In this part, I'll talk about how I migrated my accounting setup to the Cloud, and what I have learned in the process.</em></p>
<h2 id="the-goal-accessing-my-finances-from-anywhere">The goal: Accessing my finances from anywhere …</h2><p><em>In <a href="/blog/hacking-on-my-finances.html">part 1</a> of this series, I talked about the setup that I'm using to manage my finances and investments. In this part, I'll talk about how I migrated my accounting setup to the Cloud, and what I have learned in the process.</em></p>
<h2 id="the-goal-accessing-my-finances-from-anywhere">The goal: Accessing my finances from anywhere</h2>
<p>Currently, I <a href="/blog/hacking-on-my-finances.html">manage my finances using beancount</a>, a Python based plain-text accounting <a href="https://beancount.github.io/">library</a>. It allows me to create a personal ledger (aka, the <code>beancount</code> file), and then visualize my assets and expenses using <a href="https://beancount.github.io/fava/">Fava</a> - a web interface/explorer for it. </p>
<p>Although it works great in my machine, I envisioned something a bit more streamlined where:</p>
<ul>
<li>I update the ledger file locally</li>
<li>I commit the changed file to a private repository</li>
<li>The <code>beancount</code> file is validated ("bean-check runs without problems")</li>
<li>I can access the fava web interface from anywhere</li>
<li>The web interface is protected (I don't want <em>everyone</em> analyzing my finances)</li>
<li>Every time I commit a new beancount file, the fava web interface should update</li>
</ul>
<p>My goal was to automate this sequence of events, and to take maximum advantage of Cloud technologies during that process.</p>
<p>To do it, I used a combination of <a href="https://beancount.github.io/fava/">Fava</a>, <a href="https://www.docker.com/">Docker</a>, <a href="https://docs.github.com/en/free-pro-team@latest/actions/quickstart">GitHub Actions</a>, <a href="https://aws.amazon.com/elasticbeanstalk/">AWS Elastic Beanstalk</a>, and <a href="https://www.cloudflare.com/">Cloudflare</a>. </p>
<p>Here's a <a href="https://github.com/duarteocarmo/hacking-on-my-finances">sanitized version of the repo</a> containing all the necessary files. </p>
<p>And a simplified view of the architecture (using <a href="https://excalidraw.com/">excalidraw</a>):</p>
<p><br></p>
<p><center>
<img src="https://duarteocarmo.com/images/beancount-beanstalk.png" alt="Fava example" style="max-width: 100%; margin-bottom: 1em; border-radius: 5px">
</center></p>
<h2 id="step-1-using-docker-to-containerize-the-application">Step 1: Using Docker to containerize the application</h2>
<p>For the deployment, I'm using two Docker containers: </p>
<ul>
<li>A <a href="https://hub.docker.com/r/yegle/fava/">containerized version of the Fava web interface</a> that takes a <code>beancount</code> file as input and exposes the web interface</li>
<li>A <a href="https://github.com/beevelop/docker-nginx-basic-auth">docker image</a> that provides an NGINX proxy with user-password authentication</li>
</ul>
<p>To test it in my local machine, I created a <code>docker-compose.yml</code> file with both containers:</p>
<div class="codehilite"><pre><span></span><code><span class="nt">version</span><span class="p">:</span><span class="w"> </span><span class="s">"3.7"</span>
<span class="nt">services</span><span class="p">:</span>
<span class="w"> </span><span class="nt">fava</span><span class="p">:</span>
<span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">yegle/fava</span>
<span class="w"> </span><span class="nt">volumes</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="s">"./:/bean"</span>
<span class="w"> </span><span class="nt">environment</span><span class="p">:</span>
<span class="w"> </span><span class="c1"># assuming you have a filename.beancount in the current directory </span>
<span class="w"> </span><span class="nt">BEANCOUNT_FILE</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">/bean/filename.beancount</span>
<span class="w"> </span><span class="nt">auth</span><span class="p">:</span>
<span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">beevelop/nginx-basic-auth</span>
<span class="w"> </span><span class="nt">links</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">fava:fava</span>
<span class="w"> </span><span class="nt">ports</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">8000:80</span><span class="w"> </span><span class="c1"># yourmachineIP:containerIP</span>
<span class="w"> </span><span class="nt">environment</span><span class="p">:</span>
<span class="w"> </span><span class="nt">FORWARD_PORT</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">5000</span>
<span class="w"> </span><span class="nt">FORWARD_HOST</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">fava</span>
<span class="w"> </span><span class="c1"># Use this link to generate your credentials: https://hostingcanada.org/htpasswd-generator/</span>
<span class="w"> </span><span class="nt">HTPASSWD</span><span class="p">:</span><span class="w"> </span><span class="s">"foo:$apr1$odHl5EJN$KbxMfo86Qdve2FH4owePn."</span>
</code></pre></div>
<p>Once that's set up, I can run <code>docker-compose up</code>, and the application will be running in <code>http://localhost:8000</code>.</p>
<p>Now let's talk hosting.</p>
<h2 id="step-2-beancount-on-beanstalk">Step 2: Beancount on Beanstalk</h2>
<p><em>Disclaimer: I'm not a Security expert - and cannot assure this setup is 100% private and secure. Can anyone though?</em></p>
<p>I spent some time browsing for the best options to deploy a <code>docker-compose.yml</code> file, and decided to go with AWS Elastic Beanstalk. Mostly because of <a href="https://www.youtube.com/watch?v=nhqcecpi47s">this awesome video</a>, and <a href="https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/create_deploy_docker_ecstutorial.html">some great documentation from AWS</a>.</p>
<p>You'll notice that instead of a <code>docker-compose.yml</code> file, AWS requests a <code>dockerrun.aws.json</code> file, they are very similar actually. It's just Amazon's way of keeping you locked into their service. Sad. </p>
<details>
<summary>Click here to expand the <code>dockerrun.aws.json</code> file</summary>
<div class="codehilite"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">"AWSEBDockerrunVersion"</span><span class="p">:</span><span class="mi">2</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"volumes"</span><span class="p">:[</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="s2">"fava"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"host"</span><span class="p">:{</span>
<span class="w"> </span><span class="nt">"sourcePath"</span><span class="p">:</span><span class="s2">"/var/app/current"</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">],</span>
<span class="w"> </span><span class="nt">"containerDefinitions"</span><span class="p">:[</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="s2">"fava"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"image"</span><span class="p">:</span><span class="s2">"yegle/fava"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"essential"</span><span class="p">:</span><span class="kc">true</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"memory"</span><span class="p">:</span><span class="mi">128</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"environment"</span><span class="p">:[</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="s2">"BEANCOUNT_FILE"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"value"</span><span class="p">:</span><span class="s2">"/bean/filename.beancount"</span><span class="w"> </span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">],</span>
<span class="w"> </span><span class="nt">"mountPoints"</span><span class="p">:[</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"sourceVolume"</span><span class="p">:</span><span class="s2">"fava"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"containerPath"</span><span class="p">:</span><span class="s2">"/bean"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"readOnly"</span><span class="p">:</span><span class="kc">true</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">]</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="s2">"auth-nginx"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"image"</span><span class="p">:</span><span class="s2">"beevelop/nginx-basic-auth"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"essential"</span><span class="p">:</span><span class="kc">true</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"memory"</span><span class="p">:</span><span class="mi">128</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"portMappings"</span><span class="p">:[</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"hostPort"</span><span class="p">:</span><span class="mi">80</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"containerPort"</span><span class="p">:</span><span class="mi">80</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">],</span>
<span class="w"> </span><span class="nt">"links"</span><span class="p">:[</span>
<span class="w"> </span><span class="s2">"fava"</span>
<span class="w"> </span><span class="p">],</span>
<span class="w"> </span><span class="nt">"environment"</span><span class="p">:[</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="s2">"FORWARD_PORT"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"value"</span><span class="p">:</span><span class="mi">5000</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="s2">"FORWARD_HOST"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"value"</span><span class="p">:</span><span class="s2">"fava"</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"name"</span><span class="p">:</span><span class="s2">"HTPASSWD"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"value"</span><span class="p">:</span><span class="s2">"foo:$apr1$odHl5EJN$KbxMfo86Qdve2FH4owePn."</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">]</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="p">]</span>
<span class="p">}</span>
</code></pre></div>
</details>
<p>Next step is to bundle the both the <code>filename.beancount</code> and the <code>dockerrun.aws.json</code> files into a single <code>.zip</code> file, which can be uploaded to AWS Beanstalk directly. </p>
<p>And that's it, that's what is needed to run an authenticated version of fava in the web. Once uploaded, AWS provides a direct link to my protected fava instance.</p>
<p>But hold up, there's still a couple of things to automate. </p>
<h2 id="step-3-using-github-actions-to-automate-the-deployment">Step 3: Using GitHub actions to automate the deployment</h2>
<p>Logging into to my AWS console and uploading a new <code>zip</code> every time I change my <code>beancount</code> file is a pain. And I don't like pain. </p>
<p>To avoid this, I created a GitHub action that automatically watches the repo containing my <code>beancount</code> file and watches for changes in that file. If it changes, it then validates the ledger file, creates a new <code>.zip</code> version of the application, and uploads that to my AWS Beanstalk instance. </p>
<p>It uses <a href="https://github.com/einaregilsson/beanstalk-deploy">this</a> action as a base and adds a couple of features to it, like the validation of the ledger file for example. </p>
<details>
<summary>Click here to expand the GitHub action</summary>
<div class="codehilite"><pre><span></span><code><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Deploy master</span>
<span class="c1"># run this if the beancount file changes</span>
<span class="nt">on</span><span class="p">:</span>
<span class="w"> </span><span class="nt">push</span><span class="p">:</span>
<span class="w"> </span><span class="nt">paths</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="s">"filename.beancount"</span>
<span class="nt">jobs</span><span class="p">:</span>
<span class="w"> </span><span class="c1"># test this beancount file with the bean-check command</span>
<span class="w"> </span><span class="nt">test</span><span class="p">:</span>
<span class="w"> </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">ubuntu-latest</span>
<span class="w"> </span><span class="nt">steps</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Checkout source code</span>
<span class="w"> </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">actions/checkout@v1</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Setup python3</span>
<span class="w"> </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">actions/setup-python@v2</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Install setup tools</span>
<span class="w"> </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">sudo apt-get install python3-setuptools</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Install requirements</span>
<span class="w"> </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">python3 -m pip install beancount</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Check beancount file</span><span class="w"> </span>
<span class="w"> </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">bean-check $BEANCOUNT_FILE</span>
<span class="w"> </span><span class="nt">env</span><span class="p">:</span>
<span class="w"> </span><span class="nt">BEANCOUNT_FILE</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">filename.beancount</span>
<span class="w"> </span><span class="c1"># and deploy it do AWS beanstalk</span>
<span class="w"> </span><span class="nt">build</span><span class="p">:</span>
<span class="w"> </span><span class="nt">needs</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">[</span><span class="nv">test</span><span class="p p-Indicator">]</span>
<span class="w"> </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">ubuntu-latest</span>
<span class="w"> </span><span class="nt">steps</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Checkout source code</span>
<span class="w"> </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">actions/checkout@v1</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Generate deployment package</span>
<span class="w"> </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">zip deploy.zip -j $BEANCOUNT_FILE $AWS_DOCKER_FILE</span>
<span class="w"> </span><span class="nt">env</span><span class="p">:</span>
<span class="w"> </span><span class="nt">BEANCOUNT_FILE</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">filename.beancount</span>
<span class="w"> </span><span class="nt">AWS_DOCKER_FILE</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">deploy/Dockerrun.aws.json</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">Deploy to EB</span>
<span class="w"> </span><span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">einaregilsson/beanstalk-deploy@v14</span>
<span class="w"> </span><span class="nt">with</span><span class="p">:</span>
<span class="w"> </span><span class="nt">aws_access_key</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">${{ secrets.AWS_ACCESS_KEY_ID }}</span>
<span class="w"> </span><span class="nt">aws_secret_key</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">${{ secrets.AWS_SECRET_ACCESS_KEY }}</span>
<span class="w"> </span><span class="nt">application_name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">YOUR_APPLICATION_NAME</span>
<span class="w"> </span><span class="nt">environment_name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">YOUR_ENVIRONMENT_NAME</span>
<span class="w"> </span><span class="nt">version_label</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">${{ github.run_number }}</span>
<span class="w"> </span><span class="nt">region</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">YOUR_APP_REGION</span>
<span class="w"> </span><span class="nt">deployment_package</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">deploy.zip</span>
<span class="w"> </span><span class="nt">wait_for_environment_recovery</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">180</span>
</code></pre></div>
</details>
<p>Once all of this is running in a private repo, every time I commit a change to my <code>.beancount</code> file, my Beanstalk application gets updated! (It's not instant, but its fast enough!)</p>
<h2 id="step-4-securing-everything-with-cloudflare">Step 4: Securing everything with Cloudflare</h2>
<p><a href="https://www.cloudflare.com/">Cloudflare</a> is my go to tool to manage networking for all my applications. It gives me:</p>
<ul>
<li>DNS management (setting domain names)</li>
<li>HTTPS encryption</li>
<li>Website authentication and protection</li>
<li>Firewall management</li>
</ul>
<p>In a single place. Pretty insane.</p>
<p>Will not go in depth about all of the setup details here, but I can really recommend using Cloudflare. Awesome tool. </p>
<h2 id="final-notes">Final notes</h2>
<p>This was super fun to put together. It took me some hours to get everything set up nicely. But I learned a lot in the process. The setup far from perfect, but works pretty well for my use case. And that's enough. </p>
<p>The whole thing costs about 4 EUR/month which is pretty affordable. I could also just purchase a VPS for 2 EUR/month and call it a day. But wouldn't learn much in the process. </p>
<p>I also created a <a href="https://github.com/duarteocarmo/hacking-on-my-finances">sanitized version of the repo</a> with all the files if you would like to hack around a bit. </p>
<p>Hope you found this walk-through/showcase useful. My email's right in the bottom there if you have questions, don't be a stranger.</p>Building a Telegram bot in Python to track your portfolio2020-11-23T00:00:00+01:002020-11-23T00:00:00+01:00Duarte O.Carmotag:duarteocarmo.com,2020-11-23:/blog/building-a-telegram-bot-in-python-to-track-your-portfolio.html<p><em>In the past months, I’ve been spending a lot of time researching about investing: building your portfolio, back testing it, tracking its performance, and acting accordingly. One of these endeavors (and my stubbornness to build my own tools) has led me to create a telegram bot, here’s a …</em></p><p><em>In the past months, I’ve been spending a lot of time researching about investing: building your portfolio, back testing it, tracking its performance, and acting accordingly. One of these endeavors (and my stubbornness to build my own tools) has led me to create a telegram bot, here’s a small write up in hope you'll build your own.</em></p>
<h2 id="a-telegram-bot-have-you-heard-of-yahoo-finance">A Telegram Bot? Have you heard of Yahoo Finance?</h2>
<p>Yes, I have actually heard about and used <a href="https://finance.yahoo.com/">Yahoo Finance</a> to track my portfolio, but there are a couple of reasons why I think it doesn't quite cut it:</p>
<ul>
<li><strong><u>Notification systems</u></strong>: When you set up an app such as <a href="https://apps.apple.com/us/app/yahoo-finance/id328412701">Yahoo Finance</a> with your Portfolio, you can either create a widget that you visit every so often, or you can set up a system to alert you about a particular set of stocks. I consider myself a passive investor, and will not check my performance every day, or even every week. I want a system that adapts to my "passive needs". Every so often let me know the worth of my portfolio. That's it. </li>
<li><strong><u>Accuracy</u></strong>: Before researching more on the topic I thought investment instruments (i.e., stocks or funds) were pretty standardized across apps and markets. Well, I was clearly wrong. Most financial data is a bit messy. Some apps can't show your particular funds, some do, but reference other exchanges. The whole thing is a bit of a mess. So by building something I control, I can make sure I am getting the right information from the right sources, at the right time. (Particularly being an <a href="https://indexfundinvestor.eu/">European investor</a> - where information is even more scarce)</li>
<li><strong><u>Customization</u></strong>: I don't want to simply track the value of my portfolio, I also want to control how it has evolved according to my expectations. And why stop there? There is a very specific set of items I want to keep track of. Let's say tomorrow I want to know a particular piece of information about a recent IPO. Building my own system allows me to customize it exactly to both my present AND my future needs. </li>
</ul>
<p>Given these constraints (and my stubbornness to build my own tools), I decided I needed some sort of "programmable" notification system. Having heard a bit about telegram/discord bots, and being a subscriber to a couple of telegram channels myself, I decided to give <a href="https://telegram.org/">Telegram</a> a shot. </p>
<h2 id="building-a-basic-bot">Building a basic bot</h2>
<p>I can't say I was surprised to see a great Python wrapper written exactly for this purpose: <a href="https://github.com/python-telegram-bot/python-telegram-bot">python-telegram-bot</a>. Can't tell you how easy it was to set everything up using their extensive <a href="https://github.com/python-telegram-bot/python-telegram-bot/wiki">Wiki</a>. </p>
<p>Let me walk you a bit through the process. You start by installing the library:</p>
<div class="codehilite"><pre><span></span><code>$<span class="w"> </span>pip3<span class="w"> </span>install<span class="w"> </span>python-telegram-bot<span class="w"> </span>
</code></pre></div>
<p>Once that's up an running, I created a simple "shell" bot that responds whenever you send the message <code>/start</code>, let's call it <code>bot.py</code>:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># bot.py</span>
<span class="kn">from</span> <span class="nn">telegram.ext</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">Updater</span><span class="p">,</span>
<span class="n">CommandHandler</span><span class="p">,</span>
<span class="n">MessageHandler</span><span class="p">,</span>
<span class="n">Filters</span><span class="p">,</span>
<span class="n">CallbackContext</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span> <span class="nn">telegram</span> <span class="kn">import</span> <span class="n">Update</span>
<span class="c1"># define your API token: https://core.telegram.org/bots#3-how-do-i-create-a-bot </span>
<span class="n">API_TOKEN</span> <span class="o">=</span> <span class="s2">"YOUR API TOKEN"</span>
<span class="c1"># what your bot should reply when we send the /start command</span>
<span class="k">def</span> <span class="nf">start</span><span class="p">(</span><span class="n">update</span><span class="p">:</span> <span class="n">Update</span><span class="p">,</span> <span class="n">context</span><span class="p">:</span> <span class="n">CallbackContext</span><span class="p">):</span>
<span class="n">update</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">reply_text</span><span class="p">(</span><span class="s2">"Welcome :)"</span><span class="p">)</span>
<span class="c1"># the main function, with some boilerplate</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="n">updater</span> <span class="o">=</span> <span class="n">Updater</span><span class="p">(</span><span class="n">API_TOKEN</span><span class="p">,</span> <span class="n">use_context</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">dispatcher</span> <span class="o">=</span> <span class="n">updater</span><span class="o">.</span><span class="n">dispatcher</span>
<span class="n">dispatcher</span><span class="o">.</span><span class="n">add_handler</span><span class="p">(</span><span class="n">CommandHandler</span><span class="p">(</span><span class="s2">"start"</span><span class="p">,</span> <span class="n">start</span><span class="p">))</span> <span class="c1"># this line is what matters most</span>
<span class="n">updater</span><span class="o">.</span><span class="n">start_polling</span><span class="p">()</span>
<span class="n">updater</span><span class="o">.</span><span class="n">idle</span><span class="p">()</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span>
</code></pre></div>
<p>If you now navigate back to your terminal and simply run this script by doing <code>python bot.py</code>, you'll see that something is running in your terminal. Then, when you message your telegram bot, you get a nice little prompt back with "Welcome :)". </p>
<h2 id="getting-information-on-your-portfolio-example">Getting information on your portfolio (example)</h2>
<p>But we want to get a little more fancy, ideally, as an example, let's say that we want our bot to inform us on our portfolio worth. We create a <code>portfolio.py</code> file:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># portfolio.py</span>
<span class="kn">import</span> <span class="nn">yfinance</span> <span class="k">as</span> <span class="nn">yf</span> <span class="c1"># pip install yfinance</span>
<span class="c1"># you bought 2 stocks of Microsoft</span>
<span class="n">ACQUISITION_PRICE</span> <span class="o">=</span> <span class="mi">150</span>
<span class="n">ACQUISITION_QTTY</span> <span class="o">=</span> <span class="mi">2</span>
<span class="n">STOCK_NAME</span> <span class="o">=</span> <span class="s2">"MSFT"</span>
<span class="c1"># a function that returns our gains on the purchase of MSFT stocks</span>
<span class="k">def</span> <span class="nf">get_current_value</span><span class="p">():</span>
<span class="n">msft</span> <span class="o">=</span> <span class="n">yf</span><span class="o">.</span><span class="n">Ticker</span><span class="p">(</span><span class="s2">"MSFT"</span><span class="p">)</span>
<span class="n">last_value</span> <span class="o">=</span> <span class="n">yf</span><span class="o">.</span><span class="n">info</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"previousClose"</span><span class="p">)</span>
<span class="n">previous_worth</span> <span class="o">=</span> <span class="n">ACQUISITION_QTTY</span> <span class="o">*</span> <span class="n">ACQUISITION_PRICE</span>
<span class="n">current_worth</span> <span class="o">=</span> <span class="n">ACQUISITION_QTTY</span> <span class="o">*</span> <span class="n">last_value</span>
<span class="n">gain</span> <span class="o">=</span> <span class="n">current_worth</span> <span class="o">-</span> <span class="n">previous_growth</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">"Your current gains on </span><span class="si">{</span><span class="n">STOCK_NAME</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">gain</span><span class="si">:</span><span class="s2">.2f</span><span class="si">}</span><span class="s2">"</span>
</code></pre></div>
<p>The above function, <code>get_current_value</code> will inform on how much your Microsoft stock is worth at any point in time, from when you purchased it. </p>
<h2 id="integrating-financial-updates-with-our-telegram-bot">Integrating financial updates with our Telegram bot</h2>
<p>Now that we have both a telegram bot and a basic script to update us on our portfolio performance, it's time to bring both together. </p>
<p>To do so, we create two functions:</p>
<ul>
<li><code>alarm</code>: a function that gets the value of our portfolio, and returns it to the user as a response</li>
<li><code>set_update</code>: a function that makes our bot run our alarm once a week (to decrease our stress level)</li>
</ul>
<div class="codehilite"><pre><span></span><code><span class="c1"># ... the rest of your bot.py file</span>
<span class="k">def</span> <span class="nf">alarm</span><span class="p">(</span><span class="n">context</span><span class="p">):</span> <span class="c1"># FIRST IMPORTANT ADDITION</span>
<span class="n">job</span> <span class="o">=</span> <span class="n">context</span><span class="o">.</span><span class="n">job</span> <span class="c1"># get context</span>
<span class="n">text</span> <span class="o">=</span> <span class="n">get_current_value</span><span class="p">()</span> <span class="c1"># run our financial update</span>
<span class="n">context</span><span class="o">.</span><span class="n">bot</span><span class="o">.</span><span class="n">send_message</span><span class="p">(</span><span class="n">job</span><span class="o">.</span><span class="n">context</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="n">text</span><span class="p">)</span> <span class="c1"># respond with the string returned by the function</span>
<span class="k">def</span> <span class="nf">set_update</span><span class="p">(</span><span class="n">update</span><span class="p">:</span> <span class="n">Update</span><span class="p">,</span> <span class="n">context</span><span class="p">:</span> <span class="n">CallbackContext</span><span class="p">):</span> <span class="c1"># SECOND ADDITION</span>
<span class="n">chat_id</span> <span class="o">=</span> <span class="n">update</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">chat_id</span> <span class="c1"># get our chat ID</span>
<span class="n">secconds_between_runs</span> <span class="o">=</span> <span class="mi">24</span> <span class="o">*</span> <span class="mi">7</span> <span class="o">*</span> <span class="mi">60</span> <span class="o">*</span> <span class="mi">60</span> <span class="c1"># run every week (24 hours * 7 days * 60 mins * 60 secs)</span>
<span class="n">update</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">reply_text</span><span class="p">(</span><span class="s2">"Financial updates will run!"</span><span class="p">)</span> <span class="c1"># confirm to user that it will run</span>
<span class="n">context</span><span class="o">.</span><span class="n">job_queue</span><span class="o">.</span><span class="n">run_repeating</span><span class="p">(</span>
<span class="n">alarm</span><span class="p">,</span> <span class="n">interval</span><span class="o">=</span><span class="n">secconds_between_runs</span><span class="p">,</span> <span class="n">first</span><span class="o">=</span><span class="mi">30</span><span class="p">,</span> <span class="n">context</span><span class="o">=</span><span class="n">chat_id</span>
<span class="p">)</span> <span class="c1"># run the alarm as a recurring update and the first message runs 30 seconds after our update is set</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="n">updater</span> <span class="o">=</span> <span class="n">Updater</span><span class="p">(</span><span class="n">API_TOKEN</span><span class="p">,</span> <span class="n">use_context</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">dispatcher</span> <span class="o">=</span> <span class="n">updater</span><span class="o">.</span><span class="n">dispatcher</span>
<span class="n">dispatcher</span><span class="o">.</span><span class="n">add_handler</span><span class="p">(</span><span class="n">CommandHandler</span><span class="p">(</span><span class="s2">"start"</span><span class="p">,</span> <span class="n">start</span><span class="p">))</span>
<span class="n">dispatcher</span><span class="o">.</span><span class="n">add_handler</span><span class="p">(</span><span class="n">CommandHandler</span><span class="p">(</span><span class="s2">"set_update"</span><span class="p">,</span> <span class="n">set_update</span><span class="p">))</span> <span class="c1"># NEW COMMAND</span>
<span class="n">updater</span><span class="o">.</span><span class="n">start_polling</span><span class="p">()</span>
<span class="n">updater</span><span class="o">.</span><span class="n">idle</span><span class="p">()</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span>
</code></pre></div>
<p>After this, every time you send your bot the message <code>/set_update</code>, it will schedule our financial update to be run every week! (feel free to try it live by making it run every 10 minutes or so)</p>
<h2 id="adding-a-bit-of-security-and-deploying">Adding a bit of security and deploying</h2>
<p>We don't want the whole world to access our bot (or our financial updates), so, it's smart to limit your bot to respond only to yourself (or your telegram username). And easy way to do so is to add an <code>if</code> statement to your <code>set_update</code> function like so:</p>
<div class="codehilite"><pre><span></span><code><span class="k">def</span> <span class="nf">set_update</span><span class="p">(</span><span class="n">update</span><span class="p">:</span> <span class="n">Update</span><span class="p">,</span> <span class="n">context</span><span class="p">:</span> <span class="n">CallbackContext</span><span class="p">):</span>
<span class="o">...</span>
<span class="k">if</span> <span class="n">username</span> <span class="o">==</span> <span class="n">AUTHORIZED_USERNAME</span><span class="p">:</span>
<span class="n">update</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">reply_text</span><span class="p">(</span><span class="s2">"Financial updates will run!"</span><span class="p">)</span>
<span class="n">context</span><span class="o">.</span><span class="n">job_queue</span><span class="o">.</span><span class="n">run_repeating</span><span class="p">(</span>
<span class="n">alarm</span><span class="p">,</span> <span class="n">interval</span><span class="o">=</span><span class="n">every_seconds</span><span class="p">,</span> <span class="n">first</span><span class="o">=</span><span class="mi">30</span><span class="p">,</span> <span class="n">context</span><span class="o">=</span><span class="n">chat_id</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">update</span><span class="o">.</span><span class="n">message</span><span class="o">.</span><span class="n">reply_text</span><span class="p">(</span>
<span class="s2">"Sorry, but you are not authorized to use this command.."</span>
<span class="p">)</span>
</code></pre></div>
<p>This ensures your bot only gives financial updates to YOU, which is pretty important.. </p>
<p>For deployment, you only need to leave your <code>bot.py</code> script running somewhere. I chose to use one of my Virtual Private Servers and run the script in a <a href="https://en.wikipedia.org/wiki/Tmux">tmux</a> session. But there are also some <a href="https://github.com/python-telegram-bot/python-telegram-bot/wiki/Where-to-host-Telegram-Bots">good alternatives in the docs</a> if you re interested!</p>
<h2 id="closing-thoughts">Closing thoughts</h2>
<p>This was a very simple example of how you can get your bot up and running really quickly. But some things differ from the setup that I have actually in place (and the one you'll probably build):</p>
<ul>
<li>Here we used the <code>yfinance</code> data to track performance, but you can use WHATEVER you want. As an example, my bot is running some scrappers on stock exchanges related to my portfolio (and not available through the library)</li>
<li>You can also add forward looking KPIs and information (what was the best performing stock of the ones you're watching?)</li>
<li>Add some alerts about news using a library like <a href="https://newspaper.readthedocs.io/en/latest/">Newspaper3k</a>! To make everything even more dynamic :) </li>
</ul>
<p>This is why hacking on your own tools is more rewarding than just using an off the shelf app: Yes, it takes time, and yes, it can seem a lot less "fancy". But you learn a lot while doing it, and more importantly: you build it to become YOUR tool, not A tool. </p>
<p><br></p>
<p><em>Thanks for reading! If you like this post, consider <a href="mailto:me@duarteocarmo.com">reaching out</a>! I'm thinking of starting a newsletter, and I'm interested in knowing if you would potentially sign up!</em></p>Hacking on my finances2020-10-18T00:00:00+02:002020-10-18T00:00:00+02:00Duarte O.Carmotag:duarteocarmo.com,2020-10-18:/blog/hacking-on-my-finances.html<p><em>Currently, my job has taken a lot of my time. But who doesn't have time for side projects? At the end of the day - they keep us sane. So I’ve been currently hacking on a good way of managing my finances - and oh boy I’m having fun.</em> </p>
<p><strong>Update …</strong></p><p><em>Currently, my job has taken a lot of my time. But who doesn't have time for side projects? At the end of the day - they keep us sane. So I’ve been currently hacking on a good way of managing my finances - and oh boy I’m having fun.</em> </p>
<p><strong>Update</strong>: <a href="/blog/hacking-on-my-finances-part-2-beancount-on-beanstalk.html">Part 2: Beancount on Beanstalk</a></p>
<p>You can ready the whole story, or just jump to my <a href="#so-how-do-i-manage-my-finances-now">current setup.</a> </p>
<p><center>
<img src="https://duarteocarmo.com/images/fava.png" alt="Fava example" style="max-width: 100%; margin-bottom: -1em"></p>
<figcaption><a href='https://beancount.github.io/fava/' target='_blank'>Fava</a>, one of the tools I use for keeping my books</figcaption>
<p></center></p>
<h2 id="but-why-do-you-even-bother">But why do you even bother?</h2>
<p>I’ve been keeping track of my finances for about 10 years now. No it’s not something you should absolutely do, but being raised in a household where this was the norm, I’ve naturally found myself doing it from a “young age”. </p>
<p>Of course there are many reasons to track your finances, but for me, the question is pretty simple: I just want to have the power to understand where my money goes, and where my money comes from. And since “information is power”, I’ve been a bit obsessed with documenting. </p>
<h2 id="how-i-have-tracked-my-finances-in-the-past">How I have tracked my finances in the past</h2>
<p>Like every “tracking aficionado”, I started tracking all of my finances using mobile applications. I’ve used everything from <a href="https://apps.apple.com/us/app/dailycost-expense-tracker/id566587079">DailyCost</a> to <a href="https://apps.apple.com/us/app/spending-tracker/id548615579">Spending Tracker</a>. But all of these had drawbacks. Not because of the apps themselves, but because they did not fit my mindset/workflow. I want to know how much I have on account X, and how much I owe to someone next month. And even though some modern alternatives already connect to your bank accounts, I wanted something more “hackable”. </p>
<p>And so I fell into “Excel hell”. I found that I could use a simple app to track my spendings (<a href="https://www.spendee.com/">Spendee</a>) and then, at regular intervals I would put that information into Excel. There, I would create my own overview of “how things are going”, and “where my money was spent”. </p>
<p>But keeping track of things in Excel had various drawbacks:</p>
<ul>
<li>I had no connection to my banking accounts </li>
<li>Currency exchanges are a pain in the ass (I know there are plugins, but come on..)</li>
<li>I had to create a lot of custom formulas, that were a pain to maintain</li>
<li>Excel is proprietary software, and I don’t like depending on proprietary software</li>
<li>The system was not programmable to my needs - hard to extend</li>
</ul>
<p>So after 7 years tracking my finances in Excel - I decided to look for something better (for me at least)</p>
<h2 id="enter-plain-text-accounting">Enter plain text accounting</h2>
<p><a href="https://plaintextaccounting.org/">Plain text accounting</a> is a movement, or even better, a community. It’s a group of people passionate about keeping track of their finances using plain text formats, programmable interfaces, and hackable workflows. </p>
<p>Imagine having a txt file where you can manage all of your finances - and hack in workflows that fit your needs exactly. That sounded just like the solution I needed.</p>
<p>Upon further investigation of <a href="https://plaintextaccounting.org/#plain-text-accounting-apps">command line applications</a> (because who likes GUIs?) that are inline with plain text accounting, I found <a href="https://beancount.github.io/">beancount</a>. There are also other alternatives such as <a href="https://www.ledger-cli.org/">Ledger</a> (written in C++) or <a href="https://hledger.org/">hledger</a> (written in Haskell). </p>
<p>But hey, I’m a Python guy, and want to be able to hack on this to my needs, so I went with <a href="https://beancount.github.io/">beancount</a>.</p>
<h2 id="so-how-do-i-manage-my-finances-now">So how do I manage my finances now?</h2>
<p><em>Disclaimer: This is how I do it - your current situation and preferences will most likely be very different from mine - so this is by no means a tutorial - simply a showcase</em></p>
<h3 id="out-and-about">Out and about</h3>
<p>At the end of the month, I like to be able to look back and see how much I have spent in different categories such as “Entertainment”, “Groceries”, “Shopping” etc. So when I’m out in about, I usually use <a href="https://www.spendee.com/">Spendee</a> to keep track of those. Spendee has a whole world of other features - but I simply use it for tracking simple transactions.</p>
<h3 id="the-central-piece-beancount">The central piece: <a href="https://beancount.github.io/docs/">Beancount</a></h3>
<p>The whole overview of my finances, uses beancount. I’m not going to go deep on how awesome beancount is, or the whole feature set that it offers. (for that you can start with the incredible <a href="https://beancount.github.io/docs/">documentation</a>)
It basically takes a “beacount file” and allows you to generate several reports / consistency checks/ queries on that same file.<br />
Here’s an example of a beancount file:</p>
<div class="codehilite"><pre><span></span><code><span class="o">;</span><span class="w"> </span><span class="nt">creating</span><span class="w"> </span><span class="nt">an</span><span class="w"> </span><span class="nt">account</span><span class="w"> </span><span class="nt">and</span><span class="w"> </span><span class="nt">setting</span><span class="w"> </span><span class="nt">some</span><span class="w"> </span><span class="nt">balances</span>
<span class="nt">2015-01-01</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="s2">"Opening Balance for checking account"</span>
<span class="w"> </span><span class="nt">Assets</span><span class="p">:</span><span class="nd">US</span><span class="p">:</span><span class="nd">BofA</span><span class="p">:</span><span class="nd">Checking</span><span class="w"> </span><span class="nt">3490</span><span class="p">.</span><span class="nc">52</span><span class="w"> </span><span class="nt">USD</span>
<span class="w"> </span><span class="nt">Equity</span><span class="p">:</span><span class="nd">Opening-Balances</span><span class="w"> </span><span class="nt">-3490</span><span class="p">.</span><span class="nc">52</span><span class="w"> </span><span class="nt">USD</span>
<span class="o">;</span><span class="w"> </span><span class="nt">an</span><span class="w"> </span><span class="nt">example</span><span class="w"> </span><span class="nt">expense</span>
<span class="nt">2017-04-18</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="s2">"Verizon Wireless"</span><span class="w"> </span><span class="s2">""</span>
<span class="w"> </span><span class="nt">Assets</span><span class="p">:</span><span class="nd">US</span><span class="p">:</span><span class="nd">BofA</span><span class="p">:</span><span class="nd">Checking</span><span class="w"> </span><span class="nt">-85</span><span class="p">.</span><span class="nc">18</span><span class="w"> </span><span class="nt">USD</span>
<span class="w"> </span><span class="nt">Expenses</span><span class="p">:</span><span class="nd">Home</span><span class="p">:</span><span class="nd">Phone</span><span class="w"> </span><span class="nt">85</span><span class="p">.</span><span class="nc">18</span><span class="w"> </span><span class="nt">USD</span>
<span class="o">;</span><span class="w"> </span><span class="nt">another</span><span class="w"> </span><span class="nt">example</span><span class="w"> </span><span class="nt">expense</span>
<span class="nt">2017-04-23</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="s2">"Wine-Tarner Cable"</span><span class="w"> </span><span class="s2">""</span>
<span class="w"> </span><span class="nt">Assets</span><span class="p">:</span><span class="nd">US</span><span class="p">:</span><span class="nd">BofA</span><span class="p">:</span><span class="nd">Checking</span><span class="w"> </span><span class="nt">-80</span><span class="p">.</span><span class="nc">20</span><span class="w"> </span><span class="nt">USD</span>
<span class="w"> </span><span class="nt">Expenses</span><span class="p">:</span><span class="nd">Home</span><span class="p">:</span><span class="nd">Internet</span><span class="w"> </span><span class="nt">80</span><span class="p">.</span><span class="nc">20</span><span class="w"> </span><span class="nt">USD</span>
</code></pre></div>
<p>So every month, I take my spendings, input them into my beancount file, make sure my accounts and assets all match, and basically do my “bookkeeping” on that file. For this, I use a system called “Double entry counting” (learn more <a href="https://beancount.github.io/docs/the_double_entry_counting_method.html">here</a>). </p>
<h3 id="analyzing-everything-fava">Analyzing everything: <a href="https://beancount.github.io/fava/">Fava</a></h3>
<p>Even though beancount can generate some <a href="https://beancount.github.io/docs/running_beancount_and_generating_reports.html#tools">reports</a>, I have found that the terminal is not the best place to analyze data. </p>
<p>Fortunately, <a href="https://beancount.github.io/fava/">Fava</a> exists. Fava is a web interface for your beancount file. It allows you to have a nice to use, easy to navigate website, where you can:</p>
<ul>
<li>Have an overview of your accounts</li>
<li>Run queries on your transactions (Using the <a href="http://aumayr.github.io/beancount-sql-queries/">beanquery language</a>)</li>
<li>Visualize your data in different times/accounts/categories</li>
</ul>
<h3 id="access-from-anywhere">Access from anywhere</h3>
<p>To make sure I can access my beancount files anywhere, I have kept all of them synced to a nice git repo that syncs with my server. </p>
<p>I have also installed Fava on that server, which basically allows me to access my visualizations in any machine that has a web browser. </p>
<p>And oh boy do I love this setup. </p>
<h2 id="closing-thoughts">Closing thoughts</h2>
<p>I’m still improving on this setup - creating custom scripts that evaluate my position given my constraints, automatically connect to my assets, and even alarm me if something not expected happened. </p>
<p>And that’s the beauty of not using Excel. I’m now using something I can hack on and make my own - and even though that’s not a complete system - it’s a great system for me. </p>
<p><em>Thanks to <a href="https://github.com/blais">Martin Blais</a> for creating beancount and for actively maintaining and documenting such an awesome tool.</em></p>
<p><strong>Update:</strong> This post has been featured in the awesome <a href="https://plaintextaccounting.org/#articles-blog-posts" target="_blank">plain text accounting blog</a>.</p>Can I go home yet?2020-07-23T00:00:00+02:002020-07-23T00:00:00+02:00Duarte O.Carmotag:duarteocarmo.com,2020-07-23:/blog/can-i-go-home-yet.html<p>On the 18th of June, Denmark <a href="https://www.reuters.com/article/us-health-coronavirus-denmark-borders/denmark-will-reopen-to-most-european-nations-except-portugal-much-of-sweden-idUSKBN23P1OD">announced new travel policies after the Coronavirus outbreak</a>. From that date on, it allowed travel to all European countries except for Portugal and Sweden. Of course, this caused several news outlets to write on the issue (<a href="https://www.thelocal.dk/20200618/denmark-opens-to-tourists-from-every-eu-country-but-sweden">Local.dk</a>, <a href="https://politiken.dk/rejser/art7839386/Nu-kan-danskerne-tage-til-endnu-flere-steder-i-Sverige">Politiken.dk</a>, <a href="https://www.reuters.com/article/us-health-coronavirus-denmark-borders/denmark-will-reopen-to-most-european-nations-except-portugal-much-of-sweden-idUSKBN23P1OD">Reuters.com</a>). But now …</p><p>On the 18th of June, Denmark <a href="https://www.reuters.com/article/us-health-coronavirus-denmark-borders/denmark-will-reopen-to-most-european-nations-except-portugal-much-of-sweden-idUSKBN23P1OD">announced new travel policies after the Coronavirus outbreak</a>. From that date on, it allowed travel to all European countries except for Portugal and Sweden. Of course, this caused several news outlets to write on the issue (<a href="https://www.thelocal.dk/20200618/denmark-opens-to-tourists-from-every-eu-country-but-sweden">Local.dk</a>, <a href="https://politiken.dk/rejser/art7839386/Nu-kan-danskerne-tage-til-endnu-flere-steder-i-Sverige">Politiken.dk</a>, <a href="https://www.reuters.com/article/us-health-coronavirus-denmark-borders/denmark-will-reopen-to-most-european-nations-except-portugal-much-of-sweden-idUSKBN23P1OD">Reuters.com</a>). But now, one month later, let us try to investigate the issue, and whether these bans make sense.</p>
<p>Curious about why the decision was made, I stumbled upon a couple of interesting official danish sources on the decision. The first is <a href="https://www.justitsministeriet.dk/nyt-og-presse/pressemeddelelser/2020/danmark-aabner-graenserne-yderligere-og-lemper">a statement</a> where the official new policy was stated. This statement dates from June 18th and states that:</p>
<p><em>"[...]To be "open", a country must have less than 20 infected per. 100,000 inhabitants per. week. Once a country is open, the critical level for when a country changes status to "quarantine country" will be at 30 infected per. 100,000 inhabitants.[...]"</em></p>
<p>I also stumbled upon the <a href="https://www.ssi.dk/-/media/arkiv/dk/aktuelt/sygdomsudbrud/covid19/covid-19-rejsekriterier/16_07_2020_tors/tabel_11_1.pdf?la=da">official document</a> where all of these calculations where made. Where we can clearly see that both Portugal and Sweden have more than 20 infected people per week per 100.000 people. On the other hand, countries such as Spain, or Romania have less than that number, and were hence declared as "open for travel".</p>
<p>Since I am planning to go to Denmark on the beginning of August, and have heard no updates on the situation since, let's try to see how the situation evolved since the announcement:</p>
<p><center>
<img src="https://duarteocarmo.com/images/portugal.png" alt="Vim" style="max-width: 100%">
</center></p>
<p><strong>A good initial decision.</strong> Taking data from <a href="https://github.com/CSSEGISandData/COVID-19">the official Johns Hopkins repository</a>, and some <a href="https://nbhub.duarteocarmo.com/notebook/573bf718">manipulation</a>. I was able to plot the number of cases per 100.000 people of the last 7 days, for every day since February 1st. We can clearly see that in the date of the announcement, Portuguese cases were in the <em>Orange Zone</em> (.i.e slightly above 20 per 100k pax per week). However, you might notice that in the last couple of weeks, the number of cases in Portugal has started to decrease, falling into the <em>Open to travel zone</em>. </p>
<p><strong>Coronavirus is unpredictable.</strong> In the original <a href="https://www.ssi.dk/-/media/arkiv/dk/aktuelt/sygdomsudbrud/covid19/covid-19-rejsekriterier/16_07_2020_tors/tabel_11_1.pdf?la=da">list of travel bans</a>, countries such as Spain and Romania (to my surprise), were green lighted and allowed traveling to and from. Because at the date of the announcement, their number of cases per 100k people fell below 20. </p>
<p>Has this changed?</p>
<p>Yes!!</p>
<p><center>
<img src="https://duarteocarmo.com/images/others.png" alt="Vim" style="max-width: 100%">
</center></p>
<p>Upon closer inspection, notice how the number of cases per capita in Portugal has decreased in the last couple of weeks. On the other hand, <strong>the metric for Spain and Romania</strong> has exploded. This means that, according to the original criteria, these two countries should now be banned from all travel (Romania even approaches the red <em>Quarantine region</em>).</p>
<p>To answer the original question of this post: Yes, I should be allowed to go home now. (I'm from Portugal but live in Denmark.)</p>
<p>But that's just a tip of a large iceberg. And a bit shallow on my behalf. </p>
<p>Let's take some real conclusions:</p>
<ul>
<li><strong>Coronavirus response is unstable:</strong> Coronavirus moves extremely fast, what was true for Portugal a month ago (cases rising) might not be true a month after. And what was true for Spain a month ago can also start changing very quickly. </li>
<li><strong>Policy is hard:</strong> Policy making, especially in such times, is no small task. I love that Denmark can swiftly propose a legislation that is transparent and measurable. </li>
<li><strong>Metrics should be regularly updated:</strong> Having chosen a specific metric to define travel restrictions, we should make sure to update it regularly. As far as I know, the <a href="https://www.ssi.dk/-/media/arkiv/dk/aktuelt/sygdomsudbrud/covid19/covid-19-rejsekriterier/16_07_2020_tors/tabel_11_1.pdf?la=da">original list</a> only updates every 2 weeks. But as we have seen here, a lot of things can change in 2 weeks. </li>
</ul>
<p>Thanks for reading my rant about going home 😆!</p>
<p><strong>Update:</strong> <a href="https://mybinder.org/v2/gh/duarteocarmo/canigohome/master?urlpath=%2Fvoila%2Frender%2Fnotebooks%2FCanIgoHome.ipynb">Here's a link</a> for a live dashboard of the stats. </p>
<p><strong>Update 2:</strong> The list of banned countries <a href="https://www.ssi.dk/-/media/arkiv/dk/aktuelt/sygdomsudbrud/covid19/covid-19-rejsekriterier/30_07_2020_83ha/tabel_11_1_europa.pdf?la=da">has been updated</a> and I will be able to return on Sunday (2/8/2020).</p>The mini state of VIM 20192020-07-20T00:00:00+02:002020-07-20T00:00:00+02:00Duarte O.Carmotag:duarteocarmo.com,2020-07-20:/StateOfVimNbHub: Share your jupyter notebooks with the world2020-06-22T00:00:00+02:002020-06-22T00:00:00+02:00Duarte O.Carmotag:duarteocarmo.com,2020-06-22:/blog/nbhub-share-your-jupyter-notebooks-with-the-world.html<p><em><strong>TL;DR</strong>: I created a small python package that allows you to share your jupyter notebooks right from the command line (like <a href="https://nbhub.duarteocarmo.com/notebook/e6b917cb">this one</a> for example). To get started, visit <a href="https://nbhub.duarteocarmo.com">nbhub.duarteocarmo.com</a>. or <code>pip install nbhub</code>.</em></p>
<h2 id="sharing-jupyter-notebooks-is-a-pain">Sharing jupyter notebooks is a pain</h2>
<p>We use jupyter notebooks for a wide …</p><p><em><strong>TL;DR</strong>: I created a small python package that allows you to share your jupyter notebooks right from the command line (like <a href="https://nbhub.duarteocarmo.com/notebook/e6b917cb">this one</a> for example). To get started, visit <a href="https://nbhub.duarteocarmo.com">nbhub.duarteocarmo.com</a>. or <code>pip install nbhub</code>.</em></p>
<h2 id="sharing-jupyter-notebooks-is-a-pain">Sharing jupyter notebooks is a pain</h2>
<p>We use jupyter notebooks for a wide range of things: quick analyses, serious projects, experimentation, and even for creating dashboards. However, when you want to share your work with someone that is not necessarily familiar with what a “jupyter notebook” actually is, you run into some problems. </p>
<p>Let’s take a look at some of the options you have available when you want to share a notebook:</p>
<ul>
<li><strong>Send the file</strong>: Given that the person you want to share the notebook with has a good grasp on files that end with “.ipynb”, you can potentially just send them the notebook file, and let them open it on their computer. A major drawback here is that if the person you are sharing the notebook with has no clue about what a notebook is, they will have no idea on how to fire up a “.ipynb” file.</li>
<li><strong>Convert to a friendlier format and then send it</strong>: If the person you want to share the notebook with has no idea of what a notebook is, you can start by converting the notebook to, let’s say, an HTML format, and then send them the file via email. To do this, you would probably use a tool such as <a href="https://nbconvert.readthedocs.io/en/latest/">nbconvert</a>. But have you seen a notebook converted to PDF? It looks far from ideal. Also, if you convert it to HTML, not everyone (unfortunately) knows how to open “.HTML” files in their computer.</li>
<li><a href="https://nbviewer.jupyter.org/"><strong>NbViewer</strong></a>: Given that your notebook is hosted in a public repo, this is your best option. You simply go to the website, paste the url for a notebook you want to share, <a href="https://nbviewer.jupyter.org/github/duarteocarmo/technological_capabilities/blob/master/notebooks/4_1_Macro%20Level%20Analysis.ipynb">and voila</a>! However, you’ll need to set up a rapport gist to do this. And your notebook will be accessible to anyone. </li>
<li><a href="https://github.com/duarteocarmo/technological_capabilities/blob/master/notebooks/4_1_Macro%20Level%20Analysis.ipynb"><strong>GitHub</strong></a>: If your notebook is in a public repo, you can also send them the link to the notebook in GitHub. But notice how the table of contents does not work, you can’t link to a specific section, and you need to host your notebook in a repo.</li>
</ul>
<p>These are good options, but each one of them has drawbacks. In an ideal world, sharing a notebook should be as easy as sharing a link to a google doc, I envision something that:</p>
<ul>
<li>Does not require you to convert your notebook. </li>
<li>Does not require you to create a repo, public or private. </li>
<li>Does not require the person you are sharing the notebook with to learn anything new. (how to deal with .ipynb files, how to open .html files)</li>
<li>Keeps a functioning table of contents. </li>
<li>Allows you to link to a specific section. </li>
<li>Allows you to set a simple password when sharing, so that your work isn’t exposed to the whole world. </li>
<li>Allows you to share notebooks without leaving your beloved command line. </li>
</ul>
<p>Enter <a href="https://nbhub.duarteocarmo.com/"><strong>NbHub</strong></a>. </p>
<h2 id="nbhub-share-your-notebooks-from-the-command-line">NbHub: share your notebooks from the command line.</h2>
<p><em>⚠️<strong>Preliminary note</strong>: NbHub is a proof of concept, or better, <strong>NbHub is a hack</strong>. It was developed in a weekend, has no guarantees of security or encryption, and is missing features like sharing notebooks with a password. For now, it’s a glorified self-hosted nbviewer alternative with a cli tool.</em></p>
<p>Let’s first see how it works from a user’s perspective, and then I’ll dive deeper into how it works. </p>
<p>To get started, simply install the command line tool using pip (even though you should be using something like <a href="https://github.com/pipxproject/pipx">pipx</a>):</p>
<div class="codehilite"><pre><span></span><code>$<span class="w"> </span>pip3<span class="w"> </span>install<span class="w"> </span>nbhub
</code></pre></div>
<p>Now, let’s say I want to share the “Analysis.ipynb” notebook with someone. Simply run:</p>
<div class="codehilite"><pre><span></span><code>$<span class="w"> </span>nbhub<span class="w"> </span>Analysis.ipynb
</code></pre></div>
<p>You’ll be walked through a simple command-line script that asks you a couple of questions. Once you are done, you’ll receive a link such as <a href="https://nbhub.duarteocarmo.com/notebook/e6b917cb">this one</a>. By clicking it, you’ll see that your notebook is now on the web. You can just send that link to someone, and they’ll see your notebook. </p>
<p>Another thing that I love, is that if I’m sharing a very large notebook, I can even link to a specific section of it. For example, click <a href="https://nbhub.duarteocarmo.com/notebook/e6b917cb#five">here</a> to jump to the “contextual relationships” section of the example notebook. </p>
<h2 id="how-nbhub-works">How NbHub works</h2>
<p>NbHub consists of: </p>
<ul>
<li>A <a href="#the-webserver">web server</a> that receives a GET request with a notebook data field, and responds with a link to a notebook on that same web server. </li>
<li>A <a href="#the-cli-tool">command-line tool</a>: The main package that walks the user through the process of sharing the notebook. </li>
</ul>
<p>Let’s dive a bit deeper into these two:</p>
<h3 id="the-webserver">The Webserver</h3>
<p>The web server is a <a href="https://fastapi.tiangolo.com/">FastAPI</a> app with 3 endpoints:</p>
<ul>
<li><code>get("/")</code>: the homepage, or what you see when you visit <a href="nbhub.duarteocarmo.com">nbhub.duarteocarmo.com</a>. </li>
<li><code>post(“/upload”)</code>: the endpoint that receives a post request with a notebook in the data field, converts it to .html, and then stores it in the server. </li>
<li><code>get(“/notebook/id”)</code>: the endpoint that exposes a stored notebook, so that the user can see it. </li>
</ul>
<p>You can visit the <a href="https://github.com/duarteocarmo/nbhub_webservice">GitHub repo</a>, or read the code below:</p>
<div class="codehilite"><pre><span></span><code><span class="nd">@app</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"/"</span><span class="p">)</span> <span class="c1"># present homepage</span>
<span class="k">async</span> <span class="k">def</span> <span class="nf">home</span><span class="p">():</span>
<span class="n">home_page</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="s2">"static/home.html"</span><span class="p">)</span><span class="o">.</span><span class="n">read_text</span><span class="p">()</span>
<span class="k">return</span> <span class="n">fastapi</span><span class="o">.</span><span class="n">responses</span><span class="o">.</span><span class="n">HTMLResponse</span><span class="p">(</span><span class="n">content</span><span class="o">=</span><span class="n">home_page</span><span class="p">,</span> <span class="n">status_code</span><span class="o">=</span><span class="mi">200</span><span class="p">)</span>
<span class="nd">@app</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s2">"/upload"</span><span class="p">)</span> <span class="c1"># endpoint that receives notebook, converts and stores. </span>
<span class="k">async</span> <span class="k">def</span> <span class="nf">respond</span><span class="p">(</span><span class="n">request</span><span class="p">:</span> <span class="n">fastapi</span><span class="o">.</span><span class="n">Request</span><span class="p">):</span>
<span class="n">unique_id</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">uuid</span><span class="o">.</span><span class="n">uuid4</span><span class="p">())</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"-"</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">id_list</span> <span class="o">=</span> <span class="p">[</span><span class="n">item</span><span class="o">.</span><span class="n">stem</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">NOTEBOOK_STORAGE</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s2">"**/*.html"</span><span class="p">)]</span>
<span class="k">while</span> <span class="n">unique_id</span> <span class="ow">in</span> <span class="n">id_list</span><span class="p">:</span>
<span class="n">unique_id</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">uuid</span><span class="o">.</span><span class="n">uuid4</span><span class="p">())</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"-"</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">notebook_path</span> <span class="o">=</span> <span class="n">NOTEBOOK_STORAGE</span> <span class="o">/</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">unique_id</span><span class="si">}</span><span class="s2">.ipynb"</span>
<span class="n">html_path</span> <span class="o">=</span> <span class="n">NOTEBOOK_STORAGE</span> <span class="o">/</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">unique_id</span><span class="si">}</span><span class="s2">.html"</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">form</span> <span class="o">=</span> <span class="k">await</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">()</span>
<span class="n">contents</span> <span class="o">=</span> <span class="k">await</span> <span class="n">form</span><span class="p">[</span><span class="n">SITE_POST_LABEL</span><span class="p">]</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="n">notebook_json_keys</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">contents</span><span class="p">)</span><span class="o">.</span><span class="n">keys</span><span class="p">()</span>
<span class="k">assert</span> <span class="s2">"nbformat"</span> <span class="ow">in</span> <span class="n">notebook_json_keys</span>
<span class="k">assert</span> <span class="nb">len</span><span class="p">(</span><span class="n">notebook_json_keys</span><span class="p">)</span> <span class="o">==</span> <span class="mi">4</span>
<span class="k">assert</span> <span class="n">sys</span><span class="o">.</span><span class="n">getsizeof</span><span class="p">(</span><span class="n">contents</span><span class="p">)</span> <span class="o">/</span> <span class="mi">1000000</span> <span class="o"><</span> <span class="n">NOTEBOOK_SIZE_LIMIT</span>
<span class="n">file</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">notebook_path</span><span class="p">,</span> <span class="s2">"wb"</span><span class="p">)</span>
<span class="n">file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">contents</span><span class="p">)</span>
<span class="n">file</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">converter</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">run</span><span class="p">([</span><span class="s2">"jupyter"</span><span class="p">,</span> <span class="s2">"nbconvert"</span><span class="p">,</span> <span class="n">notebook_path</span><span class="p">])</span>
<span class="n">notebook_path</span><span class="o">.</span><span class="n">unlink</span><span class="p">()</span>
<span class="k">return</span> <span class="p">{</span>
<span class="s2">"status"</span><span class="p">:</span> <span class="s2">"success"</span><span class="p">,</span>
<span class="s2">"path"</span><span class="p">:</span> <span class="sa">f</span><span class="s2">"http://</span><span class="si">{</span><span class="n">SITENAME</span><span class="si">}</span><span class="s2">/notebook/</span><span class="si">{</span><span class="n">html_path</span><span class="o">.</span><span class="n">stem</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span>
<span class="s2">"password"</span><span class="p">:</span> <span class="s2">"None"</span><span class="p">,</span>
<span class="s2">"expiry date"</span><span class="p">:</span> <span class="s2">"None"</span><span class="p">,</span>
<span class="p">}</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>
<span class="k">raise</span> <span class="n">fastapi</span><span class="o">.</span><span class="n">HTTPException</span><span class="p">(</span><span class="n">status_code</span><span class="o">=</span><span class="mi">404</span><span class="p">,</span> <span class="n">detail</span><span class="o">=</span><span class="s2">"ERROR"</span><span class="p">)</span>
<span class="nd">@app</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"/notebook/</span><span class="si">{notebook_id}</span><span class="s2">"</span><span class="p">)</span> <span class="c1"># serve notebook with particular ID</span>
<span class="k">async</span> <span class="k">def</span> <span class="nf">read_notebook</span><span class="p">(</span><span class="n">notebook_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
<span class="n">file</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span><span class="n">NOTEBOOK_STORAGE</span> <span class="o">/</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">notebook_id</span><span class="si">}</span><span class="s2">.html"</span><span class="p">)</span>
<span class="k">if</span> <span class="n">file</span><span class="o">.</span><span class="n">is_file</span><span class="p">():</span>
<span class="n">file_contents</span> <span class="o">=</span> <span class="n">file</span><span class="o">.</span><span class="n">read_text</span><span class="p">()</span>
<span class="k">return</span> <span class="n">fastapi</span><span class="o">.</span><span class="n">responses</span><span class="o">.</span><span class="n">HTMLResponse</span><span class="p">(</span>
<span class="n">content</span><span class="o">=</span><span class="n">file_contents</span><span class="p">,</span> <span class="n">status_code</span><span class="o">=</span><span class="mi">200</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">raise</span> <span class="n">fastapi</span><span class="o">.</span><span class="n">HTTPException</span><span class="p">(</span>
<span class="n">status_code</span><span class="o">=</span><span class="mi">404</span><span class="p">,</span> <span class="n">detail</span><span class="o">=</span><span class="s2">"Notebook does not exist."</span>
<span class="p">)</span>
</code></pre></div>
<h3 id="the-cli-tool">The CLI tool</h3>
<p>The command-line application is a <a href="https://click.palletsprojects.com/en/7.x/">Click</a> application that emulates a post request with a given notebook. It also performs some user side checks. </p>
<p>You can visit the <a href="https://github.com/duarteocarmo/nbhub">GitHub Repo</a>, or read the main code below as well:</p>
<div class="codehilite"><pre><span></span><code><span class="kn">import</span> <span class="nn">click</span>
<span class="kn">import</span> <span class="nn">requests</span>
<span class="n">POST_URL</span> <span class="o">=</span> <span class="s2">"https://nbhub.duarteocarmo.com/upload"</span>
<span class="n">SITE_POST_LABEL</span> <span class="o">=</span> <span class="s2">"notebook-data"</span>
<span class="n">SITE_URL</span> <span class="o">=</span> <span class="s2">"https://nbhub.duarteocarmo.com"</span>
<span class="nd">@click</span><span class="o">.</span><span class="n">command</span><span class="p">()</span>
<span class="nd">@click</span><span class="o">.</span><span class="n">argument</span><span class="p">(</span>
<span class="s2">"notebook"</span><span class="p">,</span>
<span class="n">required</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="nb">type</span><span class="o">=</span><span class="n">click</span><span class="o">.</span><span class="n">Path</span><span class="p">(</span>
<span class="n">exists</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="n">file_okay</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="n">dir_okay</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="n">readable</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="n">allow_dash</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="p">),</span>
<span class="p">)</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">(</span><span class="n">notebook</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""Share notebooks from the command line.</span>
<span class="sd"> NOTEBOOK is the jupyter notebook file you would like to share.</span>
<span class="sd"> """</span>
<span class="n">check_notebook</span><span class="p">(</span><span class="n">notebook</span><span class="p">)</span>
<span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">Welcome to NbHub!"</span><span class="p">)</span>
<span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Consider supporting us at: </span><span class="si">{</span><span class="n">SITE_URL</span><span class="si">}</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="sa">f</span><span class="s2">"You are about to publish </span><span class="si">{</span><span class="n">notebook</span><span class="si">}</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="n">click</span><span class="o">.</span><span class="n">confirm</span><span class="p">(</span><span class="s2">"Are you sure you want to publish it?"</span><span class="p">,</span> <span class="n">abort</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">if</span> <span class="n">click</span><span class="o">.</span><span class="n">confirm</span><span class="p">(</span><span class="s2">"Do you wish to set a password?"</span><span class="p">):</span>
<span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
<span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span>
<span class="sa">f</span><span class="s2">"Private notebooks are not available yet! 😬, check </span><span class="si">{</span><span class="n">SITE_URL</span><span class="si">}</span><span class="s2"> for updates"</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">assert</span> <span class="n">status_ok</span><span class="p">(</span><span class="n">POST_URL</span><span class="p">)</span> <span class="o">==</span> <span class="kc">True</span>
<span class="n">files</span> <span class="o">=</span> <span class="p">{</span><span class="n">SITE_POST_LABEL</span><span class="p">:</span> <span class="nb">open</span><span class="p">(</span><span class="n">notebook</span><span class="p">,</span> <span class="s2">"rb"</span><span class="p">)}</span>
<span class="n">response</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="n">POST_URL</span><span class="p">,</span> <span class="n">files</span><span class="o">=</span><span class="n">files</span><span class="p">)</span>
<span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">200</span><span class="p">:</span>
<span class="n">link</span> <span class="o">=</span> <span class="n">response</span><span class="o">.</span><span class="n">json</span><span class="p">()</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"path"</span><span class="p">)</span>
<span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
<span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="s2">"Published! ✨"</span><span class="p">)</span>
<span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Visit your notebook at: </span><span class="si">{</span><span class="n">link</span><span class="si">}</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="s2">"Sorry, something went wrong 😔"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">check_notebook</span><span class="p">(</span><span class="n">notebook</span><span class="p">):</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">notebook</span><span class="p">:</span>
<span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="s2">"No notebook provided, nothing to do 😇"</span><span class="p">)</span>
<span class="n">click</span><span class="o">.</span><span class="n">Context</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">status_ok</span><span class="p">(</span><span class="n">url</span><span class="p">):</span>
<span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">Querying the interwebs.. 🌎"</span><span class="p">)</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
<span class="n">click</span><span class="o">.</span><span class="n">echo</span><span class="p">(</span><span class="s2">"Sorry.. Our service appears to be down atm."</span><span class="p">)</span>
<span class="n">click</span><span class="o">.</span><span class="n">Context</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span>
</code></pre></div>
<h2 id="the-road-ahead">The road ahead</h2>
<p>My idea with NbHub was simply to build something that works for me. For the past 2 months, I have been using it every week with clients or co-workers in projects. Of course, I haven’t been using it for sensitive information since the password feature is still missing. </p>
<p>In the main repo, I included a <a href="https://github.com/duarteocarmo/nbhub#roadmap">road-map</a> of features I would like to implement to make the tool even more awesome: </p>
<ul>
<li>Date limit on notebooks to be destroyed.</li>
<li>Ability to set a password on link creation for private notebooks.Or protecting notebooks with passwords. </li>
<li>Improvements to CLI like only accepting notebook format.</li>
<li>Web server improvements (auto clean ups, encryption, etc.)</li>
</ul>
<p>For now, I’ll keep using it as a hack, because this hack works, and hacks are awesome. </p>Studying in Denmark as an international student2020-06-18T14:45:00+02:002020-06-18T14:45:00+02:00Duarte O.Carmotag:duarteocarmo.com,2020-06-18:/blog/studying-in-denmark-as-an-international-student.html<p><em>It's now been almost 4 years since I first landed in Denmark to start my Master's degree at the Technical University of Denmark, here in Copenhagen. This is a small retrospective filled with tips, tricks, and memories from an international student. It serves no particular purpose other than possibly having …</em></p><p><em>It's now been almost 4 years since I first landed in Denmark to start my Master's degree at the Technical University of Denmark, here in Copenhagen. This is a small retrospective filled with tips, tricks, and memories from an international student. It serves no particular purpose other than possibly having enjoyed reading something like it before moving here.</em></p>
<hr />
<p><strong>Pick a great school.</strong> Denmark has some of the best Universities in the world. Some of them are the <a href="https://www.dtu.dk/">Technical University of Denmark (DTU)</a>, the <a href="https://cbs.dk">Copenhagen Business School (CBS)</a>, <a href="https://international.au.dk/">Aarhus University</a>, and the <a href="https://www.ku.dk/english/">University of Copenhagen (KU)</a>. When I say "best", I'm not necessarily referring to the ranking of the schools (<a href="http://www.shanghairanking.com/World-University-Rankings-2018/Denmark.html">those are very good too</a>), I'm referring to the methodology of teaching, and the immense learning that results from it.</p>
<p>Most countries in the EU also have great universities, places like London or Paris are filled with great schools. Most public Universities in Europe are pretty cheap (comparing to countries like the US). A normal public university in Portugal, for example, will set you back about 1000€ per year. In Denmark though, school is completely free. Which, as a student, is a GREAT price for extraordinary academic experience. </p>
<p><br>
<img src="https://duarteocarmo.com/images/dtu_photo.jpg" alt="DTU Images" style="">
<br>
<br></p>
<p>One of the main reasons for choosing a Danish university over others is the teaching philosophy. In most places in Europe, teachers are chosen because of their academic reputation. In Denmark, teachers are chosen because of their teaching ability. Great researchers often result in subpar teachers and vice versa. But I have found it much more interesting to learn from someone that really puts effort into teaching rather than not. It's that old motto of teachers in the south of Europe being put on a pedestal and never responding to emails, that is the complete opposite here in Denmark. You are ENCOURAGED to email, bother, discuss, and talk to your teachers at all times. Transparency is key, and every course (at least in DTU), publishes its <a href="https://evaluering.dtu.dk/kursus/42575/100589">ratings</a> and <a href="http://karakterer.dtu.dk/Histogram/1/42575/Winter-2019">grade history every year</a>.</p>
<p>Moreover, in most Master degrees, at least 1/4 of your program is completely up to you to define. This means you can choose absolutely ANY course you want to take. Still remember choosing my courses at DTU, I felt like <a href="https://kurser.dtu.dk/search">browsing Amazon for cool products to buy</a>, or even like a kid in a candy shop. Really! <a href="https://www.dtu.dk/english/education/msc/programmes/industrial_engineering_management#study-programme">Take a look at this study program</a>. </p>
<p>Here are some of my personal favorite courses in DTU (yes, these are often open access to everyone, enrolled or not):</p>
<ul>
<li><a href="http://courses.compute.dtu.dk/ipdp/">Intro to programming and data processing</a></li>
<li><a href="https://github.com/suneman/socialdataanalysis2020">Social Data Analysis and Visualization</a></li>
<li><a href="https://github.com/DeepLearningDTU/02456-deep-learning-with-PyTorch">Deep Learning</a></li>
<li><a href="https://kurser.dtu.dk/course/42575">Technology and Innovation Management</a></li>
</ul>
<p>Where I come from (Portugal), we were used to almost ignore classes during the semester and then read a 300+ page textbook 2 weeks before exams week. The result? You try to pass and get that 10/20 just so you don't have to repeat the course again the year after. Also, group work is not a thing at all. In DK, the system revolves around continuous learning. You go to class in the morning, and then sit and solve problems with the teacher during the afternoon. Also, group work is very valued, which is great preparation for your professional life. </p>
<hr />
<p><strong>Start working early.</strong> Remember that I said that school is completely free? Well, it gets better. In Denmark, there is this thing called "student jobs". Student jobs are jobs you can get where you work 2 days a week for an hourly rate while completing a degree at the same time. If you are from a European country, this means that if you get one of these, you'll be earning, on top of that hourly rate, the much raved about SU (<a href="https://www.su.dk/english/su-as-a-foreign-citizen/">Statens Uddannelsesstøtte</a>). SU is the Danish state educational great, if you get it, this means you can earn up to 821€ on TOP of your student assistant job. There's one catch though, for you to earn that grant, you must work a minimum of 43 hours per month. <a href="https://uniavisen.dk/en/su-for-international-students-how-to-apply/">There are some good articles on this</a>. </p>
<p>There are several types of student assistant jobs. A lot of my international friends got student jobs working in restaurants with foreign owners (pizza places, French restaurants, Spanish restaurants) or in bars (in the city, or even in the universities!). These are definitely not easy to find, but definitely help you during your studies. You can also work as a student assistant at your university for an hourly rate - which is a great option as well.</p>
<p>The other possibility (the one I went for), is to get a student job in a company, close to your area of expertise. A <a href="https://www.linkedin.com/jobs/search/?geoId=90009617&keywords=student%20assistant&location=Copenhagen%20Metropolitan%20Area">lot of companies offer them</a>. Some of them will require you to speak Danish, but a lot of them won't! I <a href="https://duarteocarmo.com/cv">started working for Jabra this way</a> when I got hired as a Student Assistant in the Strategy department of Jabra.</p>
<p><br>
<img src="https://duarteocarmo.com/images/ballerup.jpg" alt="Ballerup HQ" style="">
<br>
<br></p>
<p>If you are lucky enough to find work as a student assistant in a company, this exponentially raises the chances of working full-time in Denmark once your educational program is over! Most companies offer student assistants a full time position once their education is over. This allows companies to hire from a pool of talent they have worked with before, and students to get a smooth entrance into their first full-time position, in a company they already know. </p>
<hr />
<p><strong>Enjoy what Denmark has to offer</strong>. I think there are no doubts that Denmark is one of the <a href="https://www.numbeo.com/quality-of-life/rankings_by_country.jsp">best countries in the world to live in</a>. One of my favorite things here is the fact that <a href="https://copenhagenizeindex.eu/">Copenhagen is extremely bike-friendly</a>. I could not start to tell you how many km I have biked since I first moved here. Either it's going to work, shopping, seeing friends, to the beach, or to the canals for a swim, I almost ALWAYS bike. Also, you can take your bike in most public transportation for free. In fact, <a href="https://www.quora.com/How-does-Swedens-bicycle-infrastructure-compare-with-that-in-the-Netherlands-or-Copenhagen">all S-trains (Copenhagen's urban train) offer 2 carriages just for bikes</a>. If you are moving here and planning to stay, I definitely advise you to get a nice bike. You can get some pretty incredible <a href="https://www.dba.dk/soeg/?soeg=bikes">deals in DBA.dk</a>.</p>
<p><br>
<img src="https://duarteocarmo.com/images/bike_john.jpg" alt="Johnny Biking" style="">
<br>
<br></p>
<p>Housing is pretty tough when you first arrive in Denmark. Cities are filled with people and pretty packed, which results in a pretty expensive and not particularly rewarding experience. My advice? Join Facebook groups targeted at looking for rooms in the city, and check websites like <a href="boligportal.dk/">BoligPortal</a>. Furthermore, you might be better off by partnering up with one or two other students and look for a full apartment to rent rather than a single room for yourself.</p>
<p>Last and not least, learn Danish. I haven't, and regret it every day. But languages don't take up space in your brain, but immensely improve your immersion and living experience. Some employers will offer to pay for your classes, and <a href="https://www.studieskolen.dk/en/danish/online">some schools even offer online classes at a reasonable price</a>. I started this one late, but hey, its never late to learn, even if I'll eventually move back to my sunny Portugal.</p>
<p><em>Note: This post is written from the perspective of an international student from a southern European country, moving to study in Copenhagen, Denmark.</em></p>VIM for Python development (and not only)2020-06-05T12:59:00+02:002020-06-05T12:59:00+02:00Duarte O.Carmotag:duarteocarmo.com,2020-06-05:/blog/vim-for-python-development-and-not-only.html<p><center>
<img src="https://duarteocarmo.com/images/vim_01.png" alt="Vim" style="">
</center></p>
<p><em><strong>tl;dr</strong>: This is a write up on how and why I use the famously hard-to-use VIM text editor.</em></p>
<ul>
<li><em>Skip to <a href="#general-vim-setup">here</a> if you already know VIM.</em></li>
<li><em>Jump to the <a href="#vim-for-python-development">python specific section</a>.</em></li>
<li><em>See my <a href="#my-vimrc">.vimrc</a>.</em></li>
<li><em>Get my <a href="https://github.com/duarteocarmo/dotfiles">dotfiles</a>.</em></li>
</ul>
<h2 id="what-the-hell-is-vim">What the hell is VIM?</h2>
<p>We're all used to use our …</p><p><center>
<img src="https://duarteocarmo.com/images/vim_01.png" alt="Vim" style="">
</center></p>
<p><em><strong>tl;dr</strong>: This is a write up on how and why I use the famously hard-to-use VIM text editor.</em></p>
<ul>
<li><em>Skip to <a href="#general-vim-setup">here</a> if you already know VIM.</em></li>
<li><em>Jump to the <a href="#vim-for-python-development">python specific section</a>.</em></li>
<li><em>See my <a href="#my-vimrc">.vimrc</a>.</em></li>
<li><em>Get my <a href="https://github.com/duarteocarmo/dotfiles">dotfiles</a>.</em></li>
</ul>
<h2 id="what-the-hell-is-vim">What the hell is VIM?</h2>
<p>We're all used to use our mouse to click around a document. You click on a character to go to it, you select text with your mouse, and then delete with you backspace key. What if there was a better way? Something that would require a bit less jumping around interfaces? What if there was a better and faster way?</p>
<p>VIM is a text editor that completely discards the mouse, and allows you to double your productivity while editing code or text. </p>
<p>VIM is famously know to be very hard to learn, but insanely productive once you do. </p>
<p><br>
<center>
<img src="https://duarteocarmo.com/images/vim_02.png" alt="VIM illustration" style="max-width:70%;">
</center></p>
<p>So why the hell would you even use it?</p>
<h2 id="why-would-you-use-vim">Why would you use VIM?</h2>
<p>I was once the guy that had no clue how to quit VIM. "You need to do what to quit this?". I still remember going into my crontab and using <code>nano</code> to "edit" all my files. I had heard about these crazy people that use terminal based text editors like "vim" and "emacs". </p>
<p>Today I own a VIM sweater.
<br>
<center>
<img src="https://duarteocarmo.com/images/vim_03.png" alt="VIM Sweater" style="">
</center></p>
<p>I didn't start using VIM because there was X number of reasons to switch to it. I simply wanted to play around with something other people talked about online, and I fell in love. Now that I HAVE switched to it, I can definitely recommend it for the following reasons:</p>
<ul>
<li><strong>It works on all machines.</strong> Whether you are on Linux or MacOS, it comes with VIM straight out of the box. Simply go to your terminal and type <code>vi</code>. </li>
<li><strong>It's fast.</strong> VIM uses something called modal editing, that makes editing and writing code (and text) much faster. You use commands such as hitting the <code>CI"</code> keys, to change the inside of a quote! Warning, VIM cheat sheets are <a href="https://xianblog.wordpress.com/2015/03/18/the-vim-cheat-sheet/">scary.</a> </li>
<li><strong>You can make it your own.</strong> VIM allows you to completely customize how it behaves and how it looks. Don't like a key combo? Remap it! Don't like a certain behavior? Turn it off!</li>
</ul>
<h2 id="general-vim-setup">General VIM Setup</h2>
<p><center>
<img src="https://duarteocarmo.com/images/vim_04.png" alt="VIM Screenshot 1" style="">
</center></p>
<p>My favorite color scheme is <a href="https://github.com/sjl/badwolf">badwolf</a>, mainly for its Python highlighting. The markdown also doesn't look bad. The <code>html</code> though, could definitely be better. </p>
<p>For fonts, I have been currently changing the font to <a href="https://www.jetbrains.com/lp/mono/">JetBrains Mono</a> wherever I can.</p>
<p>When I am on my MacBook, I use <a href="https://www.iterm2.com/">iTerm2</a> and run VIM straight from it. On Linux, the same, no need to configure anything, I just fire <a href="https://sw.kovidgoyal.net/kitty/">Kitty</a>, and run VIM from there. </p>
<p>On Windows, I normally just run <a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10">WSL</a> with an Ubuntu Virtual Machine. Which allows me to have a relatively fast Linux machine inside Windows. <em>Note: If you go this route, definitely upgrade to <a href="https://docs.microsoft.com/en-us/windows/wsl/wsl2-index">WSL 2</a>.</em></p>
<h2 id="vim-for-python-development">VIM for Python development</h2>
<p>I use some specific plugins (with <a href="https://github.com/junegunn/vim-plug">vim-plug</a>) for making Python development easier. I know there are some even better ones, but I found that these strike a good balance: </p>
<ul>
<li><a href="https://github.com/sheerun/vim-polyglot">vim-polyglot</a>: Offers better syntax highlighting than basic VIM. </li>
<li><a href="https://github.com/psf/black/blob/master/plugin/black.vim">black</a>: When writing code, I just <code>:Black</code> and it automatically makes my code pretty again. </li>
<li><a href="https://github.com/jiangmiao/auto-pairs">auto-pairs</a>: Helps me "auto-close" brackets and parenthesis. And saves me time. </li>
<li><a href="https://github.com/ervandew/supertab">supertab</a>: I know VIM includes some sort of tab completion. And I also know there are things like <a href="https://github.com/neoclide/coc.nvim">CoC</a> and <a href="https://github.com/ycm-core/YouCompleteMe">YouCompleteMe</a> out there. But hey, I just don't want to write that long variable's name. </li>
</ul>
<p>Great, let's see that <code>.vimrc</code></p>
<h2 id="vim-for-markdown">VIM for Markdown</h2>
<p>I also like using VIM for most of my markdown editing. Either it's some documentation, or even my notes (I use <a href="https://joplinapp.org/">Joplin</a> to write down my notes and thoughts). Mainly because of its folding capabilities, I use <a href="https://github.com/plasticboy/vim-markdown">vim-markown</a></p>
<p>Great, let's see that <code>.vimrc</code></p>
<h2 id="my-vimrc">My <code>.vimrc</code></h2>
<p>Almost every line here is commented. My advice: don't copy it. Built your own from scratch, and make sure you understand every line and what it does!</p>
<div class="codehilite"><pre><span></span><code><span class="k">filetype</span> indent <span class="k">on</span> <span class="c">" load filetype-specific indent files</span>
<span class="nb">syntax</span> enable <span class="c">" enable syntax highlighting</span>
<span class="k">set</span> <span class="nb">wildmenu</span> <span class="c">" visual autocomplete for command menu</span>
<span class="k">set</span> <span class="nb">showmatch</span> <span class="c">" highlight matching !!important!!</span>
<span class="k">set</span> <span class="nb">tabstop</span><span class="p">=</span><span class="m">4</span> <span class="c">" number of visual spaces per tab</span>
<span class="k">set</span> <span class="nb">softtabstop</span><span class="p">=</span><span class="m">4</span> <span class="c">" number of spaces in tab while editing</span>
<span class="k">set</span> <span class="nb">shiftwidth</span><span class="p">=</span><span class="m">4</span> <span class="c">" when indenting with >, user 4 spaces width</span>
<span class="k">set</span> <span class="nb">expandtab</span> <span class="c">" tabs are spaces</span>
<span class="k">set</span> <span class="k">number</span> <span class="c">" show line numbers</span>
<span class="k">set</span> <span class="nb">showcmd</span> <span class="c">" show command in bottom bar</span>
<span class="k">set</span> <span class="nb">cursorline</span> <span class="c">" highlight current line</span>
<span class="k">set</span> <span class="nb">mouse</span><span class="p">=</span><span class="k">a</span> <span class="c">" mouse support? </span>
<span class="k">set</span> <span class="nb">vb</span> <span class="nb">t_vb</span><span class="p">=</span> <span class="c">" no visual bell & flash</span>
<span class="k">call</span> plug#begin<span class="p">(</span><span class="s1">'~/.vim/plugged'</span><span class="p">)</span> <span class="c">" vim-plug plugins will be downloaded there</span>
Plug <span class="s1">'sjl/badwolf'</span> <span class="c">" colorscheme</span>
Plug <span class="s1">'vim-airline/vim-airline'</span> <span class="c">" nice colored bar the the bottom of the file </span>
Plug <span class="s1">'tpope/vim-fugitive'</span> <span class="c">" git versioning and bar </span>
Plug <span class="s1">'sheerun/vim-polyglot'</span> <span class="c">" syntax highlightning for different languages</span>
Plug <span class="s1">'ervandew/supertab'</span> <span class="c">" tab autocomplete</span>
Plug <span class="s1">'jiangmiao/auto-pairs'</span> <span class="c">" auto close brackets</span>
Plug <span class="s1">'psf/black'</span><span class="p">,</span> {<span class="s1">'tag'</span>: <span class="s1">'19.10b0'</span>} <span class="c">" Black formatting</span>
Plug <span class="s1">'plasticboy/vim-markdown'</span> <span class="c">" Markdown folding </span>
Plug <span class="s1">'ctrlpvim/ctrlp.vim'</span> <span class="c">" Allows for quick searching of files</span>
<span class="k">call</span> plug#<span class="k">end</span><span class="p">()</span> <span class="c">" vim-plugs should not be declared below this.</span>
<span class="k">colorscheme</span> badwolf <span class="c">" set the colorscheme</span>
<span class="c">" Configuration for vim-markdown plugin</span>
autocmd <span class="nb">FileType</span> markdown <span class="k">let</span> <span class="k">g</span>:vim_markdown_new_list_item_indent <span class="p">=</span> <span class="m">0</span>
<span class="c">" Because we dont want to screw with PEP 8</span>
autocmd <span class="nb">FileType</span> python <span class="k">let</span> <span class="k">g</span>:black_linelength <span class="p">=</span> <span class="m">79</span> <span class="c">" max file length</span>
<span class="c">" Configuration for ctrlp.vim plugin</span>
autocmd <span class="nb">VimEnter</span> <span class="k">let</span> <span class="k">g</span>:ctrlp_working_path_mode <span class="p">=</span> <span class="s1">'r'</span> <span class="c">" recursive</span>
autocmd <span class="nb">VimEnter</span> <span class="k">let</span> <span class="k">g</span>:ctrlp_max_depth <span class="p">=</span> <span class="m">5</span> <span class="c">" max directory depth</span>
autocmd <span class="nb">VimEnter</span> <span class="k">let</span> <span class="k">g</span>:ctrlp_max_files <span class="p">=</span> <span class="m">100</span> <span class="c">" max files to parse</span>
<span class="k">set</span> <span class="nb">wildignore</span><span class="p">+=</span>*<span class="sr">/tmp/</span>*<span class="p">,</span>*.<span class="k">so</span><span class="p">,</span>*.swp<span class="p">,</span>*.zip<span class="p">,</span>*<span class="sr">/env/</span>*<span class="p">,</span>*<span class="sr">/venv/</span>* <span class="c">" Ignore directories</span>
</code></pre></div>Neural Networks for Linear Regressions using Python2020-05-22T10:37:00+02:002020-05-22T10:37:00+02:00Duarte O.Carmotag:duarteocarmo.com,2020-05-22:/blog/neural-networks-for-linear-regressions-using-python.html<p><em>Recently, I have been working on a project for <a href="https://www.dataverz.net/">Dataverz</a>, the company of my ex-thesis supervisor (and regular collaborator) <a href="https://www.parraguezr.net/">Pedro Parraguez</a>. I was looking at ways of predicting the number of collaborations between COVID-19 researchers. Here's a small technique I learned during that work.</em></p>
<p><a href="#links">Just take me to the code …</a></p><p><em>Recently, I have been working on a project for <a href="https://www.dataverz.net/">Dataverz</a>, the company of my ex-thesis supervisor (and regular collaborator) <a href="https://www.parraguezr.net/">Pedro Parraguez</a>. I was looking at ways of predicting the number of collaborations between COVID-19 researchers. Here's a small technique I learned during that work.</em></p>
<p><a href="#links">Just take me to the code.</a></p>
<h2 id="the-data">The data</h2>
<p>The data set we built is a (very) large table where every row corresponds to a collaboration between two researchers. In that row, we have information about researcher #1 and researcher #2. </p>
<p>If you are curious about the data, you can learn more about it in <a href="https://nbhub.duarteocarmo.com/notebook/07f45cd3#1.About-the-data">this</a> section of my research notebook. </p>
<h2 id="preparing-the-problem">Preparing the problem</h2>
<p>The number of collaborations between two researchers is obviously an integer (i.e John and Thomas have 1 co-authored paper on COVID-19). To model this problem we decided to start with a Linear Regression model. </p>
<p>If you are not completely familiar with it, a Linear Regression model looks at all of the columns in your data set, and multiplies each column by a number, with the goal of predicting the column you are interested in, while trying to minimize the error. </p>
<h2 id="linear-regression-model">Linear Regression Model</h2>
<p>My first attempt was to use an off-the-shelf Linear Regression model. One of the most common ones to use, is the <a href="https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html#sklearn.linear_model.LinearRegression"><code>scikit</code></a> implementation. It goes something like this:</p>
<div class="codehilite"><pre><span></span><code><span class="c1"># after creating your training and test set..</span>
<span class="n">lr</span> <span class="o">=</span> <span class="n">linear_model</span><span class="o">.</span><span class="n">LinearRegression</span><span class="p">()</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">X_train</span><span class="p">,</span> <span class="n">y_train</span><span class="p">)</span>
<span class="n">y_pred</span> <span class="o">=</span> <span class="n">lr</span><span class="o">.</span><span class="n">predict</span><span class="p">(</span><span class="n">X_test</span><span class="p">)</span>
</code></pre></div>
<p>This resulted in some OK <a href="https://nbhub.duarteocarmo.com/notebook/07f45cd3#6.Linear-Regression">results</a>. A popular metric to measure how good a Linear Regression model is, is a little something called MAE, you can think about it as an average error per prediction. </p>
<p>After fitting this model, our MAE is sitting at 0.4. This might seem OK at first because it's not a large number. However, most authors only collaborate once (.i.e most rows have a y value of 1), which means that for all of those cases, such an MAE, we are often erring on the number of collaboration by 50%(!). </p>
<p>Here's a graph of some sample collaborations (in black), and some predictions (in red). </p>
<p><center>
<img src="https://duarteocarmo.com/images/linear-regression.png" alt="Linear Regression" style="">
</center></p>
<p>Yeah, that doesn't look great. Notice how the red dots are often very far away from the black line (our truth). </p>
<h2 id="using-a-neural-network">Using a Neural Network</h2>
<p>I ended up browsing scikit's documentation for some more time, looking for other viable options to this problem. The documentation is great, really, they even have <a href="https://scikit-learn.org/stable/tutorial/machine_learning_map/index.html">a page</a> you can use to select an algorithm. </p>
<p>While browsing the <a href="https://scikit-learn.org/stable/modules/neural_networks_supervised.html#regression">Neural Networks page</a> of the docs, I came across what is called, a <a href="https://scikit-learn.org/stable/modules/generated/sklearn.neural_network.MLPRegressor.html#sklearn.neural_network.MLPRegressor">MLPRegressor.</a></p>
<p>The MLP Regressor, is basically a Neural Network, that uses squared error as a loss function, and outputs continuous values. </p>
<p>So I gave it a shot:</p>
<div class="codehilite"><pre><span></span><code><span class="n">mlp</span> <span class="o">=</span> <span class="n">pipeline</span><span class="o">.</span><span class="n">make_pipeline</span><span class="p">(</span><span class="n">preprocessing</span><span class="o">.</span><span class="n">StandardScaler</span><span class="p">(),</span>
<span class="n">neural_network</span><span class="o">.</span><span class="n">MLPRegressor</span><span class="p">(</span><span class="n">hidden_layer_sizes</span><span class="o">=</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span> <span class="mi">100</span><span class="p">),</span>
<span class="n">tol</span><span class="o">=</span><span class="mf">1e-2</span><span class="p">,</span> <span class="n">max_iter</span><span class="o">=</span><span class="mi">500</span><span class="p">,</span> <span class="n">random_state</span><span class="o">=</span><span class="mi">0</span><span class="p">))</span><span class="o">.</span><span class="n">fit</span><span class="p">(</span><span class="n">X_train</span><span class="p">,</span> <span class="n">y_train</span><span class="p">)</span>
<span class="n">y_pred</span> <span class="o">=</span> <span class="n">mlp</span><span class="o">.</span><span class="n">predict</span><span class="p">(</span><span class="n">X_test</span><span class="p">)</span>
</code></pre></div>
<p>Again, <a href="https://nbhub.duarteocarmo.com/notebook/07f45cd3#8.Neural-Network-Regression">full code here.</a></p>
<p>This model resulted on an MAE of 0.20, we just reduced our error by <strong>50%</strong> (from an MAE of 0.4 to one of 0.2). Here's a graph of some predictions from our neural network regression: </p>
<p><center>
<img src="https://duarteocarmo.com/images/neural-network.png" alt="Neural Network" style="">
</center></p>
<p>Yeah, that clearly looks much better than the previous one! </p>
<p>This means that for every prediction we are making, we are failing on average about 0.2, which is better taking into consideration that most authors only collaborate once! </p>
<h2 id="final-thoughts">Final thoughts</h2>
<p>When using Machine Learning to make predictions, starting with the basic models is always the way to go. However, the field is constantly evolving, and it's a good approach to always test out some less traditional techniques, they might surprise you! They for sure surprise me. </p>
<p>Of course, all approaches should still be <a href="https://nbhub.duarteocarmo.com/notebook/07f45cd3#9.Validation">validated</a>, to make sure they make sense, and that you're not just shooting in the dark. </p>
<p>Here are some links if you want to dig deeper into this work:</p>
<div id="links"></div>
<ul>
<li>Full article: <a href="https://dataverz.gitbook.io/coronavirus-r-and-d/matchmaking-experiments">"Matchmaking experiments using ML and Graph embedding"</a></li>
<li>Analysis and code: <a href="https://nbhub.duarteocarmo.com/notebook/07f45cd3#9.Validation">Jupyter Notebook</a></li>
<li><a href="https://duarteocarmo.com/consulting">Consulting services</a></li>
</ul>How to work from home2020-03-25T00:00:00+01:002020-03-25T00:00:00+01:00Duarte O.Carmotag:duarteocarmo.com,2020-03-25:/blog/how-to-work-from-home.html<p><em>Currently, the world is going through an epidemic crisis. Coronavirus has made most of us have to work from home, well, at least the ones who can. Foreseeably, for the next month, this will be the state of things. I have some experience working from home, although not extensive, most …</em></p><p><em>Currently, the world is going through an epidemic crisis. Coronavirus has made most of us have to work from home, well, at least the ones who can. Foreseeably, for the next month, this will be the state of things. I have some experience working from home, although not extensive, most of <a href="https://thesis.duarteocarmo.com/">my thesis</a> and <a href="https://duarteocarmo.com/cv.pdf">student assistant work</a> was done remotely from Portugal to Denmark for about a year. I actually believe I was more productive during that time, so here is my advice.</em></p>
<h2 id="the-upsides">The upsides</h2>
<p>Working from home has upsides, let's start by outlining some to get you motivated:</p>
<ul>
<li>You can actually <strong>work from anywhere</strong>: (not applicable in the current crisis), either its a train, a coffee shop, or a friend's place.</li>
<li><strong>You own your own time</strong>: You can start working when you want, stop working when you want, and pause whenever you want.</li>
<li><strong>Interruptions are much less frequent</strong> (unless you have a kid), you shut communication down when you want to. </li>
</ul>
<h2 id="have-a-setup">Have a setup</h2>
<p>Working on your laptop for a whole week is exhausting: small screen, bad body position. From home, you should be <strong>more</strong> comfortable than in the office</p>
<p>Consider buying an external monitor, a good mouse, and a keyboard. You don't need to spend a fortune. But you should also consider that <strong>you are going to spend your day working from your setup</strong>. </p>
<p>Here is some of hardware I use to get stuff done:</p>
<ul>
<li><a href="https://www.amazon.de/dp/B01E9JS5Q8/ref=sr_1_1?crid=X7MRHBHZ226R&keywords=samsung+curved+27&qid=1585059065&sprefix=samsung+curve+27%2Caps%2C191&sr=8-1">Samsung 27" monitor</a> (~$150)</li>
<li><a href="https://www.logitech.com/en-us/product/multi-device-keyboard-k380?crid=27">Logitech K380 wireless keyboard</a> (~$40)</li>
<li><a href="https://www.logitech.com/en-roeu/product/mx-master-3">Logitech MX Master mouse</a> (~$100)</li>
<li><a href="https://www.jabra.com/bluetooth-headsets/jabra-elite-85h#/">Jabra Elite 85h headphones</a> (~$150)</li>
</ul>
<p>I believe these are a very good bank for your buck. And can certainly vouch for them. </p>
<p><br/>
<br/>
<center>
<img src="https://duarteocarmo.com/images/setup.png" alt="Setup" style="width:90%;border-radius: 2px;">
</center>
<br/></p>
<h2 id="start-the-day-right">Start the day right</h2>
<p>One of the worst mistakes is to keep your pajamas on. <strong>ALWAYS</strong> shower and get dressed! Even if you're not going anywhere, getting ready puts you in the mindset of getting things done. Usually, this is how my morning goes:</p>
<ol>
<li>Get up</li>
<li>(Sports, I usually go for a run)</li>
<li>Shower</li>
<li>Make a <a href="https://www.amazon.de/dp/B003SG5XP0/ref=sr_1_7?keywords=nescafe+gold&qid=1585059650&sr=8-7">lousy cup of coffee</a></li>
<li>Read the news?</li>
<li>Sit down, and start getting stuff done!</li>
</ol>
<h2 id="plan-out-your-day">Plan out your day</h2>
<p>Before starting to work, I usually ask myself: "What do I want to accomplish today?". At the end of the day, I ask myself: "What did I do today?". For everything in between, I use <a href="https://ticktick.com">TickTick</a>, my favorite TO-DO app.</p>
<p>What I like about TickTick is the following:</p>
<ul>
<li>It's in <strong>all platforms</strong> (Android, iOS, Mac, Windows, Web).</li>
<li>Its <strong>free</strong> tier is super generous. </li>
<li>It allows me to categorize by lists, as well as add <strong>sub todos</strong>.</li>
<li>It can understand <strong>natural language</strong>: for example <code>"Bring groceries tomorrow ~personal"</code> will add "Bring groceries" to the <code>Personal</code> list, as an item to do tomorrow!</li>
</ul>
<p>At the end of the day, I like having all of my todos (Personal, Work, Side Projects, etc) in a single place, and that's exactly what I get with TickTick.</p>
<p><br/>
<br/>
<center>
<img src="https://duarteocarmo.com/images/ticktick.png" alt="TickTick" style="width:100%;">
</center>
<br/></p>
<h2 id="talk-when-you-have-to">Talk when you have to</h2>
<p><em>Email, Email, Email.</em> </p>
<p>We are surrounded by instant communication tools. Instant communication tools usually tend to disrupt your productivity. Don't get me wrong, they have a tone of advantages, but I believe that they don't allow to do serious and deep work. </p>
<p>Why? Because when someone Slacks you they expect a fast response. But what happens when someone emails you? Well, they certainly expect a delay in your response. And that's positive.</p>
<p>Email allows you to minimize interruptions, and communicate when you want to, not when others want to. </p>
<p>So close Slack, close WhatsApp, close Messenger, set your phone to Do not Disturb, and check your email 3 times a day. </p>
<p><em>Reading recommendation on the topic: <a href="https://www.goodreads.com/book/show/38900866-it-doesn-t-have-to-be-crazy-at-work">"It Doesn't Have to Be Crazy at Work"</a></em> </p>
<h2 id="listen-to-something">Listen to something</h2>
<p>This depends on the type of work, but I have found that I personally really enjoy listening to something while I am working. Either its some slides, a data analysis, or some code, listening to something in the background really allows me to concentrate. </p>
<p>Here are some of my personal favorites:</p>
<ul>
<li>A SoundCloud mix: <a href="https://soundcloud.com/sashasashamarie">Sashamarie</a>, <a href="https://soundcloud.com/soulection/">Soulection</a>, and <a href="https://soundcloud.com/complexion">Complexion</a> are some of my favorite radio shows. </li>
<li>A podcast: <a href="https://tim.blog/podcast/">Tim Ferris</a> and the <a href="https://changelog.com/podcast">Changelog</a> have it here. Oh, and I use <a href="https://github.com/insidegui/PodcastMenu">PodcastMenu</a> to control podcasts in my menubar. </li>
<li>Spotify usually also does the job. </li>
</ul>
<p><br/>
<br/>
<center>
<img src="https://duarteocarmo.com/images/soundcloud.png" alt="Soundcloud" style="width:100%;">
</center>
<br/></p>
<p>I hope some of these tips will help you get the most out of working from home! </p>
<p><em>Note: If you want to discuss some of these, or just reach out, feel free to send me an email! (address is right there on the bottom left.)</em></p>Rumps + Python: Coronavirus in your menu bar2020-03-19T00:00:00+01:002020-03-19T00:00:00+01:00Duarte O.Carmotag:github.com,2020-03-19:/duarteocarmo/coronabarManaging kindle highlights with Python and GitHub2020-02-25T00:00:00+01:002020-02-25T00:00:00+01:00Duarte O.Carmotag:duarteocarmo.com,2020-02-25:/blog/managing-kindle-highlights-with-python-and-github.html<p><strong>tl;dr:</strong> <em>use <a href="#code">this script</a> to build a <a href="https://github.com/duarteocarmo/my-personal-zen">GitHub Repo like this one</a> where you store all the highlights from your kindle books in an organized way.</em></p>
<p><strong>⚠️ Update:</strong> Want to receive your kindle highlights as a newsletter? Well, I <a href="https://kindle-highlights.email/">built something your will probably like!</a></p>
<h2 id="kindle-sucks-kindle-is-great">Kindle sucks, kindle is great …</h2><p><strong>tl;dr:</strong> <em>use <a href="#code">this script</a> to build a <a href="https://github.com/duarteocarmo/my-personal-zen">GitHub Repo like this one</a> where you store all the highlights from your kindle books in an organized way.</em></p>
<p><strong>⚠️ Update:</strong> Want to receive your kindle highlights as a newsletter? Well, I <a href="https://kindle-highlights.email/">built something your will probably like!</a></p>
<h2 id="kindle-sucks-kindle-is-great">Kindle sucks, kindle is great</h2>
<p>We all love reading in our Kindle. You can travel with more than one book at the time, you can search for words you don't understand, you have access to millions of books you can't find in your local library.. It's great!</p>
<p>But when we're older, all of the shelves in our houses will have no books, our kids won't know what we read, and we won't be able to revisit them. </p>
<p>One option is to bulk buy the physical copies in some years. </p>
<p>While that doesn't happen, why not keep all the most important highlights in a nicely kept <a href="https://github.com/duarteocarmo/my-personal-zen/tree/master/books">GitHub Repo</a>?</p>
<h2 id="highlights">Highlights</h2>
<p>When reading in my Kindle, I tend to highlight a lot of passages I find interesting. When you do so, the device locally stores a <code>My Clippings.txt</code> file that aggregates all of your highlights across different books. </p>
<h2 id="using-github">Using GitHub</h2>
<p>In the <a href="https://github.com/duarteocarmo/my-personal-zen/tree/master/books">books</a> folder of <em>"my-personal-zen"</em> repo you can notice that every book has its own markdown file where I keep all of the highlights related to it. For example, <a href="https://github.com/duarteocarmo/my-personal-zen/blob/master/books/Mans%20Search%20for%20Meaning.md">here</a> are my favorite parts of Viktor Frankl's <em>Man's Search for Meaning</em>. </p>
<h2 id="python-for-the-parsing-win">Python for the (parsing) win</h2>
<p>To make this happen, I created a small python <a href="https://github.com/duarteocarmo/my-personal-zen/blob/master/highlight_parser.py">script</a> that parses a <code>My Clippings.txt</code> file every time I connect my Kindle to my computer. And then its just a matter of moving these files to a repo and pushing it to GitHub. </p>
<p>Here's a walk through of the code that you can also find in full <a href="https://github.com/duarteocarmo/my-personal-zen/blob/master/highlight_parser.py">here</a>:<a name="code"></a> </p>
<p>We start by creating a <code>Book</code> class:</p>
<div class="codehilite"><pre><span></span><code><span class="k">class</span> <span class="nc">Book</span><span class="p">:</span>
<span class="n">book_list</span> <span class="o">=</span> <span class="nb">set</span><span class="p">()</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">title</span><span class="p">,</span> <span class="n">author</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">author</span> <span class="o">=</span> <span class="n">author</span>
<span class="bp">self</span><span class="o">.</span><span class="n">title</span> <span class="o">=</span> <span class="n">title</span>
<span class="bp">self</span><span class="o">.</span><span class="n">highlights</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">Book</span><span class="o">.</span><span class="n">book_list</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">title</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">add_highlight</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">highlight</span><span class="p">):</span>
<span class="k">if</span> <span class="n">highlight</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">highlights</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">highlight</span><span class="p">)</span>
<span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">"<Book Object>Title:</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">title</span><span class="si">}</span><span class="se">\t</span><span class="s2">Author:</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">author</span><span class="si">}</span><span class="se">\t</span><span class="s2">Highlights:</span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">highlights</span><span class="p">)</span><span class="si">}</span><span class="s2">"</span>
<span class="k">def</span> <span class="nf">write_book</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="nb">format</span><span class="o">=</span><span class="s2">"markdown"</span><span class="p">):</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">title</span> <span class="o">==</span> <span class="kc">None</span> <span class="ow">or</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">highlights</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"Not writting because name is None."</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="n">clean_title</span> <span class="o">=</span> <span class="s2">""</span><span class="o">.</span><span class="n">join</span><span class="p">(</span>
<span class="p">[</span><span class="n">c</span> <span class="k">for</span> <span class="n">c</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">title</span> <span class="k">if</span> <span class="n">c</span><span class="o">.</span><span class="n">isalpha</span><span class="p">()</span> <span class="ow">or</span> <span class="n">c</span><span class="o">.</span><span class="n">isdigit</span><span class="p">()</span> <span class="ow">or</span> <span class="n">c</span> <span class="o">==</span> <span class="s2">" "</span><span class="p">]</span>
<span class="p">)</span><span class="o">.</span><span class="n">rstrip</span><span class="p">()</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">clean_title</span><span class="si">}</span><span class="s2">.md"</span><span class="p">,</span> <span class="s2">"w+"</span><span class="p">)</span> <span class="k">as</span> <span class="n">file</span><span class="p">:</span>
<span class="n">file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="sa">f</span><span class="s2">"# </span><span class="si">{</span><span class="n">clean_title</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
<span class="n">file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="k">for</span> <span class="n">h</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">highlights</span><span class="p">:</span>
<span class="n">clean_text</span> <span class="o">=</span> <span class="n">h</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">,</span> <span class="s2">" "</span><span class="p">)</span>
<span class="n">file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="sa">f</span><span class="s2">"- </span><span class="si">{</span><span class="n">clean_text</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
<span class="n">file</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="n">file</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</code></pre></div>
<p>After that, we create a <code>Highlight</code> class:</p>
<div class="codehilite"><pre><span></span><code><span class="k">class</span> <span class="nc">Highlight</span><span class="p">:</span>
<span class="n">total_highlights</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">):</span>
<span class="p">(</span>
<span class="bp">self</span><span class="o">.</span><span class="n">title</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">author</span><span class="p">,</span>
<span class="bp">self</span><span class="o">.</span><span class="n">content</span><span class="p">,</span>
<span class="p">)</span> <span class="o">=</span> <span class="n">Highlight</span><span class="o">.</span><span class="n">parse_single_highlight</span><span class="p">(</span><span class="n">raw_string</span><span class="p">)</span>
<span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">"<Highlight Object> Title:</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">title</span><span class="si">}</span><span class="se">\t</span><span class="s2">Author:</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">author</span><span class="si">}</span><span class="se">\t</span><span class="s2">Content:</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">content</span><span class="si">}</span><span class="s2">"</span>
<span class="nd">@staticmethod</span>
<span class="k">def</span> <span class="nf">parse_single_highlight</span><span class="p">(</span><span class="n">highlight_string</span><span class="p">):</span>
<span class="n">splitted_string</span> <span class="o">=</span> <span class="n">highlight_string</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
<span class="n">author_line</span> <span class="o">=</span> <span class="n">splitted_string</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="n">content</span> <span class="o">=</span> <span class="n">splitted_string</span><span class="p">[</span><span class="o">-</span><span class="mi">2</span><span class="p">]</span>
<span class="n">regex</span> <span class="o">=</span> <span class="sa">r</span><span class="s2">"\((.*?)\)"</span>
<span class="n">match</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="s2">"\((.*)\)"</span><span class="p">,</span> <span class="n">author_line</span><span class="p">)</span>
<span class="k">if</span> <span class="n">match</span><span class="p">:</span>
<span class="n">author</span> <span class="o">=</span> <span class="n">match</span><span class="o">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">title</span> <span class="o">=</span> <span class="n">author_line</span><span class="p">[:</span> <span class="n">match</span><span class="o">.</span><span class="n">start</span><span class="p">()]</span>
<span class="k">return</span> <span class="n">title</span><span class="p">,</span> <span class="n">author</span><span class="p">,</span> <span class="n">content</span>
<span class="k">return</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span><span class="p">,</span> <span class="kc">None</span>
</code></pre></div>
<p>Once those are created, just run the following script to output the markdown files:</p>
<div class="codehilite"><pre><span></span><code><span class="n">current_directory</span> <span class="o">=</span> <span class="n">pathlib</span><span class="o">.</span><span class="n">Path</span><span class="o">.</span><span class="n">cwd</span><span class="p">()</span>
<span class="n">parsed_books</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span>
<span class="nb">set</span><span class="p">(</span><span class="n">file</span><span class="o">.</span><span class="n">stem</span> <span class="k">for</span> <span class="n">file</span> <span class="ow">in</span> <span class="n">current_directory</span><span class="o">.</span><span class="n">glob</span><span class="p">(</span><span class="s2">"**/*.md"</span><span class="p">))</span>
<span class="p">)</span>
<span class="n">highlight_separator</span> <span class="o">=</span> <span class="s2">"=========="</span>
<span class="n">highlight_json</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span>
<span class="n">library</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s2">"My Clippings.txt"</span><span class="p">,</span> <span class="s2">"r"</span><span class="p">)</span> <span class="k">as</span> <span class="n">file</span><span class="p">:</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">file</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
<span class="n">highlights</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="n">highlight_separator</span><span class="p">)</span>
<span class="k">for</span> <span class="n">raw_string</span> <span class="ow">in</span> <span class="n">highlights</span><span class="p">:</span>
<span class="n">h</span> <span class="o">=</span> <span class="n">Highlight</span><span class="p">(</span><span class="n">raw_string</span><span class="p">)</span>
<span class="k">if</span> <span class="n">h</span><span class="o">.</span><span class="n">title</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">Book</span><span class="o">.</span><span class="n">book_list</span><span class="p">:</span>
<span class="n">b</span> <span class="o">=</span> <span class="n">Book</span><span class="p">(</span><span class="n">h</span><span class="o">.</span><span class="n">title</span><span class="p">,</span> <span class="n">h</span><span class="o">.</span><span class="n">author</span><span class="p">)</span>
<span class="n">b</span><span class="o">.</span><span class="n">add_highlight</span><span class="p">(</span><span class="n">h</span><span class="o">.</span><span class="n">content</span><span class="p">)</span>
<span class="n">library</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">b</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">for</span> <span class="n">b</span> <span class="ow">in</span> <span class="n">library</span><span class="p">:</span>
<span class="k">if</span> <span class="n">b</span><span class="o">.</span><span class="n">title</span> <span class="o">==</span> <span class="n">h</span><span class="o">.</span><span class="n">title</span><span class="p">:</span>
<span class="n">b</span><span class="o">.</span><span class="n">add_highlight</span><span class="p">(</span><span class="n">h</span><span class="o">.</span><span class="n">content</span><span class="p">)</span>
<span class="k">for</span> <span class="n">book</span> <span class="ow">in</span> <span class="n">library</span><span class="p">:</span>
<span class="k">if</span> <span class="n">book</span><span class="o">.</span><span class="n">title</span><span class="p">:</span>
<span class="k">if</span> <span class="n">book</span><span class="o">.</span><span class="n">title</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">parsed_books</span><span class="p">:</span>
<span class="n">book</span><span class="o">.</span><span class="n">write_book</span><span class="p">(</span><span class="nb">format</span><span class="o">=</span><span class="s2">"markdown"</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">book</span><span class="o">.</span><span class="n">title</span><span class="si">}</span><span class="s2"> is already written."</span><span class="p">)</span>
</code></pre></div>
<p>Now you are all set!</p>From jupyter notebooks to web apps2019-12-23T12:00:00+00:002019-12-23T12:00:00+00:00Duarte O.Carmotag:pbpython.com,2019-12-23:/interactive-dashboards.htmlMy first research paper2019-11-28T08:00:00+00:002019-11-28T08:00:00+00:00Duarte O.Carmotag:duarteocarmo.com,2019-11-28:/blog/my-first-research-paper.html<p>After a lot of work, it finally got published!</p>
<p>My first research paper <strong>'Quantifying technological change as a combinatorial process'</strong>, is now available in the November issue of <a href="https://www.sciencedirect.com/journal/technological-forecasting-and-social-change/about/aims-and-scope">Technological Forecasting and Social Change</a>. </p>
<p>Why does that matter? Well, a couple of things first..</p>
<h3 id="what-is-the-paper-about">What is the paper about?</h3>
<p>This paper …</p><p>After a lot of work, it finally got published!</p>
<p>My first research paper <strong>'Quantifying technological change as a combinatorial process'</strong>, is now available in the November issue of <a href="https://www.sciencedirect.com/journal/technological-forecasting-and-social-change/about/aims-and-scope">Technological Forecasting and Social Change</a>. </p>
<p>Why does that matter? Well, a couple of things first..</p>
<h3 id="what-is-the-paper-about">What is the paper about?</h3>
<p>This paper basically studies ways of looking at research papers as data(meta, I know!). By taking words mentioned in the paper, its authors, the location where it was written, and more metadata, we can build a network of research on a particular topic. </p>
<p>Here is a rough example on how we build a matrix of similarity between years: we look at the research terms used in each year, and we see if they have also been used in years after. If they have, then those years must be similar.</p>
<p>Now that you have the gist of it, what we actually do is that we look at the evolution of combination of terms ("corn" + "hydrolysis" for example) throughout the years. By analyzing this evolution, we can deduce where research is going - and probably predict it too!</p>
<p><br>
<center>
<img src="https://duarteocarmo.com/images/method.png" alt="JupyterLab" style="width:90%; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);">
</center>
<br></p>
<p>That's where the name of the paper comes from, we are basically studying how technology (and its study) changes over the years by looking at how papers of different years use different combinations of technical terms. </p>
<h3 id="who-wrote-the-paper">Who wrote the paper?</h3>
<p>This paper was a collaboration between my thesis supervisor <a href="https://www.parraguezr.net/">Pedro Parraguez</a>, <a href="https://www.dtu.dk/english/service/phonebook/person?id=122454&tab=2&qt=dtupublicationquery">Stanko Škec</a> and <a href="https://www.dtu.dk/english/service/phonebook/person?id=59683&tab=1">Anja Maier</a>.</p>
<p>Oh, and me :) </p>
<p>All from the <a href="https://www.man.dtu.dk/">Management Department</a> of the <a href="https://www.dtu.dk/english">Technical University of Denmark</a>.</p>
<h3 id="where-can-i-find-it">Where can I find it?</h3>
<p>You can find it on <a href="https://www.sciencedirect.com/science/article/pii/S004016251930006X#!">Elsevier</a>.</p>
<h3 id="why-isnt-it-open-access">Why isn't it open access?</h3>
<p>Long story short, it was out of my control. I was only a collaborator in this research. I am a supporter of open source and open access and will to continue to support it to the best of my abilities. </p>
<p><a href="https://duarteocarmo.com/pdfs/quantifying-tech-change.pdf">wink 😉</a></p>
<p>You can find out more about this topic by diving deeper into <a href="https://thesis.duarteocarmo.com/">my thesis</a>.</p>Report Automation using Python, Papermill and Rclone2019-07-29T20:43:05+00:002019-07-29T20:43:05+00:00Duarte O.Carmotag:duarteocarmo.com,2019-07-29:/blog/report-automation-using-python-papermill-and-rclone.html<p>During the month of July I wrote two blog posts for the popular <a href="https://pbpython.com/">Practical Business Python blog</a>. The Practical Business Python blog is one of the top 20 most popular blogs on python with about <a href="https://www.similarweb.com/website/pbpython.com#overview">200.000 visits</a> per month. </p>
<p>The posts focus on how you can build an automation …</p><p>During the month of July I wrote two blog posts for the popular <a href="https://pbpython.com/">Practical Business Python blog</a>. The Practical Business Python blog is one of the top 20 most popular blogs on python with about <a href="https://www.similarweb.com/website/pbpython.com#overview">200.000 visits</a> per month. </p>
<p>The posts focus on how you can build an automation system that generates <code>Html</code> reports from excel files. The system uses python, jupyter, papermill, spruces and Rclone. </p>
<p>Here are the links to both parts:</p>
<ul>
<li><a href="https://pbpython.com/papermil-rclone-report-1.html">Part 1: Concept presentation</a></li>
<li><a href="https://pbpython.com/papermil-rclone-report-2.html">Part 2: Architecture and final solution</a></li>
</ul>
<p>These posts were featured in the <a href="https://pythonbytes.fm/episodes/show/142/there-s-a-bandit-in-the-python-space">Python Bytes podcast</a> (jump to 12:39):</p>
<iframe width="100%" height="166" scrolling="no" frameborder="no" allow="autoplay" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/662152787&color=%232a7ae2&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&show_teaser=true">
</iframe>
<p><br/>
The architecture of the automation solution and final script follow:
<center>
<img src="https://duarteocarmo.com/images/architecture.png" alt="JupyterLab" style="width:90%; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);">
</center>
<br/></p>
<p>Here is the code I used to automatically sync the reports on server:</p>
<div class="codehilite"><pre><span></span><code><span class="kn">import</span> <span class="nn">subprocess</span>
<span class="kn">import</span> <span class="nn">sys</span>
<span class="kn">import</span> <span class="nn">papermill</span> <span class="k">as</span> <span class="nn">papermill</span>
<span class="n">REMOTE_FOLDER</span> <span class="o">=</span> <span class="s2">"your cloud folder name"</span>
<span class="n">LOCAL_FOLDER</span> <span class="o">=</span> <span class="s2">"your local folder name"</span>
<span class="n">TEMPLATE_NOTEBOOK</span> <span class="o">=</span> <span class="s2">"template_notebook.ipynb"</span>
<span class="k">def</span> <span class="nf">get_new_files</span><span class="p">(</span><span class="n">remote_folder</span><span class="p">,</span> <span class="n">local_folder</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> A function that returns files that were uploaded to the cloud folder and </span>
<span class="sd"> do not exist in our local folder. </span>
<span class="sd"> """</span>
<span class="c1"># list the files in our cloud folder</span>
<span class="n">list_cloud</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">run</span><span class="p">(</span>
<span class="p">[</span><span class="s2">"rclone"</span><span class="p">,</span> <span class="s2">"lsf"</span><span class="p">,</span> <span class="sa">f</span><span class="s2">"remote:</span><span class="si">{</span><span class="n">remote_folder</span><span class="si">}</span><span class="s2">"</span><span class="p">],</span>
<span class="n">capture_output</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="n">text</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
<span class="p">)</span>
<span class="c1"># transform the command output into a list</span>
<span class="n">cloud_directories</span> <span class="o">=</span> <span class="n">list_cloud</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)[</span><span class="mi">0</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"In the cloud we have: </span><span class="se">\n</span><span class="si">{</span><span class="n">cloud_directories</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
<span class="c1"># list the files in our local folder</span>
<span class="n">list_cloud</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">run</span><span class="p">(</span>
<span class="p">[</span><span class="s2">"ls"</span><span class="p">,</span> <span class="n">local_folder</span><span class="p">],</span> <span class="n">capture_output</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="kc">True</span>
<span class="p">)</span>
<span class="c1"># transform the command output into a list</span>
<span class="n">local_directories</span> <span class="o">=</span> <span class="n">list_cloud</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)[</span><span class="mi">0</span><span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"In the local copy we have: </span><span class="se">\n</span><span class="si">{</span><span class="n">local_directories</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
<span class="c1"># create a list with the differences between the two lists above</span>
<span class="n">new_files</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="nb">set</span><span class="p">(</span><span class="n">cloud_directories</span><span class="p">)</span> <span class="o">-</span> <span class="nb">set</span><span class="p">(</span><span class="n">local_directories</span><span class="p">))</span>
<span class="k">return</span> <span class="n">new_files</span>
<span class="k">def</span> <span class="nf">sync_directories</span><span class="p">(</span><span class="n">remote_folder</span><span class="p">,</span> <span class="n">local_folder</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> A function that syncs a remote folder with a local folder</span>
<span class="sd"> with rclone. </span>
<span class="sd"> """</span>
<span class="n">sync</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">run</span><span class="p">(</span>
<span class="p">[</span><span class="s2">"rclone"</span><span class="p">,</span> <span class="s2">"sync"</span><span class="p">,</span> <span class="sa">f</span><span class="s2">"remote:</span><span class="si">{</span><span class="n">remote_folder</span><span class="si">}</span><span class="s2">"</span><span class="p">,</span> <span class="n">local_folder</span><span class="p">]</span>
<span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Syncing local directory with cloud...."</span><span class="p">)</span>
<span class="k">return</span> <span class="n">sync</span><span class="o">.</span><span class="n">returncode</span>
<span class="k">def</span> <span class="nf">run_notebook</span><span class="p">(</span><span class="n">excel_report</span><span class="p">,</span> <span class="n">template_notebook</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> A function that runs a notebook against an excel report</span>
<span class="sd"> via papermill. </span>
<span class="sd"> """</span>
<span class="n">no_extension_name</span> <span class="o">=</span> <span class="n">excel_report</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">"."</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">papermill</span><span class="o">.</span><span class="n">execute_notebook</span><span class="p">(</span>
<span class="n">template_notebook</span><span class="p">,</span>
<span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">no_extension_name</span><span class="si">}</span><span class="s2">.ipynb"</span><span class="p">,</span>
<span class="n">parameters</span><span class="o">=</span><span class="nb">dict</span><span class="p">(</span><span class="n">filename</span><span class="o">=</span><span class="n">excel_report</span><span class="p">),</span>
<span class="p">)</span>
<span class="k">return</span> <span class="n">no_extension_name</span>
<span class="k">def</span> <span class="nf">generate_html_report</span><span class="p">(</span><span class="n">notebook_file</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> A function that converts a notebook into an html</span>
<span class="sd"> file. </span>
<span class="sd"> """</span>
<span class="n">generate</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">run</span><span class="p">(</span>
<span class="p">[</span><span class="s2">"jupyter"</span><span class="p">,</span> <span class="s2">"nbconvert"</span><span class="p">,</span> <span class="n">notebook_file</span><span class="p">,</span> <span class="s2">"--to=html"</span><span class="p">]</span>
<span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"HTML Report was generated"</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">def</span> <span class="nf">push_to_cloud</span><span class="p">(</span><span class="n">remote_folder</span><span class="p">,</span> <span class="n">filename</span><span class="p">):</span>
<span class="w"> </span><span class="sd">"""</span>
<span class="sd"> A function that pushes to a remote cloud folder</span>
<span class="sd"> a specific file. </span>
<span class="sd"> """</span>
<span class="n">push</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">run</span><span class="p">(</span>
<span class="p">[</span><span class="s2">"rclone"</span><span class="p">,</span> <span class="s2">"copy"</span><span class="p">,</span> <span class="n">filename</span><span class="p">,</span> <span class="sa">f</span><span class="s2">"remote:</span><span class="si">{</span><span class="n">remote_folder</span><span class="si">}</span><span class="s2">"</span><span class="p">]</span>
<span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Report Published!!!"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">main</span><span class="p">():</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Starting updater.."</span><span class="p">)</span>
<span class="c1"># detect if there are new files in the remote folder</span>
<span class="n">new_files</span> <span class="o">=</span> <span class="n">get_new_files</span><span class="p">(</span>
<span class="n">remote_folder</span><span class="o">=</span><span class="n">REMOTE_FOLDER</span><span class="p">,</span> <span class="n">local_folder</span><span class="o">=</span><span class="n">LOCAL_FOLDER</span>
<span class="p">)</span>
<span class="c1"># if there are none, exit</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">new_files</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Everything is synced. No new files."</span><span class="p">)</span>
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">()</span>
<span class="c1"># else, continue</span>
<span class="k">else</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"There are files missing."</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="n">new_files</span><span class="p">)</span>
<span class="c1"># sync directories to get new excel report</span>
<span class="n">sync_directories</span><span class="p">(</span><span class="n">remote_folder</span><span class="o">=</span><span class="n">REMOTE_FOLDER</span><span class="p">,</span> <span class="n">local_folder</span><span class="o">=</span><span class="n">LOCAL_FOLDER</span><span class="p">)</span>
<span class="c1"># generate new notebook and extract the name</span>
<span class="n">clean_name</span> <span class="o">=</span> <span class="n">run_notebook</span><span class="p">(</span><span class="n">new_files</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="c1"># the new notebook generate will have the following name</span>
<span class="n">notebook_name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">clean_name</span><span class="si">}</span><span class="s2">.ipynb"</span>
<span class="c1"># generate the html report from the notebook</span>
<span class="n">generate_html_report</span><span class="p">(</span><span class="n">notebook_name</span><span class="p">)</span>
<span class="c1"># the notebook name will be the following</span>
<span class="n">html_report_name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"</span><span class="si">{</span><span class="n">clean_name</span><span class="si">}</span><span class="s2">.html"</span>
<span class="c1"># push the new notebook to the cloud</span>
<span class="n">push_to_cloud</span><span class="p">(</span><span class="n">html_report</span><span class="o">=</span><span class="n">html_report_name</span><span class="p">,</span> <span class="n">remote_folder</span><span class="o">=</span><span class="n">ONEDRIVE_FOLDER</span><span class="p">)</span>
<span class="c1"># make sure everything is synced again</span>
<span class="n">sync_directories</span><span class="p">(</span><span class="n">remote_folder</span><span class="o">=</span><span class="n">REMOTE_FOLDER</span><span class="p">,</span> <span class="n">local_folder</span><span class="o">=</span><span class="n">LOCAL_FOLDER</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Updater finished."</span><span class="p">)</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"main"</span><span class="p">:</span>
<span class="n">main</span><span class="p">()</span>
</code></pre></div>Contributing to JupyterLab2019-06-08T00:00:00+02:002019-06-08T00:00:00+02:00Duarte O.Carmotag:duarteocarmo.com,2019-06-08:/blog/contributing-to-jupyterlab.html<p><em>For a long time, I've been a lover of python. The language, the ecosystem, the projects, the conferences, and pretty much everything around it. However, the deeper I get into the ecosystem, the more I'm aware of the enormous amount of open source infrastructure that feeds it. One of the …</em></p><p><em>For a long time, I've been a lover of python. The language, the ecosystem, the projects, the conferences, and pretty much everything around it. However, the deeper I get into the ecosystem, the more I'm aware of the enormous amount of open source infrastructure that feeds it. One of the things I always wanted to do, was to contribute to an open source project.</em></p>
<p>This post is about just that.</p>
<h3 id="the-project-jupyterlab">The project: JupyterLab</h3>
<p>I have used python for a wide range of project types, but data analysis and data science is <a href="https://profile-summary-for-github.com/user/duarteocarmo">definitely a majority</a>. I love using jupyter notebooks as an interactive playing field to solve a problem using data. </p>
<p><a href="https://jupyterlab.readthedocs.io/en/latest/#">JupyterLab</a> is the tool that (in my opinion) will succeed the traditional jupyter notebooks as a browser based IDE. I've been using JupyterLab as a tool in my work and free time, and even though I don't think it's totally ready for prime time, I really love it.
<br/>
<br/>
<center>
<img src="https://duarteocarmo.com/images/jupyterlab.png" alt="JupyterLab" style="width:80%; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);">
</center>
<br/></p>
<p>For me, JupyterLab is a big step up from the traditional jupyter notebook interface. It provides awesome features such as an integrated console, support for other file formats, exporting options, a more modern interface, and much more!</p>
<h3 id="how-it-happened">How it happened</h3>
<p>While working on a project for <a href="https://duarteocarmo.com/about/">Jabra</a>, I wanted to share some of my work internally. Other people in my org don´t necessarily have a way of reading <code>.ipynb</code> files (notebooks) or even python installed in their system. Therefore, I often need to to export my notebooks as <code>.html</code> files. But this time, I wanted to create a presentation. </p>
<p>However, after a long time looking into how to do that, I finally <a href="https://github.com/jupyterlab/jupyterlab/issues/5018">found an issue that addressed it.</a> After finding it, I commented:
<br/>
<br/>
<center>
<img src="https://duarteocarmo.com/images/issue.png" alt="JupyterLab" style="width:80%; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);">
</center>
<br/></p>
<p>I was instantly called out by one of the main contributors, asking if I would consider contributing to the project and opening a <a href="https://help.github.com/en/articles/about-pull-requests">pull request</a> (PR).</p>
<p>And so my open source contribution journey began. </p>
<h3 id="contributing">Contributing</h3>
<p>So my mission was to add a piece to the <a href="https://jupyterlab.readthedocs.io/en/latest/#">documentation</a> of the project that explained how users can create a presentation from a jupyter notebook. I'm not going to go through all of the details of the process but I want to give a general overview. </p>
<p>The first step was to follow a couple of tutorials (for example <a href="https://opensource.guide/how-to-contribute/">this</a> good one) on how I could create this "PR". </p>
<p>After reading up on it, I understood that the first step was to <a href="https://guides.github.com/activities/forking/">fork</a> the JupyterLab repo. This allows you to have your own version of the repo, basically your own copy of the repo. After cloning <a href="https://github.com/duarteocarmo/jupyterlab">my copy of the repo</a> to my local machine, I created a <a href="https://github.com/duarteocarmo/jupyterlab/tree/docs/exporting">branch</a> where I would start creating the modifications. </p>
<p>The next step was to understand how I could possibly start changing the documentation of the project. Thankfully, JupyterLab has a <a href="https://github.com/jupyterlab/jupyterlab/blob/master/CONTRIBUTING.md">great guide</a> on how to contribute to documentation. </p>
<p>I basically needed to create a <code>.rst</code> (restructured text) file where I explained how a user could export their notebook into a presentation. A <code>.rst</code> file is pretty similar to a markdown file that then gets rendered into an HTML page (using something called <a href="http://www.sphinx-doc.org/en/stable/">sphinx</a>). Here is a screenshot of me editing the file and previewing my changes.
<br/>
<br/>
<center>
<img src="https://duarteocarmo.com/images/wip.png" alt="JupyterLab" style="width:100%; ">
</center>
<br/></p>
<p>After adding all of the necessary documentation, I made sure that everything passed the tests described in the contribution guide. After that was done, I pushed all of my changes to my branch. </p>
<p>When you do that, GitHub will automatically suggest the creation of a pull request with a click of a button. And so I <a href="https://github.com/jupyterlab/jupyterlab/pull/6472">created one</a>:
<br/>
<br/>
<center>
<img src="https://duarteocarmo.com/images/pull-request.png" alt="JupyterLab" style="width:80%; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);">
</center>
<br/></p>
<p>Excited about it, I commented and mentioned the contributors that first asked me for the pull request, saying it was ready. After a bit of back and forth (and a couple of additions), it was finally <a href="https://github.com/jupyterlab/jupyterlab/commit/eafd1f972cd9dae27fd3087a252a22138516bf2f">merged into the master branch</a>! (Which means, it was published!)</p>
<h3 id="result">Result</h3>
<p>For me, the biggest, most important result of all, was the fact that <strong>I got to help in a project that is not only used by a wide range of people, but also by me!</strong></p>
<p>If you want to browse the part of the documentation I wrote, you can go to the <a href="https://jupyterlab.readthedocs.io/en/latest/user/export.html">"Exporting notebooks" section of the official JupyterLab documentation</a>. </p>
<p>Here is a snippet of the page:
<br/>
<br/>
<center>
<img src="https://duarteocarmo.com/images/result-doc.png" alt="JupyterLab" style="width:80%; box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);">
</center>
<br/></p>
<p>Oh, and I also got <a href="https://github.com/duarteocarmo">a cool badge in my GitHub profile.</a> 😜</p>Creating devtuga2019-03-22T00:00:00+01:002019-03-22T00:00:00+01:00Duarte O.Carmotag:duarteocarmo.com,2019-03-22:/blog/creating-devtuga.html<p>So I finally got to it. After finishing my Msc.Thesis and relaxing for a couple of months in my sunny home country of Portugal, I built a 'big' project. Here are some words about it. </p>
<p>This is a rundown of some of the tools I used. <strong>(by no means …</strong></p><p>So I finally got to it. After finishing my Msc.Thesis and relaxing for a couple of months in my sunny home country of Portugal, I built a 'big' project. Here are some words about it. </p>
<p>This is a rundown of some of the tools I used. <strong>(by no means a tutorial!!)</strong></p>
<p><a href="#links">I just want the code man.</a></p>
<h2 id="1the-idea">1.The idea</h2>
<p>I keep a lot of great ideas for giant technology companies in my notes app. But this time, the goal was just to build something from scratch.</p>
<p>I'm a big fan of <a href="https://news.ycombinator.com">hackernews</a> and I also always felt that in Portugal, there are not many "community focused" websites. Therefore, I decided to create a hackernews clone for Portuguese hackers. </p>
<p><center>
<img src="https://duarteocarmo.com/images/hackernews.png" alt="Hackernews" style="width:80%">
<br />
<figcaption>The inspiration</figcaption></p>
<p></center></p>
<p>Alright, that being said. What tools did I use to build it? </p>
<h2 id="2the-technology">2.The technology</h2>
<h4 id="21python">2.1.<a href="https://www.python.org/">Python</a></h4>
<p>I would be lying if I told you python was not my favorite language. If I can build it, I prefer to build it with python. For some years now, I have been totally embedded in the language's ecosystem. From data science projects, web development, devops, guis, or just scripts that help people around me. I think python is big, and it's here to stay. For me, it's a bit like writing poetry. </p>
<div class="codehilite"><pre><span></span><code><span class="n">fruits</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"apples"</span><span class="p">,</span> <span class="s2">"oranges"</span><span class="p">,</span> <span class="s2">"bananas"</span><span class="p">]</span>
<span class="k">for</span> <span class="n">fruit</span> <span class="ow">in</span> <span class="n">fruits</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">"I love </span><span class="si">{</span><span class="n">fruit</span><span class="si">}</span><span class="s2">!"</span><span class="p">)</span> <span class="c1"># f strings are like crack. </span>
</code></pre></div>
<p>So python 3 was set. But how to build a hackernews clone using it? </p>
<h4 id="22flask">2.2.<a href="http://flask.pocoo.org/">Flask</a></h4>
<p>I have experimented with various python web frameworks such as <a href="https://www.djangoproject.com/">django</a> or <a href="https://trypyramid.com/">pyramid</a>, but in my opinion, nothing quite compares to <a href="http://flask.pocoo.org/">flask</a>. The sheer simplicity of it is just mind boggling. </p>
<p>For example, the snippet bellow, will give you a page with "Hello world" in it. Now isn't that awesome?</p>
<div class="codehilite"><pre><span></span><code><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span>
<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="vm">__name__</span><span class="p">)</span>
<span class="nd">@app</span><span class="o">.</span><span class="n">route</span><span class="p">(</span><span class="s2">"/"</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">hello</span><span class="p">():</span>
<span class="k">return</span> <span class="s2">"Hello World!"</span>
</code></pre></div>
<p>This is just a small snipped of the syntax of flask. This actually got more complicated than this, but in flask, the general idea is that each function (in this case function <code>hello</code>), returns some HTML (in this case, the string <code>"Hello World""</code>). </p>
<p>OK, you made some pages with some functions, what about data, and models?</p>
<h4 id="23sqlalchemy">2.3.<a href="https://www.sqlalchemy.org/">SQLAlchemy</a></h4>
<p>In order to make things work in our website, I had to come up with a way of managing all of the posts, users, comments, and votes. This "system" would have to both interact with my code, and at the same time, with a database (because we want to save information).</p>
<p>There are a bunch of ways of doing this, but I decided to use SQL Alchemy. The basic idea is that you define a "model" in your code that can automatically interact with a database. </p>
<p>Here is an example of the <code>User</code> class:</p>
<div class="codehilite"><pre><span></span><code><span class="k">class</span> <span class="nc">User</span><span class="p">(</span><span class="n">UserMixin</span><span class="p">,</span> <span class="n">db</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
<span class="nb">id</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">username</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">String</span><span class="p">(</span><span class="mi">64</span><span class="p">),</span> <span class="n">index</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">email</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">String</span><span class="p">(</span><span class="mi">120</span><span class="p">),</span> <span class="n">index</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="n">password_hash</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">String</span><span class="p">(</span><span class="mi">128</span><span class="p">))</span>
<span class="n">posts</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">relationship</span><span class="p">(</span><span class="s2">"Post"</span><span class="p">,</span> <span class="n">backref</span><span class="o">=</span><span class="s2">"author"</span><span class="p">,</span> <span class="n">lazy</span><span class="o">=</span><span class="s2">"dynamic"</span><span class="p">)</span>
<span class="n">comments</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">relationship</span><span class="p">(</span><span class="s2">"Comment"</span><span class="p">,</span> <span class="n">backref</span><span class="o">=</span><span class="s2">"author"</span><span class="p">,</span> <span class="n">lazy</span><span class="o">=</span><span class="s2">"dynamic"</span><span class="p">)</span>
<span class="n">about_me</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">String</span><span class="p">(</span><span class="mi">140</span><span class="p">))</span>
<span class="n">karma</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">Integer</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">timestamp</span> <span class="o">=</span> <span class="n">db</span><span class="o">.</span><span class="n">Column</span><span class="p">(</span><span class="n">db</span><span class="o">.</span><span class="n">DateTime</span><span class="p">,</span> <span class="n">index</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">datetime</span><span class="o">.</span><span class="n">utcnow</span><span class="p">())</span>
</code></pre></div>
<p>This will create a <code>User</code> table in our SQL database and allow us, through python code, to interact with the model. </p>
<p>Browse all the models I created <a href="https://github.com/duarteocarmo/devtuga-news/blob/master/app/models.py">here</a>. </p>
<h4 id="24docker">2.4.<a href="https://www.docker.com/">Docker</a></h4>
<p>After building a website in flask that worked in my local machine, I had to put it onto the web. As this was a learning process I decided to understand what all the fuss around docker was about. What is docker? It is basically a "mini" virtual machine. So mini, that you can run multiple on the same real virtual machine. Each mini virtual machine is called a container. </p>
<p>For this process, I had to create two containers. One for my flask application, and one for my database. (why two and not one is a story for another post).</p>
<p>But how do you do that? Well, the simple principle is that you create something called a <code>Dockerfile</code> which is a set of instructions docker follows, in order to create a container. Here is an example: </p>
<div class="codehilite"><pre><span></span><code><span class="k">FROM</span><span class="w"> </span><span class="s">python:3.7.1-alpine</span>
<span class="k">COPY</span><span class="w"> </span>requirements.txt<span class="w"> </span>requirements.txt<span class="w"> </span>
<span class="k">RUN</span><span class="w"> </span>python<span class="w"> </span>-m<span class="w"> </span>venv<span class="w"> </span>venv<span class="w"> </span>
<span class="k">RUN</span><span class="w"> </span>venv/bin/pip<span class="w"> </span>install<span class="w"> </span>--upgrade<span class="w"> </span>pip
<span class="k">RUN</span><span class="w"> </span>venv/bin/pip<span class="w"> </span>install<span class="w"> </span>-r<span class="w"> </span>requirements.txt
<span class="k">RUN</span><span class="w"> </span>venv/bin/pip<span class="w"> </span>install<span class="w"> </span><span class="nv">gunicorn</span><span class="o">==</span><span class="m">19</span>.8.1
<span class="k">RUN</span><span class="w"> </span>venv/bin/pip<span class="w"> </span>install<span class="w"> </span>pymysql<span class="w"> </span>
<span class="k">COPY</span><span class="w"> </span>app<span class="w"> </span>app
<span class="k">COPY</span><span class="w"> </span>migrations<span class="w"> </span>migrations
<span class="k">COPY</span><span class="w"> </span>dev.py<span class="w"> </span>config.py<span class="w"> </span>boot.sh<span class="w"> </span>./
<span class="k">RUN</span><span class="w"> </span>chmod<span class="w"> </span>+x<span class="w"> </span>boot.sh
<span class="k">ENV</span><span class="w"> </span>FLASK_APP<span class="w"> </span>dev.py
<span class="k">RUN</span><span class="w"> </span>chown<span class="w"> </span>-R<span class="w"> </span>devtuga:devtuga<span class="w"> </span>./<span class="w"> </span>
<span class="k">EXPOSE</span><span class="w"> </span><span class="s">5000</span>
<span class="k">ENTRYPOINT</span><span class="w"> </span><span class="p">[</span><span class="s2">"./boot.sh"</span><span class="p">]</span>
</code></pre></div>
<p>After creating these instructions and running them, we basically can have two containers running, here are mine:</p>
<div class="codehilite"><pre><span></span><code>»<span class="w"> </span>sudo<span class="w"> </span>docker<span class="w"> </span>ps
CONTAINER<span class="w"> </span>ID<span class="w"> </span>IMAGE<span class="w"> </span>COMMAND<span class="w"> </span>CREATED<span class="w"> </span>STATUS<span class="w"> </span>PORTS<span class="w"> </span>NAMES
7baab35c09b7<span class="w"> </span>devtuga:latest<span class="w"> </span><span class="s2">"./boot.sh"</span><span class="w"> </span><span class="m">4</span><span class="w"> </span>hours<span class="w"> </span>ago<span class="w"> </span>Up<span class="w"> </span><span class="m">4</span><span class="w"> </span>hours<span class="w"> </span><span class="m">0</span>.0.0.0:80->5000/tcp<span class="w"> </span>devtuga
89348e814f92<span class="w"> </span>mysql/mysql-server:5.7<span class="w"> </span><span class="s2">"/entrypoint.sh mysq…"</span><span class="w"> </span><span class="m">30</span><span class="w"> </span>hours<span class="w"> </span>ago<span class="w"> </span>Up<span class="w"> </span><span class="m">30</span><span class="w"> </span>hours<span class="w"> </span><span class="o">(</span>healthy<span class="o">)</span><span class="w"> </span><span class="m">3306</span>/tcp,<span class="w"> </span><span class="m">33060</span>/tcp<span class="w"> </span>mysql
</code></pre></div>
<h2 id="3the-process">3.The process</h2>
<p>I took a long time getting everything up and running (<a href="https://github.com/duarteocarmo/devtuga-news/graphs/commit-activity">about a month according to the GitHub repository</a>) but I had a lot of fun, and frustration also. In the end, I got a much better understanding of how real web applications work. So it was definitely worth it. </p>
<h2 id="4the-result">4.The Result</h2>
<p>So <a href="https://devtuga.herokuapp.com/">here's the result</a> after some long hours of frustrating but very fun work. </p>
<p><center>
<img src="https://duarteocarmo.com/images/devtuga.png" alt="Hackernews" style="width:120%">
<br />
<figcaption>I called it: <a href="https://devtuga.herokuapp.com/">devtuga.herokuapp.com</a> </figcaption></p>
<p></center></p>
<h3 id="link-hub">Link hub</h3>
<p><a name="links"></a> </p>
<ul>
<li><a href="https://devtuga.herokuapp.com/">Just show me the final result.</a></li>
<li><a href="https://github.com/duarteocarmo/devtuga-news">I just came here for the code.</a></li>
<li><a href="https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world">I want a tutorial</a></li>
</ul>Hackernews clone using flask2018-12-07T01:02:05+00:002018-12-07T01:02:05+00:00Duarte O.Carmotag:github.com,2018-12-07:/duarteocarmo/flask_hackernewsAnalise de dados da assembleia portuguesa2018-08-13T20:43:05+00:002018-08-13T20:43:05+00:00Duarte O.Carmotag:github.com,2018-08-13:/duarteocarmo/assembleia