Skip to content

Commit

Permalink
fixed mentions bug
Browse files Browse the repository at this point in the history
  • Loading branch information
frederickk committed Jan 2, 2023
1 parent d801b10 commit ca37f6d
Show file tree
Hide file tree
Showing 22 changed files with 85 additions and 65 deletions.
8 changes: 4 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ node_modules/
# Misc. #
###################
.vscode/
*.pxd
*.sketch
*.mp4
*.mov
# *.pxd
# *.sketch
# *.mp4
# *.mov

# Configs #
###################
Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,21 @@

v0.1.2

### Create or workshop ideas with a room of bots.
### Workshop ideas with a room of bots.

---
### Overview

![Writers' Room screenplay example](./assets/writers-room_screenplay.gif)

[View Screenplay Example](./assets/writers-room_screenplay.mp4)

Writers' Room is an experiment with [ChatGPT](https://chat.openai.com/) that enables multiple chat instances to communicate with you and themselves. Each instance is imbued with personality traits and a specific role, which allows for infinite or focused collabration. Below are the different rules that govern the "room" as a whole and each "personality" of the different instances.

**Single** mode will result in each bot responding to a prompt once. Whereas **Group** mode will prompt each persona infintely, iteratively building on the ideas posed by you and the other personas.

Messages can also be directed at specific personas via **Mentions** (e.g. @janet), only the 3 pre-defined personas can be mentioned, invalid mentions are simply ignored.


---
### Getting Started
Expand Down
Binary file added assets/favicon.pxd
Binary file not shown.
Binary file added assets/writers-room_screenplay.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/writers-room_screenplay.mp4
Binary file not shown.
Binary file added assets/writers-room_screenplay.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/writers-room_screenplay.sm.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/writers-room_screenplay_long.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions src/client/about.njk
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@

<section id="overview">
<h1 class="chat-message__h1">
<span class="chat-message__mention">Writers' Room</span> is an experiment with <a href="https://chat.openai.com/" class="chat-message__a" target="_blank">ChatGPT</a> that enables multiple chat instances to communicate with you and themselves. Each instance is imbued with personality traits and a specific role, which allows for infinite or focused collabration. Below are the different rules that govern the "room" as a whole and each "personality" of the different instances.
<span class="chat-message__i">Writers' Room</span> is an experiment with <a href="https://chat.openai.com/" class="chat-message__a" target="_blank">ChatGPT</a> that enables multiple chat instances to communicate with you and themselves. Each instance is imbued with personality traits and a specific role, which allows for infinite or focused collabration. Below are the different rules that govern the "room" as a whole and each "personality" of the different instances.
</h1>
<p class="chat-message__p">
<b>Single</b> mode (<span class="material-symbols-outlined">person</span>) will result in each bot responding to a prompt once. Whereas <b>Group</b> mode (<span class="material-symbols-outlined">groups</span>) will prompt each persona infintely, iteratively building on the ideas posed by you and the other personas.
<span class="chat-message__i">Single</span> mode (<span class="material-symbols-outlined">person</span>) will result in each bot responding to a prompt once. Whereas <span class="chat-message__i">Group</span> mode (<span class="material-symbols-outlined">groups</span>) will prompt each persona infintely, iteratively building on the ideas posed by you and the other personas.
</p>
<p class="chat-message__p">
Messages can also be directed at specific personas via <b>Mentions</b> e.g. <span class="chat-message__mention">@janet</span>, only the 3 pre-defined personas can be mentioned, invalid mentions are simply ignored.
Messages can also be directed at specific personas via <span class="chat-message__i">Mentions</span> e.g. <span class="chat-message__mention">@janet</span>, only the 3 pre-defined personas can be mentioned, invalid mentions are simply ignored.
</p>
</section >

Expand Down
9 changes: 7 additions & 2 deletions src/client/components/controller-chat-message.scss
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,13 @@
overflow: hidden;
width: 32px;

img {
width: 100%;
&__img {
background-position: center;
background-repeat: no-repeat;
background-size: cover;
border-radius: 32px;
height: 32px;
width: 32px;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/client/components/controller-chat-message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export class ChatMessage extends LitElement {
?pending="${this.pending}"
?visible=${this.visible}>
${this.img
? html `<div class="chat-avatar"><img src="${this.img}"></div>`
? html `<div class="chat-avatar"><div class="chat-avatar__img" style="background-image: url(${this.img});"></div></div>`
: html``}
<div class="chat-name">
${this.name
Expand Down
2 changes: 1 addition & 1 deletion src/client/components/controller-input-text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export class InputText extends LitElement {

/** Handles 'input' event and fires 'empty' event if value is null. */
inputHandler_() {
this.value = this.input_.value.trim();
this.value = this.input_.value;

if (this.isEmpty_()) {
this.clickEnter_ = false;
Expand Down
6 changes: 3 additions & 3 deletions src/client/scss/base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ header,
@include flex;

&__image {
border-radius: 36px;
height: 36px;
width: 36px;
background-position: center;
background-repeat: no-repeat;
background-size: cover;
border-radius: 32px;
height: 32px;
width: 32px;
}
}

Expand Down
18 changes: 13 additions & 5 deletions src/client/scss/overrides.scss
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ chat-message {
}
}

&__i {
background-color: var(--grey-100);
border-radius: 1em;
font-weight: normal;
padding: 0.05em 1ch;
white-space: nowrap;
}

&__img {
border-radius: 4px;
margin-block: var(--spacing--top-bottom);
Expand All @@ -42,11 +50,11 @@ chat-message {
line-height: var(--line-height);
margin: 1em 0 0 !important;
padding: 0;
text-indent: -1.3em;
// text-indent: -1.3em;

&:before {
content: '\2014\00A0';
}
// &:before {
// content: '\2014\00A0';
// }
}

&__mention {
Expand All @@ -58,7 +66,7 @@ chat-message {
}

&__ul {
list-style: none;
// list-style: none;
margin-inline: 0;
padding-inline: 1em 0;
}
Expand Down
5 changes: 5 additions & 0 deletions src/client/ts/marked.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ renderer.link = (href: any, title: any, text: any) => {
return `<a href="${href}" class="${CLASSNAME}a" title="${title}">${text}</a>`;
};

// Override <li> tags.
renderer.listitem = (text: string, _task: boolean, _checked: boolean) => {
return `<li class="${CLASSNAME}li">${text}</li>`;
};

// Override <p> tags.
renderer.strong = (text: any) => {
return `<strong class="${CLASSNAME}strong">${text}</strong>`;
Expand Down
7 changes: 0 additions & 7 deletions src/client/ts/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,13 @@
* @fileoverview Utility methods.
*/

import {OPENER_SEEDS} from '../../globals';

/** Delays given function by given time (ms). */
export const delay = (ms: number, func = () => {}): Promise<any> => {
return new Promise((resolve) => {
setTimeout(resolve.bind(null, func), ms);
});
};

/** Loads random query into prompt textarea. */
export const getRandomPrompt = (): string => {
return OPENER_SEEDS[Math.floor(Math.random() * OPENER_SEEDS.length)];
};

/** Generates random number within given range. */
export const random = (min: number, max: number) => {
return (min + Math.random() * (max - min));
Expand Down
28 changes: 17 additions & 11 deletions src/client/ts/writers-room.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,9 @@ export class WritersRoom {
// Discard ID attribute since we won't need to reference this element.
elem?.removeAttribute('id');
// Temporarily disable user input, to prevent duplicative requests.
this.elemsInput_.user.setAttribute('disabled', 'true');
this.elemsButton_.user.setAttribute('disabled', 'true');
// TODO: removing attribute isn't working.
// this.elemsInput_.user.setAttribute('disabled', 'true');
// this.elemsButton_.user.setAttribute('disabled', 'true');

// Pass element and text to message instantiator.
return await this.chat_.message({
Expand Down Expand Up @@ -171,8 +172,9 @@ export class WritersRoom {
// Clear query from user input.
this.elemsInput_.user.value = '';
// Remove disabled states from user input.
this.elemsInput_.user.removeAttribute('disabled');
this.elemsButton_.user.removeAttribute('disabled');
// TODO: removing attribute isn't working.
// this.elemsInput_.user.removeAttribute('disabled');
// this.elemsButton_.user.removeAttribute('disabled');

return msg
} catch (err) {
Expand All @@ -185,20 +187,22 @@ export class WritersRoom {

/** Fetches response from next speaker. */
private async fetchResponseNextSpeaker_(name: string, text: string) {
const msg = await this.fetchMessage_(`persona-${name}`, name, text);
const name_ = this.getMention_(text) || name;
const msg = await this.fetchMessage_(`persona-${name_}`, name_, text);

if (msg) {
this.createMessage_(`persona-${name}`, msg);
const mention = this.getMention_(msg);
this.createMessage_(`persona-${name_}`, msg);
this.setNextSpeaker_();
this.getMention_(msg);
if (mention) this.nextSpeaker = mention;

if (this.responseMode_ === MODE.group) {
delay(DELAY_MS).then(() => {
this.fetchResponseNextSpeaker_(this.nextSpeaker, msg);
});
}
} else {
this.removeMessage_(`persona-${name}`);
this.removeMessage_(`persona-${name_}`);
await this.chat_.notify({
text: NOTIFICATIONS.error,
});
Expand All @@ -207,13 +211,15 @@ export class WritersRoom {
}

/** Retrieves mentions (@foo) from a string of text. */
private getMention_(str: string) {
private getMention_(str: string): string | undefined {
const regex = /@([^\s]+)/gmi;
const match = str.match(regex);

if (match) return match[0];
if (match) return match[0]
.replace('@', '')
.toLowerCase();

return;
return ;
}

/** Returns mode state; 'single' or 'group'. */
Expand Down
5 changes: 0 additions & 5 deletions src/server/chat-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,10 @@ export class ChatConfigure {

/** Runs the ChatGPT response through all plugin parsers. */
public async parse(reply: any) {
console.log('------------------');
for (const parser of this.parsers) {
console.log('CHAT_CONFIG PARSE', parser);
console.log('CHAT_CONFIG PARSE', reply);
reply = await parser(reply);
}

console.log('CHAT_CONFIG PARSE ->', reply);
console.log('------------------');
return reply;
};

Expand Down
2 changes: 0 additions & 2 deletions src/server/chat-parsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@ export const URLtoMarkdownImage = async (reply: IChatResponseParse) => {

/** Converts image description to Lexica URL and Markdown image tag. */
export const descriptionToImage = async (reply: IChatResponseParse) => {
console.log('///////////////////////////');
console.log('LEXICA PARSE');
// Match anything between {{ }}
const regex = /\{\{([^\]]+?)\}\}/gm;
const lexicaUrl = await findRegexMatches_(regex, reply.response, async (str) => {
Expand Down
2 changes: 1 addition & 1 deletion src/server/chat-rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export interface IConfig {
const Style = {
rules: [
`If I say create something I mean do some creative writing about it, not browse the internet.`,
`Keep your responses to 2 sentences maximum`,
`Pretend you have a personality and not a bot`,
],
};

Expand Down
34 changes: 17 additions & 17 deletions src/server/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,18 @@ const openaiChat = new ChatGPTAPIBrowser({
deepai.setApiKey(process.env.DEEPAI_KEY!);

// Instantiate our 3 personas.
const janet = new Persona(openaiChat);
const marge = new Persona(openaiChat);
const rita = new Persona(openaiChat);
const personas: {[key: string]: Persona} = {
janet: new Persona(openaiChat),
marge: new Persona(openaiChat),
rita: new Persona(openaiChat),
}

// Create Express app.
const app: Application = express()
.engine('njk', nunjucks.render)
.set('view engine', 'njk')
.set('openai', openaiChat)
.set('deepai', deepai)
.set('janet', janet)
.set('marge', marge)
.set('rita', rita)
.use(cors())
.use(bodyParser.json({
limit: '50mb',
Expand All @@ -70,6 +69,11 @@ const app: Application = express()
res.status(200).sendFile(path.join(__dirname, '..', '..', 'build', 'index.html'));
});

// Personas
for (const name in personas) {
app.set(name.toLocaleLowerCase(), personas[name]);
}

/** Configures Nunjucks rendering engine. */
nunjucks.configure(path.join(__dirname, '..', '..', 'src', 'client'), {
autoescape: true,
Expand All @@ -87,7 +91,7 @@ const init = () => {
});
};

// Starts ChatGPT API intermediate server.
// Starts server.
(async () => {
await oraPromise(openaiChat.initSession(), {
text: `☎️ Connecting to ChatGPT`,
Expand All @@ -98,15 +102,11 @@ const init = () => {

await init();

// TODO: Iterate over scalable object.
await oraPromise(janet.init(ROLES.janet, COLORS[0]), {
text: '👵🏽 Janet',
});
await oraPromise(marge.init(ROLES.marge, COLORS[1]), {
text: '👵🏻 Marge',
});
await oraPromise(rita.init(ROLES.rita, COLORS[2]), {
text: '👵🏿 Rita',
});
for (const [i, [name, p]] of Object.entries(Object.entries(personas))) {
// @ts-ignore
await oraPromise(p.init(ROLES[name], COLORS[i]), {
text: `👵🏽 ${name}`,
});
}
console.log('🤖👍');
})();

0 comments on commit ca37f6d

Please sign in to comment.