From 5afe1f8bf83c5776f415a726a83bfb66777ef68c Mon Sep 17 00:00:00 2001 From: Daniel Karbach Date: Fri, 6 Sep 2024 16:58:41 +0200 Subject: [PATCH] add context bot chatbot log --- app/Http/Controllers/ChatBotLogController.php | 32 +++++++ resources/js/components/chat-bot-logs/Item.js | 93 +++++++++++++++---- resources/js/components/chat-logs/Item.js | 53 +++++++++++ resources/js/components/chat-logs/List.js | 19 ++++ resources/js/i18n/de.js | 4 + resources/js/i18n/en.js | 4 + resources/sass/app.scss | 1 + resources/sass/chatlog.scss | 4 + routes/api.php | 1 + 9 files changed, 195 insertions(+), 16 deletions(-) create mode 100644 resources/js/components/chat-logs/Item.js create mode 100644 resources/js/components/chat-logs/List.js create mode 100644 resources/sass/chatlog.scss diff --git a/app/Http/Controllers/ChatBotLogController.php b/app/Http/Controllers/ChatBotLogController.php index 86bb690..62c2885 100644 --- a/app/Http/Controllers/ChatBotLogController.php +++ b/app/Http/Controllers/ChatBotLogController.php @@ -3,6 +3,8 @@ namespace App\Http\Controllers; use App\Models\ChatBotLog; +use App\Models\ChatLog; +use Carbon\Carbon; use Illuminate\Http\Request; class ChatBotLogController extends Controller { @@ -12,4 +14,34 @@ class ChatBotLogController extends Controller { return $logs->get()->toJson(); } + public function getContext(ChatBotLog $entry) { + $log = ChatLog::where('command', '=', 'PRIVMSG') + ->where('channel_id', '=', $entry->channel_id) + ->where('created_at', '<=', $entry->created_at) + ->orderBy('created_at', 'DESC') + ->limit(10) + ->get() + ->reverse() + ->values(); + $original = null; + if ($entry->origin_id) { + try { + $original = ChatLog::where('command', '=', 'PRIVMSG') + ->where('channel_id', '=', $entry->origin->channel_id) + ->where('id', '<', $entry->origin_id) + ->orderBy('created_at', 'DESC') + ->limit(10) + ->get() + ->reverse() + ->values(); + } catch (\Exception $e) { + // original was deleted perhaps + } + } + return [ + 'current' => $log, + 'original' => $original, + ]; + } + } diff --git a/resources/js/components/chat-bot-logs/Item.js b/resources/js/components/chat-bot-logs/Item.js index 9b4cfcb..395ad33 100644 --- a/resources/js/components/chat-bot-logs/Item.js +++ b/resources/js/components/chat-bot-logs/Item.js @@ -1,10 +1,14 @@ +import axios from 'axios'; import moment from 'moment'; import PropTypes from 'prop-types'; import React from 'react'; -import { ListGroup } from 'react-bootstrap'; +import { Button, Col, ListGroup, Row } from 'react-bootstrap'; import { useTranslation } from 'react-i18next'; import ChannelLink from '../channel/Link'; +import List from '../chat-logs/List'; +import Icon from '../common/Icon'; +import Loading from '../common/Loading'; import { getUserName } from '../../helpers/User'; const getEntryDate = entry => moment(entry.created_at).fromNow(); @@ -41,30 +45,87 @@ const getEntryInfo = (entry, t) => { }; const Item = ({ entry = {} }) => { + const [context, setContext] = React.useState(null); + const [contextLoading, setContextLoading] = React.useState(true); + const [showContext, setShowContext] = React.useState(false); + const { t } = useTranslation(); - return -
+ React.useEffect(() => { + if (context || !showContext) return; + const ctrl = new AbortController(); + axios + .get(`/api/chatbotlogs/${entry.id}/context`, { + signal: ctrl.signal + }) + .then(response => { + setContextLoading(false); + setContext(response.data); + }) + .catch(error => { + if (!axios.isCancel(error)) { + setContextLoading(false); + setContext(null); + } + }); + return () => { + ctrl.abort(); + }; + }, [context, showContext]); + + return +
- {entry.text} -
- {entry.origin ? +
+ {entry.text} +
+ {entry.origin ? +
+ {getEntryOrigin(entry, t)} +
+ : null}
- {getEntryOrigin(entry, t)} + {getEntryInfo(entry, t)}
- : null} -
- {getEntryInfo(entry, t)}
-
- {entry.channel ?
- + {entry.channel ? + + : null} + +
+
+ {showContext ? +
+ {contextLoading ? + + : null} + {context ? + + +

{t('chatBotLog.context')}

+ + + {context.original ? + +

{t('chatBotLog.originalContext')}

+ + + : null} +
+ : null}
: null}
; diff --git a/resources/js/components/chat-logs/Item.js b/resources/js/components/chat-logs/Item.js new file mode 100644 index 0000000..52110e3 --- /dev/null +++ b/resources/js/components/chat-logs/Item.js @@ -0,0 +1,53 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; + +const getChatterColor = entry => { + if (entry.tags && entry.tags['color']) { + return entry.tags['color']; + } + return 'inherit'; +}; + +const getChatterNick = entry => { + if (entry.tags && entry.tags['display-name']) { + return entry.tags['display-name']; + } + return entry.nick; +}; + +const getTextContent = entry => { + if (entry.params && entry.params.length >= 2) { + return entry.params[1]; + } + return entry.text_content; +}; + +const getTimestamp = entry => { + if (entry.tags && entry.tags['tmi-sent-ts']) { + return new Date(parseInt(entry.tags['tmi-sent-ts'], 10)); + } + return new Date(entry.created_at); +}; + +const Item = ({ entry }) => { + const { t } = useTranslation(); + + return
+
+ + {t('chatBotLog.shortTimestamp', { date: getTimestamp(entry) })} + + {getChatterNick(entry)} +
+
{getTextContent(entry)}
+
; +}; + +Item.propTypes = { + entry: PropTypes.shape({ + text_content: PropTypes.string, + }).isRequired, +}; + +export default Item; diff --git a/resources/js/components/chat-logs/List.js b/resources/js/components/chat-logs/List.js new file mode 100644 index 0000000..8da17e2 --- /dev/null +++ b/resources/js/components/chat-logs/List.js @@ -0,0 +1,19 @@ +import PropTypes from 'prop-types'; +import React from 'react'; + +import Item from './Item'; + +const List = ({ log = [] }) => { + return
+ {log.map(entry => + + )} +
; +}; + +List.propTypes = { + log: PropTypes.arrayOf(PropTypes.shape({ + })), +}; + +export default List; diff --git a/resources/js/i18n/de.js b/resources/js/i18n/de.js index ce3faa6..3e32cee 100644 --- a/resources/js/i18n/de.js +++ b/resources/js/i18n/de.js @@ -98,6 +98,7 @@ export default { unset: 'Zurücksetzen', }, chatBotLog: { + context: 'Kontext', empty: 'Noch keine Nachrichten erfasst', heading: 'Chat Bot Protokoll', info: { @@ -108,6 +109,9 @@ export default { origin: { chatLog: 'Quelle: {{ nick }} in {{ channel }} am {{ date, L LT }}', }, + originalContext: 'Ursprünglicher Kontext', + shortTimestamp: '{{ date, HH:mm:ss }}', + showContext: 'Kontext zeigen', }, content: { attribution: 'Attribution', diff --git a/resources/js/i18n/en.js b/resources/js/i18n/en.js index afd1aa1..b8d8721 100644 --- a/resources/js/i18n/en.js +++ b/resources/js/i18n/en.js @@ -98,6 +98,7 @@ export default { unset: 'Unset', }, chatBotLog: { + context: 'Context', empty: 'No messages on protocol yet', heading: 'Chat Bot Log', info: { @@ -108,6 +109,9 @@ export default { origin: { chatLog: 'Source: {{ nick }} in {{ channel }} on {{ date, L LT }}', }, + originalContext: 'Original context', + shortTimestamp: '{{ date, hh:mm:ss }}', + showContext: 'Show context', }, content: { attribution: 'Attribution', diff --git a/resources/sass/app.scss b/resources/sass/app.scss index 7554a9e..910d382 100644 --- a/resources/sass/app.scss +++ b/resources/sass/app.scss @@ -7,6 +7,7 @@ // Custom @import 'common'; @import 'channels'; +@import 'chatlog'; @import 'discord'; @import 'doors'; @import 'episodes'; diff --git a/resources/sass/chatlog.scss b/resources/sass/chatlog.scss new file mode 100644 index 0000000..63f9a00 --- /dev/null +++ b/resources/sass/chatlog.scss @@ -0,0 +1,4 @@ +.chat-log-list { + padding: 0.5ex 1ex; + background: $dark; +} diff --git a/routes/api.php b/routes/api.php index e3ced1d..2818414 100644 --- a/routes/api.php +++ b/routes/api.php @@ -40,6 +40,7 @@ Route::put('channels/{channel}/guessing-game/{name}', 'App\Http\Controllers\Chan Route::get('guessing-game-monitor/{key}', 'App\Http\Controllers\ChannelController@getGuessingGameMonitor'); Route::get('chatbotlogs', 'App\Http\Controllers\ChatBotLogController@search'); +Route::get('chatbotlogs/{entry}/context', 'App\Http\Controllers\ChatBotLogController@getContext'); Route::get('content', 'App\Http\Controllers\TechniqueController@search'); Route::get('content/{tech:name}', 'App\Http\Controllers\TechniqueController@single'); -- 2.39.2