From f4f834ab6e4bd40b5aef0d78f6092a4e0d541265 Mon Sep 17 00:00:00 2001 From: Aidan Cornelius-Bell Date: Sun, 8 Dec 2024 17:13:21 +1030 Subject: [PATCH] Added the ability to send posts to summariser (not currently av. outside the admin view); bundle update --- app/assets/stylesheets/application.css | 4 ++ app/controllers/posts_controller.rb | 47 +++++++++++++++++++ app/services/kagi_summarizer_service.rb | 47 +++++++++++++++++++ app/views/posts/_post.html.erb | 7 ++- app/views/posts/index.html.erb | 13 ++--- app/views/posts/show.html.erb | 6 +-- config/credentials.yml.enc | 2 +- config/routes.rb | 14 ++++-- .../20241208061729_add_summary_to_posts.rb | 5 ++ db/schema.rb | 3 +- 10 files changed, 132 insertions(+), 16 deletions(-) create mode 100644 app/services/kagi_summarizer_service.rb create mode 100644 db/migrate/20241208061729_add_summary_to_posts.rb diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 0332ca8..4f0692b 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -535,6 +535,10 @@ input[type="submit"], font-size: 0.875rem; } +.button.summary { + margin-top: 5px; +} + .button.danger { background-color: #dc3545; color: var(--body-text); diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 1c6685c..ef1d82b 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -120,6 +120,53 @@ class PostsController < ApplicationController redirect_to posts_path end + def summarize + @post = Post.find(params[:id]) + Rails.logger.debug "Attempting to summarize post #{@post.id} (#{@post.post_type})" + + summarizer = KagiSummarizerService.new + + # Determine what content to summarize based on post type + content_to_summarize = if @post.bookmark? && @post.url.present? + Rails.logger.debug "Using URL for summarization: #{@post.url}" + @post.url + elsif @post.content.present? + Rails.logger.debug "Using content for summarization (first 100 chars): #{@post.content.truncate(100)}" + @post.content + else + Rails.logger.warn "No content available for summarization" + nil + end + + if content_to_summarize.nil? + redirect_to @post, alert: 'No content or URL available to summarize.' + return + end + + type = @post.bookmark? && @post.url.present? ? :url : :text + result = summarizer.summarize(content_to_summarize, type) + + Rails.logger.debug "Summarization result: #{result.inspect}" + + if result && result['output'].present? + success = @post.update(summary: result['output']) + Rails.logger.debug "Update post with summary: #{success ? 'successful' : 'failed'}" + if success + redirect_to @post, notice: 'Summary generated successfully.' + else + Rails.logger.error "Failed to save summary: #{@post.errors.full_messages}" + redirect_to @post, alert: "Failed to save summary: #{@post.errors.full_messages.join(', ')}" + end + else + error_message = if result + "API returned success but no summary output was present" + else + "Failed to generate summary from API" + end + Rails.logger.error error_message + redirect_to @post, alert: error_message + end + end private # Use callbacks to share common setup or constraints between actions. diff --git a/app/services/kagi_summarizer_service.rb b/app/services/kagi_summarizer_service.rb new file mode 100644 index 0000000..318dd8c --- /dev/null +++ b/app/services/kagi_summarizer_service.rb @@ -0,0 +1,47 @@ +class KagiSummarizerService + include HTTParty + base_uri 'https://kagi.com/api/v0' + + def initialize + @options = { + headers: { + 'Authorization': "Bot #{Rails.application.credentials.kagi[:api_key]}", + 'Content-Type': 'application/json' + } + } + Rails.logger.debug "KagiSummarizerService initialized with options: #{@options.inspect}" + end + + def summarize(content, type = :text) + Rails.logger.debug "Summarizing #{type} content: #{content.truncate(100)}" + + body = if type == :url + { + url: content, + engine: 'agnes', + summary_type: 'summary' + } + else + { + text: content, + engine: 'agnes', + summary_type: 'summary' + } + end + + Rails.logger.debug "Sending request to Kagi API with body: #{body.inspect}" + + response = self.class.post('/summarize', @options.merge(body: body.to_json)) + Rails.logger.debug "Received response from Kagi API: Status #{response.code}, Body: #{response.body}" + + if response.success? + parsed_response = JSON.parse(response.body) + Rails.logger.debug "Parsed response: #{parsed_response.inspect}" + parsed_response + else + Rails.logger.error "Kagi API error: #{response.code} - #{response.body}" + Rails.logger.error "Full response object: #{response.inspect}" + nil + end + end +end diff --git a/app/views/posts/_post.html.erb b/app/views/posts/_post.html.erb index c9a9407..fff5bb9 100644 --- a/app/views/posts/_post.html.erb +++ b/app/views/posts/_post.html.erb @@ -29,9 +29,14 @@ <%= post.tags %>

+

+ Summary: + <%= post.summary %> +

+

Content: - <%= post.content %> + <%= if post&.content? then post.rendered_content.html_safe else "No content." end %>

diff --git a/app/views/posts/index.html.erb b/app/views/posts/index.html.erb index 70da4e4..9a58f61 100644 --- a/app/views/posts/index.html.erb +++ b/app/views/posts/index.html.erb @@ -11,11 +11,11 @@ - - - - - + + + + + @@ -29,6 +29,7 @@ <%= link_to "View", post, class: "button small" %> <%= link_to "Edit", edit_post_path(post), class: "button small" %> <%= link_to "Delete", post, method: :delete, data: { confirm: "Are you sure you want to delete this post?" }, class: "button small danger" %> + <%= button_to "Generate Summary", summarize_post_path(post), class: "button small summary", data: { confirm: 'This will call the Kagi API. Continue?' } %> <% end %> @@ -41,4 +42,4 @@
<%= paginate @posts %>
-<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/posts/show.html.erb b/app/views/posts/show.html.erb index 739d9cf..2f00e08 100644 --- a/app/views/posts/show.html.erb +++ b/app/views/posts/show.html.erb @@ -3,12 +3,12 @@ <%= link_to "Back to posts", posts_path, class: "button" %>
-
+
<%= render @post %> - +
<%= link_to "Edit this post", edit_post_path(@post), class: "button" %> - + <%= button_to "Summarise this post", summarize_post_path(@post), class: "button" %> <%= button_to "Destroy this post", @post, method: :delete %>
diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc index 19f60ef..f16cdbe 100644 --- a/config/credentials.yml.enc +++ b/config/credentials.yml.enc @@ -1 +1 @@ -R6pLqAgOKbr+y07Is0RC9w3wQKbkr2h2KZO4RNpGCPAaE+X9ZK6i3AdB0XYfDiBRfvtj05EhYDJ+Yr72985yeeRhnppVqkwNK1mWp+SGfY+KVvaKI7HFYG8igI0LthDAdsyeoA2+ElpZgjHCCLqz36gRKSY/KEbT/y0NukHdQRzsWFHwqgY85vQK9gRfDBpM72h4iPwb9TOPvMtJuVwfaIAdcDY0OqaQpTlFIGjh/bT9njHuO2h4mJ6dCBJYoFR0+8oCpd8hHWHtxeB4bsqKspfxrNvFTYEDQUnNwJEbQGNl14577rhEshQ2WfgUVFGzTzfEpzQmFZZJtnWhJuJbgVaxUwH5STUKWEWNY5/gD2vgp1oj0aUO6eiyOjz5YCkUieR2RV3hVF+yvOMb9NTt2EBYjJGeoqngzKi/Hq0xnLHIRmkoFHPvuC1RHn0Ucg1Nez4cmWppoOK3xm/b0H2lKsWi97vkkii38lqtfmmRFtsdXf4AvFOQ2NWpFlLKLwHT87/bU32XIzPObwErw/wv9irxrBMAlDDqOTqtqd6k3liddoNGCqUqHLxSC0IoH/G2tdg1PzoKBvtIVyjtctYtUnta1vgjpz727WCSSYO6gDTOxTkRmwc++DcBAzOJFkYSz8gFm02TjHaBhzXQeqw=--fmjiwM3a6xuvqqTn--wwZXJd1Zcs5AJV/lQbpCtw== \ No newline at end of file +v2C864ebli2Zlrpg1eDeEn17NBNNghNeT86hcfSfebENXaStabVwZbEfgHTryFxZcISmAZE4rjjdcJcFSqTNQwvUvLGWaT3efR8WyZ2QQP14OSwL8+hnHDpDXLJrQIDUOHFF+aLaN0/uh3UPbFkBIf6eYyDVO+PP3jxb5bXsNC5wkqiCA/gBDuZoCLGrX9Pnw2nPWcXptVV2H2PVcQOaJDUcJl4yFJBSU3/cV/f9yFPV70cfrqUxU5hSHxHqfSZUF9bh/A6AAkvVWBOgJIETA3DiIS0fvoMSRK5uQuDWsaY7fdc947QXw4VrdvFSQqAegzzDjNYgLtZIqQ2GHDhaRWnmsVGf7IqA/6tKb6jGIc0G/Y7Mtdoa4s177dAdrMaIr+PM4ZMMbACYq1WbQWZ1IfMttyId0tAlRRlVbAFPOhFxElCHEWWlq1t3xGwgFDQOyfzX3P2Cr1FCeVXJb8VwGz32CceOna6BnhzRns6mQKt6VI+uAh6T2Uoe+krtM1jb6XT5+u0qZ8jo9P/iibCeeBZr9JBQ4rE+8AIvHOIZNuq7nZQDAHL+s9WtVrkvVjpRQ28dpccbjyQFvXhjqFUFIVGDTITi31FaHcjNBMhZyMKLtv/c9ASojRFrkBoDTgulGq8v+uEnW/3HPNkW+X3fqRXtjt1URKS+Qz57J7JOWt/EvX/f7PCG--pBijWvzkta+/36PZ--LnhGLSczKJbXJk9B8MyGRQ== \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 9df6e47..f4dcd09 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -9,7 +9,7 @@ Rails.application.routes.draw do resources :pages, only: [:index, :show] end end - + resources :mailing_lists, only: [:index] do collection do post 'subscribe' @@ -29,14 +29,20 @@ Rails.application.routes.draw do get 'export', to: 'posts#export' post 'import', to: 'posts#import' resources :api_keys - devise_for :users, controllers: { - registrations: 'users/registrations', + devise_for :users, controllers: { + registrations: 'users/registrations', confirmations: 'users/confirmations', sessions: 'users/sessions' } get 'users/two_factor_authentication', to: 'users/two_factor_authentication#show' post 'users/two_factor_authentication', to: 'users/two_factor_authentication#create' - resources :posts + + resources :posts do + member do + post :summarize + end + end + get '/feed', to: 'pubview#rss', as: 'rss', defaults: { format: 'rss' } get '/feed/dispatches', to: 'pubview#dispatches_rss', as: 'dispatches_rss', defaults: { format: 'rss' } get '/join', to: "pubview#join" diff --git a/db/migrate/20241208061729_add_summary_to_posts.rb b/db/migrate/20241208061729_add_summary_to_posts.rb new file mode 100644 index 0000000..6efb25e --- /dev/null +++ b/db/migrate/20241208061729_add_summary_to_posts.rb @@ -0,0 +1,5 @@ +class AddSummaryToPosts < ActiveRecord::Migration[7.2] + def change + add_column :posts, :summary, :text + end +end diff --git a/db/schema.rb b/db/schema.rb index ddc1cd4..ffb94b5 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.2].define(version: 2024_10_09_212849) do +ActiveRecord::Schema[7.2].define(version: 2024_12_08_061729) do create_table "api_keys", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.string "key" t.datetime "created_at", null: false @@ -38,6 +38,7 @@ ActiveRecord::Schema[7.2].define(version: 2024_10_09_212849) do t.string "url" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.text "summary" t.index ["post_type"], name: "index_posts_on_post_type" t.index ["published_at"], name: "index_posts_on_published_at" t.index ["slug"], name: "index_posts_on_slug", unique: true -- 2.39.5
TitleTypeCreatedTagsActionsTitleTypeCreatedTagsActions