fix: report 504 — cap triase LLM 5 artikel, narasi_awam persist ke payload; report FE bahasa awam
This commit is contained in:
@@ -52,12 +52,17 @@ func AnalyzeSentiment(ctx context.Context, d Deps, ticker string) model.AgentRes
|
|||||||
pos, neg, neu := 0, 0, 0
|
pos, neg, neu := 0, 0, 0
|
||||||
var keyEvents []string
|
var keyEvents []string
|
||||||
useLLM := d.LLM != nil && d.LLM.Available()
|
useLLM := d.LLM != nil && d.LLM.Available()
|
||||||
|
// Cap LLM triage calls: each is one HTTP round-trip to OmniRoute
|
||||||
|
// (~5-15s). More than 5 articles and report generation exceeds the
|
||||||
|
// 60s reverse-proxy read timeout -> 504 with a persisted-but-stale
|
||||||
|
// report. Rules path covers the rest via keywordSentiment.
|
||||||
|
const maxLLMTriage = 5
|
||||||
for i, a := range news.Results {
|
for i, a := range news.Results {
|
||||||
if i >= 20 {
|
if i >= 20 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
label, conf := "neutral", 0.5
|
label, conf := "neutral", 0.5
|
||||||
if useLLM {
|
if useLLM && i < maxLLMTriage {
|
||||||
label, conf = d.LLM.SentimentTriage(ctx, d.TriageModel, a.Title, a.Body)
|
label, conf = d.LLM.SentimentTriage(ctx, d.TriageModel, a.Title, a.Body)
|
||||||
} else {
|
} else {
|
||||||
label, conf = keywordSentiment(a.Title + " " + a.Body)
|
label, conf = keywordSentiment(a.Title + " " + a.Body)
|
||||||
|
|||||||
@@ -76,7 +76,8 @@ func (b *Builder) Build(ctx context.Context, ticker, profile string) (Report, in
|
|||||||
all = append(all, s.Citations...)
|
all = append(all, s.Citations...)
|
||||||
}
|
}
|
||||||
all = model.MarkStale(all, model.StaleSession(time.Now()))
|
all = model.MarkStale(all, model.StaleSession(time.Now()))
|
||||||
raw, _ := json.Marshal(map[string]any{"ticker": ticker, "sections": sections, "synthesis": synth})
|
narasi := b.narasiAwam(ctx, ticker, synth, sections)
|
||||||
|
raw, _ := json.Marshal(map[string]any{"ticker": ticker, "sections": sections, "synthesis": synth, "narasi_awam": narasi})
|
||||||
citesRaw, _ := json.Marshal(all)
|
citesRaw, _ := json.Marshal(all)
|
||||||
id, err := b.DB.SaveReport(ticker, string(raw), string(citesRaw))
|
id, err := b.DB.SaveReport(ticker, string(raw), string(citesRaw))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -86,7 +87,7 @@ func (b *Builder) Build(ctx context.Context, ticker, profile string) (Report, in
|
|||||||
Ticker: ticker, GeneratedAt: todayStr(),
|
Ticker: ticker, GeneratedAt: todayStr(),
|
||||||
Sections: sections, Synthesis: synth,
|
Sections: sections, Synthesis: synth,
|
||||||
AgentScores: results, AllCitations: all,
|
AgentScores: results, AllCitations: all,
|
||||||
NarasiAwam: b.narasiAwam(ctx, ticker, synth, sections),
|
NarasiAwam: narasi,
|
||||||
}, id, nil
|
}, id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { createSignal, For, Show, onMount } from "solid-js";
|
|||||||
import { useParams } from "@solidjs/router";
|
import { useParams } from "@solidjs/router";
|
||||||
import { api, type ReportPayload } from "../lib/api";
|
import { api, type ReportPayload } from "../lib/api";
|
||||||
import { Citations } from "../components/Citations";
|
import { Citations } from "../components/Citations";
|
||||||
|
import { Term } from "../components/Awam";
|
||||||
import { PageHead, RecBadge } from "../components/ui";
|
import { PageHead, RecBadge } from "../components/ui";
|
||||||
import { Badge } from "../components/ui/badge";
|
import { Badge } from "../components/ui/badge";
|
||||||
import { Button } from "../components/ui/button";
|
import { Button } from "../components/ui/button";
|
||||||
@@ -84,16 +85,17 @@ export default function Report() {
|
|||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
<For each={rep()!.sections}>
|
<For each={rep()!.sections}>
|
||||||
{(s) => <Card><CardHeader><CardTitle>{s.name}</CardTitle></CardHeader><CardContent><p class="whitespace-pre-wrap text-sm">{s.body}</p><div class="mt-2"><Citations items={s.citations} /></div></CardContent></Card>}
|
{(s) => <Card><CardHeader><CardTitle class="capitalize">{s.name}</CardTitle></CardHeader><CardContent><p class="whitespace-pre-wrap text-sm">{s.body}</p><div class="mt-2"><Citations items={s.citations} /></div></CardContent></Card>}
|
||||||
</For>
|
</For>
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader><CardTitle>Interrogate this report</CardTitle></CardHeader>
|
<CardHeader><CardTitle>Tanya soal report ini 💬</CardTitle></CardHeader>
|
||||||
<CardContent class="space-y-3">
|
<CardContent class="space-y-3">
|
||||||
<div class="flex gap-2">
|
<div class="flex gap-2">
|
||||||
<TextField class="flex-1"><TextFieldInput placeholder="Ask about this report…" value={question()} onInput={(e) => setQuestion(e.currentTarget.value)} /></TextField>
|
<TextField class="flex-1"><TextFieldInput placeholder="Mis. kenapa conviction-nya segitu?" value={question()} onInput={(e) => setQuestion(e.currentTarget.value)} /></TextField>
|
||||||
<Button onClick={ask} disabled={asking()}>{asking() ? "…" : "Ask"}</Button>
|
<Button onClick={ask} disabled={asking()}>{asking() ? "…" : "Tanya"}</Button>
|
||||||
</div>
|
</div>
|
||||||
<Show when={answer()}><p class="text-sm">{answer()}</p></Show>
|
<Show when={answer()}><p class="whitespace-pre-wrap text-sm">{answer()}</p></Show>
|
||||||
|
<p class="text-xs text-muted-foreground">Jawaban diambil dari data report ini + <Term kata="citations" /> — bukan karangan.</p>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</Show>
|
</Show>
|
||||||
|
|||||||
Reference in New Issue
Block a user