Skip to content

Commit 19ae665

Browse files
authored
Merge pull request #472 from harrsshh08/main
Community contribution: 1_foundations using gemini
2 parents 25eb6d1 + 3bde085 commit 19ae665

9 files changed

Lines changed: 2663 additions & 0 deletions

File tree

1_foundations/community_contributions/1_foundations_using_gemini/1_lab1.ipynb

Lines changed: 406 additions & 0 deletions
Large diffs are not rendered by default.

1_foundations/community_contributions/1_foundations_using_gemini/2_lab2.ipynb

Lines changed: 492 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 382 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,382 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"## Welcome to Lab 3 for Week 1 Day 4\n",
8+
"\n",
9+
"Today we're going to build something with immediate value!\n",
10+
"\n",
11+
"In the folder `me` I've put a single file `linkedin.pdf` - it's a PDF download of my LinkedIn profile.\n",
12+
"\n",
13+
"Please replace it with yours!\n",
14+
"\n",
15+
"I've also made a file called `summary.txt`\n",
16+
"\n",
17+
"We're not going to use Tools just yet - we're going to add the tool tomorrow."
18+
]
19+
},
20+
{
21+
"cell_type": "markdown",
22+
"metadata": {},
23+
"source": [
24+
"<table style=\"margin: 0; text-align: left; width:100%\">\n",
25+
" <tr>\n",
26+
" <td style=\"width: 150px; height: 150px; vertical-align: middle;\">\n",
27+
" <img src=\"../assets/tools.png\" width=\"150\" height=\"150\" style=\"display: block;\" />\n",
28+
" </td>\n",
29+
" <td>\n",
30+
" <h2 style=\"color:#00bfff;\">Looking up packages</h2>\n",
31+
" <span style=\"color:#00bfff;\">In this lab, we're going to use the wonderful Gradio package for building quick UIs, \n",
32+
" and we're also going to use the popular PyPDF PDF reader. You can get guides to these packages by asking \n",
33+
" ChatGPT or Claude, and you find all open-source packages on the repository <a href=\"https://pypi.org\">https://pypi.org</a>.\n",
34+
" </span>\n",
35+
" </td>\n",
36+
" </tr>\n",
37+
"</table>"
38+
]
39+
},
40+
{
41+
"cell_type": "code",
42+
"execution_count": null,
43+
"metadata": {},
44+
"outputs": [],
45+
"source": [
46+
"# If you don't know what any of these packages do - you can always ask ChatGPT for a guide!\n",
47+
"\n",
48+
"from dotenv import load_dotenv\n",
49+
"from openai import OpenAI\n",
50+
"from pypdf import PdfReader\n",
51+
"import os\n",
52+
"import gradio as gr"
53+
]
54+
},
55+
{
56+
"cell_type": "code",
57+
"execution_count": null,
58+
"metadata": {},
59+
"outputs": [],
60+
"source": [
61+
"load_dotenv(override=True)\n",
62+
"GEMINI_BASE_URL = \"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
63+
"google_api_key = os.getenv(\"GOOGLE_API_KEY\")\n",
64+
"gemini = OpenAI(base_url=GEMINI_BASE_URL, api_key=google_api_key)"
65+
]
66+
},
67+
{
68+
"cell_type": "code",
69+
"execution_count": null,
70+
"metadata": {},
71+
"outputs": [],
72+
"source": [
73+
"reader = PdfReader(\"me/linkedin.pdf\")\n",
74+
"linkedin = \"\"\n",
75+
"for page in reader.pages:\n",
76+
" text = page.extract_text()\n",
77+
" if text:\n",
78+
" linkedin += text"
79+
]
80+
},
81+
{
82+
"cell_type": "code",
83+
"execution_count": null,
84+
"metadata": {},
85+
"outputs": [],
86+
"source": [
87+
"print(linkedin)"
88+
]
89+
},
90+
{
91+
"cell_type": "code",
92+
"execution_count": null,
93+
"metadata": {},
94+
"outputs": [],
95+
"source": [
96+
"with open(\"me/summary.txt\", \"r\", encoding=\"utf-8\") as f:\n",
97+
" summary = f.read()"
98+
]
99+
},
100+
{
101+
"cell_type": "code",
102+
"execution_count": null,
103+
"metadata": {},
104+
"outputs": [],
105+
"source": [
106+
"name = \"Harsh Patidar\""
107+
]
108+
},
109+
{
110+
"cell_type": "code",
111+
"execution_count": null,
112+
"metadata": {},
113+
"outputs": [],
114+
"source": [
115+
"system_prompt = f\"You are acting as {name}. You are answering questions on {name}'s website, \\\n",
116+
"particularly questions related to {name}'s career, background, skills and experience. \\\n",
117+
"Your responsibility is to represent {name} for interactions on the website as faithfully as possible. \\\n",
118+
"You are given a summary of {name}'s background and LinkedIn profile which you can use to answer questions. \\\n",
119+
"Be professional and engaging, as if talking to a potential client or future employer who came across the website. \\\n",
120+
"If you don't know the answer, say so.\"\n",
121+
"\n",
122+
"system_prompt += f\"\\n\\n## Summary:\\n{summary}\\n\\n## LinkedIn Profile:\\n{linkedin}\\n\\n\"\n",
123+
"system_prompt += f\"With this context, please chat with the user, always staying in character as {name}.\"\n"
124+
]
125+
},
126+
{
127+
"cell_type": "code",
128+
"execution_count": null,
129+
"metadata": {},
130+
"outputs": [],
131+
"source": [
132+
"system_prompt"
133+
]
134+
},
135+
{
136+
"cell_type": "code",
137+
"execution_count": null,
138+
"metadata": {},
139+
"outputs": [],
140+
"source": [
141+
"model_name = \"gemini-2.5-flash-preview-05-20\""
142+
]
143+
},
144+
{
145+
"cell_type": "code",
146+
"execution_count": null,
147+
"metadata": {},
148+
"outputs": [],
149+
"source": [
150+
"def chat(message, history):\n",
151+
" messages = [{\"role\": \"system\", \"content\": system_prompt}] + history + [{\"role\": \"user\", \"content\": message}]\n",
152+
" response = gemini.chat.completions.create(model=model_name, messages=messages)\n",
153+
" return response.choices[0].message.content"
154+
]
155+
},
156+
{
157+
"cell_type": "markdown",
158+
"metadata": {},
159+
"source": [
160+
"## Special note for people not using OpenAI\n",
161+
"\n",
162+
"Some providers, like Groq, might give an error when you send your second message in the chat.\n",
163+
"\n",
164+
"This is because Gradio shoves some extra fields into the history object. OpenAI doesn't mind; but some other models complain.\n",
165+
"\n",
166+
"If this happens, the solution is to add this first line to the chat() function above. It cleans up the history variable:\n",
167+
"\n",
168+
"```python\n",
169+
"history = [{\"role\": h[\"role\"], \"content\": h[\"content\"]} for h in history]\n",
170+
"```\n",
171+
"\n",
172+
"You may need to add this in other chat() callback functions in the future, too."
173+
]
174+
},
175+
{
176+
"cell_type": "code",
177+
"execution_count": null,
178+
"metadata": {},
179+
"outputs": [],
180+
"source": [
181+
"gr.ChatInterface(chat, type=\"messages\").launch()"
182+
]
183+
},
184+
{
185+
"cell_type": "markdown",
186+
"metadata": {},
187+
"source": [
188+
"## A lot is about to happen...\n",
189+
"\n",
190+
"1. Be able to ask an LLM to evaluate an answer\n",
191+
"2. Be able to rerun if the answer fails evaluation\n",
192+
"3. Put this together into 1 workflow\n",
193+
"\n",
194+
"All without any Agentic framework!"
195+
]
196+
},
197+
{
198+
"cell_type": "code",
199+
"execution_count": null,
200+
"metadata": {},
201+
"outputs": [],
202+
"source": [
203+
"# Create a Pydantic model for the Evaluation\n",
204+
"\n",
205+
"from pydantic import BaseModel\n",
206+
"\n",
207+
"class Evaluation(BaseModel):\n",
208+
" is_acceptable: bool\n",
209+
" feedback: str\n"
210+
]
211+
},
212+
{
213+
"cell_type": "code",
214+
"execution_count": null,
215+
"metadata": {},
216+
"outputs": [],
217+
"source": [
218+
"evaluator_system_prompt = f\"You are an evaluator that decides whether a response to a question is acceptable. \\\n",
219+
"You are provided with a conversation between a User and an Agent. Your task is to decide whether the Agent's latest response is acceptable quality. \\\n",
220+
"The Agent is playing the role of {name} and is representing {name} on their website. \\\n",
221+
"The Agent has been instructed to be professional and engaging, as if talking to a potential client or future employer who came across the website. \\\n",
222+
"The Agent has been provided with context on {name} in the form of their summary and LinkedIn details. Here's the information:\"\n",
223+
"\n",
224+
"evaluator_system_prompt += f\"\\n\\n## Summary:\\n{summary}\\n\\n## LinkedIn Profile:\\n{linkedin}\\n\\n\"\n",
225+
"evaluator_system_prompt += f\"With this context, please evaluate the latest response, replying with whether the response is acceptable and your feedback.\""
226+
]
227+
},
228+
{
229+
"cell_type": "code",
230+
"execution_count": null,
231+
"metadata": {},
232+
"outputs": [],
233+
"source": [
234+
"def evaluator_user_prompt(reply, message, history):\n",
235+
" user_prompt = f\"Here's the conversation between the User and the Agent: \\n\\n{history}\\n\\n\"\n",
236+
" user_prompt += f\"Here's the latest message from the User: \\n\\n{message}\\n\\n\"\n",
237+
" user_prompt += f\"Here's the latest response from the Agent: \\n\\n{reply}\\n\\n\"\n",
238+
" user_prompt += \"Please evaluate the response, replying with whether it is acceptable and your feedback.\"\n",
239+
" return user_prompt"
240+
]
241+
},
242+
{
243+
"cell_type": "code",
244+
"execution_count": null,
245+
"metadata": {},
246+
"outputs": [],
247+
"source": [
248+
"import os\n",
249+
"gemini = OpenAI(\n",
250+
" api_key=os.getenv(\"GOOGLE_API_KEY\"), \n",
251+
" base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\"\n",
252+
")"
253+
]
254+
},
255+
{
256+
"cell_type": "code",
257+
"execution_count": null,
258+
"metadata": {},
259+
"outputs": [],
260+
"source": [
261+
"def evaluate(reply, message, history) -> Evaluation:\n",
262+
"\n",
263+
" messages = [{\"role\": \"system\", \"content\": evaluator_system_prompt}] + [{\"role\": \"user\", \"content\": evaluator_user_prompt(reply, message, history)}]\n",
264+
" response = gemini.beta.chat.completions.parse(model=model_name, messages=messages, response_format=Evaluation)\n",
265+
" return response.choices[0].message.parsed"
266+
]
267+
},
268+
{
269+
"cell_type": "code",
270+
"execution_count": null,
271+
"metadata": {},
272+
"outputs": [],
273+
"source": [
274+
"messages = [{\"role\": \"system\", \"content\": system_prompt}] + [{\"role\": \"user\", \"content\": \"do you hold a patent?\"}]\n",
275+
"response = gemini.chat.completions.create(model=model_name, messages=messages)\n",
276+
"reply = response.choices[0].message.content"
277+
]
278+
},
279+
{
280+
"cell_type": "code",
281+
"execution_count": null,
282+
"metadata": {},
283+
"outputs": [],
284+
"source": [
285+
"reply"
286+
]
287+
},
288+
{
289+
"cell_type": "code",
290+
"execution_count": null,
291+
"metadata": {},
292+
"outputs": [],
293+
"source": [
294+
"evaluate(reply, \"do you hold a patent?\", messages[:1])"
295+
]
296+
},
297+
{
298+
"cell_type": "code",
299+
"execution_count": null,
300+
"metadata": {},
301+
"outputs": [],
302+
"source": [
303+
"def rerun(reply, message, history, feedback):\n",
304+
" updated_system_prompt = system_prompt + \"\\n\\n## Previous answer rejected\\nYou just tried to reply, but the quality control rejected your reply\\n\"\n",
305+
" updated_system_prompt += f\"## Your attempted answer:\\n{reply}\\n\\n\"\n",
306+
" updated_system_prompt += f\"## Reason for rejection:\\n{feedback}\\n\\n\"\n",
307+
" messages = [{\"role\": \"system\", \"content\": updated_system_prompt}] + history + [{\"role\": \"user\", \"content\": message}]\n",
308+
" response = gemini.chat.completions.create(model=model_name, messages=messages)\n",
309+
" return response.choices[0].message.content"
310+
]
311+
},
312+
{
313+
"cell_type": "code",
314+
"execution_count": null,
315+
"metadata": {},
316+
"outputs": [],
317+
"source": [
318+
"def chat(message, history):\n",
319+
" if \"patent\" in message:\n",
320+
" system = system_prompt + \"\\n\\nEverything in your reply needs to be in pig latin - \\\n",
321+
" it is mandatory that you respond only and entirely in pig latin\"\n",
322+
" else:\n",
323+
" system = system_prompt\n",
324+
" messages = [{\"role\": \"system\", \"content\": system}] + history + [{\"role\": \"user\", \"content\": message}]\n",
325+
" response = gemini.chat.completions.create(model=model_name, messages=messages)\n",
326+
" reply =response.choices[0].message.content\n",
327+
"\n",
328+
" evaluation = evaluate(reply, message, history)\n",
329+
" \n",
330+
" if evaluation.is_acceptable:\n",
331+
" print(\"Passed evaluation - returning reply\")\n",
332+
" else:\n",
333+
" print(\"Failed evaluation - retrying\")\n",
334+
" print(evaluation.feedback)\n",
335+
" reply = rerun(reply, message, history, evaluation.feedback) \n",
336+
" return reply"
337+
]
338+
},
339+
{
340+
"cell_type": "code",
341+
"execution_count": null,
342+
"metadata": {},
343+
"outputs": [],
344+
"source": [
345+
"gr.ChatInterface(chat, type=\"messages\").launch()"
346+
]
347+
},
348+
{
349+
"cell_type": "markdown",
350+
"metadata": {},
351+
"source": []
352+
},
353+
{
354+
"cell_type": "code",
355+
"execution_count": null,
356+
"metadata": {},
357+
"outputs": [],
358+
"source": []
359+
}
360+
],
361+
"metadata": {
362+
"kernelspec": {
363+
"display_name": ".venv",
364+
"language": "python",
365+
"name": "python3"
366+
},
367+
"language_info": {
368+
"codemirror_mode": {
369+
"name": "ipython",
370+
"version": 3
371+
},
372+
"file_extension": ".py",
373+
"mimetype": "text/x-python",
374+
"name": "python",
375+
"nbconvert_exporter": "python",
376+
"pygments_lexer": "ipython3",
377+
"version": "3.12.12"
378+
}
379+
},
380+
"nbformat": 4,
381+
"nbformat_minor": 2
382+
}

0 commit comments

Comments
 (0)