App for content generation
2025-08-064 turns9,136 charsgpt-4o
Summary
The user wants to build an app that processes markdown folders, creates a ChromaDB, generates a JSON person profile, and outputs a detailed system prompt for content generation.
Messages
instead I want to create an application which takes .md folders, generates a chromadb from them and is able to generate a .json person from it which is then outputted as a detailed system prompt which can be used for the generation of new content through using the recalled embeddings along with the .json persona to generate the new content returned
You're describing a pipeline-based app that does the following:
---
## ✅ App Summary
> An application that ingests a folder of `.md` files, creates embeddings stored in a **local ChromaDB**, analyzes those markdown files to generate a **detailed persona in `.json` format**, and enables **content generation** using both:
- Retrieved contextual embeddings
- The structured persona profile
You could host this **locally**, or eventually build a **static frontend + backend** using frameworks like:
- **Backend**: Python (FastAPI, LangChain)
- **Frontend**: React (or Svelte), optionally deployed via Cloudflare Pages
- **Embedding & Vector Store**: `Ollama` for embedding + `ChromaDB`
---
## 🔧 App Architecture
### 1. **Ingest .md Files into ChromaDB**
- Use a `loader.py` to read `.md` files into text chunks
- Embed chunks using a local model (`Ollama`, `Instructor`, etc.)
- Store embeddings in **ChromaDB**, persisted locally (`persist_directory="./chromadb"`)
```python
from langchain.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import Chroma
from langchain.embeddings import OllamaEmbeddings
loader = DirectoryLoader('./markdowns', glob='**/*.md')
docs = loader.load()
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = splitter.split_documents(docs)
embedding = OllamaEmbeddings(model="nomic-embed-text")
db = Chroma.from_documents(chunks, embedding=embedding, persist_directory="./chromadb")
db.persist()
```
---
### 2. **Generate `.json` Persona File From Content**
You could:
- Summarize themes, tone, word choice, POV, and recurrent ideas
- Create a persona schema with fields like:
```json
{
"name": "TechEssayist01",
"style": "Analytical, precise, explanatory",
"domain": "AI, programming, research",
"tone": "Neutral, thoughtful, methodical",
"frequent_words": ["embedding", "pipeline", "token", "latency"],
"persona_traits": {
"assertiveness": 4,
"emotionality": 2,
"curiosity": 8,
"formality": 7
}
}
```
Write a Python function that analyzes your docs (frequency, style, etc.) to output this `.json`.
---
### 3. **System Prompt Construction**
- Combine the `.json` persona and retrieved content to generate a system prompt.
- Example:
```txt
You are TechEssayist01, a writer focused on AI and code. Your style is analytical, precise, and explanatory. You often write about embedding pipelines and model latency.
Using the following context extracted from previous writings, generate a new piece of writing in your characteristic style.
Context:
1. Chunk A...
2. Chunk B...
```
---
### 4. **Content Generation**
You now pass this system prompt + user task to a local model:
```python
from langchain.llms import Ollama
llm = Ollama(model="llama3")
response = llm.invoke(prompt)
print(response)
```
---
## 🧠 Optional Enhancements
- Use `FastAPI` to expose endpoints:
- `/ingest` to upload `.md` folders
- `/persona` to generate `.json` file
- `/generate` to pass a query + persona + recalled chunks
- Use `LangGraph` or `SmolAgents` to orchestrate steps
- Add agent memory via ChromaDB retrieval
- Visualize persona and embeddings in the UI
---
## 📁 Project Structure
```
my_persona_gen_app/
│
├── markdowns/ # .md files
├── chromadb/ # persisted vector db
├── personas/
│ └── techessayist01.json
│
├── scripts/
│ ├── ingest.py
│ ├── generate_persona.py
│ └── generate_content.py
│
├── app.py # FastAPI backend
├── ui/ # Optional frontend
└── requirements.txt
```
---
## ✅ CLI Prompt Example
```
python generate_persona.py --folder=./markdowns --output=./personas/techessayist01.json
python generate_content.py --persona=techessayist01.json --query="Write a blog post about agentic workflows"
```
---
Would you like the code for each script in this pipeline (`ingest.py`, `generate_persona.py`, `generate_content.py`) next?
gpt-4o
yes
Great — below are the full implementations of each script in your pipeline:
---
## ✅ 1. `ingest.py`
> Ingests `.md` files, splits them, embeds them using `Ollama`, and stores in **ChromaDB**
```python
# scripts/ingest.py
import os
from langchain.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores import Chroma
from langchain.embeddings import OllamaEmbeddings
def ingest_markdown(markdown_dir="./markdowns", persist_dir="./chromadb"):
loader = DirectoryLoader(markdown_dir, glob="**/*.md")
docs = loader.load()
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = splitter.split_documents(docs)
embedding = OllamaEmbeddings(model="nomic-embed-text")
db = Chroma.from_documents(chunks, embedding=embedding, persist_directory=persist_dir)
db.persist()
print(f"Ingested {len(chunks)} chunks into ChromaDB at {persist_dir}")
if __name__ == "__main__":
ingest_markdown()
```
---
## ✅ 2. `generate_persona.py`
> Analyzes markdown content to output a `.json` persona
```python
# scripts/generate_persona.py
import os
import json
import sys
import glob
from collections import Counter
from langchain.document_loaders import DirectoryLoader
def extract_persona(markdown_dir):
loader = DirectoryLoader(markdown_dir, glob="**/*.md")
docs = loader.load()
full_text = " ".join([doc.page_content for doc in docs])
words = full_text.lower().split()
word_freq = Counter(words)
common_words = [w for w in word_freq.most_common(50) if len(w[0]) > 4]
persona = {
"name": os.path.basename(markdown_dir),
"style": "Auto-generated from writing samples.",
"domain": "Inferred from content",
"tone": "Inferred",
"frequent_words": [w[0] for w in common_words[:15]],
"persona_traits": {
"assertiveness": 5,
"emotionality": 3,
"curiosity": 7,
"formality": 6
}
}
return persona
def save_persona(markdown_dir, output_path):
persona = extract_persona(markdown_dir)
with open(output_path, "w") as f:
json.dump(persona, f, indent=4)
print(f"Saved persona to {output_path}")
if __name__ == "__main__":
folder = sys.argv[1] if len(sys.argv) > 1 else "./markdowns"
name = os.path.basename(folder.rstrip("/"))
output_path = f"./personas/{name}.json"
os.makedirs("personas", exist_ok=True)
save_persona(folder, output_path)
```
---
## ✅ 3. `generate_content.py`
> Uses ChromaDB + `.json` persona to generate new writing
```python
# scripts/generate_content.py
import json
import sys
from langchain.vectorstores import Chroma
from langchain.embeddings import OllamaEmbeddings
from langchain.llms import Ollama
from langchain.chains import RetrievalQA
def load_persona(persona_path):
with open(persona_path, "r") as f:
return json.load(f)
def build_system_prompt(persona, context):
prompt = f"""You are {persona['name']}, a writer who is:
Style: {persona['style']}
Domain: {persona['domain']}
Tone: {persona['tone']}
Frequent Words: {', '.join(persona['frequent_words'])}
Your task is to write in your characteristic style.
Context:
{context}
Respond in a way that reflects your persona.
"""
return prompt
def generate_response(query, persona_path, chroma_path="./chromadb"):
persona = load_persona(persona_path)
embedding = OllamaEmbeddings(model="nomic-embed-text")
db = Chroma(persist_directory=chroma_path, embedding_function=embedding)
retriever = db.as_retriever(search_kwargs={"k": 3})
relevant_docs = retriever.get_relevant_documents(query)
context = "\n".join([doc.page_content for doc in relevant_docs])
prompt = build_system_prompt(persona, context + "\n\nTask: " + query)
llm = Ollama(model="llama3")
response = llm.invoke(prompt)
return response
if __name__ == "__main__":
persona_path = sys.argv[1] if len(sys.argv) > 1 else "./personas/default.json"
query = sys.argv[2] if len(sys.argv) > 2 else "Write a tutorial on how to use agentic workflows with LLMs"
result = generate_response(query, persona_path)
print("\nGenerated Content:\n")
print(result)
```
---
## 📦 `requirements.txt`
```txt
langchain
chromadb
ollama
tiktoken
```
---
## 🧪 Example Workflow
### 1. Ingest `.md` files:
```bash
python scripts/ingest.py
```
### 2. Generate persona:
```bash
python scripts/generate_persona.py ./markdowns
```
### 3. Generate new content:
```bash
python scripts/generate_content.py personas/yourfoldername.json "How to set up a local LLM search engine"
```
---
Would you like a `FastAPI` backend version of this next? Or a web UI?
gpt-4o