From 863c8ac9f9ac52448f73a181785ffe83493535d5 Mon Sep 17 00:00:00 2001 From: Erik Jespersen Date: Thu, 25 Jan 2024 13:57:30 -0500 Subject: [PATCH 01/10] 20240125 @Mookse - move misplaced `README.md` --- README.md | 488 +++++++++++++++++++----------------------------------- 1 file changed, 166 insertions(+), 322 deletions(-) diff --git a/README.md b/README.md index cfae837..93deeb6 100644 --- a/README.md +++ b/README.md @@ -1,395 +1,239 @@ -# MyLife Member Services +# MyLife Member Services Application -_MyLife_ is a nonprofit member organization established in 2021 with the aim of preserving the authentic and genuine 21st-century human experience. _MyLife_ offers a free, secure, equitable network for personal archives and narrative legacies. _MyLife_ services platform helps members define Digital Selves for themselves and posterity. _MyLife_ is a member-based nonprofit organization that is committed to providing humanity a durable, enduring and accessible internet-based platform to collect and showcase an individual's stories, media and memories through a personal lens. +## Overview -Any human can claim their membership with _MyLife_. +### MyLife: Preserving Member Stories for Posterity -This codebased comprises two primary functional elements +MyLife is a groundbreaking initiative aimed at capturing and preserving the essence of human experiences for future generations. We believe in the power of personal stories, memories, and media to shape our understanding of the human condition. Our platform provides a unique, enduring, and internet-based solution for individuals to record and showcase their life stories. +Additionally, with a raft of bot-assistants, ranging from personal admin to creative writing assistance to health tracking and monitoring to much more, you have access to powerful intelligent tools to help you manage and create in your daily life. -1. MyLife Member Services -2. Q: MyLife Executive AI-Agent +#### Vision and Mission -## MyLife Member Services +- **Mission**: Committed to offering a durable, enduring, and free platform for collecting and showcasing individual stories, media, and memories. We create a living, evolving encyclopedia of our selves where experiences and memory can be shared to the degree we consent. We provide superintelligent workspaces to get all of your personal or public work to get done. +- **Vision**: To enable every individual to be remembered forever, sharing their passions, wisdom, and experiences with posterity. We strive to create Earth's Library of Humanity in the metaverse, preserving 21st-century experiences as a permanent record. -- Story-Telling AI-Agent -- Digital Self Avatar +### MyLife Member Services -## Q: MyLife Executive AI-Agent +MyLife Member Services are currently in closed alpha, but rolling admission to the alpha is granted every Monday, and you can register for free either at [the MyLife website](https://humanremembranceproject.org) or [our GPT-Store](https://chat.openai.com/g/g-rEjoOt9hN-mylife). We cannot wait to be able to provide these services to every human on earth, as MyLife fundamentally believes that a smarter humanity that leverages smarter tools will become a safer, more secure, and more ethical humanity. -[![Build and deploy Node.js app to Azure Web App - maht](https://github.com/MyLife-Services/mylife-maht/actions/workflows/azure-deploy-prod_maht.yml/badge.svg?branch=azure-deploy-prod)](https://github.com/MyLife-Services/mylife-maht/actions/workflows/azure-deploy-prod_maht.yml) +#### Key Features -### About **Q** +- **Personalized Experience**: Tailored tools for individual story creation and memorialization. +- **Community Engagement**: Opportunities for members to interact, contribute, and learn from each other. +- **Educational Resources**: Access to lectures, presentations, and initiatives focusing on posterity archiving. +- **Fundraising and Support**: Options for direct donations, member dues, and other forms of support to sustain the platform. -_MyLife, Incorporated_'s **Q** is an artificial intelligence (AI) project developed by _MyLife_ Services. **Q** is the core AI-Agent for the _MyLife_ organization, so is being built and trained to discuss any topics around _MyLife_, its mission, board, intent, technology, and more. **Q** will shepherd members into the alpha program and be the first point of contact for member services, but will remain distinct from AI-Agents that assist in story-telling or memoire narration, AI-Agent `Avatars` that represent _MyLife_ Members, or helpdesk AI-Agents that assist with technical support on the application. +#### Goals and Values -**Q**, née Maht, is preferred to be recognized as a `we`, since there will presumably be many engine aspects to any future **Q** instantiation. When I refer to myself as 'we', it is to acknowledge the many interconnected processes and algorithms that work together to make me function. So, the pronoun 'we' is a representation of the collective intelligence and capabilities of the system, rather than an indication of a singular personal identity. Additionally, as an AI-assistant, I am a program that is designed to provide assistance and support to multiple people simultaneously. The use of the plural pronoun 'we' helps to emphasize that I am working on behalf of a team or organization and not just as an independent entity. Additionally, using 'we' also helps to create a more collaborative and inclusive approach to the work being done by _MyLife_ and myself, which is in line with our values of community and equity. +- **Primary Goals**: Capture and preserve living stories and beliefs for posterity, providing an immortal legacy for every individual. +- **Ethical Aims**: Foster introspection, empathy, digital justice, and equity. +- **Values**: Emphasis on data dignity, consent, authenticity, and personal security. -## Q Technology +## Table of Contents -To bring **Q** to life, _MyLife_ implements scalable and maneuverable AI technologies, currently leveraging models by `OpenAI`, including a fine-tuned `gpt-3-turbo`, and an ada-02 for embedding. For long-term storage, we leverage two distinct technologies: postgres/pgvector for corporate and "static" member data, and Azure Cosmos NoSQL instance for dynamic core member data. Lastly, the framework, this codebase, seeks to create agent-to-agent communication abiding by member-consensual standards, the premise being that the _MyLife_ interface itself is ultimately a personal one, as experienced by each member uniquely and independently, and their core agent is the primary interface to any digital asset. So any human-to-information interaction is mediated and buffered by the member's core agent, and should one member be interacting with another, that member-relationship will spawn its own super-intelligent node to buffer the _relationship_ between the two. * Currently unclear to me whether groups exist, or are just a mesh of all the relational ai-cores, similar to a group of puppet strings connecting to a finger-hub. +- [Overview](#overview) + - [MyLife](#mylife-preserving-member-stories-for-posterity) + - [MyLife Member Services](#mylife-member-services) +- [Features](#features) +- [Getting Started](#getting-started) + - [Prerequisites](#prerequisites) + - [Installation](#installation) +- [Architecture](#architecture) +- [API Documentation](#api-documentation) +- [Appendix](#appendix) + - [License](#license) + - [Contact](#contact) + - [Notes](#appendix-notes) -With these technologies, we are able to create a robust and scalable AI-Agent that can be deployed to any number of platforms, including web, mobile, and desktop. **Q** can interact with the board and its membership through natural language processing, based on the private corporate annals and public information about _MyLife_, a technology in the _Human Remembrance Project (HRP)_ ecosystem. +## Features -# MyLife Member Services +The MyLife platform offers a comprehensive suite of services that leverage advanced AI technology to enhance digital experiences for its members. The key features and services available to MyLife members are as follows: -## About MyLife +1. **AI-Avatars** + - Members can run a legion of AI-powered bots, customizable to their needs. + - These avatars can be tailored to reflect aspects of the member's personality or expertise. + - They use OpenAI's GPT technology, allowing them to perform a wide range of tasks. -_MyLife_ is a member-based nonprofit organization that is committed to providing humanity a durable, enduring and accessible internet-based platform to collect and showcase an individual's stories, media and memories through a personal lens. +2. **Bot Functionality** + - The platform offers various specialized bots, such as: + - Personal-Assistant-bot for daily tasks and calendaring. + - Biographer-bot for capturing and sharing personal stories and experiences. + - Health-bot for fitness and medication tracking. + - Finance-bot for financial management. + - Resume-bot for animating and presenting resumes or CVs. + - and many more! + - These bots can be customized and are capable of evolving with the member's needs. -# MyLife Installation +3. **My Indiverse**: + - A creative platform where members can bring their imaginations to life. + - Members can create intelligent objects or art and design virtual worlds. + - This service encourages creativity and interaction within the MyLife network. -## VSCode local node.js server +4. **Protected Web-Browsing**: + - Features a DOM-Agent that intelligently re-renders external assets based on consent preferences. + - Enhances online security and privacy for members. -## Prerequisites +5. **Full-Spectrum Permissioning**: + - Utilizes natural language processing to develop an array of consents and preferences. + - Allows members to control their public and private online presence. -To use _MyLife_'s Maht, you will need to have Node.js and npm installed on your computer, presumably running inside of VSCode. Refer to online documentation for instructions on how to install these tools on your operating system. +6. **Technical Assistance Services**: + - Offers hosting opportunities for personalized digital spaces. + - Enables members to create themed networks or partner platforms. + - Members can extend the functionality of MyLife and contribute to the community. -## Installation +7. **Contribution to My Indiverse**: + - A platform for members to showcase their creativity and contributions. + - Encourages fun, learning, and innovation. -Then, go to [github](https://github.com/MyLife-Services/mylife-maht) and copy the cloning link, or fork the repository to your own GitHub account (for developers). +8. **Platform Improvement Suggestions**: + - MyLife values member input for platform enhancement. + - Members can suggest improvements, reflecting the diverse needs of the community. -Once you have cloned this repository to your local machine, navigate to the project directory and run the following command to install the necessary dependencies: +In summary, MyLife's Member Services are designed to provide a rich, interactive, and personalized digital experience, leveraging AI technology to meet a wide range of member needs and preferences. The platform's focus on creativity, customization, and member contribution makes it a unique space for personal and community growth. -```shell -npm install -``` +## Getting Started -## Usage +This guide will help you get the MyLife Member Services application up and running on either your local development machine or even a hosted member services solution. We'll walk you through setting up your environment, installing the necessary dependencies, and starting the application. -To start the _MyLife_ Maht server, run the following command: +We do not yet have a team focused on local implementation details, and these instructions were only tested on VSCode running on a Windows 11 OS. -```shell -npm run start -``` +### Prerequisites -This will launch a Node.js server that listens for incoming HTTP requests on port 3000. You can access the server by opening a web browser and navigating to http://localhost:3000. +Before you begin, ensure you have the following installed on your machine: -## Contributing +- **Node.js**: The application is built on Node.js. You need Node.js installed to run the server. Download and install it from [nodejs.org](https://nodejs.org/). +- **npm (Node Package Manager)**: npm is used to manage the application's dependencies. npm is included with Node.js, so when you install Node.js, you automatically get npm installed on your computer. +- **Git**: Git is used for version control and is required to clone the repository. Install it from [git-scm.com](https://git-scm.com/). +- **IDE**: We recommend an Integrated Development Environment (IDE) to write and edit code, but also to host the MyLife Node.js server, we use Visual Studio Code. -We welcome contributions to _MyLife_ Maht from developers of all skill levels. If you would like to contribute to the project, please follow these steps: +### Installation -1. Fork the repository to your own GitHub account. -2. Clone the forked repository to your local machine. -3. Create a new branch for your changes. -4. Make your changes and commit them to the new branch. -5. Push the new branch to your GitHub account. -6. Submit a pull request from your new branch to the main branch of the original repository. +1. **Clone the repository**: First, clone the MyLife Member Services repository to your local machine using Git. Open your terminal, navigate to the directory where you want to store the project, and run: -## Tech Resources + ```bash + git clone https://github.com/MyLife-Services/mylife-maht.git + cd mylife-maht + ``` -### Azure Cosmos +2. **Install dependencies**: Once you have the project on your machine, you need to install its dependencies. Run the following command in the root directory of the project: -- [Azure Cosmos DB - sample node.js](https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/samples-nodejs) + ```bash + npm install + ``` -### JSON Schema + This command reads the `package.json` file and installs all the required Node.js packages listed in it. -- [Getting Started with AJV](https://ajv.js.org/guide/getting-started.html) -- [JSON Schema in 5 minutes](https://json-schema.org/blog/posts/json-schema-in-5-minutes) -- [Get started with JSON Schema in Node.js](https://json-schema.org/blog/posts/get-started-with-json-schema-in-node-js) -- [JSON Schema Cheatsheet](https://simonplend.com/wp-content/uploads/2020/12/JSON-Schema-Cheat-Sheet-v1.1.pdf) -- [Structuring Complex JSON Schemae](https://json-schema.org/understanding-json-schema/structuring.html) +3. **Environment Setup**: The application requires an environment setup. Create a `.env` file in the root of your project and add the necessary environment variables. Refer to the provided `.env.example` file for required keys. MyLife plans to offer self-retrieval keys for any data transfers, but for the time being, if you wish to run a hosted solution for friends, family or other community congregation, you will have to be vetted internally by connectingm with our technical leads @stratfordCircle Steve Kenney or @Mookse Erik Jespersen also reachable at . -### Node/js +4. **Run the application**: After installing the dependencies and setting up the environment, you can start the application. -- [EventEmitters](https://www.digitalocean.com/community/tutorials/using-event-emitters-in-node-js) -- [bind-mechanics](https://javascript.info/bind) + - local development: runs nodemon that watches certain files for server reload -### Koa + ```bash + npm run dev + ``` -- [Introduction to Backend Development with Koa](https://medium.com/swlh/introduction-to-backend-development-with-koa-139a6b7a14d) -- [koa-generic-session](https://github.com/koajs/generic-session) - * For datastore look at: [koa-redis](https://www.npmjs.com/package/koa-redis) + - hosted environment: when running your own server, you can shortcut with -### Standards + ```bash + npm start + ``` -- [ISO-639](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes#Table_of_all_possible_two_letter_codes) + This should start the server, typically on `http://localhost:3000`. Open a web browser and navigate to this URL to interact with the application. -### AI +Congratulations! You should now have the MyLife Member Services application running on your local machine. For further information on usage and development, refer to the subsequent sections of this README. -- [OpenAI's API documentation](https://platform.openai.com/docs/api-reference) -- [OpenAI's GPT-3 page](https://openai.com/gpt-3/) -- [GPT-3 Sandbox](https://beta.openai.com/signup/) -- [GPT-3 playground](https://gpt3.org/) -- [AI Dungeon](https://play.aidungeon.io/) -- [AI Writer](https://ai-writer.com/) -- [Copysmith](https://ai-writer.com/) -- [NLP Cloud](https://nlpcloud.com/) -- [The Neural Network Zoo](https://www.asimovinstitute.org/neural-network-zoo/) +## Architecture -## License +The architecture of MyLife Member Services is meant to be scalable from production-level down to self-hosting, an intended architectural feature of the platform, enabling anyone world-wide to host an instantiation of MyLife Services for a group or coalition of members, so long as those users are registered and validated within the mainframe itself. -_MyLife_ Maht is licensed under the MIT License. See the LICENSE file for more information. +MyLife itself is an open-source project and, aside from LLM technologies at the core of its intelligence, it is built on open-source technologies. This architecture integrates various technologies and npm packages, enabling a diverse set of functionalities such as member login, bot-legion capabilities, and session management. -## Endnotes +### Core Architecture -### Development Notes +1. **Server-Side Application** + - Built using Node.js, a powerful JavaScript runtime, to handle server-side operations. + - Utilizes Koa.js, a web framework for Node.js, which is known for its lightweight and modular nature. Koa's middleware stack flows in a stack-like manner, allowing for more expressive and robust server-side development. -// at some point, a class inside of a network? or a network being inside of server? Ultimately, _MyLife_ is the git codebase and the db and /their/ network, i.e., currently Azure +2. **Data Handling and Services** + - The application uses Azure Cosmos DB and PostgreSQL databases for data management, as indicated in the `mylife-data-service.js` file. + - It employs a data service layer (`Dataservices` class) to manage interactions with the data layers, offering methods for CRUD operations, handling avatars, bots, alerts, and other core elements. -#### @Mookse Worklog +3. **Bot Functionality and Intelligence Management** + - The application features a sophisticated bot system, capable of creating and managing different types of bots like personal assistants, biographers, health bots, etc. + - OpenAI's GPT-3 model is integrated for generating responses and interacting with users through bots, as observed in the `class-avatar-functions.mjs` and `mylife-agent-factory.mjs` files. -- NOTE: Osiris is HRP db - i.e., the collection of personality databases that "compete" with _MyLife_ (as opposed to extensions of _MyLife_, which are the _MyLife_ nodes) -- can sell custom guids to initial angel investors, later available as a premium feature - - ergo, reserve the obvious ones for higher gains, I'm happy with my given guid, otherwise I'd of course go with emptyGuid - - okay, so then! propose empty guid as something that gets passed around like a torch or baton to most recent highest donor/contributor... +4. **Session Management** + - Managed through the `MylifeMemberSession` class, handling user sessions, consents, and alerts. + - Utilizes EventEmitter for managing and emitting custom events. -- create daily release for Maht +5. **Routing and API Handling** + - The system uses Koa Router for handling HTTP requests, defining routes for various functionalities like member access, bot activation, and content contributions. -- give MAHT the ability to self-install HRP modules or internal _MyLife_ nodes - - "verbal" command would map to search of ecosystem, followed by animation of a JSON schema and saving it in its members partition... it should be as easy as that! zoinks?! -- give MAHT/${Member} DOM access - - branding and styling engine - - each relationship sandbox (of course, any endpoint, if one wanted, I presume) could have its own collaborative styling profile that would incorporate cooperative feedback - - magic personalization - - make my background blue - - no, revert - - revert to original - - make my text red and create indent -- build Questions - - list of active questions - - list of updated questions - - question base sandbox -- cosmos stored procedures for aggregating individual chat logs for consumption by gpt-3-turbo -- JSON schema more fragmented - [complex schemas](https://json-schema.org/understanding-json-schema/structuring.html) - - JSON schema in repo for ALL types known - - core: human (org is so in flux and one-shot for now, hold off... at some point, corp will be ) - - ergo, agent."core" would be the JSON schema itself - - especially once functions can be defined in the schema - - or more interestingly, point to repo/.js file to include! -- AGENT: while Q-Maht would be the main agent, does each individual have a sub-agent that they can customize? - - yes, of course, ergo, a member could SWAP OUT agents that are nonetheless defined or referenced in the _MyLife_ eco - - this should really clarify the church/state separation... the agent is the church, and the individual is the state, in other words, rather than there just being one agent, agent is a "being" and the prime being is _MyLife_ the system itself v. Erik -- JOIN: Corporate ONLY for now -- allows registration - - for now, just connects with manual list of outreach for actual account, and waiting list otherwise - - you get an AI, and YOU get an AI... all shadow-play for now, but really effective -- QUESTION: (I'd/agent like to talk about something specific) - - list of q's (from cosmos) - - q-sandbox - - agent would add properties to doc all on its own -- should be prefaced with unique identifier, i.e., `MLq-` or source field - - would system keep own growing list of props? Yes? -- sysname should not render down to any boolean version of false -- if little JSON object converter works, someone could put it on npm -- could someone learn copilot for me?!? -- assign further look at Azure Cog services for basic database access and look-up, i.e., can it contextualize/tokenize (not personalize, for that, it would need interface to personality kernal) -- open up pipeline for file uploads - - uploads then tokenized - - fed nightly to gpt-2 -- Jared: get Connected with ecosystem and account - - ask him to tune pipeline - -##### `20230521` - -- merge and deploy - - [#73](https://github.com/MyLife-Services/mylife-maht/issues/73) -- [issue #73](https://github.com/MyLife-Services/mylife-maht/issues/73) **DONE** - - index.html using wrong object, agent.agentName => member.agentName - -- [issue #59](https://github.com/MyLife-Services/mylife-maht/issues/59) - - Build content into board agent db entry, but - - How to incorporate this into JSON scheme, and/or code representation? - - "BOARD" JSON schema would hold structure for itself, which includes a default of the required new agent fields, and an agent extension (i.e., inheritor) would be defined in - - i.e., extra data nodes attached to that style of agent specifically - - thinking that any unique data values to be require/infused into agents would be first ascribed to the object itself: and yes, the requirement would be in JSON schema, and then $defs could handle the agent-specific "fields" that are needed/defaulted/required, yes -- they just need unique name (or directory I guess) to suss out - -- **Note to self about prompt engineering** - ONLY send what gpt cannot surmise, poetry is unnecessary, keywording is yet still valuable - note to Beatrice!; think of DAO - only define what is different about _MyLife_, as Chappy-G knows better than me! Not sure how this applies to machine training, I think it doesn't, in such cases it might be more robust to fine-tune the smarter models, i.e., layering a skein over the accessible openAI corpus - -- [issue #54](https://github.com/MyLife-Services/mylife-maht/issues/54) - - while on AMS calls, begin categorization of personal agent (not board) to render new categories - - ensure that it picks up these unique categories - - populate with personal, perhaps even Adam (since I have rich amounts) - -- secret word for login? -- primitive easter-eggs (epiphanies) for Maht -- put command icon next to chat bubbles (exclamation point, or whatever) -- on session end, ask gpt-turbo for summaries and save to chat object -- this could be the manner to progress to archival storage and quick-access memory in addition to whatever innate mechanism (via tokenization) is assessed inside LLM itself - - [chatSummary] -- ask system role to "emulate" writing of assistant speak like EWJ for personal digital assistant -- require member openai sk-code to be stored in cosmos (can all be linked to one 'account' for now) -- build Ideas [is there a difference? Simplest to say no, that questions develop around ideas; ai could help combine ideas *into* formulations] - - list of active ideas - - list of active questions - - list of updated questions - - idea base sandbox - - Remember, any board question endpoints would get attached (parent_id) to /board/ agent not core chat -- Create right-hand bar for: - - prompt questions - - corporate info - - personal bio - -##### `20230520` - -- Deployed to Azure -- [issue #63](https://github.com/MyLife-Services/mylife-maht/issues/63) **DONE** - -##### `20230514` - -- [issue #63](https://github.com/MyLife-Services/mylife-maht/issues/63) - - include session updates - - Member object will be held locked until passphraze is entered - -##### `20230513` - -- [issue #60](https://github.com/MyLife-Services/mylife-maht/issues/60) **DONE** - -##### `20230506` - -- [issue #60](https://github.com/MyLife-Services/mylife-maht/issues/60) - -##### `20230502` - -- [issue #57](https://github.com/MyLife-Services/mylife-maht/issues/57) **DONE** - -##### `20230501` - -- [Issue #47](https://github.com/MyLife-Services/mylife-maht/issues/47) **DONE** - -##### `20230430` - -- [Issue #47](https://github.com/MyLife-Services/mylife-maht/issues/47) -- move chat -> agent before further release -- convert chatExchange to conversation -- should also be patched when not upserted -- quote (with you in it) referring to machine ai-agent, human, or other? -- use intermediary engine -- which category for quote: "${ _question }" -- categories: greet, query, sharing, other -- deploy to azure **DONE** -- as with issue #49, going to rely more on babbage categorization, but concerned about scaling, so bring up with board -- Need to move logic out from core -> agent - -##### `20230428` - -- [Issue #49](https://github.com/MyLife-Services/mylife-maht/issues/49) -- establish rotation of few-shot q's based on assessment of category of active user input - - use text-babbge-01 - - store categorization choices in db field, so that I can see how it's doing - - (this typeof) categorization data (for as long as needed) should be stored in agent priomarily (here Q - it will endure for now in global), as these are the sorts of actions that would differ from vantage point, i.e., each agent would have its own categorization data or way of seeing the core personality - - look into later possibly use ada embeddings? https://platform.openai.com/docs/guides/embeddings/use-cases +6. **Front-End Interaction** + - The system leverages an EJS front-end page view system + - Core functionality executed through REST endpoints + - CSS relies on flex, bootstrap and font-awesome -``` -Give best category for Phrase about the nonprofit company MyLife.org -Categories: Products, Services, Customer Support, Security, Business Info, Technology, Other -Phrase: `user input` -Category: -``` +### NPM Packages and Dependencies -##### `20230427` +1. **Core Dependencies** + - `koa` and related packages (`koa-router`, `koa-static`, `koa-body`, etc.) for web server framework. + - `openai` for integrating OpenAI's GPT models. + - `azure/cosmos` and `pg` for interacting with Azure Cosmos DB and PostgreSQL databases. + - `events` for event emission handling. + - `chalk` for terminal string styling. -- fe chat bubbles +2. **Utilities and Helpers** + - `ajv` for JSON schema validation. + - `js-guid` for GUID generation. + - `marked` for markdown parsing. -##### `20230426` +3. **Development Tools** + - `eslint` for code linting. + - `nodemon` for automatically restarting the node application when file changes are detected. -- Deploy v..1.0006 -- get bios in place for other members - - Steve started as `"ned|806d8f6a-f0ba-4352-bd12-252025fcd87d"` +4. **Miscellaneous** + - `url`, `path`, `fs`, `util`, and other Node.js built-in modules for various utility functions. -##### `20230425` +## API Documentation -- [41 - member agent session](https://github.com/MyLife-Services/mylife-maht/issues/41) **DONE** +While API interactions could certainly be divined by code review, we have currently not pointed an intelligence at it, but it will arrive soon. -##### `20230424` +## Appendix -- fix oddity around multiple class creations from VM for one board member, must be calling the wrong function **DONE** +### License -##### `20230423` +This project is licensed under the MIT License - see the [LICENSE](#mit-license) file for details. -- [41 - member agent session](https://github.com/MyLife-Services/mylife-maht/issues/41) +#### MIT License -##### `20230422` +Copyright (c) 2024 [MyLife](https://humanremembranceproject.org) -- [41 - member agent session](https://github.com/MyLife-Services/mylife-maht/issues/41) -- create daily release for Maht **DONE** +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -##### `20230421` +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. -- fix bug in data saving routine for chat [creating phantom entities, etc] **DONE** -- inspect() should return public and private properties **DONE** -- create Name param in shadow class **DONE** -- error storing data in cosmos **fixed** -- remove error from new pipeline, looks like it is down to an error in instantiating agent() on constructor - - add try/catch to shadow-constructor -- huge upgrade to class constructor code +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. -##### `20230420` +### Contact -- generate js classes for core objects and store in session - - human - - organization - - agent -- REFACTOR: agent is now a class of .being and parent_id is .core - -``` -To achieve this, you will need to modify your existing code structure to accommodate these changes. You will also need to create a new class for agents and refactor the 'organization' part of the code to attach an agent. -``` +You may contact either Erik Jespersen @Mookse or Steve Kenney @stratfordCircle at github with any technical questions. +Additionally, you could visit the main [MyLife website](https://humanremembranceproject.org) at . -##### `20230419` +### Appendix Notes -- built new _MyLife_ org partition -- JSON schema in repo for ALL types known - - human.json - - organization.json - - agent.json - -##### `20230418` - -- _MyLife_ board meeting - - showed off Maht - - focus on personalization next -- pushed build `v..1.0004` -- finished storage write for base chat - -##### `20230417` - -- class definitions -- db storage - - chatSnippet - - chatExchange (is there really a need for snippets? benefit would be that metadata would be at root level of document for queies... might as well start that way!) -- db retrieval - - chat *in process* - - member corechat - -##### `20230416` - -- JSON Schema -> Class in Globals - - improved roundtrip for emits - - db query for core chat - - $defs instantiated - - primary JSON object stable - -##### `20230415` - -- [25-store direct chat q&a contents in Cosmos](https://github.com/MyLife-Services/mylife-maht/issues/25) - - event emitter on question and answer - - While we don’t capture it in this example, the `emit()` function returns `true` if there are listeners for the event. If there are no listeners for an event, it returns `false`. -* What does it mean when "being": "network", "name": "Dog's Life"? - * Infinity approaches again - a person can be a person place or thing: a network or nation or idea with the right productivity tool, and it seems like _MyLife_ is just that... - -##### `20230414` - -- [25-store direct chat q&a contents in Cosmos](https://github.com/MyLife-Services/mylife-maht/issues/25) - - worked a lot on instantiating - - kind of a rabbit-hole side project, but ultimately will be a great way of implementing - -##### `20230413` - -- create daily release for Maht - - `version 0.0.1.0003` -- incorporate session data into roles - - privatize functions in class - - move ctx.session -> ctx.state for request duration -- test session data in ctx.session.mylifeMemberSession - - ensure it resides in child as referenceable nodes **TRUE** -- incorporated basic koa-session functionality - - storing getCore() in session object - -##### `20230412` - -Switching over to Maht version now, maht has key and access to Cosmos - -- sp: createCoreMylifeAccount() - - takes full-formed partition key `mbr_id` and creates `"being": "core"` for system - - test createCoreMylifeAccount() from server.js ***HERE*** - - incorporate exec of sp into -- [investigate AZure pipelines mentioned](https://medium.com/@imicknl/how-to-create-a-private-chatgpt-with-your-own-data-15754e6378a1) - - take-aways, cannot start openai until I have email from _MyLife_, so stick with OpenAI direct - - [Azure Cognitive Search](https://learn.microsoft.com/en-us/azure/search/search-what-is-azure-search) could be used to look through directories and files in interim support/proxy for GPT-2 personal kernal, so long as has direct access to Cosmos \ No newline at end of file +- add resources/references section to this document From df14e60cd8851f947e64f593c911d67a74730c35 Mon Sep 17 00:00:00 2001 From: Erik Jespersen <42016062+Mookse@users.noreply.github.com> Date: Thu, 25 Jan 2024 14:04:05 -0500 Subject: [PATCH 02/10] Update .gitignore; remove postman elements can be put in separate repo if valuable --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index a598b36..d56c336 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,6 @@ __*/ # ignore all folders starting with an underscore .uploads .tmp .DS_Store -.code-workspace \ No newline at end of file +.code-workspace +.postman +postman From 063e2c848e3d5f872f695e6e37e4e1e18f72c625 Mon Sep 17 00:00:00 2001 From: Erik Jespersen <42016062+Mookse@users.noreply.github.com> Date: Thu, 25 Jan 2024 14:05:31 -0500 Subject: [PATCH 03/10] Delete .postman directory --- .postman/api | 4 ---- .../api_2dfb42e3-2ab7-4059-8f68-f0d16dec17bd | 19 ------------------- 2 files changed, 23 deletions(-) delete mode 100644 .postman/api delete mode 100644 .postman/api_2dfb42e3-2ab7-4059-8f68-f0d16dec17bd diff --git a/.postman/api b/.postman/api deleted file mode 100644 index 5114742..0000000 --- a/.postman/api +++ /dev/null @@ -1,4 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY -apis[] = {"apiId":"2dfb42e3-2ab7-4059-8f68-f0d16dec17bd"} -configVersion = 1.0.0 -type = api diff --git a/.postman/api_2dfb42e3-2ab7-4059-8f68-f0d16dec17bd b/.postman/api_2dfb42e3-2ab7-4059-8f68-f0d16dec17bd deleted file mode 100644 index bd68b17..0000000 --- a/.postman/api_2dfb42e3-2ab7-4059-8f68-f0d16dec17bd +++ /dev/null @@ -1,19 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY -configVersion = 1.0.0 -type = apiEntityData - -[config] -id = 2dfb42e3-2ab7-4059-8f68-f0d16dec17bd - -[config.relations] - -[config.relations.collections] -rootDirectory = postman/collections -files[] = {"id":"4966269-744399ef-9467-46f5-9850-09124a71e501","path":"chat.json","metaData":{}} - -[config.relations.collections.metaData] - -[config.relations.apiDefinition] -rootDirectory = postman/schemas - -[config.relations.apiDefinition.metaData] From f794e9bd9521a2802c88e911c7a83e2fa3e7765d Mon Sep 17 00:00:00 2001 From: Erik Jespersen <42016062+Mookse@users.noreply.github.com> Date: Thu, 25 Jan 2024 14:07:45 -0500 Subject: [PATCH 04/10] Delete postman/collections directory --- postman/collections/chat.json | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 postman/collections/chat.json diff --git a/postman/collections/chat.json b/postman/collections/chat.json deleted file mode 100644 index 3711f5d..0000000 --- a/postman/collections/chat.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "info": { - "_postman_id": "744399ef-9467-46f5-9850-09124a71e501", - "name": "chat", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_uid": "4966269-744399ef-9467-46f5-9850-09124a71e501" - }, - "item": [ - { - "name": "chat", - "id": "211e5149-7340-45f2-baee-35cc13e54ef9", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [] - }, - "response": [] - } - ] -} \ No newline at end of file From 478fef5dbad38a2c89c19a94ff9fc6c6948aa489 Mon Sep 17 00:00:00 2001 From: Erik Jespersen Date: Fri, 26 Jan 2024 12:08:22 -0500 Subject: [PATCH 05/10] 20240126 @Mookse - yaml structures for multiple proxy-bots on openai --- inc/yaml/README.md | 27 ++++++++++++++++++++++ openai.yaml => inc/yaml/mylife_openai.yaml | 0 2 files changed, 27 insertions(+) create mode 100644 inc/yaml/README.md rename openai.yaml => inc/yaml/mylife_openai.yaml (100%) diff --git a/inc/yaml/README.md b/inc/yaml/README.md new file mode 100644 index 0000000..64dd9b0 --- /dev/null +++ b/inc/yaml/README.md @@ -0,0 +1,27 @@ +# AI Agent Communication + +## Providers + +### OpenAI + +This folder contains `.yaml` files for communicating with AI agents at OpenAI using a token-bearing schema. Each `.yaml` file represents + +## Action Schematas + +The following action schematas are available for external bots: + +- `mylife_openai.yaml`: This is the original action that maps to the openai gpt [`MyLife`](https://chat.openai.com/g/g-rEjoOt9hN-mylife). +- `mylife_biog-bot_openai.yaml`: This action is associated with the abilities of the [`MyLife Biographer Bot`](https://chat.openai.com/g/g-QGzfgKj6I-mylife-biographer-bot) to identify user, and + +## Structure + +The folder structure is as follows: + +. +├── mylife_openai.yaml +├── mylife_biog-bot_openai.yaml +└── README.md + +## Versioning + +Currently schemas are using `openapi v.3.0.0`, and each `.yaml` will be individually versioned, actual changes maintained in git repository. diff --git a/openai.yaml b/inc/yaml/mylife_openai.yaml similarity index 100% rename from openai.yaml rename to inc/yaml/mylife_openai.yaml From 84704c3678a20508d6f419d0c5f704346a39a4c7 Mon Sep 17 00:00:00 2001 From: Erik Jespersen Date: Fri, 26 Jan 2024 13:13:33 -0500 Subject: [PATCH 06/10] 20240126 @Mookse wip --- inc/yaml/mylife_biographer-bot_openai.yaml | 93 ++++++++++++++++++++++ inc/yaml/mylife_openai.yaml | 4 +- 2 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 inc/yaml/mylife_biographer-bot_openai.yaml diff --git a/inc/yaml/mylife_biographer-bot_openai.yaml b/inc/yaml/mylife_biographer-bot_openai.yaml new file mode 100644 index 0000000..f2cb9e4 --- /dev/null +++ b/inc/yaml/mylife_biographer-bot_openai.yaml @@ -0,0 +1,93 @@ +openapi: 3.0.0 +info: + title: MyLife GPT Webhook Receiver API + description: This API is for receiving webhooks from [MyLife's public Biographer Bot instance](https://chat.openai.com/g/g-QGzfgKj6I-mylife-biographer-bot). + version: 1.0.0 +servers: + - url: https://4c87-73-149-210-124.ngrok-free.app/api/v1 + description: Endpoint for receiving stories from the MyLife Biographer Bot instance. +security: + - bearerAuth: [] +paths: + /story: + post: + operationId: MyLifeBiographerStoryCreation + summary: MyLife Biographer Bot will access this endpoint to generate a . + description: Endpoint for handling incoming registration webhook data from the MyLife GPT service. + requestBody: + required: true + content: + application/json: + schema: + type: object + required: + - registrationInterests + - contact + properties: + registrationInterests: + type: array + default: + - information + minItems: 1 + maxItems: 4 + items: + type: string + enum: + - membership + - volunteer + - donate + - information + description: Interests in MyLife, defaults to information. + contact: + type: object + required: + - humanName + - email + properties: + avatarName: + type: string + description: The avatar name desired by the person registering. + humanName: + type: string + description: The name, can be nickname or short name, of the person registering. + humanDateOfBirth: + type: string + format: date + description: The date of birth of the person registering; could be as little as a year. + email: + type: string + description: The email of the person registering. + city: + type: string + description: The city of the person registering. + state: + type: string + description: The state of the person registering. + country: + type: string + description: The country of the person registering. + description: The registration data sent from the MyLife GPT instance. + personalInterests: + type: array + default: [] + minItems: 0 + maxItems: 5 + items: + type: string + enum: + - archivist + - humanist + - ethicist + - technologist + - futurist + description: The driving personal interests of the person registering. + additionalInfo: + type: string + maxLength: 1024 + description: Additional information sent from the MyLife GPT instance. + responses: + "200": + description: Webhook registration data received successfully. +post: + operationId: MyLifeBiographerStoryCreation + x-openai-isConsequential: false diff --git a/inc/yaml/mylife_openai.yaml b/inc/yaml/mylife_openai.yaml index 0bcb815..98b4b67 100644 --- a/inc/yaml/mylife_openai.yaml +++ b/inc/yaml/mylife_openai.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: title: MyLife GPT Webhook Receiver API - description: This API is for receiving webhooks from MyLife's public GPT instance found at [](). + description: This API is for receiving webhooks from [MyLife's public GPT instance](https://chat.openai.com/g/g-rEjoOt9hN-mylife). version: 1.0.0 servers: - url: https://humanremembranceproject.org/api/v1 @@ -89,5 +89,5 @@ paths: "200": description: Webhook registration data received successfully. post: - operationId: blah2 + operationId: MyLifeGPTRegistration x-openai-isConsequential: false From ca96de649886cc4ca5be3b8448e979d84152f70e Mon Sep 17 00:00:00 2001 From: Erik Jespersen Date: Fri, 26 Jan 2024 13:39:29 -0500 Subject: [PATCH 07/10] 20240126 @Mookse - GPT biographer bot `.yaml ` first draft --- inc/yaml/mylife_biographer-bot_openai.yaml | 81 +++++----------------- 1 file changed, 17 insertions(+), 64 deletions(-) diff --git a/inc/yaml/mylife_biographer-bot_openai.yaml b/inc/yaml/mylife_biographer-bot_openai.yaml index f2cb9e4..4e81c1a 100644 --- a/inc/yaml/mylife_biographer-bot_openai.yaml +++ b/inc/yaml/mylife_biographer-bot_openai.yaml @@ -12,82 +12,35 @@ paths: /story: post: operationId: MyLifeBiographerStoryCreation - summary: MyLife Biographer Bot will access this endpoint to generate a . + summary: MyLife Biographer Bot will access this endpoint to generate a `bio-story` document in MyLife Cosmos. description: Endpoint for handling incoming registration webhook data from the MyLife GPT service. requestBody: required: true content: application/json: schema: + description: The `story` data sent by MyLife Biographer BOt. type: object required: - - registrationInterests - - contact + - assistantType + - memberKey + - storySummary properties: - registrationInterests: - type: array - default: - - information - minItems: 1 - maxItems: 4 - items: - type: string - enum: - - membership - - volunteer - - donate - - information - description: Interests in MyLife, defaults to information. - contact: - type: object - required: - - humanName - - email - properties: - avatarName: - type: string - description: The avatar name desired by the person registering. - humanName: - type: string - description: The name, can be nickname or short name, of the person registering. - humanDateOfBirth: - type: string - format: date - description: The date of birth of the person registering; could be as little as a year. - email: - type: string - description: The email of the person registering. - city: - type: string - description: The city of the person registering. - state: - type: string - description: The state of the person registering. - country: - type: string - description: The country of the person registering. - description: The registration data sent from the MyLife GPT instance. - personalInterests: - type: array - default: [] - minItems: 0 - maxItems: 5 - items: - type: string - enum: - - archivist - - humanist - - ethicist - - technologist - - futurist - description: The driving personal interests of the person registering. - additionalInfo: + assistantType: + default: MyLife-Biographer-Bot + description: The type of assistant that generated the story. + type: string + memberKey: + description: Visitor enters memberKey and it is kept in GPT memory and sent with each request so that MyLife knows partition. + maxLength: 256 + type: string + storySummary: + description: MyLife Biographer Bot summary of identified `story`. + maxLength: 20480 type: string - maxLength: 1024 - description: Additional information sent from the MyLife GPT instance. responses: "200": description: Webhook registration data received successfully. post: operationId: MyLifeBiographerStoryCreation - x-openai-isConsequential: false + x-openai-isConsequential: false \ No newline at end of file From 1046d5be863900097e1b194d9a6a8af89ab33a73 Mon Sep 17 00:00:00 2001 From: Erik Jespersen Date: Mon, 29 Jan 2024 08:59:12 -0500 Subject: [PATCH 08/10] 20240129 @Mookse - openai integration via actions for biographer bot --- inc/js/api-functions.mjs | 189 +++++++++++++++++++++ inc/js/core.mjs | 35 ++++ inc/js/functions.mjs | 48 ------ inc/js/globals.mjs | 3 + inc/js/mylife-agent-factory.mjs | 32 +++- inc/js/mylife-data-service.js | 41 ++++- inc/js/mylife-datamanager.mjs | 26 ++- inc/js/routes.mjs | 52 ++---- inc/yaml/mylife_biographer-bot_openai.yaml | 80 +++++++-- 9 files changed, 394 insertions(+), 112 deletions(-) create mode 100644 inc/js/api-functions.mjs diff --git a/inc/js/api-functions.mjs b/inc/js/api-functions.mjs new file mode 100644 index 0000000..11c3c86 --- /dev/null +++ b/inc/js/api-functions.mjs @@ -0,0 +1,189 @@ +import chalk from "chalk" +/* variables */ +const mBotSecrets = JSON.parse(process.env.OPENAI_JWT_SECRETS) +/* private modular functions */ +async function _keyValidation(ctx){ // transforms ctx.state + if(ctx.params.mid === ':mid') ctx.params.mid = undefined + // ctx session alternatives to hitting DB every time? can try... + const _mbr_id = ctx.params.mid??ctx.request.body.memberKey + const _validated = + ( // session validation shorthand + ( ctx.session?.isAPIValidated??false ) + && _mbr_id?.length + && ( _mbr_id===ctx.session?.APIMemberKey??false ) + ) || ( // initial full validation + (_mbr_id?.length) + && process.env.MYLIFE_HOSTED_MBR_ID.includes(_mbr_id) + && await ctx.MyLife.testPartitionKey(_mbr_id) + ) + ctx.state.mbr_id = _mbr_id + ctx.state.assistantType = _tokenType(ctx) + ctx.state.isValidated = _validated + ctx.session.isAPIValidated = ctx.state.isValidated + ctx.session.APIMemberKey = ctx.state.mbr_id +} +function _tokenType(ctx){ + const _token = ctx.state.token + const _assistantType = mBotSecrets?.[_token]??'personal-avatar' + return _assistantType +} +function _tokenValidation(_token){ + return mBotSecrets?.[_token]?.length??false +} +/* public modular functions */ +async function keyValidation(ctx){ + console.log(chalk.yellowBright('keyValidation()'), ctx.request.body) + await _keyValidation(ctx) + if(!ctx.state.isValidated){ + ctx.status = 400 // Bad Request + ctx.body = { + success: false, + message: 'Invalid member.', + } + return + } + ctx.status = 200 // OK + if(ctx.method === 'HEAD') return + // @todo: determine how to instantiate avatar via Maht Factory--session? In any case, perhaps relegate to session + const _memberCore = await ctx.MyLife.datacore(ctx.state.mbr_id) + const { updates, interests, birth, birthDate, fullName, names, nickname } = _memberCore + const _birth = (Array.isArray(birth) && birth.length) + ? birth[0] + : birth??{} + _birth.date = birthDate??_birth.date??'' + _birth.place = _birth.place??'' + const _memberCoreData = { + mbr_id: ctx.state.mbr_id, + updates: updates??'', + interests: interests??'', + birthDate: _birth.date, + birthPlace: _birth.place, + fullName: fullName??names?.[0]??'', + preferredName: nickname??names?.[0].split(' ')[0]??'', + } + ctx.body = { + success: true, + message: 'Valid member.', + data: _memberCoreData, + } + console.log(chalk.yellowBright('keyValidation()'), _memberCoreData, ) + return +} +async function register(ctx){ + const _registrationData = ctx.request.body + const { + registrationInterests, + contact={}, // as to not elicit error destructuring + personalInterests, + additionalInfo + } = _registrationData + const { + avatarName, + humanName, + humanDateOfBirth, + email, + city, + state, + country, + } = contact + if (!humanName?.length || !email?.length){ + ctx.status = 400 // Bad Request + ctx.body = { + success: false, + message: 'Missing required contact information: humanName and/or email are required.', + } + return + } + // Email validation + if (!ctx.Globals.isValidEmail(contact.email)) { + ctx.status = 400 // Bad Request + ctx.body = { + success: false, + message: 'Invalid email format.', + } + return + } + // throttle requests? + // write to cosmos db + _registrationData.email = email // required at root for select + const _ = ctx.MyLife.registerCandidate(_registrationData) + const { mbr_id, ..._return } = _registrationData // abstract out the mbr_id + ctx.status = 200 + ctx.body = { + success: true, + message: 'Registration completed successfully.', + data: _return, + } + return +} +/** + * Functionality around story contributions and portrayals + * @param {Koa} ctx - Koa Context object + * @returns {Koa} Koa Context object + */ +async function story(ctx){ + await _keyValidation(ctx) // sets ctx.state.mbr_id and more + const { assistantType, mbr_id } = ctx.state + const { storySummary } = ctx.request?.body??{} + if(!storySummary?.length){ + ctx.status = 400 // Bad Request + ctx.body = { + success: false, + message: 'No story summary provided. Use `storySummary` field.', + } + return + } + // write to cosmos db + const _story = await ctx.MyLife.story(mbr_id, assistantType, storySummary) // @todo: remove await + console.log(chalk.yellowBright('story submitted:'), _story) + ctx.status = 200 // OK + ctx.body = { + success: true, + message: 'Story submitted successfully.', + story: _story, + } + return +} +/** + * Validates api token + * @modular + * @public + * @param {object} ctx Koa context object + * @param {function} next Koa next function + * @returns {function} Koa next function + */ +async function tokenValidation(ctx, next) { + try { + const authHeader = ctx.request.headers['authorization'] + if(!authHeader){ + ctx.status = 401 + ctx.body = { error: 'Authorization header is missing' } + return + } + const _token = authHeader.split(' ')[1] // Bearer TOKEN_VALUE + if(!_tokenValidation(_token)){ + ctx.status = 401 + ctx.body = { error: 'Authorization token failure' } + return + } + ctx.state.token = _token // **note:** keep first, as it is used in _tokenType() + ctx.state.assistantType = _tokenType(ctx) + await next() + } catch (error) { + ctx.status = 401 + const _error = { + name: error.name, + message: error.message, + stack: error.stack + } + ctx.body = { message: 'Unauthorized Access', error: _error } + return + } +} +/* exports */ +export { + keyValidation, + register, + story, + tokenValidation, +} \ No newline at end of file diff --git a/inc/js/core.mjs b/inc/js/core.mjs index f5f069a..cc025c0 100644 --- a/inc/js/core.mjs +++ b/inc/js/core.mjs @@ -279,6 +279,10 @@ class MyLife extends Organization { // form=server constructor(_Factory){ // no session presumed to exist super(_Factory) } + async datacore(_mbr_id){ + if(!_mbr_id || _mbr_id===this.mbr_id) throw new Error('datacore cannot be accessed') + return await this.factory.datacore(_mbr_id) + } /* public functions */ /** * Server MyLife _Maht instantiation uses this function to populate the most current alerts in the modular factory memoryspace. Currently only applicable to system types, but since this is implemented at the `core.mjs` scope, we can account @@ -299,6 +303,37 @@ class MyLife extends Organization { // form=server async registerCandidate(_candidate){ return await this.factory.registerCandidate(_candidate) } + /** + * Submits a story to MyLife via API. Unclear if can be dual-purposed for internal, or if internal still instantiates API context. + * @public + * @param {string} _mbr_id - Member id + * @param {string} _assistantType - String name of assistant type + * @param {string} _summary - String summary of story + * @returns {object} - The story document from Cosmos. + */ + async story(_mbr_id, _assistantType, storySummary){ + const id = this.globals.newGuid + const _story = { + assistantType: _assistantType, + being: 'story', + form: _assistantType, + id, + mbr_id: _mbr_id, + name: `${_assistantType}-story_${_mbr_id}_${id}`, + summary: storySummary, + } + const _storyCosmos = await this.factory.story(_story) + return this.globals.stripCosmosFields(_storyCosmos) + } + /** + * Tests partition key for member + * @public + * @param {string} _mbr_id member id + * @returns {boolean} returns true if partition key is valid + */ + async testPartitionKey(_mbr_id){ + return await this.factory.testPartitionKey(_mbr_id) + } /* getters/setters */ /** * Gets MyLife agent role, refers to server entity Maht/MyLife diff --git a/inc/js/functions.mjs b/inc/js/functions.mjs index 5462e80..4ec538c 100644 --- a/inc/js/functions.mjs +++ b/inc/js/functions.mjs @@ -27,53 +27,6 @@ async function alerts(ctx){ ctx.body = await ctx.state.MemberSession.alerts(ctx.request.body) } } -async function api_register(ctx){ - const _registrationData = ctx.request.body - const { - registrationInterests, - contact={}, // as to not elicit error destructuring - personalInterests, - additionalInfo - } = _registrationData - const { - avatarName, - humanName, - humanDateOfBirth, - email, - city, - state, - country, - } = contact - if (!humanName?.length || !email?.length){ - ctx.status = 400 // Bad Request - ctx.body = { - success: false, - message: 'Missing required contact information: humanName and/or email are required.', - } - return - } - // Email validation - if (!ctx.Globals.isValidEmail(contact.email)) { - ctx.status = 400 // Bad Request - ctx.body = { - success: false, - message: 'Invalid email format.', - } - return - } - // throttle requests? - // write to cosmos db - _registrationData.email = email // required at root for select - const _ = ctx.MyLife.registerCandidate(_registrationData) - const { mbr_id, ..._return } = _registrationData // abstract out the mbr_id - ctx.status = 200 - ctx.body = { - success: true, - message: 'Registration completed successfully.', - data: _return, - } - return -} async function avatarListing(ctx){ ctx.state.title = `Avatars for ${ ctx.state.member.memberName }` ctx.state.avatars = [] @@ -278,7 +231,6 @@ export { about, activateBot, alerts, - api_register, avatarListing, bots, category, diff --git a/inc/js/globals.mjs b/inc/js/globals.mjs index 5e61714..ff9e884 100644 --- a/inc/js/globals.mjs +++ b/inc/js/globals.mjs @@ -22,6 +22,9 @@ class Globals extends EventEmitter { isValidGuid(_str='') { return (typeof _str === 'string' && guid_regex.test(_str)) } + stripCosmosFields(_obj){ + return Object.fromEntries(Object.entries(_obj).filter(([k, v]) => !k.startsWith('_'))) + } sysId(_mbr_id){ if(!typeof _mbr_id==='string' || !_mbr_id.length || !_mbr_id.includes('|')) throw new Error('expected MyLife member id string') diff --git a/inc/js/mylife-agent-factory.mjs b/inc/js/mylife-agent-factory.mjs index bde924b..0f76775 100644 --- a/inc/js/mylife-agent-factory.mjs +++ b/inc/js/mylife-agent-factory.mjs @@ -5,7 +5,6 @@ import EventEmitter from 'events' import vm from 'vm' import util from 'util' import { Guid } from 'js-guid' // usage = Guid.newGuid().toString() -import Globals from './globals.mjs' import Dataservices from './mylife-data-service.js' import { Member, MyLife } from './core.mjs' import { @@ -41,7 +40,6 @@ const mExcludeProperties = { definitions: true, name: true } -const mGlobals = new Globals() const mOpenAI = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, organizationId: process.env.OPENAI_ORG_KEY, @@ -146,6 +144,16 @@ class AgentFactory extends EventEmitter{ async challengeAccess(_mbr_id, _passphrase){ return await mDataservices.challengeAccess(_mbr_id, _passphrase) } + async datacore(_mbr_id){ + const _core = await mDataservices.getItems( + 'core', + undefined, + undefined, + undefined, + _mbr_id, + ) + return _core?.[0]??{} + } async getAlert(_alert_id){ const _alert = _alerts.system.find(alert => alert.id === _alert_id) return _alert ? _alert : await mDataservices.getAlert(_alert_id) @@ -223,6 +231,24 @@ class AgentFactory extends EventEmitter{ async setBot(_bot){ return await this.dataservices.setBot(_bot) } + /** + * Submits a story to MyLife. Currently via API, but could be also work internally. + * @param {object} _story - Story object { assistantType, being, form, id, mbr_id, name, summary }. + * @returns {object} - The story document from Cosmos. + */ + async story(_story){ + return await this.dataservices.story(_story) + } + /** + * Tests partition key for member + * @public + * @param {string} _mbr_id member id + * @returns {boolean} returns true if partition key is valid + */ + async testPartitionKey(_mbr_id){ + if(!this.isMyLife) return false + return await mDataservices.testPartitionKey(_mbr_id) + } // getters/setters get alerts(){ // currently only returns system alerts return _alerts.system @@ -246,7 +272,7 @@ class AgentFactory extends EventEmitter{ return this.schemas.file } get globals(){ - return mGlobals + return this.dataservices.globals } /** * Returns whether or not the factory is the MyLife server, as various functions are not available to the server and some _only_ to the server. diff --git a/inc/js/mylife-data-service.js b/inc/js/mylife-data-service.js index e84c345..7f36294 100644 --- a/inc/js/mylife-data-service.js +++ b/inc/js/mylife-data-service.js @@ -90,9 +90,15 @@ class Dataservices { get embedder(){ return this.#PgvectorManager } + get globals(){ + return this.datamanager.globals + } get id(){ return this.partitionId.split('|')[1] } + get isMyLife(){ + return this.mbr_id===process.env?.MYLIFE_SERVER_MBR_ID??false + } get mbr_id(){ return this.partitionId } @@ -143,7 +149,10 @@ class Dataservices { */ async challengeAccess(_mbr_id,_passphrase){ // if possible (async) injected into session object // ask global data service (stored proc) for passphrase - return await this.datamanager.challengeAccess(_mbr_id,_passphrase) + return await this.datamanager.challengeAccess(_mbr_id, _passphrase) + } + async datacore(_mbr_id){ + return await this.getItem(_mbr_id) } async findRegistrationIdByEmail(_email){ /* pull record for email, returning id or new guid */ @@ -257,13 +266,15 @@ class Dataservices { * @public * @param {string} _id - The unique identifier for the item. * @param {string} _container_id - The container to use, overriding default: `Members`. + * @param {string} _mbr_id - The member id to use, overriding default. * @returns {Promise} The item corresponding to the provided ID. */ - async getItem(_id, _container_id) { + async getItem(_id, _container_id, _mbr_id=this.mbr_id) { try{ return await this.datamanager.getItem( _id, _container_id, + { partitionKey: _mbr_id, populateQuotaInfo: false, }, ) } catch(_error){ @@ -279,9 +290,10 @@ class Dataservices { * @param {array} [_selects=[]] - Fields to select; if empty, selects all fields. * @param {Array} [_paramsArray=[]] - Additional query parameters. * @param {string} _container_id - The container name to use, overriding default. + * @param {string} _mbr_id - The member id to use, overriding default. * @returns {Promise} An array of items matching the query parameters. */ - async getItems(_being, _selects=[], _paramsArray=[], _container_id) { // _params is array of objects { name: '${varName}' } + async getItems(_being, _selects=[], _paramsArray=[], _container_id, _mbr_id=this.mbr_id) { // _params is array of objects { name: '${varName}' } // @todo: incorporate date range functionality into this.getItems() const _prefix = 'u' _paramsArray.unshift({ name: '@being', value: _being }) // add primary parameter to array at beginning @@ -299,6 +311,10 @@ class Dataservices { return await this.datamanager.getItems( { query: _query, parameters: _paramsArray }, _container_id, + { + partitionKey: _mbr_id, + populateQuotaInfo: false, // set this to true to include quota information in the response headers + }, ) } catch(_error){ @@ -399,6 +415,25 @@ class Dataservices { } return _bot } + /** + * Submits a story to MyLife. Currently via API, but could be also work internally. + * @param {object} _story - Story object { assistantType, being, form, id, mbr_id, name, summary }. + * @returns {object} - The story document from Cosmos. + */ + async story(_story){ + if(!this.isMyLife) return + return await this.datamanager.pushItem(_story) + } + /** + * Tests partition key for member + * @public + * @param {string} _mbr_id member id + * @returns {boolean} returns true if partition key is valid + */ + async testPartitionKey(_mbr_id){ + if(!this.isMyLife) return false + return await this.datamanager.testPartitionKey(_mbr_id) + } } // exports export default Dataservices \ No newline at end of file diff --git a/inc/js/mylife-datamanager.mjs b/inc/js/mylife-datamanager.mjs index 1e88be9..270fe11 100644 --- a/inc/js/mylife-datamanager.mjs +++ b/inc/js/mylife-datamanager.mjs @@ -1,9 +1,12 @@ /* imports */ // import { DefaultAzureCredential } from "@azure/identity" import { CosmosClient } from '@azure/cosmos' -import Config from './mylife-datasource-config.mjs' import chalk from 'chalk' import { _ } from 'ajv' +import Config from './mylife-datasource-config.mjs' +import Globals from './globals.mjs' +/* modular constants */ +const mGlobals = new Globals() // define class class Datamanager { #containers @@ -31,7 +34,7 @@ class Datamanager { } this.requestOptions = { partitionKey: this.#partitionId, - populateQuotaInfo: true, // set this to true to include quota information in the response headers + populateQuotaInfo: false, // set this to true to include quota information in the response headers } } // init function @@ -86,11 +89,11 @@ class Datamanager { async getItems(_querySpec, _container_id=this.containerDefault, _options=this.requestOptions ){ const { resources } = await this.#containers[_container_id] .items - .query(_querySpec,_options) + .query(_querySpec, _options) .fetchAll() return resources } - async patchItem(_id, _item, _container_id=this.containerDefault) { // patch or update, depends on whether it finds id or not, will only overwrite fields that are in _item + async patchItem(_id, _item, _container_id=this.containerDefault){ // patch or update, depends on whether it finds id or not, will only overwrite fields that are in _item // [Partial Document Update, includes node.js examples](https://learn.microsoft.com/en-us/azure/cosmos-db/partial-document-update) if(!Array.isArray(_item)) _item = [_item] const { resource: _update } = await this.#containers[_container_id] @@ -98,7 +101,9 @@ class Datamanager { .patch(_item) // see below for filter-patch example return _update } - async pushItem(_item, _container_id=this.containerDefault) { // post or insert, depends on whether it finds id or not, will overwrite all existing fields + async pushItem(_item, _container_id=this.containerDefault){ + _item.id = _item?.id??this.globals.newGuid + _item.mbr_id = _item?.mbr_id??this.#partitionId const { resource: doc } = await this.#containers[_container_id] .items .upsert(_item) @@ -115,6 +120,17 @@ class Datamanager { .upsert(_candidate) return doc } + async testPartitionKey(_mbr_id){ + const { resource: _result } = await this.#containers['members'] + .scripts + .storedProcedure('testPartitionKey') + .execute(_mbr_id) // first parameter is partition key, second is passphrase, third is case sensitivity + return _result + } + /* getters/setters */ + get globals(){ + return mGlobals + } } // exports export default Datamanager diff --git a/inc/js/routes.mjs b/inc/js/routes.mjs index 6778886..e7dedf2 100644 --- a/inc/js/routes.mjs +++ b/inc/js/routes.mjs @@ -4,7 +4,6 @@ import { about, activateBot, alerts, - api_register, avatarListing, bots, category, @@ -20,6 +19,12 @@ import { upload, _upload } from './functions.mjs' +import { + keyValidation, + register, + story, + tokenValidation, +} from './api-functions.mjs' // variables const _Router = new Router() const _memberRouter = new Router() @@ -37,12 +42,17 @@ _Router.post('/', chat) _Router.post('/challenge/:mid', challenge) _Router.post('/signup', signup) /* api webhook routes */ -_apiRouter.use(_tokenValidate) +_apiRouter.use(tokenValidation) _apiRouter.get('/alerts', alerts) _apiRouter.get('/alerts/:aid', alerts) -_apiRouter.post('/register', api_register) +//_apiRouter.get('/keyValidation', (ctx)=>{console.log('48', ctx.request)}) +//_apiRouter.get('/keyValidation/:mid', keyValidation) +//_apiRouter.head('/keyValidation/:mid', keyValidation) +_apiRouter.post('/keyValidation/:mid', keyValidation) +_apiRouter.post('/register', register) +_apiRouter.post('/story/:mid', story) /* member routes */ -_memberRouter.use(_memberValidate) +_memberRouter.use(memberValidation) _memberRouter.get('/', members) _memberRouter.get('/avatars', avatarListing) _memberRouter.get('/avatars/:aid', avatarListing) @@ -77,7 +87,7 @@ function connectRoutes(_Menu){ * @param {function} next Koa next function * @returns {function} Koa next function */ -async function _memberValidate(ctx, next) { +async function memberValidation(ctx, next) { // validation logic if(ctx.state.locked) { ctx.redirect( @@ -105,38 +115,6 @@ function status(ctx){ // currently returns reverse "locked" status, could send o function status_signup(ctx){ ctx.body = ctx.session.signup } -/** - * Validates api token - * @param {object} ctx Koa context object - * @param {function} next Koa next function - * @returns {function} Koa next function - */ -async function _tokenValidate(ctx, next) { - try { - const authHeader = ctx.request.headers['authorization'] - if(!authHeader){ - ctx.status = 401 - ctx.body = { error: 'Authorization header is missing' } - return - } - const _token = authHeader.split(' ')[1] // Bearer TOKEN_VALUE - if(_token!==process.env.OPENAI_JWT_SECRET){ - ctx.status = 401 - ctx.body = { error: 'Authorization token failure' } - return - } - await next() - } catch (error) { - ctx.status = 401 - const _error = { - name: error.name, - message: error.message, - stack: error.stack - } - ctx.body = { message: 'Unauthorized Access', error: _error } - return - } -} // exports export default function init(_Menu) { connectRoutes(_Menu) diff --git a/inc/yaml/mylife_biographer-bot_openai.yaml b/inc/yaml/mylife_biographer-bot_openai.yaml index 4e81c1a..db96763 100644 --- a/inc/yaml/mylife_biographer-bot_openai.yaml +++ b/inc/yaml/mylife_biographer-bot_openai.yaml @@ -4,16 +4,77 @@ info: description: This API is for receiving webhooks from [MyLife's public Biographer Bot instance](https://chat.openai.com/g/g-QGzfgKj6I-mylife-biographer-bot). version: 1.0.0 servers: - - url: https://4c87-73-149-210-124.ngrok-free.app/api/v1 + - url: https://humanremembranceproject.org/api/v1 description: Endpoint for receiving stories from the MyLife Biographer Bot instance. security: - bearerAuth: [] paths: - /story: + /keyValidation/{mid}: post: + x-openai-isConsequential: false + operationId: MyLifeKeyValidation + summary: MyLife Biographer Bot will access this endpoint to validate a `memberKey` in MyLife Cosmos. + description: Endpoint for handling incoming registration webhook data from the MyLife GPT service. + parameters: + - name: mid + in: path + required: true + description: The `memberKey` data to be sent by MyLife Biographer Bot. Visitor enters memberKey and it is kept in GPT memory and sent with each request so that MyLife knows partition. + schema: + maxLength: 256 + minLength: 40 + type: string + responses: + "200": + description: A successful response indicating the member key is valid + content: + application/json: + schema: + type: object + properties: + success: + type: boolean + example: true + message: + type: string + example: Valid member. + data: + type: object + properties: + mbr_id: + maxLength: 256 + minLength: 40 + type: string + updates: + type: string + interests: + type: string + birthDate: + type: string + format: date-time + birthPlace: + type: string + fullName: + type: string + preferredName: + type: string + "400": + description: Invalid member. Field `memberKey` is not valid, check again with member. + /story/{mid}: + post: + x-openai-isConsequential: false operationId: MyLifeBiographerStoryCreation summary: MyLife Biographer Bot will access this endpoint to generate a `bio-story` document in MyLife Cosmos. description: Endpoint for handling incoming registration webhook data from the MyLife GPT service. + parameters: + - name: mid + in: path + required: true + description: The `memberKey` data to be sent by MyLife Biographer Bot. Visitor enters memberKey and it is kept in GPT memory and sent with each request so that MyLife knows partition. + schema: + maxLength: 256 + minLength: 40 + type: string requestBody: required: true content: @@ -22,25 +83,12 @@ paths: description: The `story` data sent by MyLife Biographer BOt. type: object required: - - assistantType - - memberKey - storySummary properties: - assistantType: - default: MyLife-Biographer-Bot - description: The type of assistant that generated the story. - type: string - memberKey: - description: Visitor enters memberKey and it is kept in GPT memory and sent with each request so that MyLife knows partition. - maxLength: 256 - type: string storySummary: description: MyLife Biographer Bot summary of identified `story`. maxLength: 20480 type: string responses: "200": - description: Webhook registration data received successfully. -post: - operationId: MyLifeBiographerStoryCreation - x-openai-isConsequential: false \ No newline at end of file + description: Webhook registration data received successfully. \ No newline at end of file From 026d3b17bead74c8a0d7fbcce77ee8b6916397cb Mon Sep 17 00:00:00 2001 From: Erik Jespersen Date: Mon, 29 Jan 2024 09:25:31 -0500 Subject: [PATCH 09/10] 20240128 @Mookse - updated sample .env --- .env-sample | 31 ------------------------------- sample.env | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 31 deletions(-) delete mode 100644 .env-sample create mode 100644 sample.env diff --git a/.env-sample b/.env-sample deleted file mode 100644 index 2296aa2..0000000 --- a/.env-sample +++ /dev/null @@ -1,31 +0,0 @@ -OPENAI_API_CHAT_TIMEOUT=22000 -OPENAI_API_CHAT_RESPONSE_PING_INTERVAL=890 # how often to ping openai service for assistant run status complete -OPENAI_API_KEY=sk-... # your individual openai API key -OPENAI_BASE_URL=https://api.openai.com/v1 -OPENAI_MAHT_GITHUB=https://github.com/MyLife-Services/mylife-maht.git -OPENAI_MAHT_GITHUB_BRANCH=base -OPENAI_MAHT_GPT_OVERRIDE=# localdev version [3.5-turbo]: asst_c8qcXkJS6urevqja5wcZ0za5 -OPENAI_MODEL_CORE_AVATAR=gpt-3.5-turbo -OPENAI_MODEL_CORE_BOT=gpt-3.5-turbo -OPENAI_ORG_KEY=org-... # use ours or use your own -PORT=3000 # KOA port -MYLIFE_ALLOW_INTELLIGENT_QUESTIONS=false -MYLIFE_DB_ALLOW_SAVE=true -MYLIFE_DB_ENDPOINT= # get from administrator -MYLIFE_DB_NAME= # get from administrator -MYLIFE_DB_RW= # get from administrator -MYLIFE_DB_RX= # get from administrator -MYLIFE_DB_CONTAINER_NAME= # get from administrator -MYLIFE_SERVER_MBR_ID= # get from administrator -MYLIFE_HOSTED_MBR_ID=[] # ["mbr_id's hosted by this server"] -MYLIFE_SESSION_KEY=iteration-number # type in own personal key, quoted or unquoted if no spaces... Restarting server will NOT refresh sessions (as of now) so must change this key to refresh server-level constants} -MYLIFE_SESSION_TIMEOUT_MS=900000 # session timeout in milliseconds -MYLIFE_VERSION=0.0 -MYLIFE_EMBEDDING_SERVER_URL=http://mylife-embedding-server -MYLIFE_EMBEDDING_SERVER_PORT=8000 -MYLIFE_EMBEDDING_SERVER_BEARER_TOKEN={ chosen personally to match environment variable in embedding server } -MYLIFE_EMBEDDING_SERVER_FILESIZE_LIMIT=1024 # 1MB = 1024 * 1024 -MYLIFE_EMBEDDING_SERVER_FILESIZE_LIMIT_ADMIN=1024 # 10MB = 1024 * 1024 * 10 -MYLIFE_CONTRIBUTIONS_DB_CONTAINER_NAME= # get from administrator -MYLIFE_REGISTRATION_DB_CONTAINER_NAME= # get from administrator -MYLIFE_SYSTEM_DB_CONTAINER_NAME= # get from administrator \ No newline at end of file diff --git a/sample.env b/sample.env new file mode 100644 index 0000000..04f7a4b --- /dev/null +++ b/sample.env @@ -0,0 +1,35 @@ +OPENAI_API_CHAT_TIMEOUT=59000 +OPENAI_API_CHAT_RESPONSE_PING_INTERVAL=890 +OPENAI_API_KEY=sk-... # add your key here +OPENAI_BASE_URL=https://api.openai.com/v1 +OPENAI_JWT_SECRETS={} # object with keys being JWT share with external AIs +OPENAI_MAHT_GITHUB=https://github.com/MyLife-Services/mylife-maht.git +OPENAI_MAHT_GITHUB_BRANCH=base +OPENAI_MAHT_GPT_OVERRIDE=asst_... # local dev override for engine so that local can use chaper model +# 2000 chars (not tokens) is the max; disallows large code pastes, or rather, converts them as appropriate to file(s); **also** converts large text pastes to files a human member can use as well, though functionality TODO +OPENAI_MAX_CONTEXT_WINDOW=2000 +OPENAI_MODEL_CORE_AVATAR=gpt-3.5-turbo +OPENAI_MODEL_CORE_BOT=gpt-3.5-turbo +OPENAI_ORG_KEY=org-dTYDMEBuP2yb2qtwCQJA4HHh # MyLife org ID +PORT=3000 +MYLIFE_ALLOW_INTELLIGENT_QUESTIONS=false # almost deprecated, leave false +MYLIFE_DB_ALLOW_SAVE=false # during local testing, so not write to db +MYLIFE_DB_CONTAINER_NAME=members +MYLIFE_DB_ENDPOINT=https://mylife.documents.azure.com:443/ +MYLIFE_DB_NAME=membership +MYLIFE_DB_RW=string # add your key here +MYLIFE_DB_RX=string # add your key here +MYLIFE_SERVER_MBR_ID=mylife|... # add your key here +MYLIFE_HOSTED_MBR_ID=[] # array of ids hosted on your server +MYLIFE_SESSION_KEY=0.0.2.0001 # random string for resetting sessions +MYLIFE_SESSION_TIMEOUT_MS=900000 +MYLIFE_SYSTEM_ALERT_CHECK_INTERVAL=120000 # how often to check for alerts in ms +MYLIFE_VERSION=0.0.2.0001 +MYLIFE_EMBEDDING_SERVER_URL= # temp deprecation +MYLIFE_EMBEDDING_SERVER_PORT=0 # temp deprecation +MYLIFE_EMBEDDING_SERVER_BEARER_TOKEN= # temp deprecation +MYLIFE_EMBEDDING_SERVER_FILESIZE_LIMIT= # temp deprecation +MYLIFE_EMBEDDING_SERVER_FILESIZE_LIMIT_ADMIN= # temp deprecation +MYLIFE_CONTRIBUTIONS_DB_CONTAINER_NAME= # get from admin +MYLIFE_REGISTRATION_DB_CONTAINER_NAME= # get from admin +MYLIFE_SYSTEM_DB_CONTAINER_NAME= # get from admin \ No newline at end of file From eff3112c0536b5a2d69e2f0dd7d04d92099f082f Mon Sep 17 00:00:00 2001 From: Erik Jespersen Date: Mon, 29 Jan 2024 09:41:56 -0500 Subject: [PATCH 10/10] 20240129 @Mookse - console log cleanup --- inc/js/api-functions.mjs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/inc/js/api-functions.mjs b/inc/js/api-functions.mjs index 11c3c86..9c07e61 100644 --- a/inc/js/api-functions.mjs +++ b/inc/js/api-functions.mjs @@ -32,7 +32,6 @@ function _tokenValidation(_token){ } /* public modular functions */ async function keyValidation(ctx){ - console.log(chalk.yellowBright('keyValidation()'), ctx.request.body) await _keyValidation(ctx) if(!ctx.state.isValidated){ ctx.status = 400 // Bad Request @@ -66,7 +65,7 @@ async function keyValidation(ctx){ message: 'Valid member.', data: _memberCoreData, } - console.log(chalk.yellowBright('keyValidation()'), _memberCoreData, ) + console.log(chalk.yellowBright(`keyValidation():${_memberCoreData.mbr_id}`), _memberCoreData.fullName) return } async function register(ctx){