init
						commit
						f52cfe1117
					
				| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
 | 
			
		||||
DB_USER=
 | 
			
		||||
DB_PASSWORD=
 | 
			
		||||
DB_HOST=
 | 
			
		||||
DB_PORT=
 | 
			
		||||
DB_NAME=
 | 
			
		||||
 | 
			
		||||
SMTP_SERVER=
 | 
			
		||||
SMTP_PORT=
 | 
			
		||||
SMTP_USERNAME=
 | 
			
		||||
SMTP_PASSWORD=
 | 
			
		||||
 | 
			
		||||
HUGGINGFACE_API_TOKEN=
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
.env
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
source 'https://rubygems.org'
 | 
			
		||||
 | 
			
		||||
gem 'pg'
 | 
			
		||||
gem 'net-smtp'
 | 
			
		||||
gem 'httparty'
 | 
			
		||||
gem 'dotenv'
 | 
			
		||||
gem 'erb'
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,36 @@
 | 
			
		|||
GEM
 | 
			
		||||
  remote: https://rubygems.org/
 | 
			
		||||
  specs:
 | 
			
		||||
    bigdecimal (3.1.9)
 | 
			
		||||
    cgi (0.4.2)
 | 
			
		||||
    csv (3.3.2)
 | 
			
		||||
    dotenv (3.1.7)
 | 
			
		||||
    erb (4.0.4)
 | 
			
		||||
      cgi (>= 0.3.3)
 | 
			
		||||
    httparty (0.22.0)
 | 
			
		||||
      csv
 | 
			
		||||
      mini_mime (>= 1.0.0)
 | 
			
		||||
      multi_xml (>= 0.5.2)
 | 
			
		||||
    mini_mime (1.1.5)
 | 
			
		||||
    multi_xml (0.7.1)
 | 
			
		||||
      bigdecimal (~> 3.1)
 | 
			
		||||
    net-protocol (0.2.2)
 | 
			
		||||
      timeout
 | 
			
		||||
    net-smtp (0.5.1)
 | 
			
		||||
      net-protocol
 | 
			
		||||
    pg (1.5.9)
 | 
			
		||||
    timeout (0.4.3)
 | 
			
		||||
 | 
			
		||||
PLATFORMS
 | 
			
		||||
  arm64-darwin-24
 | 
			
		||||
  ruby
 | 
			
		||||
 | 
			
		||||
DEPENDENCIES
 | 
			
		||||
  dotenv
 | 
			
		||||
  erb
 | 
			
		||||
  httparty
 | 
			
		||||
  net-smtp
 | 
			
		||||
  pg
 | 
			
		||||
 | 
			
		||||
BUNDLED WITH
 | 
			
		||||
   2.6.2
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,114 @@
 | 
			
		|||
require 'bundler'
 | 
			
		||||
Bundler.require(:default)
 | 
			
		||||
 | 
			
		||||
require 'pg'
 | 
			
		||||
require 'net/smtp'
 | 
			
		||||
require 'httparty'
 | 
			
		||||
require 'json'
 | 
			
		||||
require 'dotenv'
 | 
			
		||||
require 'erb'
 | 
			
		||||
require 'date'
 | 
			
		||||
require 'tempfile'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Load environment variables from.env file
 | 
			
		||||
Dotenv.load
 | 
			
		||||
 | 
			
		||||
DB_USER = ENV.fetch('DB_USER')
 | 
			
		||||
DB_PASSWORD = ENV.fetch('DB_PASSWORD')
 | 
			
		||||
DB_HOST = ENV.fetch('DB_HOST')
 | 
			
		||||
DB_PORT = ENV.fetch('DB_PORT')
 | 
			
		||||
DB_NAME = ENV.fetch('DB_NAME')
 | 
			
		||||
 | 
			
		||||
SMTP_SERVER = ENV.fetch('SMTP_SERVER')
 | 
			
		||||
SMTP_PORT = ENV.fetch('SMTP_PORT').to_i
 | 
			
		||||
SMTP_USERNAME = ENV.fetch('SMTP_USERNAME')
 | 
			
		||||
SMTP_PASSWORD = ENV.fetch('SMTP_PASSWORD')
 | 
			
		||||
 | 
			
		||||
HUGGINGFACE_API_URL = 'https://router.huggingface.co/hf-inference/models/mistralai/Mixtral-8x7B-Instruct-v0.1/v1/chat/completions'
 | 
			
		||||
HUGGINGFACE_API_TOKEN = ENV.fetch('HUGGINGFACE_API_TOKEN')
 | 
			
		||||
 | 
			
		||||
MAIL_BODY_PROMPT = <<-END
 | 
			
		||||
Analyze my recent weeks listening history and suggest a movie/comic character or celebrity that embodies the mood and spirit of my diverse music choices. Please keep the response concise and engaging, suitable for a marketing email.
 | 
			
		||||
Here are the titles that were listened to this week
 | 
			
		||||
 | 
			
		||||
END
 | 
			
		||||
 | 
			
		||||
def fetch_titles_from_db()
 | 
			
		||||
  one_week_ago = Date.today - 7
 | 
			
		||||
  connection = PG.connect(:dbname => DB_NAME, :host => DB_HOST, :user => DB_USER, :password => DB_PASSWORD)
 | 
			
		||||
 | 
			
		||||
  result = connection.exec_params("SELECT item_title FROM activities WHERE created_at >= $1 ORDER BY created_at DESC", [one_week_ago])
 | 
			
		||||
  connection.close
 | 
			
		||||
  results = []
 | 
			
		||||
  results = result.map { |row| row['item_title']} if result.any?
 | 
			
		||||
  return results
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
def generate_email_body(titles)
 | 
			
		||||
  return "You didnt listen to any music this week :`(" unless titles
 | 
			
		||||
 | 
			
		||||
  puts "Calling HF"
 | 
			
		||||
  body = mistral_request_body(titles)
 | 
			
		||||
  response = HTTParty.post(HUGGINGFACE_API_URL, headers: { 'Content-Type':'application/json','Authorization' => "Bearer #{HUGGINGFACE_API_TOKEN}" }, body: body)
 | 
			
		||||
  JSON.parse(response.body)['choices'][0]['message']['content']
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
def mistral_request_body(titles)
 | 
			
		||||
  formated_titles = titles.join(", ")
 | 
			
		||||
  {
 | 
			
		||||
    model: "mistralai/Mixtral-8x7B-Instruct-v0.1",
 | 
			
		||||
    messages: [
 | 
			
		||||
      {
 | 
			
		||||
        role: "user",
 | 
			
		||||
        content: "#{MAIL_BODY_PROMPT} #{formated_titles}"
 | 
			
		||||
      }
 | 
			
		||||
    ],
 | 
			
		||||
    max_tokens: 1000,
 | 
			
		||||
    stream: false
 | 
			
		||||
  }.to_json
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
def send_email(to, subject, body)
 | 
			
		||||
  current_time = Time.now.utc
 | 
			
		||||
  formatted_time = current_time.strftime("%a, %-d %b %Y %H:%M:%S %z")
 | 
			
		||||
 | 
			
		||||
  msg = <<-END
 | 
			
		||||
Subject: #{subject}
 | 
			
		||||
From: Weekly 1activity <#{SMTP_USERNAME}>
 | 
			
		||||
To: #{to}
 | 
			
		||||
Date: #{formatted_time}
 | 
			
		||||
MIME-Version: 1.0
 | 
			
		||||
Content-Type: text/html; charset=utf-8
 | 
			
		||||
 | 
			
		||||
#{body}
 | 
			
		||||
END
 | 
			
		||||
 | 
			
		||||
  smtp = Net::SMTP.new(SMTP_SERVER, SMTP_PORT)
 | 
			
		||||
  smtp.enable_starttls_auto
 | 
			
		||||
  smtp.start do |server|
 | 
			
		||||
    a = server.authenticate(SMTP_USERNAME, SMTP_PASSWORD)
 | 
			
		||||
    puts a.string
 | 
			
		||||
    begin
 | 
			
		||||
    a= server.send_message(msg, SMTP_USERNAME, to)
 | 
			
		||||
    puts a.string
 | 
			
		||||
    rescue Net::SMTPFatalError => e
 | 
			
		||||
      puts e.message
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
def main
 | 
			
		||||
  titles = fetch_titles_from_db
 | 
			
		||||
  total_plays = titles.length
 | 
			
		||||
  body = generate_email_body(titles)
 | 
			
		||||
  puts "HF done"
 | 
			
		||||
  template = ERB.new File.read('./template/mail.html.erb')
 | 
			
		||||
  html_body = template.result_with_hash({body: body, total_plays: total_plays})
 | 
			
		||||
  title = "Weekly listening report #{Date.today}"
 | 
			
		||||
  send_email("listening@sgui.de", title, html_body)
 | 
			
		||||
  puts "Email sent with subject: #{title}"
 | 
			
		||||
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
main
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,38 @@
 | 
			
		|||
<!DOCTYPE html>
 | 
			
		||||
<html lang/en>
 | 
			
		||||
<head>
 | 
			
		||||
  <meta charset="UTF-8">
 | 
			
		||||
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
			
		||||
  <title>Weekly listening report <%= Date.today.to_s %></title>
 | 
			
		||||
  <style>
 | 
			
		||||
    body { font-family: Arial, sans-serif; line-height: 1.5; margin: 0; padding: 0; }
 | 
			
		||||
   .container { max-width: 600px; margin: auto; }
 | 
			
		||||
   .header { background-color: #1DB954; color: #fff; padding: 20px; text-align: center; font-size: 24px; }
 | 
			
		||||
   .content { padding: 20px; }
 | 
			
		||||
    h1 { font-size: 32px; margin-top: 0; }
 | 
			
		||||
    p { margin-bottom: 15px; }
 | 
			
		||||
   .cta { background-color: #1DB954; border: none; border-radius: 5px; color: #fff; cursor: pointer; display: inline-block; font-size: 16px; padding: 10px 20px; text-decoration: none; }
 | 
			
		||||
   .cta:hover { background-color: #1ED760; }
 | 
			
		||||
   .footer { background-color: #f5f5f5; padding: 20px; text-align: center; font-size: 12px; color: #777; }
 | 
			
		||||
   .footer a { color: #1DB954; text-decoration: none; }
 | 
			
		||||
   .footer a:hover { text-decoration: underline; }
 | 
			
		||||
    @media only screen and (max-width: 600px) {
 | 
			
		||||
     .container { width: 100%; }
 | 
			
		||||
     .header,.footer { text-align: left; }
 | 
			
		||||
      h1 { font-size: 28px; }
 | 
			
		||||
    }
 | 
			
		||||
  </style>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
  <div class="container">
 | 
			
		||||
    <div class="header">Your listening report for <%= Date.today.to_s %></div>
 | 
			
		||||
    <div class="content">
 | 
			
		||||
      <h1>Heyo!</h1>
 | 
			
		||||
      <p>Total plays <%= total_plays %></p>
 | 
			
		||||
      <p><%= body %></p>
 | 
			
		||||
      <a href="#" class="cta">Listen Now</a>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="footer"><a href="#">Unsubscribe</a> | <a href="#">Privacy Policy</a></div>
 | 
			
		||||
  </div>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
		Loading…
	
		Reference in New Issue