File size: 10,271 Bytes
0af0679 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 |
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Multi-model Evaluation LinkedIn Summary and FAQ"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import os\n",
"import gradio as gr\n",
"from dotenv import load_dotenv\n",
"from pypdf import PdfReader\n",
"from pathlib import Path\n",
"from IPython.display import Markdown, display\n",
"from anthropic import Anthropic\n",
"from openai import OpenAI # Used here to call Ollama-compatible API and Google Gemini\n",
"\n",
"load_dotenv(override=True)"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"OpenAI API Key not set\n",
"Anthropic API Key exists and begins sk-ant-\n",
"Google API Key exists and begins AI\n",
"DeepSeek API Key not set (and this is optional)\n",
"Groq API Key exists and begins gsk_\n"
]
}
],
"source": [
"# Print the key prefixes to help with any debugging\n",
"\n",
"openai_api_key = os.getenv('OPENAI_API_KEY')\n",
"anthropic_api_key = os.getenv('ANTHROPIC_API_KEY')\n",
"google_api_key = os.getenv('GOOGLE_API_KEY')\n",
"deepseek_api_key = os.getenv('DEEPSEEK_API_KEY')\n",
"groq_api_key = os.getenv('GROQ_API_KEY')\n",
"\n",
"if openai_api_key:\n",
" print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
"else:\n",
" print(\"OpenAI API Key not set\")\n",
" \n",
"if anthropic_api_key:\n",
" print(f\"Anthropic API Key exists and begins {anthropic_api_key[:7]}\")\n",
"else:\n",
" print(\"Anthropic API Key not set (and this is optional)\")\n",
"\n",
"if google_api_key:\n",
" print(f\"Google API Key exists and begins {google_api_key[:2]}\")\n",
"else:\n",
" print(\"Google API Key not set (and this is optional)\")\n",
"\n",
"if deepseek_api_key:\n",
" print(f\"DeepSeek API Key exists and begins {deepseek_api_key[:3]}\")\n",
"else:\n",
" print(\"DeepSeek API Key not set (and this is optional)\")\n",
"\n",
"if groq_api_key:\n",
" print(f\"Groq API Key exists and begins {groq_api_key[:4]}\")\n",
"else:\n",
" print(\"Groq API Key not set (and this is optional)\")"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"anthropic = Anthropic()\n",
"\n",
"# === Load PDF and extract resume text ===\n",
"\n",
"reader = PdfReader(\"../claude_based_chatbot_tc/me/linkedin.pdf\")\n",
"linkedin = \"\"\n",
"for page in reader.pages:\n",
" text = page.extract_text()\n",
" if text:\n",
" linkedin += text\n",
"\n",
"# === Create the shared FAQ generation prompt ===\n",
"faq_prompt = (\n",
" \"Please read the following professional background and resume content carefully. \"\n",
" \"Based on this information, generate a well-structured FAQ (Frequently Asked Questions) document that reflects the subject’s professional background.\\n\\n\"\n",
" \"== RESUME TEXT START ==\\n\"\n",
" f\"{linkedin}\\n\"\n",
" \"== RESUME TEXT END ==\\n\\n\"\n",
"\n",
" \"**Instructions:**\\n\"\n",
" \"- Write at least 15 FAQs.\\n\"\n",
" \"- Each entry should be in the format:\\n\"\n",
" \" - Q: [Question here]\\n\"\n",
" \" - A: [Answer here]\\n\"\n",
" \"- Focus on real-world questions that recruiters, collaborators, or website visitors would ask.\\n\"\n",
" \"- Be concise, accurate, and use only the information in the resume. Do not speculate or invent details.\\n\"\n",
" \"- Use a professional tone suitable for publishing on a personal website.\\n\\n\"\n",
"\n",
" \"Output only the FAQ content. Do not include commentary, headers, or formatting outside of the Q/A list.\"\n",
")\n",
"\n",
"messages = [{\"role\": \"user\", \"content\": faq_prompt}]\n",
"evaluators = []\n",
"answers = []\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Anthropic API Call\n",
"\n",
"model_name = \"claude-3-7-sonnet-latest\"\n",
"\n",
"claude = Anthropic()\n",
"faq_prompt = claude.messages.create(\n",
" model=model_name, \n",
" messages=messages, \n",
" max_tokens=1000\n",
")\n",
"\n",
"faq_answer = faq_prompt.content[0].text\n",
"\n",
"display(Markdown(faq_answer))\n",
"evaluators.append(model_name)\n",
"answers.append(faq_answer)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# === 2. Google Gemini Call ===\n",
"\n",
"gemini = OpenAI(api_key=google_api_key, base_url=\"https://generativelanguage.googleapis.com/v1beta/openai/\")\n",
"model_name = \"gemini-2.5-flash\"\n",
"\n",
"faq_prompt = gemini.chat.completions.create(model=model_name, messages=messages)\n",
"faq_answer = faq_prompt.choices[0].message.content\n",
"\n",
"display(Markdown(faq_answer))\n",
"evaluators.append(model_name)\n",
"answers.append(faq_answer)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# === 2. Ollama Groq Call ===\n",
"\n",
"groq = OpenAI(api_key=groq_api_key, base_url=\"https://api.groq.com/openai/v1\")\n",
"model_name = \"llama-3.3-70b-versatile\"\n",
"\n",
"faq_prompt = groq.chat.completions.create(model=model_name, messages=messages)\n",
"faq_answer = faq_prompt.choices[0].message.content\n",
"\n",
"display(Markdown(faq_answer))\n",
"evaluators.append(model_name)\n",
"answers.append(faq_answer)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# It's nice to know how to use \"zip\"\n",
"\n",
"for evaluator, answer in zip(evaluators, answers):\n",
" print(f\"Evaluator: {evaluator}\\n\\n{answer}\")\n",
"\n",
"\n",
"# Let's bring this together - note the use of \"enumerate\"\n",
"\n",
"together = \"\"\n",
"for index, answer in enumerate(answers):\n",
" together += f\"# Response from evaluator {index+1}\\n\\n\"\n",
" together += answer + \"\\n\\n\""
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"formatter = f\"\"\"You are a meticulous AI evaluator tasked with synthesizing multiple assistant-generated career FAQs and summaries into one high-quality file. You have received {len(evaluators)} drafts based on the same resume, each containing a 2-line summary and a set of FAQ questions with answers.\n",
"\n",
"---\n",
"**Original Request:**\n",
"\"{faq_prompt}\"\n",
"---\n",
"\n",
"Your goal is to combine the strongest parts of each submission into a single, polished output. This will be the final `faq.txt` that lives in a public-facing portfolio folder.\n",
"\n",
"**Evaluation & Synthesis Instructions:**\n",
"\n",
"1. **Prioritize Accuracy:** Only include information clearly supported by the resume. Do not invent or speculate.\n",
"2. **Best Questions Only:** Select the most relevant and insightful FAQ questions. Discard weak, redundant, or generic ones.\n",
"3. **Edit for Quality:** Improve the clarity and fluency of answers. Fix grammar, wording, or formatting inconsistencies.\n",
"4. **Merge Strengths:** If two assistants answer the same question differently, combine the best phrasing and facts from each.\n",
"5. **Consistency in Voice:** Ensure a single professional tone throughout the summary and FAQ.\n",
"\n",
"**Required Output Structure:**\n",
"\n",
"1. **2-Line Summary:** Start with the best or synthesized version of the summary, capturing key career strengths.\n",
"2. **FAQ Entries:** Follow with at least 8–12 strong FAQ entries in this format:\n",
"\n",
"Q: [Question] \n",
"A: [Answer]\n",
"\n",
"---\n",
"**Examples of Strong FAQ Topics:**\n",
"- Key technical skills or languages\n",
"- Past projects or employers\n",
"- Teamwork or communication style\n",
"- Remote work or leadership experience\n",
"- Career goals or current availability\n",
"\n",
"This will be saved as a plain text file (`faq.txt`). Ensure the tone is accurate, clean, and helpful. Do not add unnecessary commentary or meta-analysis. The final version should look like it was written by a professional assistant who knows the subject well.\n",
"\"\"\"\n",
"\n",
"formatter_messages = [{\"role\": \"user\", \"content\": formatter}]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# === 1. Final (Claude) API Call ===\n",
"anthropic = Anthropic(api_key=anthropic_api_key)\n",
"faq_prompt = anthropic.messages.create(\n",
" model=\"claude-3-7-sonnet-latest\",\n",
" messages=formatter_messages,\n",
" max_tokens=1000,\n",
")\n",
"results = faq_prompt.content[0].text\n",
"display(Markdown(results))\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"gr.ChatInterface(results, type=\"messages\").launch()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": ".venv",
"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.12.10"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
|