Skip to content

Commit

Permalink
Merge pull request #24 from freemocap/jon/add-context-command
Browse files Browse the repository at this point in the history
Add "`/chat`" to right-click context menu
  • Loading branch information
jonmatthis authored Jan 25, 2024
2 parents 345d39e + 63bacdc commit e16fd28
Show file tree
Hide file tree
Showing 10 changed files with 196 additions and 89 deletions.
8 changes: 4 additions & 4 deletions src/core/ai/openai/dto/speech-to-text.dto.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import {
IsString,
IsIn,
IsOptional,
IsMimeType,
IsNumber,
Min,
IsOptional,
IsString,
Max,
IsMimeType,
Min,
} from 'class-validator';
import { Type } from 'class-transformer';

Expand Down
6 changes: 3 additions & 3 deletions src/core/ai/openai/dto/text-to-speech.dto.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {
IsString,
IsIn,
IsOptional,
IsNumber,
Min,
IsOptional,
IsString,
Max,
Min,
} from 'class-validator';
import { Type } from 'class-transformer';

Expand Down
2 changes: 1 addition & 1 deletion src/core/ai/openai/openai-audio.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { OpenaiSecretsService } from './openai-secrets.service';
import { OpenAI } from 'openai';
import { createReadStream, promises } from 'fs';
import { promises } from 'fs';
import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
import { TextToSpeechDto } from './dto/text-to-speech.dto';
import * as path from 'path';
Expand Down
1 change: 1 addition & 0 deletions src/core/chatbot/chatbot-response.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Injectable, Logger } from '@nestjs/common';
import { ChatbotManagerService } from './chatbot-manager.service';
import { OpenaiChatService } from '../ai/openai/openai-chat.service';

class StreamResponseOptions {
/**
* Character limit to split the outgoing data
Expand Down
1 change: 0 additions & 1 deletion src/core/database/collections/ai-chats/ai-chat.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Document, Types } from 'mongoose';
import { ContextRoute } from './context-route.provider';
import { User } from '../users/user.schema';
import { Couplet } from '../couplets/couplet.schema';
import { OpenAiChatConfig } from '../../../ai/openai/openai-chat.service';

export type AiChatDocument = AiChat & Document;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,11 @@ export class DiscordOnMessageService {
if (!this.activeChats.has(message.channel.id)) {
await this._reloadChatFromDatabase(message);
}
await this._messageService.respondToMessage(message, message.author.id);
await this._messageService.respondToMessage(
message,
message,
message.author.id,
);
}

private async _reloadChatFromDatabase(message: Message<boolean>) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import { Attachment } from 'discord.js';
import { OpenaiAudioService } from '../../../../core/ai/openai/openai-audio.service';
import axios from 'axios';
import * as path from 'path';
import * as fs from 'fs';
import { createReadStream, createWriteStream } from 'fs';
import { promisify } from 'util';
import * as stream from 'stream';
import * as fs from 'fs';

@Injectable()
export class DiscordAttachmentService {
constructor(
Expand Down
141 changes: 104 additions & 37 deletions src/interfaces/discord/services/threads/discord-chat.service.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { Injectable, Logger } from '@nestjs/common';
import { Context, Options, SlashCommand, SlashCommandContext } from 'necord';
import { DiscordTextDto } from '../../dto/discord-text.dto';
import {
CacheType,
ChatInputCommandInteraction,
EmbedBuilder,
userMention,
} from 'discord.js';
Context,
MessageCommand,
MessageCommandContext,
Options,
SlashCommand,
SlashCommandContext,
TargetMessage,
} from 'necord';
import { DiscordTextDto } from '../../dto/discord-text.dto';
import { EmbedBuilder, Message, ThreadChannel, userMention } from 'discord.js';
import { DiscordMessageService } from './discord-message.service';
import { DiscordOnMessageService } from '../events/discord-on-message.service';

Expand All @@ -24,7 +27,7 @@ export class DiscordChatService {
description:
'Opens a thread at this location and sets up a aiChat with with the chatbot.',
})
public async onChatCommand(
public async onSlashChatCommand(
@Context() [interaction]: SlashCommandContext,
@Options({ required: false }) startingText?: DiscordTextDto,
) {
Expand All @@ -35,16 +38,20 @@ export class DiscordChatService {
}

this.logger.log(
`Creating thread with starting text:'${startingText.text}' in channel: name= ${interaction.channel.name}, id=${interaction.channel.id} `,
`Recieved '/chat' command with starting text:'${startingText.text}' in channel: name= ${interaction.channel.name}, id=${interaction.channel.id} `,
);
const thread = await this._createNewThread(
startingText.text,
interaction,
);
const thread = await this._createNewThread(startingText, interaction);

const firstThreadMessage = await thread.send(
`Starting new chat with initial message:\n\n> ${startingText.text}`,
);

await this._onMessageService.addActiveChat(firstThreadMessage);
await this._messageService.respondToMessage(
firstThreadMessage,
firstThreadMessage,
interaction.user.id,
true,
Expand All @@ -54,36 +61,96 @@ export class DiscordChatService {
}
}

private async _createNewThread(
startingText: DiscordTextDto,
interaction: ChatInputCommandInteraction<CacheType>,
@MessageCommand({
name: 'Open `/chat` thread',
})
public async onMessageContextChatCommand(
@Context() [interaction]: MessageCommandContext,
@TargetMessage() message: Message,
) {
const maxThreadNameLength = 100; // Discord's maximum thread name length
let threadName = startingText.text;
if (threadName.length > maxThreadNameLength) {
threadName = threadName.substring(0, maxThreadNameLength);
await interaction.deferReply();

try {
const { humanInputText, attachmentText } =
await this._messageService.extractMessageContent(message);

this.logger.log(
`Received 'message context menu' command for Message: ${message.id} in channel: name= ${interaction.channel.name}, id=${message.channel.id} `,
);
const thread = await this._createNewThread(
humanInputText + attachmentText,
interaction,
);

const firstThreadMessage = await thread.send(
`Starting new chat with initial message:\n\n> ${
humanInputText + attachmentText
}`,
);

await this._onMessageService.addActiveChat(firstThreadMessage);
await this._messageService.respondToMessage(
firstThreadMessage,
thread,
interaction.user.id,
true,
);
} catch (error) {
this.logger.error(`Caught error: ${error}`);
}
const threadTitleEmbed = new EmbedBuilder()
.setColor(0x0099ff)
.setAuthor({
name: `Thread created by ${interaction.user.username}`,
iconURL: interaction.user.avatarURL(),
})
.setTimestamp()
.addFields({
name: '`skellybot` source code:',
value: 'https://github.com/freemocap/skellybot',
}

private async _createNewThread(startingTextString: string, interaction) {
try {
const maxThreadNameLength = 100; // Discord's maximum thread name length
let threadName = startingTextString;
if (threadName.length > maxThreadNameLength) {
threadName = threadName.substring(0, maxThreadNameLength);
}
const threadTitleEmbed = new EmbedBuilder()
.setColor(0x0099ff)
.setAuthor({
name: `Thread created by ${interaction.user.username}`,
iconURL: interaction.user.avatarURL(),
})
.setTimestamp()
.addFields({
name: '`skellybot` source code:',
value: 'https://github.com/freemocap/skellybot',
});

let threadAnchorMessage: Message;

if (interaction.channel instanceof ThreadChannel) {
threadAnchorMessage = await interaction.channel.parent.send({
content: `Thread Created for user: ${userMention(
interaction.user.id,
)} with starting text:\n\n> ${startingTextString}`,
embeds: [threadTitleEmbed],
});
} else {
threadAnchorMessage = await interaction.channel.send({
content: `Thread Created for user: ${userMention(
interaction.user.id,
)} with starting text:\n\n> ${startingTextString}`,
embeds: [threadTitleEmbed],
});
}

const thread = await threadAnchorMessage.startThread({
name: threadName,
});

const threadCreationMessage = await interaction.editReply({
content: `Thread Created for user: ${userMention(
interaction.user.id,
)} with starting text:\n\n> ${startingText.text}`,
embeds: [threadTitleEmbed],
attachments: [],
});
return await threadCreationMessage.startThread({
name: threadName,
});
await interaction.editReply({
content: `Created thread: \n\n> ${thread.name}: ${thread.url}`,
ephemeral: !(interaction.channel instanceof ThreadChannel),
});

return thread;
} catch (error) {
this.logger.error(
`Something went wrong during '_createNewThread()': Caught error: '${error}'`,
);
}
}
}
Loading

0 comments on commit e16fd28

Please sign in to comment.