| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| """ |
| followupTracker(id): //you will get the email from Database/FollowUps/sent_emails.db using 'id' |
| make a separate database for such cases in the Database/EmailsUnderReview |
| and also add a column for context which will come along from the database |
| " company_email TEXT, |
| role TEXT, |
| date_applied DATETIME, |
| followup_date DATETIME, |
| status TEXT, |
| Unique_application_id TEXT, |
| message_id TEXT, |
| body_json TEXT |
| )" |
| in the new database there will be a new column for overall summary and write it in bullet points as |
| there might be existing bullet points so simple add an extra so basically |
| context contains all the summaries of past emails which will. be used to generate a followup email |
| and rest everything same as body json will contain new email generated as a followup and |
| will be saved in the database |
| so followups are handled properly and no problem occurs |
| the column in new database:"overall_summary" |
| and remember that all other informations should be carried along especially the |
| unique_application_id |
| |
| Use the github token to generate new email |
| "def generate_application_body(company_data: dict, user_data: dict) -> str: |
| |
| if not GITHUB_TOKEN: |
| print("Error: GITHUB_TOKEN not found in environment variables.") |
| return "{}" |
| |
| # Initialize the Azure/GitHub inference client |
| try: |
| endpoint = "https://models.github.ai/inference" |
| client = ChatCompletionsClient( |
| endpoint=endpoint, |
| credential=AzureKeyCredential(GITHUB_TOKEN), |
| ) |
| print("Client initialized successfully") |
| except Exception as e: |
| print(f"Error initializing client: {e}") |
| return "{}"" |
| |
| use "def call_llm(system_prompt, user_query): |
| payload = { |
| "system_prompt": system_prompt, |
| "query": user_query, |
| "max_new_tokens": 1000 |
| } |
| response = requests.post(LLM_URL, json=payload) |
| if response.status_code == 200: |
| return response.json()["response"] |
| raise Exception(f"LLM Error: {response.text}")" |
| |
| to summarize the emails |
| |
| |
| |
| """ |
| import os |
| import sqlite3 |
| import json |
| import requests |
| from datetime import datetime |
|
|
| |
| from azure.ai.inference import ChatCompletionsClient |
| from azure.ai.inference.models import SystemMessage, UserMessage |
| from azure.core.credentials import AzureKeyCredential |
| from dotenv import load_dotenv |
|
|
| |
| |
| |
| |
| |
| load_dotenv(dotenv_path=os.path.join(os.environ.get('WORKSPACE_ROOT', '.'), 'backend/.env')) |
| GITHUB_TOKEN = os.getenv("GITHUB_TOKEN") |
| LLM_URL = "https://unscotched-devon-interpapillary.ngrok-free.dev/generate" |
|
|
| def call_llm(system_prompt: str, user_query: str) -> str: |
| """ |
| Calls your custom local LLM endpoint to summarize the previous email. |
| """ |
| payload = { |
| "system_prompt": system_prompt, |
| "query": user_query, |
| "max_new_tokens": 1000 |
| } |
| try: |
| response = requests.post(LLM_URL, json=payload) |
| response.raise_for_status() |
| return response.json().get("response", "No response generated.") |
| except Exception as e: |
| raise Exception(f"Local LLM Error: {e}") |
|
|
| def generate_application_body(company_email: str, company_name: str, context: str) -> str: |
| """ |
| Uses GitHub Models (gpt-4o) to generate the new follow-up email. |
| """ |
| if not GITHUB_TOKEN: |
| print("β Error: GITHUB_TOKEN not found.") |
| return "{}" |
|
|
| try: |
| endpoint = "https://models.github.ai/inference" |
| client = ChatCompletionsClient( |
| endpoint=endpoint, |
| credential=AzureKeyCredential(GITHUB_TOKEN), |
| ) |
| print("π€ GitHub Client initialized successfully.") |
| |
| system_prompt = "You are an AI assistant helping a textile sales manager write professional follow-up emails for B2B outreach." |
| user_prompt = f""" |
| Company: {company_name} |
| Company Email: {company_email} |
| Past Context / Summaries: |
| {context} |
| |
| Write a polite, concise follow-up email asking if they've had a chance to review our previous proposal. |
| Format the output STRICTLY as valid JSON. Do not include markdown formatting like ```json. |
| Structure: |
| {{ |
| "body": {{ |
| "generated_content": "Subject: Following up on our partnership proposal - [Company Name]<br><br>Hi Team,<br><br>..." |
| }} |
| }} |
| """ |
|
|
| response = client.complete( |
| messages=[ |
| SystemMessage(content=system_prompt), |
| UserMessage(content=user_prompt) |
| ], |
| model="gpt-4o", |
| temperature=0.7, |
| max_tokens=1000 |
| ) |
| |
| |
| content = response.choices[0].message.content.strip() |
| if content.startswith("```json"): |
| content = content[7:-3].strip() |
| elif content.startswith("```"): |
| content = content[3:-3].strip() |
| |
| return content |
|
|
| except Exception as e: |
| print(f"β Error generating follow-up email: {e}") |
| return "{}" |
|
|
| |
| |
| |
| def followupTracker(record_id): |
| """ |
| Extracts the old email, summarizes it, generates a new follow-up email, |
| and saves the entire package to the EmailsUnderReview database. |
| """ |
| source_db_path = os.path.join(os.environ.get('WORKSPACE_ROOT', '.'), 'Database/FollowUps/sent_emails.db') |
| dest_dir = os.path.join(os.environ.get('WORKSPACE_ROOT', '.'), 'Database/EmailsUnderReview') |
| os.makedirs(dest_dir, exist_ok=True) |
| dest_db_path = os.path.join(dest_dir, 'followups_under_review.db') |
|
|
| |
| try: |
| source_conn = sqlite3.connect(source_db_path) |
| source_conn.row_factory = sqlite3.Row |
| cursor = source_conn.cursor() |
|
|
| |
| cursor.execute("SELECT * FROM sent_applications WHERE id = ? OR Unique_application_id = ?", (record_id, str(record_id))) |
| record = cursor.fetchone() |
|
|
| if not record: |
| print(f"β No record found in sent_emails.db with ID: {record_id}") |
| return |
|
|
| company_email = record["company_email"] |
| company_name = record["company_name"] |
| generated_subject = record["generated_subject"] |
| followup_date = record["followup_date"] |
| unique_application_id = record["Unique_application_id"] |
| message_id = record["message_id"] |
| old_body_json_str = record["body_json"] |
|
|
| except sqlite3.Error as e: |
| print(f"β Source Database error: {e}") |
| return |
| finally: |
| if 'source_conn' in locals() and source_conn: |
| source_conn.close() |
|
|
| |
| try: |
| old_data = json.loads(old_body_json_str) |
| |
| old_email_text = old_data.get("body", {}).get("generated_content", "No content found.") |
| except Exception: |
| |
| old_email_text = old_body_json_str |
|
|
| try: |
| print("π Summarizing previous email via Local LLM...") |
| summary_sys_prompt = "You summarize emails concisely into exactly one short sentence." |
| summary_query = f"Summarize this email:\n{old_email_text}" |
| new_summary_text = call_llm(summary_sys_prompt, summary_query) |
| |
| current_date = datetime.now().strftime('%Y-%m-%d') |
| new_bullet = f"β’ {current_date}: {new_summary_text.strip()}" |
| print(f"β
Summary generated: {new_bullet}") |
| except Exception as e: |
| print(f"β οΈ Summarization skipped or failed: {e}") |
| new_bullet = f"β’ {datetime.now().strftime('%Y-%m-%d')}: Follow-up initiated for {company_name}." |
|
|
| |
| try: |
| dest_conn = sqlite3.connect(dest_db_path) |
| dest_cursor = dest_conn.cursor() |
|
|
| dest_cursor.execute(''' |
| CREATE TABLE IF NOT EXISTS followups_pending ( |
| id INTEGER PRIMARY KEY AUTOINCREMENT, |
| company_email TEXT, |
| company_name TEXT, |
| generated_subject TEXT, |
| followup_date DATETIME, |
| status TEXT, |
| Unique_application_id TEXT, |
| message_id TEXT, |
| body_json TEXT, |
| context TEXT, |
| overall_summary TEXT |
| ) |
| ''') |
|
|
| |
| dest_cursor.execute("SELECT overall_summary, context FROM followups_pending WHERE Unique_application_id = ?", (unique_application_id,)) |
| existing_record = dest_cursor.fetchone() |
|
|
| if existing_record: |
| existing_summary = existing_record[0] if existing_record[0] else "" |
| overall_summary = f"{existing_summary}\n{new_bullet}" |
| context = existing_record[1] if existing_record[1] else f"Company: {company_name} ({company_email})" |
| is_update = True |
| else: |
| overall_summary = new_bullet |
| context = f"Company: {company_name} ({company_email})\nInitial Outreach: {generated_subject}" |
| is_update = False |
|
|
| |
| full_context_for_llm = f"{context}\n\nEmail History:\n{overall_summary}" |
|
|
| |
| print("βοΈ Generating new follow-up email draft via GitHub Models...") |
| new_email_json_str = generate_application_body(company_email, company_name, full_context_for_llm) |
|
|
| status = "Draft Generated - Pending Review" |
|
|
| |
| if is_update: |
| dest_cursor.execute(''' |
| UPDATE followups_pending |
| SET status = ?, body_json = ?, overall_summary = ?, context = ? |
| WHERE Unique_application_id = ? |
| ''', (status, new_email_json_str, overall_summary, full_context_for_llm, unique_application_id)) |
| print(f"β
Updated existing tracker and saved new draft. (ID: {unique_application_id})") |
| else: |
| dest_cursor.execute(''' |
| INSERT INTO followups_pending |
| (company_email, company_name, generated_subject, followup_date, status, Unique_application_id, message_id, body_json, context, overall_summary) |
| VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) |
| ''', ( |
| company_email, company_name, generated_subject, followup_date, status, unique_application_id, message_id, new_email_json_str, full_context_for_llm, overall_summary |
| )) |
| print(f"β
Created new tracker and saved first follow-up draft. (ID: {unique_application_id})") |
|
|
| dest_conn.commit() |
|
|
| except sqlite3.Error as e: |
| print(f"β Destination Database error: {e}") |
| finally: |
| if 'dest_conn' in locals() and dest_conn: |
| dest_conn.close() |
| print("Done! π") |
|
|
| |
| |
| |
| if __name__ == "__main__": |
| import sys |
| try: |
| raw_input = sys.stdin.read().strip() |
| if not raw_input: |
| print(json.dumps({"ok": False, "error": "No input provided"})) |
| sys.exit(1) |
| |
| payload = json.loads(raw_input) |
| record_id = payload.get("id") |
| |
| if not record_id: |
| print(json.dumps({"ok": False, "error": "Missing 'id' in input"})) |
| sys.exit(1) |
| |
| |
| followupTracker(record_id) |
| |
| |
| print(json.dumps({"ok": True})) |
| |
| except Exception as e: |
| print(json.dumps({"ok": False, "error": str(e)})) |
| sys.exit(1) |