diff --git a/asianpaint-detail-dark.png b/asianpaint-detail-dark.png
new file mode 100644
index 00000000..78946cf5
Binary files /dev/null and b/asianpaint-detail-dark.png differ
diff --git a/asianpaint-final-dark.png b/asianpaint-final-dark.png
new file mode 100644
index 00000000..a2fbfc69
Binary files /dev/null and b/asianpaint-final-dark.png differ
diff --git a/asianpaint-improved-dark.png b/asianpaint-improved-dark.png
new file mode 100644
index 00000000..cfbe80e6
Binary files /dev/null and b/asianpaint-improved-dark.png differ
diff --git a/audit-dashboard-dark.png b/audit-dashboard-dark.png
new file mode 100644
index 00000000..769f45ed
Binary files /dev/null and b/audit-dashboard-dark.png differ
diff --git a/audit-dashboard-full.png b/audit-dashboard-full.png
new file mode 100644
index 00000000..85a7e8ba
Binary files /dev/null and b/audit-dashboard-full.png differ
diff --git a/audit-history-full.png b/audit-history-full.png
new file mode 100644
index 00000000..98f06720
Binary files /dev/null and b/audit-history-full.png differ
diff --git a/audit-howItWorks-dark.png b/audit-howItWorks-dark.png
new file mode 100644
index 00000000..6bcb1fe3
Binary files /dev/null and b/audit-howItWorks-dark.png differ
diff --git a/audit-howItWorks-full.png b/audit-howItWorks-full.png
new file mode 100644
index 00000000..b9fe7e96
Binary files /dev/null and b/audit-howItWorks-full.png differ
diff --git a/audit-stock-datasources.png b/audit-stock-datasources.png
new file mode 100644
index 00000000..558a8c18
Binary files /dev/null and b/audit-stock-datasources.png differ
diff --git a/audit-stock-debates.png b/audit-stock-debates.png
new file mode 100644
index 00000000..3da0b0a8
Binary files /dev/null and b/audit-stock-debates.png differ
diff --git a/audit-stock-detail.png b/audit-stock-detail.png
new file mode 100644
index 00000000..d3d96b91
Binary files /dev/null and b/audit-stock-detail.png differ
diff --git a/audit-stock-pipeline.png b/audit-stock-pipeline.png
new file mode 100644
index 00000000..b49ed075
Binary files /dev/null and b/audit-stock-pipeline.png differ
diff --git a/audit2-dashboard-after-fix.png b/audit2-dashboard-after-fix.png
new file mode 100644
index 00000000..71b40a66
Binary files /dev/null and b/audit2-dashboard-after-fix.png differ
diff --git a/audit2-dashboard-fixed.png b/audit2-dashboard-fixed.png
new file mode 100644
index 00000000..15ae77f5
Binary files /dev/null and b/audit2-dashboard-fixed.png differ
diff --git a/audit2-dashboard-full.png b/audit2-dashboard-full.png
new file mode 100644
index 00000000..3eb4509c
Binary files /dev/null and b/audit2-dashboard-full.png differ
diff --git a/audit2-history-full.png b/audit2-history-full.png
new file mode 100644
index 00000000..19ed1a8f
Binary files /dev/null and b/audit2-history-full.png differ
diff --git a/audit2-howitworks-full.png b/audit2-howitworks-full.png
new file mode 100644
index 00000000..b9fe7e96
Binary files /dev/null and b/audit2-howitworks-full.png differ
diff --git a/audit2-stockcards-companyname.png b/audit2-stockcards-companyname.png
new file mode 100644
index 00000000..4ae38ed8
Binary files /dev/null and b/audit2-stockcards-companyname.png differ
diff --git a/audit2-stockdetail-full.png b/audit2-stockdetail-full.png
new file mode 100644
index 00000000..c5be2ecb
Binary files /dev/null and b/audit2-stockdetail-full.png differ
diff --git a/audit3-asianpaint-bottom.png b/audit3-asianpaint-bottom.png
new file mode 100644
index 00000000..ac6027c9
Binary files /dev/null and b/audit3-asianpaint-bottom.png differ
diff --git a/audit3-dashboard-1440-dark.png b/audit3-dashboard-1440-dark.png
new file mode 100644
index 00000000..bef16f1b
Binary files /dev/null and b/audit3-dashboard-1440-dark.png differ
diff --git a/audit3-dashboard-1440-light.png b/audit3-dashboard-1440-light.png
new file mode 100644
index 00000000..e6d0fad5
Binary files /dev/null and b/audit3-dashboard-1440-light.png differ
diff --git a/audit3-dashboard-dark.png b/audit3-dashboard-dark.png
new file mode 100644
index 00000000..08406d8a
Binary files /dev/null and b/audit3-dashboard-dark.png differ
diff --git a/audit3-dashboard-final-light.png b/audit3-dashboard-final-light.png
new file mode 100644
index 00000000..6df06fea
Binary files /dev/null and b/audit3-dashboard-final-light.png differ
diff --git a/audit3-dashboard-fixed-light.png b/audit3-dashboard-fixed-light.png
new file mode 100644
index 00000000..6df06fea
Binary files /dev/null and b/audit3-dashboard-fixed-light.png differ
diff --git a/audit3-dashboard-light.png b/audit3-dashboard-light.png
new file mode 100644
index 00000000..05759a75
Binary files /dev/null and b/audit3-dashboard-light.png differ
diff --git a/audit3-history-expanded-light.png b/audit3-history-expanded-light.png
new file mode 100644
index 00000000..93983f4f
Binary files /dev/null and b/audit3-history-expanded-light.png differ
diff --git a/audit3-history-light.png b/audit3-history-light.png
new file mode 100644
index 00000000..4af3ab8c
Binary files /dev/null and b/audit3-history-light.png differ
diff --git a/audit3-howit-works-light.png b/audit3-howit-works-light.png
new file mode 100644
index 00000000..b9fe7e96
Binary files /dev/null and b/audit3-howit-works-light.png differ
diff --git a/audit3-mobile-dark.png b/audit3-mobile-dark.png
new file mode 100644
index 00000000..9400741b
Binary files /dev/null and b/audit3-mobile-dark.png differ
diff --git a/dashboard-dark-audit.png b/dashboard-dark-audit.png
new file mode 100644
index 00000000..49c3a560
Binary files /dev/null and b/dashboard-dark-audit.png differ
diff --git a/dashboard-dark-bottom.png b/dashboard-dark-bottom.png
new file mode 100644
index 00000000..9a475460
Binary files /dev/null and b/dashboard-dark-bottom.png differ
diff --git a/dashboard-dark-full.png b/dashboard-dark-full.png
new file mode 100644
index 00000000..5a6ba516
Binary files /dev/null and b/dashboard-dark-full.png differ
diff --git a/dashboard-dark-top.png b/dashboard-dark-top.png
new file mode 100644
index 00000000..93b38e92
Binary files /dev/null and b/dashboard-dark-top.png differ
diff --git a/dashboard-full-audit.png b/dashboard-full-audit.png
new file mode 100644
index 00000000..c51fe780
Binary files /dev/null and b/dashboard-full-audit.png differ
diff --git a/dashboard-improved-dark.png b/dashboard-improved-dark.png
new file mode 100644
index 00000000..08406d8a
Binary files /dev/null and b/dashboard-improved-dark.png differ
diff --git a/dashboard-light-top.png b/dashboard-light-top.png
new file mode 100644
index 00000000..44131913
Binary files /dev/null and b/dashboard-light-top.png differ
diff --git a/desktop-dark-grid-final.png b/desktop-dark-grid-final.png
new file mode 100644
index 00000000..7298fb28
Binary files /dev/null and b/desktop-dark-grid-final.png differ
diff --git a/frontend/backend/database.py b/frontend/backend/database.py
index 35f956b8..327af908 100644
--- a/frontend/backend/database.py
+++ b/frontend/backend/database.py
@@ -8,6 +8,118 @@ from typing import Optional
DB_PATH = Path(__file__).parent / "recommendations.db"
+NIFTY_50_NAMES = {
+ 'RELIANCE': 'Reliance Industries Ltd',
+ 'TCS': 'Tata Consultancy Services Ltd',
+ 'HDFCBANK': 'HDFC Bank Ltd',
+ 'INFY': 'Infosys Ltd',
+ 'ICICIBANK': 'ICICI Bank Ltd',
+ 'HINDUNILVR': 'Hindustan Unilever Ltd',
+ 'ITC': 'ITC Ltd',
+ 'SBIN': 'State Bank of India',
+ 'BHARTIARTL': 'Bharti Airtel Ltd',
+ 'KOTAKBANK': 'Kotak Mahindra Bank Ltd',
+ 'LT': 'Larsen & Toubro Ltd',
+ 'AXISBANK': 'Axis Bank Ltd',
+ 'ASIANPAINT': 'Asian Paints Ltd',
+ 'MARUTI': 'Maruti Suzuki India Ltd',
+ 'HCLTECH': 'HCL Technologies Ltd',
+ 'SUNPHARMA': 'Sun Pharmaceutical Industries Ltd',
+ 'TITAN': 'Titan Company Ltd',
+ 'BAJFINANCE': 'Bajaj Finance Ltd',
+ 'WIPRO': 'Wipro Ltd',
+ 'ULTRACEMCO': 'UltraTech Cement Ltd',
+ 'NESTLEIND': 'Nestle India Ltd',
+ 'NTPC': 'NTPC Ltd',
+ 'POWERGRID': 'Power Grid Corporation of India Ltd',
+ 'M&M': 'Mahindra & Mahindra Ltd',
+ 'TATAMOTORS': 'Tata Motors Ltd',
+ 'ONGC': 'Oil & Natural Gas Corporation Ltd',
+ 'JSWSTEEL': 'JSW Steel Ltd',
+ 'TATASTEEL': 'Tata Steel Ltd',
+ 'ADANIENT': 'Adani Enterprises Ltd',
+ 'ADANIPORTS': 'Adani Ports and SEZ Ltd',
+ 'COALINDIA': 'Coal India Ltd',
+ 'BAJAJFINSV': 'Bajaj Finserv Ltd',
+ 'TECHM': 'Tech Mahindra Ltd',
+ 'HDFCLIFE': 'HDFC Life Insurance Company Ltd',
+ 'SBILIFE': 'SBI Life Insurance Company Ltd',
+ 'GRASIM': 'Grasim Industries Ltd',
+ 'DIVISLAB': "Divi's Laboratories Ltd",
+ 'DRREDDY': "Dr. Reddy's Laboratories Ltd",
+ 'CIPLA': 'Cipla Ltd',
+ 'BRITANNIA': 'Britannia Industries Ltd',
+ 'EICHERMOT': 'Eicher Motors Ltd',
+ 'APOLLOHOSP': 'Apollo Hospitals Enterprise Ltd',
+ 'INDUSINDBK': 'IndusInd Bank Ltd',
+ 'HEROMOTOCO': 'Hero MotoCorp Ltd',
+ 'TATACONSUM': 'Tata Consumer Products Ltd',
+ 'BPCL': 'Bharat Petroleum Corporation Ltd',
+ 'UPL': 'UPL Ltd',
+ 'HINDALCO': 'Hindalco Industries Ltd',
+ 'BAJAJ-AUTO': 'Bajaj Auto Ltd',
+ 'LTIM': 'LTIMindtree Ltd',
+}
+
+
+def _truncate_at_word(text: str, max_len: int) -> str:
+ """Truncate text at a word boundary to avoid mid-word cuts."""
+ if len(text) <= max_len:
+ return text
+ truncated = text[:max_len]
+ last_space = truncated.rfind(' ')
+ if last_space > max_len * 0.6:
+ return truncated[:last_space] + '...'
+ return truncated + '...'
+
+
+def _extract_reason(raw_analysis: str) -> str:
+ """Extract clean reason text from raw LLM analysis output.
+
+ Strips markdown bold markers and skips the metadata prefix
+ (FINAL DECISION, HOLD_DAYS, CONFIDENCE, RISK_LEVEL) to return
+ the actual analytical content, truncated at word boundaries.
+ """
+ if not raw_analysis:
+ return ''
+
+ text = raw_analysis.replace('**', '').strip()
+
+ # Look for "RISK ASSESSMENT:" or "RISK_ASSESSMENT:" and return text after it
+ for marker in ('RISK ASSESSMENT:', 'RISK_ASSESSMENT:'):
+ idx = text.upper().find(marker.upper())
+ if idx != -1:
+ after = text[idx + len(marker):].strip()
+ if after:
+ return _truncate_at_word(after, 500)
+
+ # Look for the last substantive paragraph after metadata lines
+ lines = text.split('\n')
+ content_lines = []
+ past_metadata = False
+ for line in lines:
+ stripped = line.strip()
+ if not stripped:
+ continue
+ upper_line = stripped.upper()
+ is_metadata = (
+ upper_line.startswith('FINAL DECISION:')
+ or upper_line.startswith('HOLD_DAYS:')
+ or upper_line.startswith('CONFIDENCE:')
+ or upper_line.startswith('RISK_LEVEL:')
+ )
+ if is_metadata:
+ past_metadata = True
+ continue
+ if past_metadata or not is_metadata:
+ content_lines.append(stripped)
+
+ if content_lines:
+ return _truncate_at_word(' '.join(content_lines), 500)
+
+ # Fallback: return original text truncated
+ return _truncate_at_word(text, 500)
+
def sanitize_decision(raw: str) -> str:
"""Extract BUY/SELL/HOLD from potentially noisy LLM output.
@@ -1470,18 +1582,18 @@ def update_daily_recommendation_summary(date: str):
buy_count += 1
buy_stocks.append({
'symbol': row['symbol'],
- 'company_name': row['company_name'] or row['symbol'],
+ 'company_name': NIFTY_50_NAMES.get(row['symbol'], row['company_name'] or row['symbol']),
'confidence': row['confidence'] or 'MEDIUM',
- 'reason': (row['raw_analysis'] or '')[:200],
+ 'reason': _extract_reason(row['raw_analysis'] or ''),
'rank': row['rank']
})
elif decision == 'SELL':
sell_count += 1
sell_stocks.append({
'symbol': row['symbol'],
- 'company_name': row['company_name'] or row['symbol'],
+ 'company_name': NIFTY_50_NAMES.get(row['symbol'], row['company_name'] or row['symbol']),
'confidence': row['confidence'] or 'MEDIUM',
- 'reason': (row['raw_analysis'] or '')[:200],
+ 'reason': _extract_reason(row['raw_analysis'] or ''),
'rank': row['rank']
})
else:
diff --git a/frontend/backend/recommendations.db b/frontend/backend/recommendations.db
index 9b5e8dbe..30026f3e 100644
Binary files a/frontend/backend/recommendations.db and b/frontend/backend/recommendations.db differ
diff --git a/frontend/src/components/StockCard.tsx b/frontend/src/components/StockCard.tsx
index cc6aac08..c6bb3e07 100644
--- a/frontend/src/components/StockCard.tsx
+++ b/frontend/src/components/StockCard.tsx
@@ -1,6 +1,13 @@
import { Link } from 'react-router-dom';
import { TrendingUp, TrendingDown, Minus, ChevronRight, Clock } from 'lucide-react';
import type { StockAnalysis, Decision } from '../types';
+import { NIFTY_50_STOCKS } from '../types';
+
+/** Resolve the display name for a stock, falling back to NIFTY_50_STOCKS when the backend stored the ticker as company_name */
+function getCompanyName(symbol: string, providedName?: string): string {
+ if (providedName && providedName !== symbol) return providedName;
+ return NIFTY_50_STOCKS.find(s => s.symbol === symbol)?.company_name || symbol;
+}
interface StockCardProps {
stock: StockAnalysis;
@@ -151,7 +158,7 @@ export default function StockCard({ stock, showDetails = true, compact = false }
}`} aria-hidden="true" />
{stock.symbol}
·
- {stock.company_name}
+ {getCompanyName(stock.symbol, stock.company_name)}
@@ -172,7 +179,7 @@ export default function StockCard({ stock, showDetails = true, compact = false }
{stock.symbol}
- {stock.company_name}
+ {getCompanyName(stock.symbol, stock.company_name)}
{showDetails && (
@@ -201,7 +208,7 @@ export function StockCardCompact({ stock }: { stock: StockAnalysis }) {
{stock.symbol}
·
- {stock.company_name}
+ {getCompanyName(stock.symbol, stock.company_name)}
diff --git a/frontend/src/components/TopPicks.tsx b/frontend/src/components/TopPicks.tsx
index 579e3ad0..42566f06 100644
--- a/frontend/src/components/TopPicks.tsx
+++ b/frontend/src/components/TopPicks.tsx
@@ -3,6 +3,21 @@ import { Trophy, AlertTriangle, TrendingUp, TrendingDown, ChevronRight } from 'l
import type { TopPick, StockToAvoid } from '../types';
import { RankBadge } from './StockCard';
+/** Extract just the risk assessment reasoning from raw LLM output */
+function cleanReason(reason?: string): string {
+ if (!reason) return '';
+ let text = reason.replace(/\*\*/g, '').replace(/\*/g, '');
+ // Try to extract text after "RISK ASSESSMENT:" or "RISK_ASSESSMENT:"
+ const riskMatch = text.match(/RISK[_ ]ASSESSMENT:\s*([\s\S]*)/i);
+ if (riskMatch) return riskMatch[1].trim();
+ // Fallback: strip known metadata prefixes
+ text = text.replace(/FINAL DECISION:\s*\w+\s*/i, '');
+ text = text.replace(/HOLD_DAYS:\s*\S+\s*/i, '');
+ text = text.replace(/CONFIDENCE:\s*\w+\s*/i, '');
+ text = text.replace(/RISK_LEVEL:\s*\w+\s*/i, '');
+ return text.trim();
+}
+
interface TopPicksProps {
picks: TopPick[];
}
@@ -44,7 +59,7 @@ export default function TopPicks({ picks }: TopPicksProps) {
BUY
- {pick.reason?.replace(/\*\*/g, '').replace(/\*/g, '')}
+ {cleanReason(pick.reason)}
-
+
{stocks.map((stock) => {
return (
-
+
{stock.symbol}
SELL
-
{stock.reason?.replace(/\*\*/g, '').replace(/\*/g, '')}
+ {stock.company_name && stock.company_name !== stock.symbol && (
+
{stock.company_name}
+ )}
+
{cleanReason(stock.reason)}
diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx
index 480bcd59..42318262 100644
--- a/frontend/src/pages/Dashboard.tsx
+++ b/frontend/src/pages/Dashboard.tsx
@@ -264,7 +264,7 @@ export default function Dashboard() {
// Normal mode: only show analyzed stocks
return (recommendation ? Object.values(recommendation.analysis) : []).map(s => ({
symbol: s.symbol,
- company_name: s.company_name,
+ company_name: NIFTY_50_STOCKS.find(n => n.symbol === s.symbol)?.company_name || s.company_name,
liveState: 'completed' as StockLiveState,
analysis: s,
}));
@@ -538,8 +538,8 @@ export default function Dashboard() {
{/* How It Works Section */}
- {/* Top Picks and Avoid Section - Side by Side Compact */}
-
+ {/* Top Picks and Avoid Section - Side by Side when both present */}
+
0 ? 'lg:grid-cols-2' : ''}`}>
{recommendation.top_picks.length > 0 && (
)}
@@ -561,10 +561,10 @@ export default function Dashboard() {
setFilter('ALL')}
aria-pressed={filter === 'ALL'}
- className={`px-2.5 py-1 text-xs font-medium rounded-md transition-all focus:outline-none focus:ring-2 focus:ring-nifty-500 focus:ring-offset-1 dark:focus:ring-offset-slate-800 ${
+ className={`px-2.5 py-1 text-xs font-medium rounded-md transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-nifty-500 focus:ring-offset-1 dark:focus:ring-offset-slate-800 ${
filter === 'ALL'
? 'bg-nifty-600 text-white shadow-sm'
- : 'bg-gray-100 dark:bg-slate-600 text-gray-700 dark:text-gray-200 hover:bg-gray-200 dark:hover:bg-slate-500'
+ : 'bg-gray-100 dark:bg-slate-600 text-gray-700 dark:text-gray-200 hover:bg-gray-200 dark:hover:bg-slate-500 active:scale-95'
}`}
>
All ({total})
@@ -572,10 +572,10 @@ export default function Dashboard() {
setFilter('BUY')}
aria-pressed={filter === 'BUY'}
- className={`px-2.5 py-1 text-xs font-medium rounded-md transition-all focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-1 dark:focus:ring-offset-slate-800 ${
+ className={`px-2.5 py-1 text-xs font-medium rounded-md transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-1 dark:focus:ring-offset-slate-800 ${
filter === 'BUY'
? 'bg-green-600 text-white shadow-sm'
- : 'bg-green-50 dark:bg-green-900/30 text-green-700 dark:text-green-400 hover:bg-green-100 dark:hover:bg-green-900/50'
+ : 'bg-green-50 dark:bg-green-900/30 text-green-700 dark:text-green-400 hover:bg-green-100 dark:hover:bg-green-900/50 active:scale-95'
}`}
>
Buy ({buy})
@@ -583,10 +583,10 @@ export default function Dashboard() {
setFilter('HOLD')}
aria-pressed={filter === 'HOLD'}
- className={`px-2.5 py-1 text-xs font-medium rounded-md transition-all focus:outline-none focus:ring-2 focus:ring-amber-500 focus:ring-offset-1 dark:focus:ring-offset-slate-800 ${
+ className={`px-2.5 py-1 text-xs font-medium rounded-md transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-amber-500 focus:ring-offset-1 dark:focus:ring-offset-slate-800 ${
filter === 'HOLD'
? 'bg-amber-600 text-white shadow-sm'
- : 'bg-amber-50 dark:bg-amber-900/30 text-amber-700 dark:text-amber-400 hover:bg-amber-100 dark:hover:bg-amber-900/50'
+ : 'bg-amber-50 dark:bg-amber-900/30 text-amber-700 dark:text-amber-400 hover:bg-amber-100 dark:hover:bg-amber-900/50 active:scale-95'
}`}
>
Hold ({hold})
@@ -594,10 +594,10 @@ export default function Dashboard() {
setFilter('SELL')}
aria-pressed={filter === 'SELL'}
- className={`px-2.5 py-1 text-xs font-medium rounded-md transition-all focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-1 dark:focus:ring-offset-slate-800 ${
+ className={`px-2.5 py-1 text-xs font-medium rounded-md transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-1 dark:focus:ring-offset-slate-800 ${
filter === 'SELL'
? 'bg-red-600 text-white shadow-sm'
- : 'bg-red-50 dark:bg-red-900/30 text-red-700 dark:text-red-400 hover:bg-red-100 dark:hover:bg-red-900/50'
+ : 'bg-red-50 dark:bg-red-900/30 text-red-700 dark:text-red-400 hover:bg-red-100 dark:hover:bg-red-900/50 active:scale-95'
}`}
>
Sell ({sell})
@@ -605,7 +605,7 @@ export default function Dashboard() {
|
setSortBy(sortBy === 'rank' ? 'symbol' : 'rank')}
- className={`px-2.5 py-1 text-xs font-medium rounded-md transition-all focus:outline-none focus:ring-2 focus:ring-nifty-500 focus:ring-offset-1 dark:focus:ring-offset-slate-800 ${
+ className={`px-2.5 py-1 text-xs font-medium rounded-md transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-nifty-500 focus:ring-offset-1 dark:focus:ring-offset-slate-800 active:scale-95 ${
sortBy === 'rank'
? 'bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-400'
: 'bg-gray-100 dark:bg-slate-600 text-gray-700 dark:text-gray-200 hover:bg-gray-200 dark:hover:bg-slate-500'
@@ -623,7 +623,7 @@ export default function Dashboard() {
placeholder="Search by symbol or company name..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
- className="w-full pl-9 pr-9 py-2 text-sm rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-nifty-500 focus:border-transparent"
+ className="w-full pl-9 pr-9 py-2 text-sm rounded-lg border border-gray-200 dark:border-slate-600 bg-white dark:bg-slate-700 text-gray-900 dark:text-gray-100 placeholder-gray-400 dark:placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-nifty-500 focus:border-nifty-400 dark:focus:border-nifty-500 transition-all duration-200"
/>
{searchQuery && (
-
+
{filteredItems.map((item) => {
// COMPLETED with analysis data: clickable link
if (item.liveState === 'completed' && item.analysis) {
@@ -645,14 +645,14 @@ export default function Dashboard() {
-
+
{item.symbol}
-
+
{item.company_name}
{item.analysis.hold_days != null && item.analysis.hold_days > 0 && item.analysis.decision !== 'SELL' && (
@@ -755,7 +755,7 @@ export default function Dashboard() {
{/* Compact CTA */}
{stock.symbol}
-
{stock.company_name}
+
{(stock.company_name && stock.company_name !== stock.symbol) ? stock.company_name : (NIFTY_50_STOCKS.find(n => n.symbol === stock.symbol)?.company_name || stock.company_name)}
diff --git a/frontend/src/pages/StockDetail.tsx b/frontend/src/pages/StockDetail.tsx
index c2853d81..f42ccd26 100644
--- a/frontend/src/pages/StockDetail.tsx
+++ b/frontend/src/pages/StockDetail.tsx
@@ -20,6 +20,21 @@ import { api } from '../services/api';
import { useSettings } from '../contexts/SettingsContext';
import type { FullPipelineData, PipelineStep, PipelineStepStatus } from '../types/pipeline';
+/** Extract just the risk assessment reasoning from raw LLM output */
+function cleanReason(reason?: string): string {
+ if (!reason) return '';
+ let text = reason.replace(/\*\*/g, '').replace(/\*/g, '');
+ // Try to extract text after "RISK ASSESSMENT:" or "RISK_ASSESSMENT:"
+ const riskMatch = text.match(/RISK[_ ]ASSESSMENT:\s*([\s\S]*)/i);
+ if (riskMatch) return riskMatch[1].trim();
+ // Fallback: strip known metadata prefixes
+ text = text.replace(/FINAL DECISION:\s*\w+\s*/i, '');
+ text = text.replace(/HOLD_DAYS:\s*\S+\s*/i, '');
+ text = text.replace(/CONFIDENCE:\s*\w+\s*/i, '');
+ text = text.replace(/RISK_LEVEL:\s*\w+\s*/i, '');
+ return text.trim();
+}
+
// Type for real backtest data from API
interface BacktestResult {
date: string;
@@ -940,17 +955,31 @@ export default function StockDetail() {
) : backtestResults.length > 0 ? (
- {backtestResults.map((entry, idx) => (
-
+ {backtestResults.map((entry, idx) => {
+ const isWeekend = [0, 6].includes(new Date(entry.date).getDay());
+ return (
+
{/* Date */}
-
+
{new Date(entry.date).toLocaleDateString('en-IN', {
day: 'numeric',
month: 'short',
})}
-
+
{new Date(entry.date).toLocaleDateString('en-IN', { weekday: 'short' })}
@@ -1005,7 +1034,8 @@ export default function StockDetail() {
)}
- ))}
+ );
+ })}
) : history.length > 0 ? (
@@ -1077,10 +1107,10 @@ export default function StockDetail() {
-
+
Top Pick:
-
- {latestRecommendation.top_picks.find(p => p.symbol === symbol)?.reason?.replace(/\*\*/g, '').replace(/\*/g, '')}
+
+ {cleanReason(latestRecommendation.top_picks.find(p => p.symbol === symbol)?.reason)}
@@ -1091,10 +1121,10 @@ export default function StockDetail() {
-
+
Avoid:
-
- {latestRecommendation.stocks_to_avoid.find(s => s.symbol === symbol)?.reason?.replace(/\*\*/g, '').replace(/\*/g, '')}
+
+ {cleanReason(latestRecommendation.stocks_to_avoid.find(s => s.symbol === symbol)?.reason)}
diff --git a/github-final-check.png b/github-final-check.png
new file mode 100644
index 00000000..a0b904bc
Binary files /dev/null and b/github-final-check.png differ
diff --git a/github-readme-check.png b/github-readme-check.png
new file mode 100644
index 00000000..a2b36db7
Binary files /dev/null and b/github-readme-check.png differ
diff --git a/github-readme-dashboard-screenshot.png b/github-readme-dashboard-screenshot.png
new file mode 100644
index 00000000..295ece8d
Binary files /dev/null and b/github-readme-dashboard-screenshot.png differ
diff --git a/github-readme-footer.png b/github-readme-footer.png
new file mode 100644
index 00000000..f1aac80c
Binary files /dev/null and b/github-readme-footer.png differ
diff --git a/github-readme-header.png b/github-readme-header.png
new file mode 100644
index 00000000..0ef178ec
Binary files /dev/null and b/github-readme-header.png differ
diff --git a/github-readme-screenshots.png b/github-readme-screenshots.png
new file mode 100644
index 00000000..d51572f2
Binary files /dev/null and b/github-readme-screenshots.png differ
diff --git a/github-readme-top.png b/github-readme-top.png
new file mode 100644
index 00000000..ab22af4e
Binary files /dev/null and b/github-readme-top.png differ
diff --git a/history-audit-full.png b/history-audit-full.png
new file mode 100644
index 00000000..15019dbf
Binary files /dev/null and b/history-audit-full.png differ
diff --git a/history-fixes-verification.png b/history-fixes-verification.png
new file mode 100644
index 00000000..1eb7327c
Binary files /dev/null and b/history-fixes-verification.png differ
diff --git a/history-light-full.png b/history-light-full.png
new file mode 100644
index 00000000..54403eb4
Binary files /dev/null and b/history-light-full.png differ
diff --git a/history-light-stocks-expanded.png b/history-light-stocks-expanded.png
new file mode 100644
index 00000000..191bb39e
Binary files /dev/null and b/history-light-stocks-expanded.png differ
diff --git a/history-page-audit.png b/history-page-audit.png
new file mode 100644
index 00000000..b2589c93
Binary files /dev/null and b/history-page-audit.png differ
diff --git a/history-test-1-initial.png b/history-test-1-initial.png
new file mode 100644
index 00000000..a633a717
Binary files /dev/null and b/history-test-1-initial.png differ
diff --git a/history-test-dark-top.png b/history-test-dark-top.png
new file mode 100644
index 00000000..ed806c38
Binary files /dev/null and b/history-test-dark-top.png differ
diff --git a/history-test-trade-timeline.png b/history-test-trade-timeline.png
new file mode 100644
index 00000000..c23faa3f
Binary files /dev/null and b/history-test-trade-timeline.png differ
diff --git a/how-it-works-dark.png b/how-it-works-dark.png
new file mode 100644
index 00000000..967550f4
Binary files /dev/null and b/how-it-works-dark.png differ
diff --git a/how-it-works-light.png b/how-it-works-light.png
new file mode 100644
index 00000000..0e507eb2
Binary files /dev/null and b/how-it-works-light.png differ
diff --git a/mobile-dark-dashboard.png b/mobile-dark-dashboard.png
new file mode 100644
index 00000000..bfd8b8c0
Binary files /dev/null and b/mobile-dark-dashboard.png differ
diff --git a/mobile-dark-grid-fixed.png b/mobile-dark-grid-fixed.png
new file mode 100644
index 00000000..417556dd
Binary files /dev/null and b/mobile-dark-grid-fixed.png differ
diff --git a/mobile-dark-grid.png b/mobile-dark-grid.png
new file mode 100644
index 00000000..a8d93e2c
Binary files /dev/null and b/mobile-dark-grid.png differ
diff --git a/qa-dashboard-hero-viewport.png b/qa-dashboard-hero-viewport.png
new file mode 100644
index 00000000..75ea909c
Binary files /dev/null and b/qa-dashboard-hero-viewport.png differ
diff --git a/stock-detail-asianpaint-light.png b/stock-detail-asianpaint-light.png
new file mode 100644
index 00000000..d6a10f38
Binary files /dev/null and b/stock-detail-asianpaint-light.png differ
diff --git a/stock-detail-dark-audit.png b/stock-detail-dark-audit.png
new file mode 100644
index 00000000..05fa3f36
Binary files /dev/null and b/stock-detail-dark-audit.png differ
diff --git a/verify-dashboard-fixed.png b/verify-dashboard-fixed.png
new file mode 100644
index 00000000..3eb4509c
Binary files /dev/null and b/verify-dashboard-fixed.png differ