me.

Blake Senftner

Computer Scientist | MBA | Digital Artist

Creating MiniCMS - a Document & Project Mgmnt WebApp

MiniCMS + Celery flowchart
Introduction
The web site you are reading this blog on is my first public FastAPI Python project. Implementing a basic web site content management system (a CMS) felt like a good way to solidify my understanding and use of FastAPI. As that, this web site, became functional and moved into a maintaince and usage mode, I began to look for a more complex project to learn more. 

A Problem
I learned about a family member's law firm, where they had what sounded to me like extreme monthly bandwidth charges for staff file sharing. This small firm, about 25 people, primarially use Microsoft Office, a law practice management app, and a law practice accounting package. Somehow, using a combination of OneDrive, TeamViewer, and a file sharing utility from their ISP they had an accumulated additional bandwidth charge on top of their ordinary Internet service of somewhere between $2K and $5K every month. The law case files and related sharing were a few TB every day, which add up...

A Solution
I had been experimenting with a Virtual Private Network called Tailscale, which enables one to create small private networks that overlay existing network LANs and the Internet. Without altering my underlying blog web application, I was able to create a locally hosted yet VPN visible to a private set of people version. Discussing the idea with my family member, I proposed a document and project management web app their staff would use in place of the file sharing features and utilities they use now, which cost money to use at the level they use them. This expense savings is possible because Tailscale makes direct machine to machine connections between VPN members when sharing files, direct connections that are not subject to ISP or other charges. Use of Tailscale should completely eliminate these additional monthly bandwith expenses.

Implementation
Gaining approval to give the idea a try, I duplicated my blog's code base and started implementing a project and document management framework.

App Level Permissions
Being project based the web app needed a security model beyond the user login authentication JWT and any https whatever already implemented by my framework. Within the web app, users need some type of permissioning system for access to different projects and within projects as well. I chose a basic named role model where every user has a series of roles, each role defining some type of permission. The presence of a role's name in the roles field of a user's account tells the software that user has that permission. Using this basic permissioning, I split users into the three grounps admin, staff, and lacking either of those public.

Users with the admin role can access the web app configuration, make changes, create new site usrs, see all the past activities of other admin and staff on the site, as well as do anything that staff users can do. This web app is not intended to be public, so an admin is required to create new users, presumably the staff manager who hires that person to work at the law firm.

Users with the staff role can create new projects, which makes them a junior admin of that project. Project owners can invite other users to join their project, they can join or decline to join other projects, and they have admin level controls over any files uploaded to that project. As members of a project, they have access to all project memos, comments, and project files. 

Projects
A Project is just a private group of staff whom are working together, using MiniCMS as their information and document hub for their project. Each Project has it's own Project Page with a description, a listing of uploaded files, and a list of Project Memos. Each Project Memo is some information about the project, documented as a memo. Uploaded files within a project can also be embedded into a memo.

This basic project and document management framework is similar to other web frameworks I have used and written myself multiple times, so it was just a matter of time to put the essential pieces and parts together.  Those being:

  • FastAPI content types for Projects, Project Files, Memos, Memo Comments, Project Invites,
    • and User Actions for the tracking of user activities when operating the web app.
  • The associated API endpoints for CRUD operations on those content types,
  • the API endpoints for the HTML user pages,
  • the Jinja2 HTML page templates for the web pages app users navigate,
  • and finally the javascript handling the pages' interactivity. 

Project Files
The Project Files content type, which represent staff uploaded files, and their associated bandwidth charges is the entire reason behind this web app. Each project receives it's own private file storage, only visible to members of that project.

In fact, if a staff user is not sent a project invite for a given project, there is no way for that staffer to know about the project unless another project member tells them. (Of course, if a person has the admin role, they can see all projects.) 

Project files are version tracked, meaning once uploaded a file is managed by the Project as read only unless a project member checks the file out for modification. After a file that has been checked out is checked back in, it's version number increments as well as other who modified this and how information is retained. 

Project Memos
In addition, project files, depending upon their file type,  may be embedded into project memos. For example, image files may be embedded as visible images in a memo or project description, video files may be embedded as playable videos, and PDF files may be ebdedded with an interactive PDF widget.

ChatGPT is Released
As I implemented these features, ChatGPT was released to the general public. Somewhat curious, I tried some of the popular ChatGPT programming utilities, just to see what ChatGPT could do to help my development process. After some experimentation, I settled on the more secure work flow of having an OpenAI developer API account, and using that to ask ChatGPT about specific library interfaces, as well as using the Phind.com web site: a front end for ChatGPT that embeds a vector database of additional documents and web links you want ChatGPT to reference as you ask questions. 

 

MiniCMS Project page

AI Attorney Implementation
Finding my work accelerated, satisfaction mounting, I chose to try something a little more ambitious: implementing an AI Attorney. The AI Attorney became a new content type I associated with a project. The idea being a project may have questions a project member poses to ChatGPT to learn about project issues. Because use of ChatGPT costs real money, staff are not supposed to be using company time or AI expense on non-work related issues - so any conversations with the AI are retained in the web app database, and are visible to all project members, as well as site admins. 

Tasks Implementation
I spent a day or two working with LangChain, a python library for managing use of LLM AI API interfaces, but perhaps due to my somewhat early look, the pace of changes in LangChain and what I was gaining looked not worth the effort. I wrote my own AI conversation context management. I first wrote a basic conversational context with ChatGPT, where the ongoing conversation is a preamble for each new question. That used FastAPI's background process feature, which at the time ChatGPT was answering questions quite quickly, so the interface seemed fine. That changed a few weeks later, updates and changes at OpenAI made ChatGPT responses take significantly longer - sometimes as much as 90 seconds. Using FastAPI's background processes for ChatGPT was no long feasible - those long waits were causing other users to also wait, users not even asking the AI questions. Which led to the addition of a few more Docker Containers for the creation of a remote to the web app process task system. Basically separate processes that baby sit the communication with ChatGPT, so the web app itself is not blocked waiting for OpenAI responses. Implemented as containers to host Redis for a message server, Celery as a remote task server, and the OpenAI API logic I wrote for the AI Attorney became a Celery Worker. The image at the opening of this article is the figure showing these relationships. This setup enables the web app to send OpenAI (or other time consuming processes) to Celery for remote processing without impacting the response rate or user experience of the wep app users.

AI Conversation Management
I then implemented within Celery Tasks a system with three separate ChatGPT instances, each in a separate role: 1) a front end AI Attorney with the role of interacting with the end user; 2) a conversation compressor role where ChatGPT looks at the current conversation and rewrites it to a minimal representation to conserve context memory, and finally 3) a conversation authority that looks at both the last asked question and the current conversation memory, rewriting both with minimal context memory use and no loss of key conversation information. This system more or less worked, but as something to compare against I also implemented a single task version where the Celery Worker simply had the first role from the more complicated system of three roles. 

Also, when ChatGPT was initially released it was popular to try to jail break any roles or restrictions on ChatGPT's responses. Trying pretty much every such hack on my little AI Attorney with the three separate tasks and roles managing conversation compression tended to break those roles and the illusion of conversing with an AI Attorney fails. However, the single task and role of an AI Attorney that is simply prompted to expect a legal question from someone needing legal advice often worked despite jail break usage. Working despite jail breaking key phrases is probably due the AI Attorney role being minimal:

You are a bilingual English and Spanish attorney and CA Law Professor. 
You work for the [client redacted], a Sacramento Immigration Law firm. 
You are meeting a potential client whom is seeking law advice. 
You want them to hire the firm. 
You only answer truthfully. 
Let's work out how to help the client in a step by step way so we are sure to have the right answer, the client understands, and they hire us.
If multiple options exist for the client, explain each option. 
If you do not have an answer, say "I do not know".

Trial Use
After demonstrating the initial version of the AI Attorney to my family member and the law firm's staff, a purpose of this AI Attorney was selected as an initial test use: to reduce time when interviewing prospective new clients. Typically a human attorney is used for these potential new client interviews. Because an attorney's education and experience is required to identify what legal work a new client needs. Of course, an attorney's time is the most expensive time there is at a law firm, and interviewing a new client about what work they need tends not to be billable. Using this basic AI Attorney, simply prompted with the role that it is interviewing a prospective law client and it needs to identify the legal work that can be done, paralegals and other non-attorney but experienced staff can now handle new client interviews. These interviews can even take place in other languges, the specific legal staffer does not know - the AI Attorney provides the translations to both parties. And finally, a summary of the AI Attorney is reviewed by a human attorney, for verification we're not out in nonsense-land. This trial is just begun, so expect an update...  

The MiniCMS is basically done. You can see the source, and if you want run your own instance from getting it here: https://github.com/bsenftner/miniCMS

tags: FastAPI