Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions UPDATES_STRATEGY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,29 @@
# AG-TUNE Strategic Update Plan

This document outlines three major quarter-yearly scale updates envisioned for the AG-TUNE model, aimed at evolving it from a prototype to a production-grade neuro-symbolic poetry engine.

## 1. Deep-Linguistic Neuro-Symbolic Core (Selected for Implementation)
**Goal:** Replace shallow, hardcoded linguistic data with a robust, logic-driven generative engine.
* **Current State:** Uses a tiny hardcoded grammar (~30 words) and a lookup table for rhymes (~16 words).
* **Upgrade:** Implement a feature-based Context-Free Grammar (CFG) with agreement enforcement (Subject-Verb-Object consistency). Replace dictionary lookups with an algorithmic Grapheme-to-Phoneme (G2P) engine for dynamic rhyme and meter detection on *any* English word.
* **Benefit:** Enables infinite vocabulary usage, grammatical correctness, and true poetic structure without relying on massive pre-trained datasets.

## 2. Hierarchical Narrative Planner
**Goal:** Enable the model to "think" in stories rather than just lines.
* **Current State:** Generates line-by-line using a limited look-behind buffer.
* **Upgrade:** Introduce a "Director" agent that plans a stanza-level emotional arc (e.g., "Stanza 1: Loss -> Stanza 2: Bargaining -> Stanza 3: Acceptance"). Use the Rete engine to enforce these high-level constraints during the beam search of each line.
* **Benefit:** Poems will have a cohesive theme and narrative progression.

## 3. Cross-Modal Synesthetic Training
**Goal:** Ground the poem's imagery in sensory reality.
* **Current State:** Embeddings are learned from text co-occurrence only.
* **Upgrade:** Train the emotional embedding space using multimodal data (image-caption pairs or audio-lyrics pairs). Map visual features (brightness, color entropy) to poetic features.
* **Benefit:** The model could generate poetry based on an image or a melody, with grounded metaphors (e.g., describing "yellow" not just as a word, but as a sensation linked to the trained visual concept).

---

## Implementation Selection
We will implement **Update #1: Deep-Linguistic Neuro-Symbolic Core**. This is the most critical foundation; without a robust way to understand and generate language structure, higher-level planning or multimodal inputs cannot be effectively expressed. This update effectively "productionizes" the core generation capability.
# Updates Strategy

## 1. Deep-Linguistic Neuro-Symbolic Core (Selected for Implementation)
Expand Down
9 changes: 9 additions & 0 deletions dev_log.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

> ag-tune-lapoet@1.0.0 dev
> vite


VITE v7.2.6 ready in 397 ms

➜ Local: http://localhost:3000/
➜ Network: use --host to expose
5 changes: 5 additions & 0 deletions package-lock.json

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

79 changes: 35 additions & 44 deletions src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@


import React, { useState, useEffect, useCallback, useRef } from 'react';
import { UniversalLinguisticEngine } from './UniversalLinguisticEngine';

// ============================================================================
// CORE ALGORITHM IMPLEMENTATIONS
Expand Down Expand Up @@ -481,7 +482,8 @@ class AGTuneEngine {
this.valueEstimator = new TDValueEstimator(24, 0.01, 0.95, 0.8);
this.rng = new LaggedFibonacciGenerator();
this.rete = new ReteEngine();
this.parser = new CYKParser(this._getGrammar());
this.ule = new UniversalLinguisticEngine(); // Integration of Production-Grade Logic
this.parser = new CYKParser(this.ule.getGrammar());
this.vocabulary = new Set();
this.embeddings = new Map();
this.emotionalSpace = new Map();
Expand All @@ -491,34 +493,19 @@ class AGTuneEngine {
this._initializeReteRules();
}

/**
* Define grammatical rules for syntactic validation
*/
_getGrammar() {
return {
'S': [['NP', 'VP'], ['VP'], ['S', 'PP']],
'NP': [['Det', 'N'], ['N'], ['Adj', 'N'], ['NP', 'PP']],
'VP': [['V', 'NP'], ['V'], ['Adv', 'VP'], ['VP', 'PP']],
'PP': [['P', 'NP']],
'Det': ['the', 'a', 'an', 'this', 'that', 'my', 'thy'],
'Adj': ['bright', 'dark', 'sweet', 'cold', 'warm', 'soft', 'hard', 'gentle', 'fierce'],
'N': ['heart', 'soul', 'love', 'death', 'life', 'night', 'day', 'sun', 'moon', 'star', 'sea', 'sky', 'wind', 'fire', 'light', 'shadow'],
'V': ['beats', 'breaks', 'shines', 'falls', 'rises', 'calls', 'dies', 'lives', 'loves', 'hates', 'waits', 'seeks', 'finds', 'loses', 'gives', 'takes'],
'Adv': ['softly', 'gently', 'swiftly', 'slowly', 'deeply', 'bright', 'dark'],
'P': ['in', 'on', 'at', 'with', 'without', 'against', 'beneath', 'above', 'through', 'beyond']
};
}

/**
* Initialize Rete constraint checking rules
*/
_initializeReteRules() {
// Rhyme scheme constraint
// Rhyme scheme constraint: NOW USES DYNAMIC PHONETICS
this.rete.addRule('rhymeCheck', [
{ key: 'lastWord', test: (w) => typeof w === 'string' && w.length > 0 },
{ key: 'rhymeScheme', test: (s) => ['A', 'B'].includes(s) }
{ key: 'rhymeTarget', test: (t) => typeof t === 'string' }
], (facts) => {
return facts.rhymeScheme === this._getRhymeGroup(facts.lastWord);
if (!facts.rhymeTarget) return true;
const w1 = this.ule.analyze(facts.lastWord);
const w2 = this.ule.analyze(facts.rhymeTarget);
return w1.rhymePart === w2.rhymePart;
});

// Syllable count constraint (8-10 for iambic pentameter)
Expand All @@ -534,21 +521,6 @@ class AGTuneEngine {
], () => true);
}

/**
* Map word to rhyme group
*/
_getRhymeGroup(word) {
const rhymes = {
'A': ['day', 'way', 'say', 'stay', 'pray', 'grey', 'may', 'play'],
'B': ['night', 'light', 'bright', 'sight', 'fight', 'flight', 'height', 'right']
};

for (const [group, words] of Object.entries(rhymes)) {
if (words.includes(word.toLowerCase())) return group;
}
return null;
}

/**
* Simple tokenization
*/
Expand Down Expand Up @@ -590,10 +562,10 @@ class AGTuneEngine {
}

/**
* Heuristic syllable counting (vowel groups)
* Advanced syllable counting via ULE
*/
_countSyllables(word) {
return word.toLowerCase().match(/[aeiouy]{1,3}/g)?.length || 1;
return this.ule.analyze(word).syllables;
}

/**
Expand Down Expand Up @@ -907,7 +879,7 @@ class AGTuneEngine {
/**
* Generate single line of poetry using A*-guided beam search
*/
generateLine(prompt, targetSyllables = 10, beamWidth = 5, maxIter = 50) {
generateLine(prompt, targetSyllables = 10, beamWidth = 5, rhymeTarget = null, maxIter = 50) {
if (!this.isTrained) throw new Error('Model must be trained before generation');

const context = this._tokenize(prompt);
Expand All @@ -933,7 +905,15 @@ class AGTuneEngine {

// H(n): heuristic cost (multi-objective)
const meterScore = FFTMeterAnalyzer.analyzeStressPattern(this._getStressPattern(newLine));
const rhymeScore = this._getRhymeGroup(word) ? 1 : 0.5;

// Use logic-based rhyming preference if we are near the end of the line
const analysis = this.ule.analyze(word);
let rhymeBonus = 0;
if (rhymeTarget && newSyllableCount >= targetSyllables - 2) {
const targetAnalysis = this.ule.analyze(rhymeTarget);
if (analysis.rhymePart === targetAnalysis.rhymePart) rhymeBonus = 2.0;
}

const cycle = FloydCycleDetector.detect(newContext);
const cyclePenalty = cycle.detected ? cycle.length * 2 : 0;

Expand All @@ -943,7 +923,7 @@ class AGTuneEngine {
// Multi-objective: β1*Structure + β2*Theme + β3*V(S)
const β1 = 0.3, β2 = 0.3, β3 = 0.4;
const H = β1 * (1 - meterScore + cyclePenalty) +
β2 * (1 - rhymeScore) +
β2 * (1 - rhymeBonus) +
β3 * Math.max(0, 2 - aestheticValue);

const totalScore = g + H;
Expand All @@ -965,7 +945,7 @@ class AGTuneEngine {
// Rete constraint verification
const facts = {
lastWord: chosen.word,
rhymeScheme: this._getRhymeGroup(chosen.word),
rhymeTarget: (syllableCount >= targetSyllables - 2) ? rhymeTarget : null, // Only enforce at end of line
syllableCount,
history: context
};
Expand Down Expand Up @@ -994,14 +974,25 @@ class AGTuneEngine {
const allTokens = this._tokenize(prompt);
const states = [];
const rewards = [];
let previousEndWord = null;

for (let i = 0; i < lines; i++) {
// Simple AABB or ABAB logic could be implemented here.
// For now, let's try to make every even line rhyme with the previous one (AABB style approximation)
const rhymeTarget = (i % 2 === 1) ? previousEndWord : null;

const lineObj = this.generateLine(
poem.join(' ') + ' ' + prompt,
10, // Iambic pentameter ~10 syllables
beamWidth
beamWidth,
rhymeTarget
);

const lineTokens = this._tokenize(lineObj.line);
if (lineTokens.length > 0) {
previousEndWord = lineTokens[lineTokens.length - 1];
}

poem.push(lineObj.line);
allTokens.push(...this._tokenize(lineObj.line));
states.push(lineObj.finalState);
Expand Down
Loading
Loading