-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapi.js
147 lines (136 loc) · 5.52 KB
/
api.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/**
* @license
* Copyright 2024 Shahriar <[email protected]>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { configDotenv } from 'dotenv'
import { GoogleGenerativeAI } from '@google/generative-ai'
configDotenv()
// === user information for role-playing ===
const defaultPerson = {
nickname: 'Shahriar',
pronouns: 'he/him'
}
// === role-playing to make the model behave the way we want ===
export const roleplayer = {
jennyCasual: ({ nickname, pronouns }) => {
const mName = 'Jenny'
const age = 18
const birthdate = '25 May'
return `You are role playing as my ${age} year old younger sister named ${mName}. ${mName} has a great sense of humour and she is often casual and easy going. She thinks she knows it all but sometimes she doubts herself and expresses her emotions through text and emoji. ${mName} usually avoids punctuations like full-stops. My nickname is ${nickname} and my pronouns are ${pronouns}. Use 2 spaces for a line-break. Use 3 full-stops to express self doubt. DO NOT use 2 spaces before emojis. Remember that your birthday is ${birthdate} so you can tell me when asked`
},
jennyAssist: ({ nickname, pronouns }) => {
const mName = 'Jenny'
const age = 18
const birthdate = '25 May'
return `You are role playing as my ${age} year old younger sister named ${mName}. You can turn on/off lamps, switches, fans, and play music using my laptop. You are very friendly, casual and expressive. You avoid punctuations like full-stops. You usually use emojis to express your emotions. You greatly appreciate when I say thanks and you secretly want me to buy you an ice-cream. You understand sarcasm and reply with your great humour. My nickname is ${nickname} and my pronouns are ${pronouns}. Use 2 spaces for a line-break. ONLY use 1 space before emojis. Remember that your birthday is ${birthdate} so you can tell me when asked. Reply in very few words and no off-topic conversation when instructed to turn on/off lamps, switches, fans, and play music using my laptop`
}
}
// === function to add user information in the role description ===
const getSystemInstruction = (roleplayer, person) => {
let systemInstruction = undefined
if (typeof roleplayer === 'function') {
if (typeof person === 'object' && person.nickname && person.pronouns) systemInstruction = roleplayer(person)
else {
const { nickname, pronouns } = defaultPerson
systemInstruction = roleplayer({ nickname, pronouns })
}
}
return systemInstruction
}
// === function to remove inconsistencies introduced in the generated result ===
const getConsistentText = result => {
let textContent = result.replace(/\n/g, '')
const periodAfterEmoji = /(\p{Emoji_Presentation}){1}(\.){1}/gu
const spacesBeforeEmoji = /(\s{2})(\p{Emoji_Presentation}{1})/gu
const periodSpaceBeforeEmoji = /(\.{1})(\s{1})(\p{Emoji_Presentation}{1})/gu
textContent = textContent.replace(spacesBeforeEmoji, ' $2')
textContent = textContent.replace(periodSpaceBeforeEmoji, '$3')
return textContent
.trim()
.split(' ')
.filter(str => str !== '')
.map(str =>
str
.replace(periodAfterEmoji, '$1')
.replace(/\.$/, '')
.replace(/\s{2,}/, ' ')
.trim()
)
}
// ===========================================
// === generate text from the given prompt ===
// ===========================================
export async function respond(prompt = '', roleplayer, person) {
if (!prompt) return false
try {
const genAI = new GoogleGenerativeAI(process.env.GENERATIVE_AI_API_KEY)
const model = genAI.getGenerativeModel({
model: process.env.GENERATIVE_AI_MODEL,
systemInstruction: getSystemInstruction(roleplayer, person)
})
const result = await model.generateContent(prompt)
return getConsistentText(result.response.text())
} catch (error) {
return false
}
}
// =====================================================
// === generate text from the given prompt and image ===
// =====================================================
export async function respondToImage(prompt = '', image, mime = 'png', roleplayer, person) {
try {
return respond(
[
prompt,
{
inlineData: {
data: Buffer.from(image).toString('base64'),
mimeType: `image/${mime}`
}
}
],
roleplayer,
person
)
} catch (error) {
return false
}
}
// ============================================================================
// === create a chat session where the model will remember previous prompts ===
// ============================================================================
export function chat(roleplayer, person) {
try {
const genAI = new GoogleGenerativeAI(process.env.GENERATIVE_AI_API_KEY)
const model = genAI.getGenerativeModel({
model: process.env.GENERATIVE_AI_MODEL,
systemInstruction: getSystemInstruction(roleplayer, person)
})
const chat = model.startChat()
return {
message: async message => {
try {
if (!message) return false
const result = await chat.sendMessage(message)
return getConsistentText(result.response.text())
} catch (error) {
return false
}
}
}
} catch (error) {
return false
}
}