mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-08-07 22:45:20 +02:00
AI chat layout skeleton
This commit is contained in:
parent
dd75cadebc
commit
d1b83541c1
23 changed files with 231 additions and 1 deletions
17
app/controllers/chats_controller.rb
Normal file
17
app/controllers/chats_controller.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
class ChatsController < ApplicationController
|
||||
def index
|
||||
Current.user.update!(current_chat: nil)
|
||||
@chats = Current.user.chats.ordered
|
||||
end
|
||||
|
||||
def create
|
||||
@chat = Current.user.chats.create_with_defaults!
|
||||
|
||||
redirect_to chat_path(@chat)
|
||||
end
|
||||
|
||||
def show
|
||||
@chat = Current.user.chats.find(params[:id])
|
||||
Current.user.update!(current_chat: @chat)
|
||||
end
|
||||
end
|
18
app/controllers/messages_controller.rb
Normal file
18
app/controllers/messages_controller.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
class MessagesController < ApplicationController
|
||||
before_action :set_chat
|
||||
|
||||
def create
|
||||
@message = @chat.messages.create!(message_params.merge(role: "user"))
|
||||
|
||||
redirect_to chat_path(@chat)
|
||||
end
|
||||
|
||||
private
|
||||
def set_chat
|
||||
@chat = Current.user.chats.find(params[:chat_id])
|
||||
end
|
||||
|
||||
def message_params
|
||||
params.require(:message).permit(:content)
|
||||
end
|
||||
end
|
23
app/models/chat.rb
Normal file
23
app/models/chat.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
class Chat < ApplicationRecord
|
||||
belongs_to :user
|
||||
has_many :messages, dependent: :destroy
|
||||
has_one :user_current_chat, class_name: "User", foreign_key: :current_chat_id, dependent: :nullify
|
||||
|
||||
validates :title, presence: true
|
||||
|
||||
scope :ordered, -> { order(created_at: :desc) }
|
||||
|
||||
class << self
|
||||
def create_with_defaults!
|
||||
create!(
|
||||
title: "New chat #{Time.current.strftime("%Y-%m-%d %H:%M:%S")}",
|
||||
messages: [
|
||||
Message.new(
|
||||
role: "system",
|
||||
content: "You are a helpful personal finance assistant.",
|
||||
)
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
10
app/models/message.rb
Normal file
10
app/models/message.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
class Message < ApplicationRecord
|
||||
belongs_to :chat
|
||||
|
||||
enum :role, { user: "user", assistant: "assistant", system: "system" }
|
||||
|
||||
validates :content, presence: true
|
||||
validates :role, presence: true
|
||||
|
||||
scope :conversation, -> { where(debug_mode: false, role: [ :user, :assistant ]) }
|
||||
end
|
|
@ -1,10 +1,12 @@
|
|||
class User < ApplicationRecord
|
||||
has_secure_password
|
||||
|
||||
belongs_to :current_chat, class_name: "Chat", optional: true
|
||||
belongs_to :family
|
||||
has_many :sessions, dependent: :destroy
|
||||
has_many :impersonator_support_sessions, class_name: "ImpersonationSession", foreign_key: :impersonator_id, dependent: :destroy
|
||||
has_many :impersonated_support_sessions, class_name: "ImpersonationSession", foreign_key: :impersonated_id, dependent: :destroy
|
||||
has_many :chats, dependent: :destroy
|
||||
accepts_nested_attributes_for :family, update_only: true
|
||||
|
||||
validates :email, presence: true, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP }
|
||||
|
|
3
app/views/chats/_chat.html.erb
Normal file
3
app/views/chats/_chat.html.erb
Normal file
|
@ -0,0 +1,3 @@
|
|||
<%= link_to chat_path(chat) do %>
|
||||
<%= chat.title %>
|
||||
<% end %>
|
6
app/views/chats/_chat_nav.html.erb
Normal file
6
app/views/chats/_chat_nav.html.erb
Normal file
|
@ -0,0 +1,6 @@
|
|||
<div>
|
||||
<p>Chat nav</p>
|
||||
|
||||
<%= button_to "New chat", chats_path, method: :post, class: "btn btn-primary", data: { turbo_frame: "chat_content" } %>
|
||||
<%= link_to "All chats", chats_path, data: { turbo_frame: "chat_content" } %>
|
||||
</div>
|
9
app/views/chats/index.html.erb
Normal file
9
app/views/chats/index.html.erb
Normal file
|
@ -0,0 +1,9 @@
|
|||
<%= turbo_frame_tag "chat_content" do %>
|
||||
<% if @chats.empty? %>
|
||||
<p>No chats</p>
|
||||
<% else %>
|
||||
<div class="flex flex-col gap-2">
|
||||
<%= render @chats %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% end %>
|
13
app/views/chats/show.html.erb
Normal file
13
app/views/chats/show.html.erb
Normal file
|
@ -0,0 +1,13 @@
|
|||
<%= turbo_frame_tag "chat_content" do %>
|
||||
<div class="flex flex-col gap-4 justify-between h-full">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold mb-6"><%= @chat.title %></h2>
|
||||
|
||||
<div class="space-y-6">
|
||||
<%= render @chat.messages.conversation %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%= render "messages/form", chat: @chat %>
|
||||
</div>
|
||||
<% end %>
|
|
@ -57,5 +57,23 @@
|
|||
<%= yield %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<%= tag.div class: class_names("py-4 shrink-0 flex flex-col justify-between gap-6 h-full overflow-y-auto transition-all duration-300 w-[375px]") do %>
|
||||
<div class="bg-white p-4">
|
||||
<%= render "chats/chat_nav" %>
|
||||
</div>
|
||||
|
||||
<div id="chat-content" class="grow p-4 bg-white" data-turbo-permanent>
|
||||
<% if Current.user.current_chat.present? %>
|
||||
<%= turbo_frame_tag "chat_content", src: chat_path(Current.user.current_chat), loading: "lazy" do %>
|
||||
<p>Loading chat...</p>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<%= turbo_frame_tag "chat_content", src: chats_path, loading: "lazy" do %>
|
||||
<p>Loading chats...</p>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
|
6
app/views/messages/_form.html.erb
Normal file
6
app/views/messages/_form.html.erb
Normal file
|
@ -0,0 +1,6 @@
|
|||
<%# locals: (chat:) %>
|
||||
|
||||
<%= styled_form_with model: chat.messages.build, url: chat_messages_path(chat), method: :post, class: "space-y-4" do |f| %>
|
||||
<%= f.text_area :content, size: "50x5" %>
|
||||
<%= f.submit "Send message" %>
|
||||
<% end %>
|
8
app/views/messages/_message.html.erb
Normal file
8
app/views/messages/_message.html.erb
Normal file
|
@ -0,0 +1,8 @@
|
|||
<div>
|
||||
<p class="text-sm text-gray-500">
|
||||
role: <%= message.role %>
|
||||
</p>
|
||||
<p class="text-gray-900">
|
||||
<%= message.content %>
|
||||
</p>
|
||||
</div>
|
Loading…
Add table
Add a link
Reference in a new issue