Skip to content

dsdeshna/verse-ai

Repository files navigation

Verse - AI Poetry Style Studio

Verse is a full-stack web application that analyzes your existing poems and uses that analysis to help you generate new writing in your own voice. You upload a collection of your work, the app builds a style profile from it, and you can then generate new poems, edit them inline, or have a conversation about your writing patterns.

The core idea is that generation should be grounded in something real about your writing rather than just a generic prompt. So the app runs a proper NLP analysis first, and that data feeds directly into every LLM call the app makes.


Features

Style Profiles

You create a profile by giving it a name and pasting in poems you have already written. The app analyzes them and stores a quantitative fingerprint of your style: top thematic words by TF-IDF score, sentiment score, average line length, and rhyme density. It also sends the poems to an LLM for a qualitative literary interpretation covering tone, imagery, recurring themes, and structural patterns. Profiles persist in localStorage so they are there when you come back.

You can build multiple profiles for different collections, since most people write differently depending on what they are working on.

Poem Generation

You give a theme or prompt, choose a similarity level on a slider, and the app generates a poem that tries to match your style. The similarity slider changes the actual instruction in the prompt, ranging from "feel free to experiment" at one end to "closely follow the style" at the other. Two candidates are generated at slightly different temperatures and scored for originality against your source poems using trigram overlap. The one with the higher originality score gets returned.

Inline Editing

After a poem is generated, you can select any text in it with your mouse. A small popup appears anchored to the selection, where you type an instruction like "make this darker" or "cut it to one line." The app rewrites only the selected portion while keeping the surrounding lines as context, then splices the result back in. The changed section highlights briefly so you can see what shifted.

Style Chatbot

A slide-in panel where you can ask questions about your writing. The chatbot has access to the full quantitative analysis and LLM interpretation for the profile, plus sample poems, plus conversation history from the last six turns. So you can ask things like "what kinds of imagery do I tend to use?" and get an answer that is grounded in your actual work rather than a generic response.

Auto Style Name

Each profile gets a short poetic name generated from its style features, something like "Fractured Midnight Elegy." It shows up as a subtitle under the profile name.

Theming

Five color themes (Rose Petal, Lavender Dusk, Sage Garden, Peach Sunset, Midnight Blue) with full dark mode support. Themes are built as CSS custom property sets so switching is instant with no layout reflow. Both the color theme and dark mode preference save to localStorage alongside your profiles.


Technical details

Stack

Built with Next.js 16 (App Router) and React 19. LLM inference runs through the Groq SDK. Animations use Framer Motion 12. Styling uses Tailwind CSS v4 with a CSS variable design system layered on top. State lives in a React Context that syncs to localStorage. UUIDs come from the uuid package.

NLP pipeline

src/lib/nlp.js is a pure JavaScript NLP implementation with no external library dependencies. It runs entirely server-side inside the /api/analyze route.

Tokenizer: Splits on whitespace, strips non-alphabetic characters, filters stop words. The specific addition for poetry: words that start with a capital letter but are not the first word on a line are skipped. Poets frequently capitalize mid-line for emphasis ("the Sun rose, and Death followed"), and treating those as meaningful content tokens distorts the vocabulary analysis.

TF-IDF: Computes term frequency-inverse document frequency across all poems in a profile, then averages the document vectors into a centroid. The centroid represents the distinctive thematic vocabulary of the whole collection. The formula uses +1 smoothing on the IDF to avoid division by zero on small corpora:

tfidf(t, d) = (count(t, d) / total_tokens(d)) * log((N + 1) / df(t))

Top words: A separate pass computes raw frequency across all poems and returns the top 20 tokens, displayed in the dashboard as size- and opacity-scaled chips where more frequent words appear larger and more opaque.

Sentiment analysis: Lexicon-based scorer with curated word sets for positive and negative poetic language. The lists are tuned for the vocabulary that shows up in poetry ("bliss", "abyss", "radiant", "wither") rather than general-purpose sentiment lists. Returns a float score plus a label, both of which get injected into generation prompts.

Rhyme density: Takes the last three characters of each line's final word and compares adjacent lines. Returns a float between 0 and 1. This gets passed to the LLM so it knows how strictly to rhyme.

Average line length: Mean word count across all non-empty lines in the corpus. Passed to the generation prompt so line structure is roughly consistent with the original writing.

Style vector: The TF-IDF centroid stored as a flat array of floats. Used for cosine similarity comparisons between profiles or documents.

Similarity and originality checking

src/lib/similarity.js has two separate utilities.

Cosine similarity runs on the TF-IDF style vectors to measure how close two documents are in terms of thematic vocabulary.

Trigram overlap checks generated text against the source corpus for originality. It extracts all three-word sequences from both texts and computes what fraction overlap. If the max overlap across all source poems is above 0.3, the poem is considered too derivative. During generation, the server runs this on both candidates and picks whichever scores lower overlap.

LLM orchestration

src/lib/groq.js is a wrapper around the Groq SDK with a three-model fallback chain: Llama 4 Maverick first, then Llama 3.3 70B, then Mixtral 8x7B. If one model fails, it logs a warning and tries the next. All three failing throws a descriptive error with the last failure message attached.

callGroq handles standard text completion. callGroqJSON enables JSON mode and runs a regex extraction on the response as a fallback for when the model still wraps output in markdown fences.

API routes

All routes are Next.js serverless functions in src/app/api/.

POST /api/analyze takes an array of poem strings, runs the full NLP pipeline, and returns style features plus the style vector.

POST /api/what-ai-thinks sends poems to Groq and requests a structured literary interpretation as JSON. Returns toneDescription, imageryStyle, writingStyle, themes, distinctPatterns, and llmSummary.

POST /api/generate-poem combines the quantitative features and qualitative interpretation into a single generation prompt. Accepts a similarity float that changes the prompt instruction text. Runs two-candidate generation, scores both for originality, and returns the better one with its score.

POST /api/edit-poem accepts the full poem, the selected text, an editing instruction, and the style context. It extracts the 200 characters before and after the selection for context, then asks the LLM to rewrite only the selected portion. Returns the replacement text, which the client splices back into the poem string.

POST /api/chat is the chatbot endpoint. It takes a user message, the full style profile (both quantitative and qualitative), sample poems, and up to the last six conversation turns. Temperature is set to 0.6 to keep responses specific rather than overly creative. Returns the assistant reply.

POST /api/style-name generates a short evocative name for the style based on its features. Runs at temperature 0.9. Returns a plain string.

State and persistence

src/context/AppContext.js manages all application state: the profile array, the active color theme, and dark mode. It reads from localStorage on mount and writes back on every state change. A loaded boolean gates rendering to prevent a hydration flash on first load.

Each profile is a flat object containing its UUID, name, source poems, style features, style vector, LLM interpretation, generated poems, and auto-generated style name. Profile operations (add, update, delete, get by ID) are useCallback-wrapped to keep references stable.

UI

The home screen shows profiles as floating animated cards using Framer Motion keyframe animations on the y-axis. The profile page has a two-column layout: a sticky left panel with stats and collapsible source poem cards, and a main panel with the word frequency visualization, LLM interpretation, and saved generated poems. The poem editor shows a text view where mouse selections trigger a floating popup. The chatbot is a slide-in overlay panel that greets you by the profile name when it opens.


Getting started

You need Node.js 18 or higher and a Groq API key (free at console.groq.com).

git clone https://github.com/yourusername/verse
cd verse
npm install

Create a .env.local file in the root directory:

GROQ_API_KEY=your_key_here
npm run dev

Open http://localhost:3000.


Project structure

src/
├── app/
│   ├── api/
│   │   ├── analyze/route.js          # NLP feature extraction
│   │   ├── chat/route.js             # Style-aware chatbot
│   │   ├── edit-poem/route.js        # Inline selection editing
│   │   ├── generate-poem/route.js    # Two-candidate poem generation
│   │   ├── style-name/route.js       # Auto style name generation
│   │   └── what-ai-thinks/route.js   # LLM literary interpretation
│   ├── profile/[id]/page.js          # Dynamic profile route
│   ├── globals.css                   # CSS variables and base styles
│   ├── layout.js                     # Root layout with AppProvider
│   └── page.js                       # Home screen
├── components/
│   ├── AddPoemsModal.js              # Add more poems to an existing profile
│   ├── CreateProfileModal.js         # Profile creation flow
│   ├── Dashboard.js                  # Stats, word cloud, saved poems view
│   ├── GenerationInterface.js        # Prompt input and similarity slider
│   ├── PoemEditor.js                 # Generated poem with inline editing
│   ├── ProfileBubble.js              # Animated home screen card
│   ├── StyleChatbot.js               # Slide-in chat panel
│   ├── ThemeSwitcher.js              # Color theme and dark mode controls
│   └── ThemeWrapper.js               # CSS variable injection
├── context/
│   └── AppContext.js                 # Global state and localStorage sync
└── lib/
    ├── groq.js                       # Groq SDK wrapper with model fallback
    ├── nlp.js                        # TF-IDF, sentiment, rhyme, tokenizer
    └── similarity.js                 # Cosine similarity and n-gram overlap

License

MIT

About

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors