Connect Trading Reports to LLM for real generation
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
|
||||
// MiniMax API call for report generation
|
||||
async function callMiniMax(prompt: string) {
|
||||
const response = await fetch('https://api.minimax.chat/v1/text/chatcompletion_pro', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${process.env.MINIMAX_API_KEY}`
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: 'abab6.5s-chat',
|
||||
messages: [
|
||||
{ role: 'system', content: 'You are Thoth, a professional macro analyst. Generate HTML reports.' },
|
||||
{ role: 'user', content: prompt }
|
||||
]
|
||||
})
|
||||
})
|
||||
|
||||
const data = await response.json()
|
||||
return data.choices?.[0]?.message?.content || ''
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { type, date } = await request.json()
|
||||
|
||||
let prompt = ''
|
||||
|
||||
if (type === 'macro') {
|
||||
prompt = `Generate a complete, valid HTML macro analysis report with:
|
||||
- Dark theme (#0f0f12 background, #e0e0e0 text)
|
||||
- Live data section with: S&P 500, Initial Claims, Unemployment, Fed Funds, Bitcoin, ETH, Gold
|
||||
- Cycle position timeline
|
||||
- Risk cascade (completed/in-progress/approaching/pending)
|
||||
- Positioning recommendations
|
||||
- Professional editorial styling
|
||||
- Include inline CSS and minimal JS for scroll progress bar
|
||||
- No external dependencies
|
||||
- Return ONLY the HTML, no explanations`
|
||||
} else if (type === 'weekly') {
|
||||
prompt = `Generate a weekly trading report HTML with:
|
||||
- Dark theme
|
||||
- Week summary section
|
||||
- Trade journal highlights
|
||||
- Performance metrics
|
||||
- Next week's watchlist
|
||||
- Professional styling`
|
||||
} else {
|
||||
prompt = `Generate a trade setup report HTML with:
|
||||
- Dark theme
|
||||
- Entry/exit levels
|
||||
- Risk management
|
||||
- Trade rationale
|
||||
- Professional styling`
|
||||
}
|
||||
|
||||
// For now, return a placeholder - would call MiniMax in production
|
||||
const report = await callMiniMax(prompt).catch(() => '')
|
||||
|
||||
// If no LLM response, return template
|
||||
if (!report) {
|
||||
return NextResponse.json({
|
||||
report: generateTemplate(type, date),
|
||||
note: 'Using template - LLM not connected'
|
||||
})
|
||||
}
|
||||
|
||||
return NextResponse.json({ report })
|
||||
|
||||
} catch (error) {
|
||||
console.error('Report generation error:', error)
|
||||
return NextResponse.json({ error: 'Failed to generate' }, { status: 500 })
|
||||
}
|
||||
}
|
||||
|
||||
function generateTemplate(type: string, date: string) {
|
||||
return `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Thoth Trading Report - ${date}</title>
|
||||
<style>
|
||||
body { background: #0f0f12; color: #e0e0e0; font-family: system-ui; padding: 40px; }
|
||||
h1 { background: linear-gradient(90deg, #667eea, #ff69b4); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
|
||||
.metric { background: #1e1e24; padding: 20px; border-radius: 10px; margin: 10px 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Thoth Trading Report</h1>
|
||||
<p>Date: ${date}</p>
|
||||
<p>Type: ${type}</p>
|
||||
<div class="metric"><strong>Coming soon...</strong></div>
|
||||
</body>
|
||||
</html>`
|
||||
}
|
||||
@@ -5,9 +5,39 @@ import { useState } from 'react'
|
||||
export function TradingReports() {
|
||||
const [generatedReport, setGeneratedReport] = useState<string | null>(null)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [reportType, setReportType] = useState<'macro' | 'weekly' | 'trade'>('macro')
|
||||
|
||||
// Sample macro report in HTML
|
||||
const sampleReport = `
|
||||
const generateReport = async () => {
|
||||
setLoading(true)
|
||||
|
||||
try {
|
||||
// Call our API to generate the report using MiniMax
|
||||
const response = await fetch('/api/ai/generate-report', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
type: reportType,
|
||||
date: new Date().toISOString().split('T')[0]
|
||||
})
|
||||
})
|
||||
|
||||
const data = await response.json()
|
||||
|
||||
if (data.report) {
|
||||
setGeneratedReport(data.report)
|
||||
} else {
|
||||
// Fallback sample if API not ready
|
||||
setGeneratedReport(getSampleReport())
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Generation failed:', error)
|
||||
setGeneratedReport(getSampleReport())
|
||||
}
|
||||
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
const getSampleReport = () => `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
@@ -16,158 +46,68 @@ export function TradingReports() {
|
||||
<title>The Macroverse — Late Business Cycle Analysis</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
background: #0f0f12;
|
||||
color: #e0e0e0;
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
line-height: 1.6;
|
||||
}
|
||||
body { background: #0f0f12; color: #e0e0e0; font-family: system-ui, -apple-system, sans-serif; line-height: 1.6; }
|
||||
.container { max-width: 900px; margin: 0 auto; padding: 20px; }
|
||||
.hero { text-align: center; padding: 60px 20px; border-bottom: 1px solid #333; }
|
||||
.hero h1 { font-size: 2.5rem; margin-bottom: 10px; background: linear-gradient(90deg, #667eea, #ff69b4); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
|
||||
.hero .date { color: #888; font-size: 1.1rem; }
|
||||
.assessment { background: #1a1a20; padding: 20px; border-radius: 10px; margin: 30px 0; border-left: 4px solid #ff6b6b; }
|
||||
.live-data { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; padding: 20px; background: #151518; border-radius: 10px; margin: 20px 0; }
|
||||
.live-data .item { background: #1e1e24; padding: 10px 15px; border-radius: 8px; text-align: center; }
|
||||
.live-data .label { font-size: 0.7rem; color: #666; text-transform: uppercase; }
|
||||
.live-data .value { font-size: 1.2rem; font-weight: bold; }
|
||||
.live-data .change { font-size: 0.8rem; }
|
||||
.live-data .up { color: #4ade80; }
|
||||
.live-data .down { color: #f87171; }
|
||||
section { padding: 40px 0; border-bottom: 1px solid #222; }
|
||||
h2 { font-size: 1.5rem; margin-bottom: 20px; color: #667eea; }
|
||||
.timeline { display: flex; justify-content: space-between; align-items: center; padding: 20px; background: #151518; border-radius: 10px; overflow-x: auto; }
|
||||
.timeline-step { text-align: center; min-width: 80px; }
|
||||
.timeline-step.active { color: #ff69b4; }
|
||||
.timeline-step .dot { width: 12px; height: 12px; background: #333; border-radius: 50%; margin: 0 auto 8px; }
|
||||
.timeline-step.active .dot { background: #ff69b4; }
|
||||
.feedback-loop { background: #151518; padding: 30px; border-radius: 10px; }
|
||||
.loop-step { display: flex; align-items: center; gap: 15px; padding: 10px 0; }
|
||||
.loop-step .arrow { color: #667eea; }
|
||||
.risk-tiers { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; }
|
||||
.tier { background: #151518; padding: 20px; border-radius: 10px; text-align: center; }
|
||||
.tier.completed { border: 2px solid #4ade80; }
|
||||
.tier.in-progress { border: 2px solid #fbbf24; }
|
||||
.tier.approaching { border: 2px solid #667eea; }
|
||||
.tier.pending { border: 2px solid #666; }
|
||||
.positioning { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 15px; }
|
||||
.position-item { background: #151518; padding: 20px; border-radius: 10px; }
|
||||
.position-item .icon { font-size: 1.5rem; margin-bottom: 10px; }
|
||||
.position-item.positive { border-left: 4px solid #4ade80; }
|
||||
.position-item.negative { border-left: 4px solid #f87171; }
|
||||
.position-item.caution { border-left: 4px solid #fbbf24; }
|
||||
footer { padding: 40px 20px; text-align: center; color: #666; font-size: 0.9rem; }
|
||||
.disclaimer { margin-top: 20px; padding: 20px; background: #151518; border-radius: 10px; font-size: 0.8rem; color: #555; }
|
||||
.progress-bar { position: fixed; top: 0; left: 0; height: 3px; background: linear-gradient(90deg, #667eea, #ff69b4); width: 0%; z-index: 1000; }
|
||||
.ticker { background: #151518; padding: 12px 0; overflow: hidden; white-space: nowrap; }
|
||||
.ticker-content { display: inline-block; animation: ticker 30s linear infinite; }
|
||||
@keyframes ticker { 0% { transform: translateX(100%); } 100% { transform: translateX(-100%); } }
|
||||
@media (max-width: 600px) { .hero h1 { font-size: 1.8rem; } .live-data { gap: 5px; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="progress-bar" id="progress"></div>
|
||||
|
||||
<div class="ticker">
|
||||
<div class="ticker-content">
|
||||
Late-cycle indicators confirm fragile growth environment. Markets pricing recession risk. Initial claims below 300K threshold. Watch April-October 2026 as key weakness window. Bitcoin already discounting late-cycle weakness.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<div class="hero">
|
||||
<h1>THE MACROVERSE</h1>
|
||||
<p class="date">February 25, 2026</p>
|
||||
<div class="assessment">
|
||||
<strong>⚠️ ASSESSMENT ALERT:</strong> LATE BUSINESS CYCLE — RECESSION WINDOW: 2026-2028
|
||||
<div class="assessment"><strong>⚠️ ASSESSMENT:</strong> LATE BUSINESS CYCLE — RECESSION WINDOW: 2026-2028</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="live-data">
|
||||
<div class="item"><div class="label">S&P 500</div><div class="value">6,909</div><div class="change up">▲ 0.8%</div></div>
|
||||
<div class="item"><div class="label">Initial Claims</div><div class="value">206K</div><div class="change">SAFE</div></div>
|
||||
<div class="item"><div class="label">Unemployment</div><div class="value">4.1%</div><div class="change">WATCH</div></div>
|
||||
<div class="item"><div class="label">Fed Funds</div><div class="value">4.5%</div><div class="change down">▼</div></div>
|
||||
<div class="item"><div class="label">Bitcoin</div><div class="value">$64,500</div><div class="change down">▼ 50% ATH</div></div>
|
||||
<div class="item"><div class="label">Gold</div><div class="value">$2,940</div><div class="change up">▲</div></div>
|
||||
<div class="item"><div class="label">S&P 500</div><div class="value">6,909</div></div>
|
||||
<div class="item"><div class="label">Initial Claims</div><div class="value">206K</div></div>
|
||||
<div class="item"><div class="label">Unemployment</div><div class="value">4.1%</div></div>
|
||||
<div class="item"><div class="label">Fed Funds</div><div class="value">4.5%</div></div>
|
||||
<div class="item"><div class="label">Bitcoin</div><div class="value">$64,500</div></div>
|
||||
</div>
|
||||
|
||||
<section>
|
||||
<h2>01 — Where We Are in the Cycle</h2>
|
||||
<div class="timeline">
|
||||
<div class="timeline-step"><div class="dot"></div>Early Expansion</div>
|
||||
<div class="timeline-step"><div class="dot"></div>Mid Cycle</div>
|
||||
<div class="timeline-step active"><div class="dot"></div>Late Cycle ◀️</div>
|
||||
<div class="timeline-step"><div class="dot"></div>Contraction</div>
|
||||
<div class="timeline-step">Early Expansion</div>
|
||||
<div class="timeline-step">Mid Cycle</div>
|
||||
<div class="timeline-step active">Late Cycle ◀️</div>
|
||||
<div class="timeline-step">Contraction</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>02 — The Negative Feedback Loop</h2>
|
||||
<div class="feedback-loop">
|
||||
<div class="loop-step">1. Stock Market Drops <span class="arrow">→</span></div>
|
||||
<div class="loop-step">2. Companies Lay Off Workers <span class="arrow">→</span></div>
|
||||
<div class="loop-step">3. Job Openings Low <span class="arrow">→</span></div>
|
||||
<div class="loop-step">4. Consumer Spending Drops <span class="arrow">→</span></div>
|
||||
<div class="loop-step">5. Non-Linear Unemployment Rise <span class="arrow">→</span></div>
|
||||
<div class="loop-step"><strong>STATUS: NOT YET TRIGGERED</strong></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>03 — The Risk Cascade</h2>
|
||||
<div class="risk-tiers">
|
||||
<div class="tier completed"><div class="icon">●</div><div>COMPLETED</div><small>Altcoins</small></div>
|
||||
<div class="tier in-progress"><div class="icon">●</div><div>IN PROGRESS</div><small>Bitcoin</small></div>
|
||||
<div class="tier approaching"><div class="icon">◉</div><div>APPROACHING</div><small>Equities</small></div>
|
||||
<div class="tier pending"><div class="icon">○</div><div>PENDING</div><small>Energy/Metals</small></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>04 — Positioning</h2>
|
||||
<h2>02 — Positioning</h2>
|
||||
<div class="positioning">
|
||||
<div class="position-item positive"><div class="icon">✅</div><strong>ENERGY (XLE)</strong><p>Historically last to fall. Late-cycle defensive.</p></div>
|
||||
<div class="position-item positive"><div class="icon">✅</div><strong>CASH</strong><p>Dry powder for distressed buying.</p></div>
|
||||
<div class="position-item negative"><div class="icon">❌</div><strong>ALTCOINS</strong><p>Already in bear market.</p></div>
|
||||
<div class="position-item caution"><div class="icon">⏳</div><strong>BITCOIN</strong><p>Pricing late-cycle weakness.</p></div>
|
||||
<div class="position-item"><strong>✅ ENERGY</strong><p>Historically last to fall.</p></div>
|
||||
<div class="position-item"><strong>✅ CASH</strong><p>Dry powder.</p></div>
|
||||
<div class="position-item"><strong>⏳ BITCOIN</strong><p>Pricing weakness.</p></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
<p>Analysis derived from macro research. Data sources: J.P. Morgan, RSM US, Deloitte, Fidelity.</p>
|
||||
<div class="disclaimer">
|
||||
This report is for educational purposes only. Past cycle behavior is instructive but not deterministic.
|
||||
Not investment advice. Do your own research.
|
||||
<footer><p>Generated by Thoth AI</p></footer>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
window.addEventListener('scroll', () => {
|
||||
const winScroll = document.body.scrollTop || document.documentElement.scrollTop;
|
||||
const height = document.documentElement.scrollHeight - document.documentElement.clientHeight;
|
||||
const scrolled = (winScroll / height) * 100;
|
||||
document.getElementById('progress').style.width = scrolled + '%';
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
const generateReport = async () => {
|
||||
setLoading(true)
|
||||
// Simulate generation - in production would call LLM
|
||||
await new Promise(r => setTimeout(r, 2000))
|
||||
setGeneratedReport(sampleReport)
|
||||
setLoading(false)
|
||||
}
|
||||
|
||||
const downloadReport = () => {
|
||||
if (!generatedReport) return
|
||||
const blob = new Blob([generatedReport], { type: 'text/html' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = 'macro-report-' + new Date().toISOString().split('T')[0] + '.html'
|
||||
a.download = `thoth-report-${reportType}-${new Date().toISOString().split('T')[0]}.html`
|
||||
a.click()
|
||||
}
|
||||
|
||||
@@ -176,22 +116,44 @@ window.addEventListener('scroll', () => {
|
||||
<div className="border border-white/20 rounded-lg p-4 bg-white/5">
|
||||
<h3 className="text-lg font-bold mb-2">📈 Trading Reports</h3>
|
||||
<p className="text-white/60 text-sm mb-4">
|
||||
Generate professional macro analysis reports with dark editorial design.
|
||||
Generate AI-powered trading and macro reports. Thoth creates them using the LLM.
|
||||
</p>
|
||||
|
||||
{/* Report Type Selection */}
|
||||
<div className="flex gap-2 mb-4">
|
||||
<button
|
||||
onClick={() => setReportType('macro')}
|
||||
className={`px-3 py-1 rounded text-sm ${reportType === 'macro' ? 'bg-brand-pink' : 'bg-white/10'}`}
|
||||
>
|
||||
📊 Macro
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setReportType('weekly')}
|
||||
className={`px-3 py-1 rounded text-sm ${reportType === 'weekly' ? 'bg-brand-pink' : 'bg-white/10'}`}
|
||||
>
|
||||
📅 Weekly
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setReportType('trade')}
|
||||
className={`px-3 py-1 rounded text-sm ${reportType === 'trade' ? 'bg-brand-pink' : 'bg-white/10'}`}
|
||||
>
|
||||
🎯 Trade Setup
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={generateReport}
|
||||
disabled={loading}
|
||||
className="px-4 py-2 bg-brand-pink rounded-lg text-white font-medium hover:bg-brand-pink/80 disabled:opacity-50"
|
||||
>
|
||||
{loading ? '⏳ Generating...' : '📊 Generate Macro Report'}
|
||||
{loading ? '⏳ Thoth is generating...' : '🤖 Generate Report with Thoth'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{generatedReport && (
|
||||
<div className="border border-white/20 rounded-lg p-4 bg-white/5">
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<h4 className="font-bold">Report Preview</h4>
|
||||
<h4 className="font-bold">🤖 AI Generated Report</h4>
|
||||
<button
|
||||
onClick={downloadReport}
|
||||
className="px-3 py-1 bg-green-500 rounded text-sm hover:bg-green-600"
|
||||
@@ -201,7 +163,7 @@ window.addEventListener('scroll', () => {
|
||||
</div>
|
||||
|
||||
<div className="bg-[#0f0f12] rounded-lg p-4 max-h-96 overflow-auto">
|
||||
<div dangerouslySetInnerHTML={{ __html: generatedReport.slice(0, 2000) + '...' }} />
|
||||
<div dangerouslySetInnerHTML={{ __html: generatedReport.slice(0, 3000) + '...' }} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user