1 /*
2 * Copyright 2012-2025 CodeLibs Project and the Others.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13 * either express or implied. See the License for the specific language
14 * governing permissions and limitations under the License.
15 */
16 package org.codelibs.fess.entity;
17
18 import java.io.Serializable;
19 import java.time.LocalDateTime;
20 import java.util.ArrayList;
21 import java.util.List;
22 import java.util.Map;
23
24 /**
25 * Represents a message in a chat conversation.
26 *
27 * @author FessProject
28 */
29 public class ChatMessage implements Serializable {
30
31 private static final long serialVersionUID = 1L;
32
33 /** The role identifier for user messages. */
34 public static final String ROLE_USER = "user";
35
36 /** The role identifier for assistant messages. */
37 public static final String ROLE_ASSISTANT = "assistant";
38
39 /** The unique identifier for this message. */
40 private String id;
41
42 /** The role of the message sender (user or assistant). */
43 private String role;
44
45 /** The content of the message. */
46 private String content;
47
48 /** The timestamp when the message was created. */
49 private LocalDateTime timestamp;
50
51 /** The list of sources referenced in this message. */
52 private List<ChatSource> sources;
53
54 /** The HTML-rendered content for display. */
55 private String htmlContent;
56
57 /**
58 * Default constructor.
59 */
60 public ChatMessage() {
61 this.timestamp = LocalDateTime.now();
62 this.sources = new ArrayList<>();
63 }
64
65 /**
66 * Creates a new chat message with the specified role and content.
67 *
68 * @param role the message role
69 * @param content the message content
70 */
71 public ChatMessage(final String role, final String content) {
72 this();
73 this.role = role;
74 this.content = content;
75 }
76
77 /**
78 * Creates a user message with the specified content.
79 *
80 * @param content the message content
81 * @return a new user message
82 */
83 public static ChatMessage userMessage(final String content) {
84 return new ChatMessage(ROLE_USER, content);
85 }
86
87 /**
88 * Creates an assistant message with the specified content.
89 *
90 * @param content the message content
91 * @return a new assistant message
92 */
93 public static ChatMessage assistantMessage(final String content) {
94 return new ChatMessage(ROLE_ASSISTANT, content);
95 }
96
97 /**
98 * Gets the message ID.
99 *
100 * @return the message ID
101 */
102 public String getId() {
103 return id;
104 }
105
106 /**
107 * Sets the message ID.
108 *
109 * @param id the message ID
110 */
111 public void setId(final String id) {
112 this.id = id;
113 }
114
115 /**
116 * Gets the message role.
117 *
118 * @return the message role
119 */
120 public String getRole() {
121 return role;
122 }
123
124 /**
125 * Sets the message role.
126 *
127 * @param role the message role
128 */
129 public void setRole(final String role) {
130 this.role = role;
131 }
132
133 /**
134 * Gets the message content.
135 *
136 * @return the message content
137 */
138 public String getContent() {
139 return content;
140 }
141
142 /**
143 * Sets the message content.
144 *
145 * @param content the message content
146 */
147 public void setContent(final String content) {
148 this.content = content;
149 }
150
151 /**
152 * Gets the message timestamp.
153 *
154 * @return the message timestamp
155 */
156 public LocalDateTime getTimestamp() {
157 return timestamp;
158 }
159
160 /**
161 * Sets the message timestamp.
162 *
163 * @param timestamp the message timestamp
164 */
165 public void setTimestamp(final LocalDateTime timestamp) {
166 this.timestamp = timestamp;
167 }
168
169 /**
170 * Gets the list of sources referenced in the message.
171 *
172 * @return the list of sources
173 */
174 public List<ChatSource> getSources() {
175 return sources;
176 }
177
178 /**
179 * Sets the list of sources referenced in the message.
180 *
181 * @param sources the list of sources
182 */
183 public void setSources(final List<ChatSource> sources) {
184 this.sources = sources;
185 }
186
187 /**
188 * Adds a source to the message.
189 *
190 * @param source the source to add
191 */
192 public void addSource(final ChatSource source) {
193 if (sources == null) {
194 sources = new ArrayList<>();
195 }
196 sources.add(source);
197 }
198
199 /**
200 * Checks if this is a user message.
201 *
202 * @return true if this is a user message
203 */
204 public boolean isUser() {
205 return ROLE_USER.equals(role);
206 }
207
208 /**
209 * Checks if this is an assistant message.
210 *
211 * @return true if this is an assistant message
212 */
213 public boolean isAssistant() {
214 return ROLE_ASSISTANT.equals(role);
215 }
216
217 /**
218 * Gets the HTML-rendered content.
219 *
220 * @return the HTML content, or null if not rendered
221 */
222 public String getHtmlContent() {
223 return htmlContent;
224 }
225
226 /**
227 * Sets the HTML-rendered content.
228 *
229 * @param htmlContent the HTML content
230 */
231 public void setHtmlContent(final String htmlContent) {
232 this.htmlContent = htmlContent;
233 }
234
235 /**
236 * Represents a source document referenced in the chat response.
237 */
238 public static class ChatSource implements Serializable {
239
240 private static final long serialVersionUID = 1L;
241
242 /** The index of this source in the result list. */
243 private int index;
244
245 /** The title of the source document. */
246 private String title;
247
248 /** The URL of the source document. */
249 private String url;
250
251 /** The document ID. */
252 private String docId;
253
254 /** A snippet from the source document. */
255 private String snippet;
256
257 /** The ViewHelper-processed URL for display. */
258 private String urlLink;
259
260 /** The go link URL for navigation with access control and click logging. */
261 private String goUrl;
262
263 /**
264 * Default constructor.
265 */
266 public ChatSource() {
267 }
268
269 /**
270 * Creates a new chat source from a document map.
271 *
272 * @param index the source index
273 * @param doc the document map containing source data
274 */
275 public ChatSource(final int index, final Map<String, Object> doc) {
276 this.index = index;
277 String titleValue = toStringOrNull(doc.get("title"));
278 if (titleValue == null || titleValue.isEmpty()) {
279 titleValue = toStringOrNull(doc.get("content_title"));
280 }
281 this.title = titleValue;
282 this.url = toStringOrNull(doc.get("url"));
283 this.docId = toStringOrNull(doc.get("doc_id"));
284 this.snippet = toStringOrNull(doc.get("content_description"));
285 this.urlLink = toStringOrNull(doc.get("url_link"));
286 }
287
288 private static String toStringOrNull(final Object value) {
289 if (value == null) {
290 return null;
291 }
292 if (value instanceof String) {
293 return (String) value;
294 }
295 return value.toString();
296 }
297
298 /**
299 * Gets the source index.
300 *
301 * @return the source index
302 */
303 public int getIndex() {
304 return index;
305 }
306
307 /**
308 * Sets the source index.
309 *
310 * @param index the source index
311 */
312 public void setIndex(final int index) {
313 this.index = index;
314 }
315
316 /**
317 * Gets the source title.
318 *
319 * @return the source title
320 */
321 public String getTitle() {
322 return title;
323 }
324
325 /**
326 * Sets the source title.
327 *
328 * @param title the source title
329 */
330 public void setTitle(final String title) {
331 this.title = title;
332 }
333
334 /**
335 * Gets the source URL.
336 *
337 * @return the source URL
338 */
339 public String getUrl() {
340 return url;
341 }
342
343 /**
344 * Sets the source URL.
345 *
346 * @param url the source URL
347 */
348 public void setUrl(final String url) {
349 this.url = url;
350 }
351
352 /**
353 * Gets the document ID.
354 *
355 * @return the document ID
356 */
357 public String getDocId() {
358 return docId;
359 }
360
361 /**
362 * Sets the document ID.
363 *
364 * @param docId the document ID
365 */
366 public void setDocId(final String docId) {
367 this.docId = docId;
368 }
369
370 /**
371 * Gets the source snippet.
372 *
373 * @return the source snippet
374 */
375 public String getSnippet() {
376 return snippet;
377 }
378
379 /**
380 * Sets the source snippet.
381 *
382 * @param snippet the source snippet
383 */
384 public void setSnippet(final String snippet) {
385 this.snippet = snippet;
386 }
387
388 /**
389 * Gets the ViewHelper-processed URL for display.
390 *
391 * @return the URL link
392 */
393 public String getUrlLink() {
394 return urlLink;
395 }
396
397 /**
398 * Sets the ViewHelper-processed URL for display.
399 *
400 * @param urlLink the URL link
401 */
402 public void setUrlLink(final String urlLink) {
403 this.urlLink = urlLink;
404 }
405
406 /**
407 * Gets the go link URL for navigation.
408 *
409 * @return the go URL
410 */
411 public String getGoUrl() {
412 return goUrl;
413 }
414
415 /**
416 * Sets the go link URL for navigation.
417 *
418 * @param goUrl the go URL
419 */
420 public void setGoUrl(final String goUrl) {
421 this.goUrl = goUrl;
422 }
423 }
424 }