feat: add purchases generation
This commit is contained in:
@@ -4,7 +4,6 @@
|
||||
"es2021": true
|
||||
},
|
||||
"extends": [
|
||||
"next/core-web-vitals",
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier"
|
||||
@@ -17,8 +16,7 @@
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
"@typescript-eslint/consistent-type-definitions": "error",
|
||||
"react-hooks/rules-of-hooks": "error",
|
||||
"react-hooks/exhaustive-deps": "error"
|
||||
}
|
||||
"@typescript-eslint/consistent-type-definitions": "error"
|
||||
},
|
||||
"ignorePatterns": ["node_modules/", "dist/"]
|
||||
}
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -132,5 +132,6 @@ dist
|
||||
.editorconfig
|
||||
|
||||
personas/
|
||||
purchases/
|
||||
|
||||
.DS_Store
|
||||
@@ -4,7 +4,7 @@
|
||||
"start": "prisma generate && node dist/index.js",
|
||||
"dev": "nodemon src/index.ts",
|
||||
"build": "tsc",
|
||||
"lint": "next lint",
|
||||
"lint": "eslint . --fix",
|
||||
"format": "prettier --config .prettierrc '**/*.{ts,json,md}' --write",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"prepare": "husky install",
|
||||
|
||||
20
src/index.ts
20
src/index.ts
@@ -1,17 +1,15 @@
|
||||
import { makeRequest } from './utils/anthropicClient';
|
||||
import { savePersonaJson } from './utils/savePersonaJson';
|
||||
import { savePersonaDb } from './utils/savePersonaDb';
|
||||
import { generatePromptWithMBTI } from './utils/personalityTrait';
|
||||
import { generate as generatePersona } from './persona/store';
|
||||
|
||||
const prompt =
|
||||
'Generate a detailed, realistic persona with specific real-world values including store names, brands and locations. Use frequencies per week, ISO timestamps relative to the current week. Personality trait: <MBTI_AND_TRAITS_HERE>';
|
||||
import { generate as generatePurchases } from './purchase/store';
|
||||
|
||||
const fullPrompt = generatePromptWithMBTI(prompt);
|
||||
const personaPromise = generatePersona();
|
||||
|
||||
const personaPromise = makeRequest(fullPrompt);
|
||||
personaPromise.then(id => {
|
||||
console.log(`Persona generated! Now generating purchases for id ${id}`);
|
||||
|
||||
personaPromise.then(persona => {
|
||||
savePersonaDb(persona).then(id => savePersonaJson(persona, id));
|
||||
const purchasesPromise = generatePurchases(id);
|
||||
|
||||
console.log('New persona:', persona);
|
||||
purchasesPromise.then(() => {
|
||||
console.log('Purchases generated!');
|
||||
});
|
||||
});
|
||||
|
||||
47
src/persona/store.ts
Normal file
47
src/persona/store.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
import { prisma } from '../utils/prismaClient';
|
||||
import fs from 'fs';
|
||||
import { Persona } from './types';
|
||||
import { Tool } from './tool';
|
||||
import { makeRequest } from '../utils/anthropicClient';
|
||||
import { createFolderIfNotExists } from '../utils/createFolder';
|
||||
|
||||
const prompt =
|
||||
'Generate a detailed, realistic customer persona that follows the schema structure exactly. Create someone whose traits, habits, and behaviors form a coherent narrative about their purchasing decisions. Randomly select one option from each seed group: LIFE STAGE [young professional | mid-career parent | empty nester | recent graduate | career shifter | semi-retired | newly married | single parent | remote worker | retiree] FINANCIAL STYLE [debt-averse minimalist | luxury spender | budget optimizer | investment-focused | experience seeker | conscious consumer | tech enthusiast | security planner | impulse buyer | traditional saver] LOCATION [urban core | older suburb | new suburb | small town | rural area | coastal city | mountain town | college town | cultural district | tech hub] SPECIAL FACTOR [health-focused | hobby enthusiast | side hustler | community leader | creative professional | outdoor adventurer | tech worker | environmental advocate | cultural enthusiast | academic] ATTITUDE [optimist | pragmatist | skeptic] TECH COMFORT [early adopter | mainstream | traditional] SOCIAL STYLE [extrovert | ambivert | introvert] SEASON [winter | spring | summer | fall]. Ensure all numerical values and scores are justified by the persona context and lifestyle.';
|
||||
|
||||
export async function generate() {
|
||||
const result = (await makeRequest(prompt, Tool as any)) as Persona;
|
||||
|
||||
const id = await saveToDb(result);
|
||||
|
||||
await saveToJson(result, id);
|
||||
|
||||
console.log('Persona:', result.core.name);
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
export async function saveToDb(persona: Persona) {
|
||||
const result = await prisma.user.create({
|
||||
data: {
|
||||
name: persona.core.name,
|
||||
age: persona.core.age,
|
||||
persona: JSON.stringify(persona)
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`Persona ${result.name} inserted in DB with id ${result.id}`);
|
||||
|
||||
return result.id;
|
||||
}
|
||||
|
||||
export async function saveToJson(persona: Persona, id: number) {
|
||||
await createFolderIfNotExists('personas');
|
||||
|
||||
await fs.promises.writeFile(
|
||||
`personas/${id}.json`,
|
||||
JSON.stringify(persona),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
console.log(`Persona ${persona.core.name} saved as persona/${id}.json`);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
export const PersonaTool = {
|
||||
export const Tool = {
|
||||
name: 'PersonaSchema' as const,
|
||||
input_schema: {
|
||||
type: 'object' as const,
|
||||
@@ -1,55 +1,55 @@
|
||||
type Pet = {
|
||||
interface Pet {
|
||||
[key: string]: any;
|
||||
};
|
||||
}
|
||||
|
||||
type FrequencyObject = {
|
||||
interface FrequencyObject {
|
||||
name: string;
|
||||
frequency: number;
|
||||
};
|
||||
}
|
||||
|
||||
type SubscriptionBill = {
|
||||
interface SubscriptionBill {
|
||||
name: string;
|
||||
amount: number;
|
||||
date: string | Date;
|
||||
};
|
||||
}
|
||||
|
||||
type ActivityObject = {
|
||||
interface ActivityObject {
|
||||
name: string;
|
||||
frequency: number;
|
||||
schedule?: string[];
|
||||
};
|
||||
}
|
||||
|
||||
type BrandLoyalty = {
|
||||
interface BrandLoyalty {
|
||||
name: string;
|
||||
loyaltyScore: number;
|
||||
};
|
||||
}
|
||||
|
||||
type Event = {
|
||||
interface Event {
|
||||
name: string;
|
||||
date: string | Date;
|
||||
details?: string;
|
||||
};
|
||||
}
|
||||
|
||||
type TimelineActivity = {
|
||||
interface TimelineActivity {
|
||||
activity: string;
|
||||
duration: string;
|
||||
location?: string;
|
||||
};
|
||||
}
|
||||
|
||||
type RegularStop = {
|
||||
interface RegularStop {
|
||||
location: string;
|
||||
purpose: string;
|
||||
frequency: string;
|
||||
};
|
||||
}
|
||||
|
||||
type SpendingCategories = {
|
||||
interface SpendingCategories {
|
||||
[category: string]: {
|
||||
preference: number;
|
||||
frequency: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export type Persona = {
|
||||
export interface Persona {
|
||||
core: {
|
||||
age: number;
|
||||
name: string;
|
||||
@@ -115,9 +115,4 @@ export type Persona = {
|
||||
upcoming_events: Event[];
|
||||
recent_changes: string[];
|
||||
};
|
||||
};
|
||||
|
||||
export interface MBTIType {
|
||||
type: string;
|
||||
traits: string[];
|
||||
}
|
||||
199
src/purchase/promptGenerator.ts
Normal file
199
src/purchase/promptGenerator.ts
Normal file
@@ -0,0 +1,199 @@
|
||||
import { Persona } from '../persona/types';
|
||||
|
||||
function formatFrequencyList(
|
||||
items?: Array<{ name: string; frequency: number }>
|
||||
): string {
|
||||
if (!items?.length) return '(No data available)';
|
||||
return items
|
||||
.sort((a, b) => b.frequency - a.frequency)
|
||||
.map(item => `- ${item.name} (${item.frequency}x per month)`)
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
function formatCategories(categories?: {
|
||||
[key: string]: { preference: number; frequency: number };
|
||||
}): string {
|
||||
if (!categories || Object.keys(categories).length === 0)
|
||||
return '(No categories defined)';
|
||||
return Object.entries(categories)
|
||||
.map(([category, data]) => {
|
||||
const weeklyFrequency = Math.round(data.frequency * 4.33); // Monthly to weekly
|
||||
return `- ${category}: ${weeklyFrequency}x per week (preference: ${data.preference}/10)`;
|
||||
})
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
function formatActivities(
|
||||
activities?: Array<{ name: string; frequency: number; schedule?: string[] }>
|
||||
): string {
|
||||
if (!activities?.length) return '(No activities listed)';
|
||||
return activities
|
||||
.map(
|
||||
act =>
|
||||
`- ${act.name}: ${act.frequency}x per ${act.schedule ? act.schedule.join(', ') : 'week'}`
|
||||
)
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
function formatList(items?: string[]): string {
|
||||
if (!items?.length) return '(None listed)';
|
||||
return items.join(', ');
|
||||
}
|
||||
|
||||
async function generatePurchasePrompt(persona: Persona): Promise<string> {
|
||||
try {
|
||||
const sections: string[] = [];
|
||||
|
||||
sections.push(`PERSONAL PROFILE:
|
||||
Name: ${persona.core.name || 'Unknown'}
|
||||
Age: ${persona.core.age || 'Unknown'}
|
||||
Occupation: ${persona.core.occupation?.title || 'Unknown'}${
|
||||
persona.core.occupation?.level
|
||||
? ` (${persona.core.occupation.level})`
|
||||
: ''
|
||||
}
|
||||
Income: ${persona.core.occupation?.income ? `$${persona.core.occupation.income.toLocaleString()}/year` : 'Unknown'}
|
||||
Location: ${persona.core.home?.location || 'Unknown'}
|
||||
Household: ${persona.core.household?.status || 'Unknown'}${
|
||||
persona.core.household?.pets?.length
|
||||
? `\nPets: ${persona.core.household.pets
|
||||
.map(pet => `${pet.type || 'pet'} named ${pet.name}`)
|
||||
.join(', ')}`
|
||||
: ''
|
||||
}`);
|
||||
|
||||
if (persona.core.occupation?.schedule?.length) {
|
||||
sections.push(
|
||||
`WORK SCHEDULE:\n${persona.core.occupation.schedule.join('\n')}`
|
||||
);
|
||||
}
|
||||
|
||||
if (persona.preferences?.shopping) {
|
||||
sections.push(`REGULAR SHOPPING PATTERNS:
|
||||
${persona.preferences.shopping.grocery_stores?.length ? `Grocery Stores:\n${formatFrequencyList(persona.preferences.shopping.grocery_stores)}` : ''}
|
||||
${persona.preferences.shopping.coffee_shops?.length ? `\nCoffee Shops:\n${formatFrequencyList(persona.preferences.shopping.coffee_shops)}` : ''}
|
||||
${persona.preferences.shopping.restaurants?.length ? `\nRestaurants:\n${formatFrequencyList(persona.preferences.shopping.restaurants)}` : ''}
|
||||
${persona.preferences.shopping.retail?.length ? `\nRetail:\n${formatFrequencyList(persona.preferences.shopping.retail)}` : ''}`);
|
||||
}
|
||||
|
||||
if (persona.finances?.spending_patterns?.categories) {
|
||||
sections.push(
|
||||
`SPENDING CATEGORIES & FREQUENCY:\n${formatCategories(persona.finances.spending_patterns.categories)}`
|
||||
);
|
||||
}
|
||||
|
||||
if (persona.preferences || persona.finances?.spending_patterns) {
|
||||
sections.push(`PAYMENT PREFERENCES:
|
||||
${persona.preferences?.payment_methods ? `- Methods: ${formatList(persona.preferences.payment_methods)}` : ''}
|
||||
${persona.preferences?.price_sensitivity ? `- Price Sensitivity: ${persona.preferences.price_sensitivity}/10` : ''}
|
||||
${persona.finances?.spending_patterns?.impulsive_score ? `- Impulsiveness Score: ${persona.finances.spending_patterns.impulsive_score}/10` : ''}`);
|
||||
}
|
||||
|
||||
if (persona.routines?.commute?.regular_stops?.length) {
|
||||
sections.push(`REGULAR ROUTINES:
|
||||
Commute Stops:
|
||||
${persona.routines.commute.regular_stops
|
||||
.map(
|
||||
stop => `- ${stop.frequency} visits to ${stop.location} for ${stop.purpose}`
|
||||
)
|
||||
.join('\n')}`);
|
||||
}
|
||||
|
||||
if (persona.preferences) {
|
||||
const preferencesSection = [`PREFERENCES:`];
|
||||
if (persona.preferences.diet?.length) {
|
||||
preferencesSection.push(
|
||||
`- Diet: ${formatList(persona.preferences.diet)}`
|
||||
);
|
||||
}
|
||||
if (persona.preferences.brands?.length) {
|
||||
preferencesSection.push(
|
||||
`- Favorite Brands: ${persona.preferences.brands
|
||||
.map(b => `${b.name} (loyalty: ${b.loyaltyScore}/10)`)
|
||||
.join(', ')}`
|
||||
);
|
||||
}
|
||||
sections.push(preferencesSection.join('\n'));
|
||||
}
|
||||
|
||||
if (persona.habits) {
|
||||
const activitiesSection = [`REGULAR ACTIVITIES:`];
|
||||
if (persona.habits.exercise?.length) {
|
||||
activitiesSection.push(
|
||||
`Exercise:\n${formatActivities(persona.habits.exercise)}`
|
||||
);
|
||||
}
|
||||
if (persona.habits.social?.length) {
|
||||
activitiesSection.push(
|
||||
`\nSocial:\n${formatActivities(persona.habits.social)}`
|
||||
);
|
||||
}
|
||||
if (persona.habits.entertainment?.length) {
|
||||
activitiesSection.push(
|
||||
`\nEntertainment:\n${formatActivities(persona.habits.entertainment)}`
|
||||
);
|
||||
}
|
||||
sections.push(activitiesSection.join('\n'));
|
||||
}
|
||||
|
||||
if (persona.context) {
|
||||
const contextSection = [`CONTEXT:`];
|
||||
if (persona.context.upcoming_events?.length) {
|
||||
contextSection.push(
|
||||
`Upcoming Events:\n${persona.context.upcoming_events
|
||||
.map(
|
||||
event =>
|
||||
`- ${event.name} on ${event.date}${event.details ? `: ${event.details}` : ''}`
|
||||
)
|
||||
.join('\n')}`
|
||||
);
|
||||
}
|
||||
if (persona.context.stress_triggers?.length) {
|
||||
contextSection.push(
|
||||
`\nStress Triggers: ${formatList(persona.context.stress_triggers)}`
|
||||
);
|
||||
}
|
||||
if (persona.context.reward_behaviors?.length) {
|
||||
contextSection.push(
|
||||
`\nReward Behaviors: ${formatList(persona.context.reward_behaviors)}`
|
||||
);
|
||||
}
|
||||
sections.push(contextSection.join('\n'));
|
||||
}
|
||||
|
||||
if (persona.finances?.subscriptions?.length) {
|
||||
sections.push(`EXISTING SUBSCRIPTIONS (exclude from weekly purchases):
|
||||
${persona.finances.subscriptions.map(sub => `- ${sub.name}: $${sub.amount} (due: ${sub.date})`).join('\n')}`);
|
||||
}
|
||||
|
||||
sections.push(`Please generate a detailed list of purchases for one week, including:
|
||||
1. Date and time of purchase
|
||||
2. Store/vendor name
|
||||
3. Items purchased
|
||||
4. Amount spent
|
||||
5. Category of spending
|
||||
6. Whether it was planned or impulse purchase
|
||||
|
||||
Consider:
|
||||
- Regular commute stops and routines
|
||||
- Exercise and social activities
|
||||
- Dietary preferences and restrictions
|
||||
- Brand loyalties and preferred stores
|
||||
- Work schedule and regular activities
|
||||
- Price sensitivity and impulsiveness score
|
||||
- Upcoming events and potential related purchases
|
||||
${persona.context?.recent_changes?.length ? `- Recent lifestyle changes: ${formatList(persona.context.recent_changes)}` : ''}
|
||||
|
||||
Format each purchase as:
|
||||
[DATE] [TIME] | [STORE] | [ITEMS] | $[AMOUNT] | [CATEGORY] | [PLANNED/IMPULSE]
|
||||
|
||||
Generate purchases that align with the persona's lifestyle, income level, and spending patterns.`);
|
||||
|
||||
return sections.filter(section => section.trim().length > 0).join('\n\n');
|
||||
} catch (error) {
|
||||
console.error('Error generating prompt:', error);
|
||||
throw new Error('Failed to generate purchase prompt');
|
||||
}
|
||||
}
|
||||
|
||||
export default generatePurchasePrompt;
|
||||
57
src/purchase/store.ts
Normal file
57
src/purchase/store.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { prisma } from '../utils/prismaClient';
|
||||
import fs, { readFileSync } from 'fs';
|
||||
import { PurchaseList } from './types';
|
||||
import { Tool } from './tool';
|
||||
import { makeRequest } from '../utils/anthropicClient';
|
||||
import { createFolderIfNotExists } from '../utils/createFolder';
|
||||
import generatePurchasePrompt from './promptGenerator';
|
||||
|
||||
export async function generate(personaId: number) {
|
||||
const jsonFile = readFileSync(`personas/${personaId}.json`, 'utf-8');
|
||||
|
||||
const persona = JSON.parse(jsonFile);
|
||||
|
||||
const personaPrompt = await generatePurchasePrompt(persona);
|
||||
|
||||
const result = (await makeRequest(
|
||||
personaPrompt,
|
||||
Tool as any
|
||||
)) as PurchaseList;
|
||||
|
||||
await saveToDb(personaId, result);
|
||||
|
||||
await saveToJson(result, personaId);
|
||||
|
||||
console.log('Purchases:', result.items.length);
|
||||
}
|
||||
|
||||
export async function saveToDb(personaId: number, purchases: PurchaseList) {
|
||||
const result = await prisma.item.createMany({
|
||||
data: purchases.items.map(purchase => ({
|
||||
userId: personaId,
|
||||
name: purchase.name,
|
||||
amount: purchase.amount,
|
||||
datetime: purchase.datetime,
|
||||
location: purchase.location,
|
||||
notes: purchase.notes
|
||||
}))
|
||||
});
|
||||
|
||||
console.log(`Inserted ${result.count} purchases with persona ${personaId}`);
|
||||
}
|
||||
|
||||
export async function saveToJson(purchaseList: PurchaseList, id: number) {
|
||||
await createFolderIfNotExists('purchases');
|
||||
|
||||
await createFolderIfNotExists(`purchases/${id}`);
|
||||
|
||||
await fs.promises.writeFile(
|
||||
`purchases/${id}/${id}.json`,
|
||||
JSON.stringify(purchaseList),
|
||||
'utf8'
|
||||
);
|
||||
|
||||
console.log(
|
||||
`Saved ${purchaseList.items.length} purchases as purchases/${id}/${id}.json`
|
||||
);
|
||||
}
|
||||
39
src/purchase/tool.ts
Normal file
39
src/purchase/tool.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
export const Tool = {
|
||||
name: 'PurchaseSchema' as const,
|
||||
input_schema: {
|
||||
type: 'object' as const,
|
||||
properties: {
|
||||
items: {
|
||||
type: 'array' as const,
|
||||
items: {
|
||||
type: 'object' as const,
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string' as const,
|
||||
description: 'Name of the purchased item'
|
||||
},
|
||||
amount: {
|
||||
type: 'number' as const,
|
||||
description: 'Purchase amount in USD'
|
||||
},
|
||||
datetime: {
|
||||
type: 'string' as const,
|
||||
description: 'Purchase date and time in ISO 8601 format',
|
||||
format: 'date-time'
|
||||
},
|
||||
location: {
|
||||
type: 'string' as const,
|
||||
description: 'Purchase location'
|
||||
},
|
||||
notes: {
|
||||
type: 'string' as const,
|
||||
description: 'Additional purchase details (optional)'
|
||||
}
|
||||
},
|
||||
required: ['name', 'amount', 'datetime', 'location'] as const
|
||||
}
|
||||
}
|
||||
},
|
||||
required: ['items'] as const
|
||||
}
|
||||
} as const;
|
||||
11
src/purchase/types.ts
Normal file
11
src/purchase/types.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export interface Purchase {
|
||||
name: string;
|
||||
amount: number;
|
||||
datetime: string;
|
||||
location: string;
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
export interface PurchaseList {
|
||||
items: Purchase[];
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
import 'dotenv/config';
|
||||
import Anthropic from '@anthropic-ai/sdk';
|
||||
import { Persona } from './types';
|
||||
import { PersonaTool } from './personaSchema';
|
||||
|
||||
export async function makeRequest(prompt: string) {
|
||||
export async function makeRequest(prompt: string, tool: any) {
|
||||
if (!process.env.ANTHROPIC_API_KEY) {
|
||||
throw Error('Anthropic API key missing.');
|
||||
}
|
||||
@@ -16,7 +14,7 @@ export async function makeRequest(prompt: string) {
|
||||
model: 'claude-3-5-sonnet-20241022',
|
||||
max_tokens: 2000,
|
||||
temperature: 1,
|
||||
tools: [PersonaTool],
|
||||
tools: [tool],
|
||||
messages: [{ role: 'user', content: prompt }]
|
||||
});
|
||||
|
||||
@@ -33,5 +31,5 @@ export async function makeRequest(prompt: string) {
|
||||
{ type: string; input: object }
|
||||
];
|
||||
|
||||
return content[1].input as Persona;
|
||||
return content[1].input;
|
||||
}
|
||||
|
||||
18
src/utils/createFolder.ts
Normal file
18
src/utils/createFolder.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { promises as fs } from 'fs';
|
||||
|
||||
export async function createFolderIfNotExists(
|
||||
folderPath: string
|
||||
): Promise<void> {
|
||||
try {
|
||||
await fs.access(folderPath);
|
||||
console.log('Folder already exists');
|
||||
} catch {
|
||||
try {
|
||||
await fs.mkdir(folderPath, { recursive: true });
|
||||
console.log('Folder created successfully');
|
||||
} catch (error) {
|
||||
console.error('Error creating folder:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
import { MBTIType } from './types';
|
||||
|
||||
const mbtiTypes: MBTIType[] = [
|
||||
{
|
||||
type: 'INTJ',
|
||||
traits: ['analytical', 'planning-focused', 'independent', 'private']
|
||||
},
|
||||
{
|
||||
type: 'ENTJ',
|
||||
traits: ['strategic', 'leadership-oriented', 'decisive', 'organized']
|
||||
},
|
||||
{
|
||||
type: 'ISFP',
|
||||
traits: ['artistic', 'spontaneous', 'nature-loving', 'adaptable']
|
||||
},
|
||||
{ type: 'ESFJ', traits: ['caring', 'social', 'traditional', 'organized'] },
|
||||
{ type: 'INTP', traits: ['logical', 'abstract', 'adaptable', 'private'] },
|
||||
{
|
||||
type: 'ENFP',
|
||||
traits: ['enthusiastic', 'creative', 'spontaneous', 'people-oriented']
|
||||
},
|
||||
{ type: 'ISTJ', traits: ['practical', 'factual', 'organized', 'reliable'] },
|
||||
{
|
||||
type: 'ENFJ',
|
||||
traits: ['charismatic', 'inspiring', 'idealistic', 'people-focused']
|
||||
},
|
||||
{
|
||||
type: 'ISTP',
|
||||
traits: ['practical', 'adaptable', 'experiential', 'logical']
|
||||
},
|
||||
{ type: 'ESFP', traits: ['spontaneous', 'energetic', 'social', 'practical'] },
|
||||
{
|
||||
type: 'INFJ',
|
||||
traits: ['idealistic', 'organized', 'insightful', 'private']
|
||||
},
|
||||
{
|
||||
type: 'ESTP',
|
||||
traits: ['energetic', 'practical', 'spontaneous', 'experiential']
|
||||
},
|
||||
{ type: 'INFP', traits: ['idealistic', 'creative', 'authentic', 'adaptive'] },
|
||||
{
|
||||
type: 'ENTP',
|
||||
traits: ['innovative', 'adaptable', 'analytical', 'outgoing']
|
||||
},
|
||||
{ type: 'ISFJ', traits: ['practical', 'caring', 'organized', 'traditional'] },
|
||||
{
|
||||
type: 'ESTJ',
|
||||
traits: ['practical', 'organized', 'leadership-oriented', 'traditional']
|
||||
}
|
||||
];
|
||||
|
||||
export function generatePromptWithMBTI(prompt: string): string {
|
||||
const selectedType = mbtiTypes[Math.floor(Math.random() * mbtiTypes.length)];
|
||||
|
||||
const mbtiJson = JSON.stringify({
|
||||
type: selectedType.type,
|
||||
traits: selectedType.traits
|
||||
});
|
||||
|
||||
return prompt.replace('<MBTI_AND_TRAITS_HERE>', mbtiJson);
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import { prisma } from './prismaClient';
|
||||
import { Persona } from './types';
|
||||
|
||||
export async function savePersonaDb(persona: Persona) {
|
||||
const result = await prisma.user.create({
|
||||
data: {
|
||||
name: persona.core.name,
|
||||
age: persona.core.age,
|
||||
persona: JSON.stringify(persona)
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`Persona ${result.name} inserted with ID ${result.id}`);
|
||||
|
||||
return result.id;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import fs from 'fs';
|
||||
import { Persona } from './types';
|
||||
|
||||
export function savePersonaJson(persona: Persona, id: number) {
|
||||
fs.promises.writeFile(`personas/${id}.json`, JSON.stringify(persona), 'utf8');
|
||||
|
||||
console.log(`Persona ${persona.core.name} saved as persona/${id}.json`);
|
||||
}
|
||||
Reference in New Issue
Block a user