|
|
import logging |
|
|
import os |
|
|
import random |
|
|
from openai import OpenAI |
|
|
from gtts import gTTS |
|
|
import gradio as gr |
|
|
|
|
|
|
|
|
logging.basicConfig( |
|
|
level=logging.INFO, |
|
|
format='%(asctime)s - %(levelname)s - %(message)s' |
|
|
) |
|
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
|
|
|
try: |
|
|
os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY") |
|
|
if not os.environ["OPENAI_API_KEY"]: |
|
|
raise ValueError("OPENAI_API_KEY environment variable not set!") |
|
|
client = OpenAI() |
|
|
except Exception as e: |
|
|
logger.error(f"Failed to initialize OpenAI client: {e}") |
|
|
raise |
|
|
|
|
|
|
|
|
def read_chat_file(chat_file): |
|
|
"""Read the uploaded chat file and return its lines.""" |
|
|
try: |
|
|
with open(chat_file.name, "r", encoding="utf-8") as f: |
|
|
return f.readlines() |
|
|
except Exception as e: |
|
|
logger.error(f"Error reading chat file: {e}") |
|
|
raise |
|
|
|
|
|
def sample_messages(lines): |
|
|
"""Sample up to 100 random lines from the chat.""" |
|
|
if len(lines) >= 100: |
|
|
start_index = random.randint(0, len(lines) - 100) |
|
|
return lines[start_index:start_index + 100] |
|
|
return lines |
|
|
|
|
|
def summarize_chat(messages_text, name): |
|
|
"""Generate a summary of the chat using OpenAI.""" |
|
|
prompt = f"""Summarize the following WhatsApp conversation in 2–3 sentences, focusing only on notable events, emotional states, and meaningful interactions between 'You' ({name}) and the other user. |
|
|
Highlight specific events involving {name}—especially any related to health, job, mental health, or finances. |
|
|
If no major event is present, capture any noteworthy daily moments (e.g., cooking, commuting, funny moments). |
|
|
Describe how {name} is feeling and what they are going through, using the format: {name} is feeling [emotion] and going through [event]. |
|
|
Always include the name of the other user {name} is talking to. |
|
|
Exclude all sexual content. |
|
|
Do not mention if "no major event" occurred—just describe what's there. |
|
|
If a funny joke or banter is present, include that specific message in quotes for potential reuse. |
|
|
Conversation: |
|
|
{messages_text}""" |
|
|
try: |
|
|
response = client.chat.completions.create( |
|
|
model="gpt-4o-mini", |
|
|
messages=[ |
|
|
{"role": "system", "content": "You are a helpful assistant that summarizes concisely about how the user is feeling and what interactions are happening."}, |
|
|
{"role": "user", "content": prompt} |
|
|
], |
|
|
max_tokens=500, |
|
|
temperature=0.8 |
|
|
) |
|
|
return response.choices[0].message.content.strip() |
|
|
except Exception as e: |
|
|
logger.error(f"Error generating summary: {e}") |
|
|
raise |
|
|
|
|
|
def extract_story(messages_text): |
|
|
"""Extract a happy interaction from the chat.""" |
|
|
prompt = f"""Review the following conversation and extract **one clear, HAPPY & exciting interaction** between participants (e.g., playful plans like "can’t wait to see you" or "let’s cook together","you got this"). |
|
|
- Choose only **one uplifting moment** from the chat and summarize it in maximum 15 words about why they said it. |
|
|
- **Exclude all sexual or suggestive content.** |
|
|
Conversation: |
|
|
{messages_text}""" |
|
|
try: |
|
|
response = client.chat.completions.create( |
|
|
model="gpt-4o-mini", |
|
|
messages=[ |
|
|
{"role": "system", "content": "You are a cute friend finding light-hearted, heartwarming, and positive messages."}, |
|
|
{"role": "user", "content": prompt} |
|
|
], |
|
|
max_tokens=100, |
|
|
temperature=0.5 |
|
|
) |
|
|
return response.choices[0].message.content.strip() |
|
|
except Exception as e: |
|
|
logger.error(f"Error generating story: {e}") |
|
|
raise |
|
|
|
|
|
def generate_motivation(summary, story, name): |
|
|
"""Generate a motivational message about running.""" |
|
|
prompt = prompt = f""" |
|
|
Using this summary: '{summary}' |
|
|
And this interaction: '{story}' |
|
|
|
|
|
Craft a short, personal, upbeat motivational message for {name} about running. |
|
|
|
|
|
**Guidelines**: |
|
|
- Mention the other user by name and highlight the moments they shared together. |
|
|
- Emphasize how the other user brings energy and small transformations to daily life—and so does running! |
|
|
- Summarize the interactive story and why it was so uplifiting., include it *exactly as it appears* and tie it to the moment and to running. |
|
|
- Acknowledge the entire SUMMARY. |
|
|
|
|
|
*IMPORTANT* |
|
|
- If the summary or story includes *sadness, worry, or feeling overwhelmed*: |
|
|
- Acknowledge the feeling with compassion. |
|
|
- Show excitement that they overcame it!!! |
|
|
|
|
|
- If the memory is lighthearted or happy: |
|
|
- Use a tone that is FUNNY, EXCITING, and full of JOY 🎉 |
|
|
- Add a playful or empowering motivational quote. |
|
|
|
|
|
**Constraints**: |
|
|
- Word limit: 50 words max. |
|
|
- Must include the other user's name in the message. |
|
|
- End the message with: ({name}) |
|
|
""" |
|
|
|
|
|
try: |
|
|
response = client.chat.completions.create( |
|
|
model="gpt-4o-mini", |
|
|
messages=[ |
|
|
{"role": "system", "content": "You are a motivational coach using personal events and stories from a user's life."}, |
|
|
{"role": "user", "content": prompt} |
|
|
], |
|
|
max_tokens=100, |
|
|
temperature=0.7 |
|
|
) |
|
|
return response.choices[0].message.content.strip() |
|
|
except Exception as e: |
|
|
logger.error(f"Error generating motivation: {e}") |
|
|
raise |
|
|
|
|
|
def create_audio(motivation): |
|
|
"""Generate and save audio from the motivation text.""" |
|
|
try: |
|
|
tts = gTTS(motivation, lang="en") |
|
|
audio_file = "motivation.mp3" |
|
|
tts.save(audio_file) |
|
|
return audio_file |
|
|
except Exception as e: |
|
|
logger.error(f"Error generating audio: {e}") |
|
|
raise |
|
|
|
|
|
|
|
|
def motivate_me(chat_file, name): |
|
|
"""Process the chat and return summary, story, motivation, and audio.""" |
|
|
if not name: |
|
|
logger.warning("No name provided") |
|
|
return "Please enter your name!", "", "", None |
|
|
if not chat_file: |
|
|
logger.warning("No chat file uploaded") |
|
|
return "Please upload a WhatsApp chat file!", "", "", None |
|
|
|
|
|
try: |
|
|
lines = read_chat_file(chat_file) |
|
|
messages = sample_messages(lines) |
|
|
messages_text = "".join(messages) |
|
|
logger.info(f"Selected random 500 lines, last 5: {messages[-5:]}") |
|
|
|
|
|
if not messages: |
|
|
return "No messages found in the selected 500 lines!", "", "", None |
|
|
|
|
|
summary = summarize_chat(messages_text, name) |
|
|
story = extract_story(messages_text) |
|
|
motivation = generate_motivation(summary, story, name) |
|
|
audio_file = create_audio(motivation) |
|
|
|
|
|
return summary, story, motivation, audio_file |
|
|
except Exception as e: |
|
|
logger.error(f"Error processing chat: {e}") |
|
|
return f"Error: {str(e)}", "", "", None |
|
|
|
|
|
|
|
|
interface = gr.Interface( |
|
|
fn=motivate_me, |
|
|
inputs=[ |
|
|
gr.File(label="Upload WhatsApp Chat (_chat.txt)"), |
|
|
gr.Textbox(label="Your Name", value="", placeholder="Enter your name (e.g., Jamie)") |
|
|
], |
|
|
outputs=[ |
|
|
gr.Textbox(label="Conversation Summary"), |
|
|
gr.Textbox(label="Wholesome Interaction"), |
|
|
gr.Textbox(label="Your Motivation"), |
|
|
gr.Audio(label="Listen Up!") |
|
|
], |
|
|
title="Run Buddy: Your Personal Motivator", |
|
|
description="Upload your WhatsApp chat (_chat.txt) and enter your name to get a summary, a happy moment, and a running pep talk from 500 random messages! Try the sample below or download it [here](https://huggingface.co/spaces/justlearningin2025/RunBuddyMotivator/raw/main/sample_chat.txt).", |
|
|
examples=[["sample_chat.txt", "Jamie"]], |
|
|
theme="soft" |
|
|
) |
|
|
|
|
|
if __name__ == "__main__": |
|
|
interface.launch() |