feat: Standardize on Bloomberg as the default data source, update search UI with editable symbols, and enable web search capabilities.
This commit is contained in:
parent
b6222b9b4b
commit
653812a480
@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
"permissions": {
|
"permissions": {
|
||||||
"allow": [
|
"allow": [
|
||||||
"mcp__zai-web-reader__webReader"
|
"mcp__zai-web-reader__webReader",
|
||||||
|
"mcp__zai-web-search__webSearchPrime"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -213,14 +213,25 @@ async def search_stock(request: StockSearchRequest):
|
|||||||
prompt = f"""请利用Google搜索查找 "{request.query}" 对应的上市股票信息。
|
prompt = f"""请利用Google搜索查找 "{request.query}" 对应的上市股票信息。
|
||||||
|
|
||||||
返回最匹配的股票,优先返回准确匹配的公司。
|
返回最匹配的股票,优先返回准确匹配的公司。
|
||||||
|
|
||||||
|
**关键要求:Symbol 必须遵循 Bloomberg 终端专用代码格式 (Ticker Only)。**
|
||||||
|
请注意区分不同市场的代码后缀(用于确定market字段),以及某些市场的特殊代码规则(例如印度股票通常以 IN 结尾,代码可能是缩写也可能是全称,请仔细核对 Bloomberg 标准)。
|
||||||
|
|
||||||
返回格式必须是 JSON 数组,每个元素包含:
|
返回格式必须是 JSON 数组,每个元素包含:
|
||||||
- market: 市场代码(CH/HK/US/JP/VN),例如:腾讯是 HK,茅台是 CH,英伟达是 US。
|
- market: 市场代码(CH/HK/US/JP/VN/IN/EU等)。
|
||||||
- symbol: 股票代码(如果是CH,通常是6位数字;HK是5位;US是字母)。
|
- symbol: **Bloomberg标准代码** (仅Ticker,不要包含后缀)。
|
||||||
|
- 香港: "700" (不要写00700)
|
||||||
|
- 中国: "600519"
|
||||||
|
- 美国: "NVDA"
|
||||||
|
- 日本: "7203"
|
||||||
|
- 印度: "UBBL" (例如 United Breweries,不要只写 UBL)
|
||||||
|
- 欧洲: "NESN"
|
||||||
- company_name: 公司简称。
|
- company_name: 公司简称。
|
||||||
|
|
||||||
示例:
|
示例:
|
||||||
[{{"market": "HK", "symbol": "00700", "company_name": "腾讯控股"}}]
|
[{{"market": "HK", "symbol": "700", "company_name": "腾讯控股"}},
|
||||||
|
{{"market": "US", "symbol": "NVDA", "company_name": "英伟达"}},
|
||||||
|
{{"market": "IN", "symbol": "UBBL", "company_name": "United Breweries"}}]
|
||||||
|
|
||||||
请直接返回 JSON,不要添加任何其他文字。最多返回5个结果。"""
|
请直接返回 JSON,不要添加任何其他文字。最多返回5个结果。"""
|
||||||
|
|
||||||
|
|||||||
@ -54,8 +54,8 @@ function HomeInner() {
|
|||||||
// Close right sidebar on new selection
|
// Close right sidebar on new selection
|
||||||
setIsRightSidebarOpen(false)
|
setIsRightSidebarOpen(false)
|
||||||
|
|
||||||
// 如果没有传入数据源,则根据市场设置默认值
|
// 默认数据源强制为 Bloomberg
|
||||||
const targetDataSource = dataSource || (company.market === 'CN' ? 'Tushare' : 'iFinD')
|
const targetDataSource = dataSource || 'Bloomberg'
|
||||||
setSelectedDataSource(targetDataSource)
|
setSelectedDataSource(targetDataSource)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ function HomeInner() {
|
|||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<h1 className="text-3xl font-bold tracking-tight">股票分析</h1>
|
<h1 className="text-3xl font-bold tracking-tight">股票分析</h1>
|
||||||
<p className="text-muted-foreground">
|
<p className="text-muted-foreground">
|
||||||
输入公司名称或股票代码,开始全面的AI驱动的分析。支持中国、香港、美国、日本、越南的公司分析。
|
输入公司名称或股票代码,开始全面的AI驱动的分析。支持 Bloomberg 覆盖的全球市场所有标的。
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { MonitorPlay } from "lucide-react"
|
import { MonitorPlay } from "lucide-react"
|
||||||
import { useRouter, useSearchParams } from "next/navigation"
|
import { useRouter, useSearchParams } from "next/navigation"
|
||||||
import { HeaderSearch } from "@/components/header-search"
|
|
||||||
import { useEffect, useState, Suspense } from "react"
|
import { useEffect, useState, Suspense } from "react"
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
@ -255,10 +254,6 @@ function NavHeaderInner() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-[160px] ml-4">
|
|
||||||
<HeaderSearch defaultDataSource={dataSource} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Portal Target for Dynamic Content */}
|
{/* Portal Target for Dynamic Content */}
|
||||||
<div id="header-portal-target" suppressHydrationWarning className="flex-1 flex items-center justify-end px-4 gap-4 min-w-0" />
|
<div id="header-portal-target" suppressHydrationWarning className="flex-1 flex items-center justify-end px-4 gap-4 min-w-0" />
|
||||||
|
|
||||||
|
|||||||
@ -17,20 +17,21 @@ interface SearchStockProps {
|
|||||||
|
|
||||||
const DATA_SOURCES = {
|
const DATA_SOURCES = {
|
||||||
CN: [
|
CN: [
|
||||||
|
{ value: "Bloomberg", label: "Bloomberg" },
|
||||||
{ value: "Tushare", label: "Tushare (CN)" },
|
{ value: "Tushare", label: "Tushare (CN)" },
|
||||||
{ value: "iFinD", label: "iFinD" },
|
{ value: "iFinD", label: "iFinD" }
|
||||||
{ value: "Bloomberg", label: "Bloomberg" }
|
|
||||||
],
|
],
|
||||||
GLOBAL: [
|
GLOBAL: [
|
||||||
{ value: "iFinD", label: "iFinD" },
|
{ value: "Bloomberg", label: "Bloomberg" },
|
||||||
{ value: "Bloomberg", label: "Bloomberg" }
|
{ value: "iFinD", label: "iFinD" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
function SearchResultItem({ result, onSelect }: { result: SearchResult, onSelect: (r: SearchResult, ds: string) => void }) {
|
function SearchResultItem({ result, onSelect }: { result: SearchResult, onSelect: (r: SearchResult, ds: string) => void }) {
|
||||||
// 默认数据源逻辑:CN -> Tushare, 其他 -> iFinD
|
// 默认数据源逻辑:Bloomberg
|
||||||
const defaultSource = result.market === "CN" ? "Tushare" : "iFinD"
|
const defaultSource = "Bloomberg"
|
||||||
const [source, setSource] = useState(defaultSource)
|
const [source, setSource] = useState(defaultSource)
|
||||||
|
const [symbol, setSymbol] = useState(result.symbol) // Editable symbol state
|
||||||
|
|
||||||
// 根据市场获取可用数据源列表
|
// 根据市场获取可用数据源列表
|
||||||
const availableSources = result.market === "CN" ? DATA_SOURCES.CN : DATA_SOURCES.GLOBAL
|
const availableSources = result.market === "CN" ? DATA_SOURCES.CN : DATA_SOURCES.GLOBAL
|
||||||
@ -41,15 +42,19 @@ function SearchResultItem({ result, onSelect }: { result: SearchResult, onSelect
|
|||||||
{/* 顶部:公司信息 */}
|
{/* 顶部:公司信息 */}
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
<div className="flex items-start justify-between gap-2">
|
<div className="flex items-start justify-between gap-2">
|
||||||
<div className="min-w-0">
|
<div className="min-w-0 flex-1 mr-2">
|
||||||
<h3 className="font-bold text-base truncate" title={result.company_name}>
|
<h3 className="font-bold text-base truncate" title={result.company_name}>
|
||||||
{result.company_name}
|
{result.company_name}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-sm text-muted-foreground font-mono mt-0.5">
|
<div className="mt-1">
|
||||||
{result.symbol}
|
<Input
|
||||||
</p>
|
value={symbol}
|
||||||
|
onChange={(e) => setSymbol(e.target.value)}
|
||||||
|
className="h-7 text-xs font-mono bg-background/50 border-input/60"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Badge variant="secondary" className="shrink-0 text-xs font-mono">
|
<Badge variant="secondary" className="shrink-0 text-xs font-mono h-6">
|
||||||
{result.market}
|
{result.market}
|
||||||
</Badge>
|
</Badge>
|
||||||
</div>
|
</div>
|
||||||
@ -73,7 +78,7 @@ function SearchResultItem({ result, onSelect }: { result: SearchResult, onSelect
|
|||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => onSelect(result, source)}
|
onClick={() => onSelect({ ...result, symbol }, source)}
|
||||||
size="sm"
|
size="sm"
|
||||||
className="h-8 px-3 shrink-0"
|
className="h-8 px-3 shrink-0"
|
||||||
>
|
>
|
||||||
@ -158,7 +163,7 @@ export function SearchStock({ onCompanySelect }: SearchStockProps = {}) {
|
|||||||
<div className="flex gap-4 items-start">
|
<div className="flex gap-4 items-start">
|
||||||
<div className="flex-1 flex gap-2">
|
<div className="flex-1 flex gap-2">
|
||||||
<Input
|
<Input
|
||||||
placeholder="例如: 腾讯, AAPL, 00700.HK"
|
placeholder="例如: 700 HK, NVDA US, 600519 CH"
|
||||||
value={query}
|
value={query}
|
||||||
onChange={(e) => setQuery(e.target.value)}
|
onChange={(e) => setQuery(e.target.value)}
|
||||||
onKeyDown={(e) => e.key === "Enter" && handleSearch()}
|
onKeyDown={(e) => e.key === "Enter" && handleSearch()}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user