generated from nhcarrigan/template
feat: initial commit
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
prod
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit"
|
||||
},
|
||||
"eslint.validate": ["typescript"],
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import NaomisConfig from '@nhcarrigan/eslint-config';
|
||||
|
||||
export default NaomisConfig;
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "vivicrea",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"lint": "eslint src --max-warnings 0",
|
||||
"start": "op run --env-file=prod.env -- node prod/index.js",
|
||||
"test": "echo \"Error: no test specified\" && exit 0"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"packageManager": "pnpm@10.19.0",
|
||||
"devDependencies": {
|
||||
"@nhcarrigan/eslint-config": "5.2.0",
|
||||
"@nhcarrigan/typescript-config": "4.0.0",
|
||||
"@types/node": "24.9.2",
|
||||
"eslint": "9.38.0",
|
||||
"typescript": "5.9.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@google/genai": "1.28.0",
|
||||
"@nhcarrigan/discord-analytics": "0.0.6",
|
||||
"@nhcarrigan/logger": "1.1.1",
|
||||
"discord.js": "14.24.2",
|
||||
"fastify": "5.6.1"
|
||||
}
|
||||
}
|
||||
Generated
+5020
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
DISCORD_TOKEN="op://Environment Variables - Naomi/Vivicrea/Discord token"
|
||||
GEMINI_API_KEY="op://Environment Variables - Naomi/Vivicrea/gemini token"
|
||||
LOG_TOKEN="op://Environment Variables - Naomi/Alert Server/api_auth"
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @copyright NHCarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import {
|
||||
GoogleGenAI,
|
||||
} from "@google/genai";
|
||||
import { AttachmentBuilder, type MessageCreateOptions } from "discord.js";
|
||||
|
||||
/**
|
||||
* Utility class for generating project information and images.
|
||||
*/
|
||||
export class Ai {
|
||||
private readonly gemini: GoogleGenAI;
|
||||
|
||||
/**
|
||||
* Creates a new instance of the Ai class.
|
||||
* @param geminiKey - The API key for the Gemini API.
|
||||
*/
|
||||
public constructor(geminiKey: string) {
|
||||
this.gemini = new GoogleGenAI({
|
||||
apiKey: geminiKey,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an image of Naomi in the style of the prompt.
|
||||
* @returns A message create options object containing the image.
|
||||
*/
|
||||
public async generateImage(): Promise<MessageCreateOptions> {
|
||||
const response = await this.gemini.models.generateContent({
|
||||
config: {
|
||||
imageConfig: { aspectRatio: "16:9" },
|
||||
},
|
||||
contents: `Anime style full body art of "Naomi", a woman with shoulder-length wavy light dusty brown hair, light blue eyes, very pale white skin, pink glasses, small vampire fangs, a gentle smile. She is barefoot, with neatly painted pink fingernails and matching toenails. Her accessories include pink teardrop earrings and a pearl bracelet. She should be depicted in various outfits and settings, but always maintaining these core features. The art style should be clean, detailed, and vibrant. You may refer to her reference sheet at https://cdn.nhcarrigan.com/ref.png. NEVER include text in the image, no text anywhere at all.`,
|
||||
model: "gemini-2.5-flash-image",
|
||||
});
|
||||
const image = response.candidates?.[0]?.content?.parts?.find((p) => {
|
||||
return Boolean(p.inlineData);
|
||||
});
|
||||
const base64 = image?.inlineData?.data;
|
||||
if (base64 === undefined) {
|
||||
return { content: "Sorry, I was unable to generate an image for you." };
|
||||
}
|
||||
return {
|
||||
files: [
|
||||
new AttachmentBuilder(
|
||||
Buffer.from(base64, "base64"),
|
||||
{ name: "naomi.png" },
|
||||
),
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* @copyright NHCarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import { Logger } from "@nhcarrigan/logger";
|
||||
import { Client, Events, GatewayIntentBits } from "discord.js";
|
||||
import { Ai } from "./classes/ai.js";
|
||||
|
||||
if (
|
||||
process.env.GEMINI_API_KEY === undefined
|
||||
|| process.env.LOG_TOKEN === undefined
|
||||
|| process.env.DISCORD_TOKEN === undefined) {
|
||||
throw new Error(
|
||||
`GEMINI_API_KEY, LOG_TOKEN, and DISCORD_TOKEN must be set.`,
|
||||
);
|
||||
}
|
||||
|
||||
const ai = new Ai(process.env.GEMINI_API_KEY);
|
||||
const logger = new Logger("Nomena", process.env.LOG_TOKEN);
|
||||
|
||||
const bot = new Client({
|
||||
intents: [
|
||||
GatewayIntentBits.Guilds,
|
||||
GatewayIntentBits.GuildMessages,
|
||||
],
|
||||
});
|
||||
|
||||
bot.once("ready", () => {
|
||||
void logger.log("debug", "Nomena is online!");
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises -- Lazy.
|
||||
bot.on(Events.MessageCreate, async(message) => {
|
||||
if (!message.mentions.has("1434585327552430081", {
|
||||
ignoreEveryone: true,
|
||||
ignoreRepliedUser: true,
|
||||
ignoreRoles: true,
|
||||
})) {
|
||||
return;
|
||||
}
|
||||
if (message.author.id !== "465650873650118659") {
|
||||
await message.reply("Sorry, I can only generate images for Naomi.");
|
||||
}
|
||||
await message.channel.sendTyping();
|
||||
const image = await ai.generateImage();
|
||||
await message.reply(image);
|
||||
});
|
||||
|
||||
await bot.login(process.env.DISCORD_TOKEN);
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "@nhcarrigan/typescript-config",
|
||||
"compilerOptions": {
|
||||
"outDir": "./prod",
|
||||
"rootDir": "./src",
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user