Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
924b6a5
[HOP-14] Added message like bubbles with sender/reciever type style, …
Girik1105 Feb 13, 2026
1f58441
[HOP-14] Added nice scroll effects when llm answers, and scroll down …
Girik1105 Feb 17, 2026
83e5c5b
[HOP-14] Fixed comments, re added removed code
Girik1105 Feb 18, 2026
48b18bc
[HOP-17] Added conversation model and registered in admin
Girik1105 Feb 18, 2026
005e472
[HOP-17] Added urls, views and context processor for conversations (i…
Girik1105 Feb 19, 2026
f5a2c49
Merge branch 'develop' into story/HOP-14
Girik1105 Feb 20, 2026
2a52f7b
[HOP-17] fixed template, removed extra code
Girik1105 Feb 20, 2026
3d9ad77
[HOP17] Merged HOP-14 since its dependent
Girik1105 Feb 20, 2026
13e2a36
[HOP-17] Added redirect to conversation so refresh dosent lose curren…
Girik1105 Feb 20, 2026
23d8000
[HOP-17] Resolved Merge Conflicts
Girik1105 Feb 24, 2026
c0b3a4a
[HOP-17] Implemented sidebar for conversations
Girik1105 Feb 24, 2026
68c6649
[HOP-17] Added convo title
Girik1105 Feb 25, 2026
daaf35b
[HOP-17] Resolved merge conflicts
Girik1105 Feb 27, 2026
666f4df
[HOP-17] delete changed to conversations
Girik1105 Feb 27, 2026
43a403c
[HOP-19] Added question glossary with scroll to each question
Girik1105 Feb 27, 2026
d45887a
[HOP-17] Fixed merge conflicts, slight css adjustment
Girik1105 Feb 27, 2026
8dc4b75
[HOP-17] removed debug comments
Girik1105 Feb 27, 2026
7ad468e
[HOP-17] improved comments
Girik1105 Feb 27, 2026
61c9c12
[HOP-19] Fioxed merge conflicts with HOP-17
Girik1105 Feb 27, 2026
db6a617
[HOP-17] Removed wrong branch code from here
Girik1105 Feb 27, 2026
0d20585
Merge branch 'story/HOP-17' into story/HOP-19
Girik1105 Feb 27, 2026
6c7c3b7
[HOP-19] final fixes
Girik1105 Feb 27, 2026
a17e024
[HOP-17] fixed migrations, restore develop base add conversation as 0003
Girik1105 Mar 3, 2026
8993238
Merge branch 'story/HOP-17' into story/HOP-19
Girik1105 Mar 3, 2026
e4cf337
[HOP-17] Resolved merge conflicts
Girik1105 Mar 4, 2026
70d5a76
[HOP-17] Resolved merge conflicts and made path as re_path
Girik1105 Mar 4, 2026
35b9aba
[HOP-17] makemigrations --merge and migrate
Girik1105 Mar 4, 2026
3306793
[HOP-17] Fixed conversation button title
Girik1105 Mar 4, 2026
c6a17b6
Merge branch 'story/HOP-17' into story/HOP-19
Girik1105 Mar 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 19 additions & 4 deletions hospexplorer/ask/admin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
from django.contrib import admin
from ask.models import TermsAcceptance, QARecord
from ask.models import Conversation, TermsAcceptance, QARecord


class QARecordInline(admin.TabularInline):
model = QARecord
extra = 0
readonly_fields = ("question_text", "question_timestamp", "answer_text", "answer_timestamp", "is_error")
fields = ("question_text", "question_timestamp", "answer_text", "answer_timestamp", "is_error")


@admin.register(Conversation)
class ConversationAdmin(admin.ModelAdmin):
list_display = ("id", "title", "user", "created_at", "updated_at")
list_filter = ("user",)
search_fields = ("title", "user__username")
inlines = [QARecordInline]


@admin.register(TermsAcceptance)
Expand All @@ -22,11 +37,11 @@ def has_delete_permission(self, request, obj=None):

@admin.register(QARecord)
class QARecordAdmin(admin.ModelAdmin):
list_display = ["id", "user", "truncated_question", "question_timestamp", "answer_timestamp"]
list_filter = ["question_timestamp", "user"]
list_display = ["id", "user", "conversation", "truncated_question", "question_timestamp", "answer_timestamp", "is_error"]
list_filter = ["question_timestamp", "user", "is_error"]
search_fields = ["question_text", "answer_text", "user__username"]
readonly_fields = ["question_timestamp", "answer_timestamp", "answer_raw_response"]
raw_id_fields = ["user"]
raw_id_fields = ["user", "conversation"]
date_hierarchy = "question_timestamp"

def truncated_question(self, obj):
Expand Down
25 changes: 25 additions & 0 deletions hospexplorer/ask/context_processors.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,29 @@
from django.conf import settings
from django.urls import reverse
from ask.models import Conversation


def sidebar_conversations(request):
if request.user.is_authenticated:
limit = getattr(settings, "SIDEBAR_CONVERSATIONS_LIMIT", 10)
conversations = Conversation.objects.filter(
user=request.user
)[:limit]

sidebar_items = []
for conv in conversations:
label = conv.title if conv.title else conv.created_at.strftime("%b %d, %Y %I:%M %p")
sidebar_items.append({
"id": conv.id,
"label": label,
"url": reverse("ask:conversation", kwargs={"conversation_id": conv.id}),
"updated_at": conv.updated_at.isoformat(),
})
return {
"sidebar_conversations": sidebar_items,
"sidebar_conversations_limit": limit,
}
return {"sidebar_conversations": [], "sidebar_conversations_limit": 0}


# Django context processor registered in settings TEMPLATES
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Generated by Django 6.0.1 on 2026-03-03 18:19

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('ask', '0002_qarecord_is_error'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name='Conversation',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(blank=True, default='', max_length=200)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='conversations', to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['-updated_at'],
},
),
migrations.AddField(
model_name='qarecord',
name='conversation',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='qa_records', to='ask.conversation'),
preserve_default=False,
),
]
14 changes: 14 additions & 0 deletions hospexplorer/ask/migrations/0005_merge_20260304_2256.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Generated by Django 6.0.2 on 2026-03-04 22:56

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('ask', '0003_conversation_qarecord_conversation'),
('ask', '0004_merge_0003_querytask_0003_termsacceptance'),
]

operations = [
]
33 changes: 32 additions & 1 deletion hospexplorer/ask/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,27 @@ class Status(models.TextChoices):
updated_at = models.DateTimeField(auto_now=True)


class Conversation(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="conversations",
)
title = models.CharField(max_length=200, blank=True, default="")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

class Meta:
ordering = ["-updated_at"]

def __str__(self):
if self.title:
truncated = self.title[:50]
suffix = "..." if len(self.title) > 50 else ""
return f"Conversation {self.id}: {truncated}{suffix}"
return f"Conversation {self.id} ({self.user.username})"


class TermsAcceptance(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
Expand All @@ -53,6 +74,12 @@ class QARecord(models.Model):
"""
Stores a question-answer pair from user interactions with the LLM.
"""
conversation = models.ForeignKey(
Conversation,
on_delete=models.CASCADE,
related_name="qa_records",
)

# Question fields
question_text = models.TextField()
question_timestamp = models.DateTimeField(auto_now_add=True)
Expand All @@ -63,7 +90,11 @@ class QARecord(models.Model):
answer_timestamp = models.DateTimeField(null=True, blank=True)
is_error = models.BooleanField(default=False)

user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="qa_records")
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="qa_records",
)

class Meta:
ordering = ["-question_timestamp"]
Expand Down
126 changes: 126 additions & 0 deletions hospexplorer/ask/static/css/ask.css
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,128 @@
transform: translateX(-50%) scale(0.95);
}

/* Question Glossary Sidebar */

.glossary-sidebar {
position: absolute;
top: 0;
right: 0;
width: 280px;
height: 100%;
background: #ffffff;
border-left: 1px solid #e9ecef;
z-index: 20;
display: flex;
flex-direction: column;
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.06);
}

.glossary-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 1.25rem 1.25rem 1rem;
border-bottom: 1px solid #e9ecef;
flex-shrink: 0;
}

.glossary-title {
display: flex;
align-items: center;
gap: 0.5rem;
}

.glossary-title-icon {
color: #8c1d40;
flex-shrink: 0;
}

.glossary-header h6 {
font-weight: 700;
color: #212529;
}

.glossary-subtitle {
font-size: 0.7rem;
color: #6c757d;
}

.glossary-close-btn {
width: 28px;
height: 28px;
border-radius: 50%;
border: none;
background: transparent;
color: #6c757d;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: background-color 0.15s;
}

.glossary-close-btn:hover {
background: #f0f0f0;
color: #212529;
}

.glossary-list {
flex: 1;
overflow-y: auto;
padding: 0.5rem 0;
}

.glossary-item {
display: block;
width: 100%;
padding: 0.625rem 1rem;
border: none;
background: transparent;
text-align: left;
font-size: 0.85rem;
color: #8c1d40;
cursor: pointer;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
transition: background-color 0.15s;
}

.glossary-item:hover {
background: #fdf2f5;
}

.glossary-toggle-btn {
width: 42px;
height: 42px;
border-radius: 50%;
border: 1px solid #dee2e6;
background: #ffffff;
color: #495057;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: background-color 0.15s, border-color 0.15s, color 0.15s;
flex-shrink: 0;
}

.glossary-toggle-btn:hover {
background: #f8f9fa;
border-color: #8c1d40;
color: #8c1d40;
}

/* Highlight animation for scrolled-to messages */
.msg-highlight {
animation: msgHighlight 1.5s ease-out;
}

@keyframes msgHighlight {
0% { background-color: rgba(140, 29, 64, 0.15); border-radius: 0.75rem; }
100% { background-color: transparent; }
}

/* Responsive Adjustments */

@media (max-width: 768px) {
Expand All @@ -358,4 +480,8 @@
.chat-input-bar {
padding: 0.5rem 1rem;
}

.glossary-sidebar {
width: 100%;
}
}
11 changes: 10 additions & 1 deletion hospexplorer/ask/static/css/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -10894,10 +10894,19 @@ body.sb-sidenav-toggled #wrapper #sidebar-wrapper {
}

#sidebar-wrapper .question-item:hover {
border-left-color: #0d6efd;
border-left-color: #8c1d40;
background-color: #f8f9fa;
}

#sidebar-wrapper .question-item.active {
border-left-color: #8c1d40;
background-color: rgba(140, 29, 64, 0.1);
color: #8c1d40;
font-weight: 600;
border-color: transparent;
border-left: 3px solid #8c1d40;
}

#sidebar-wrapper .sidebar-section-heading {
font-weight: 600;
text-transform: uppercase;
Expand Down
Loading