165 lines
5.8 KiB
Plaintext
165 lines
5.8 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"id": "cc3d4ef7",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from google import genai\n",
|
|
"from google.genai import types\n",
|
|
"from datetime import datetime\n",
|
|
"from pydantic import BaseModel\n",
|
|
"import os\n",
|
|
"\n",
|
|
"class JobSuggestion(BaseModel):\n",
|
|
" company_name: str\n",
|
|
" company_description: str\n",
|
|
" job_title: str\n",
|
|
" application_text: str\n",
|
|
"\n",
|
|
"# Load CV from file\n",
|
|
"with open(\"cv_sebastian_egli.txt\", \"r\", encoding=\"utf-8\") as f:\n",
|
|
" cv = f.read()\n",
|
|
"\n",
|
|
"# Load already suggested companies from file (to avoid duplicates)\n",
|
|
"with open(\"already_suggested_companies.txt\", \"r\", encoding=\"utf-8\") as f:\n",
|
|
" already_suggested_companies = f.read()\n",
|
|
"\n",
|
|
"# Define boolean for even-numbered days (I want to switch un/solicited every day)\n",
|
|
"today = datetime.today()\n",
|
|
"unsolicited_application = today.day % 2 == 0\n",
|
|
"\n",
|
|
"if unsolicited_application:\n",
|
|
" query = [\"\"\"Analysiere meinen Lebenslauf (cv) und die Liste bereits vorgeschlagener Unternehmen (already_suggested_companies). \n",
|
|
"Schlage mir genau ein Unternehmen in der Nähe von Marburg vor, das noch nicht in already_suggested_companies enthalten ist \n",
|
|
"und für eine Initiativbewerbung besonders gut zu meinem Profil passt. \n",
|
|
"\n",
|
|
"Erkläre in maximal 150 Wörtern prägnant, warum dieses Unternehmen eine besonders gute Wahl für mich wäre. \n",
|
|
"Formuliere die Antwort als kurze, professionelle Email mit dem Titel: 'Neuer Jobvorschlag'. \n",
|
|
"Begründe die Eignung anhand meiner Qualifikationen und Interessen. \n",
|
|
"Füge außerdem einen einzelnen Satz hinzu, der direkt in einem Bewerbungsschreiben genutzt werden könnte, \n",
|
|
"um die Übereinstimmung zwischen mir und dem Unternehmen hervorzuheben. \n",
|
|
"\n",
|
|
"Liefere nur die Email, keine zusätzliche Erklärung.\"\"\",already_suggested_companies,cv]\n",
|
|
"else:\n",
|
|
" query = [\"\"\"Analysiere meinen Lebenslauf (cv) und die Liste bereits vorgeschlagener Unternehmen (already_suggested_companies). \n",
|
|
"Schlage mir genau eine aktuell offene Stellenausschreibung in der Nähe von Marburg vor für ein Unternehmen, das noch nicht in already_suggested_companies enthalten ist \n",
|
|
"und die besonders gut zu meinem Profil passt. \n",
|
|
"\n",
|
|
"Erkläre in maximal 150 Wörtern prägnant, warum diese Stelle eine besonders gute Wahl für mich wäre. \n",
|
|
"Formuliere die Antwort als kurze, professionelle Email mit dem Titel: 'Neuer Jobvorschlag'. \n",
|
|
"Begründe die Eignung anhand meiner Qualifikationen und Interessen. \n",
|
|
"Füge außerdem einen einzelnen Satz hinzu, der direkt in einem Bewerbungsschreiben genutzt werden könnte, \n",
|
|
"um die Übereinstimmung zwischen mir und der ausgeschriebenen Stelle hervorzuheben. \n",
|
|
"\n",
|
|
"Liefere nur die Email, keine zusätzliche Erklärung.\"\"\",already_suggested_companies,cv]"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"id": "7c68f66d",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"api_key = os.environ.get(\"GEMINI_API_KEY\")\n",
|
|
"\n",
|
|
"client = genai.Client(api_key=api_key)\n",
|
|
"\n",
|
|
"# Step 1: grounded search (necessary for live web search)\n",
|
|
"resp_grounded = client.models.generate_content(\n",
|
|
" model=\"gemini-2.5-flash\",\n",
|
|
" contents=query,\n",
|
|
" config=types.GenerateContentConfig(\n",
|
|
" tools=[types.Tool(google_search=types.GoogleSearch())]\n",
|
|
" ),\n",
|
|
")\n",
|
|
"\n",
|
|
"grounded_answer = resp_grounded.text # freeform answer"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"id": "fe54c9a2",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Step 2: convert to JSON\n",
|
|
"resp_json = client.models.generate_content(\n",
|
|
" model=\"gemini-2.5-flash\",\n",
|
|
" contents=f\"Turn this answer into JSON: {grounded_answer}\",\n",
|
|
" config=types.GenerateContentConfig(\n",
|
|
" response_mime_type=\"application/json\",\n",
|
|
" response_schema=JobSuggestion,\n",
|
|
" ),\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "476ae4e4",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Append the response to already_suggested_companies.txt\n",
|
|
"with open(\"already_suggested_companies.txt\", \"a\", encoding=\"utf-8\") as f:\n",
|
|
" f.write(\"\\n\" + resp_json.parsed.company_name)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 5,
|
|
"id": "c3d72c4f",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import smtplib\n",
|
|
"from email.mime.text import MIMEText\n",
|
|
"\n",
|
|
"gmail_key = os.environ.get(\"GMAIL_PW\")\n",
|
|
"\n",
|
|
"# Account details\n",
|
|
"sender = \"seb.egli@gmail.com\"\n",
|
|
"recipient = \"seb.egli@gmail.com\"\n",
|
|
"password = gmail_key\n",
|
|
"\n",
|
|
"# Create email\n",
|
|
"msg = MIMEText(grounded_answer)\n",
|
|
"msg[\"From\"] = sender\n",
|
|
"msg[\"To\"] = recipient\n",
|
|
"msg[\"Subject\"] = \"Neuer Jobvorschlag\"\n",
|
|
"\n",
|
|
"# Send email using Gmail's SMTP\n",
|
|
"with smtplib.SMTP_SSL(\"smtp.gmail.com\", 465) as server:\n",
|
|
" server.login(sender, password)\n",
|
|
" server.sendmail(sender, recipient, msg.as_string())"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "odc-landsat",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.13.0"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|