Skip to content
Open
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
49 changes: 49 additions & 0 deletions .github/workflows/sync.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Upstream Sync

on:
schedule:
- cron: "0 */6 * * *"
workflow_dispatch:

permissions:
contents: write
actions: write

jobs:
sync_latest_from_upstream:
name: Sync latest commits from upstream repo
runs-on: ubuntu-latest
if: ${{ github.event.repository.fork }}

steps:
# Step 1: run a standard checkout action
- name: Checkout target repo
uses: actions/checkout@v4

# Step 2: run the sync action
- name: Sync upstream changes
id: sync
uses: aormsby/Fork-Sync-With-Upstream-action@v3.4.1
with:
upstream_sync_repo: HuaYaoAI/FinGenius
upstream_sync_branch: main
target_sync_branch: main
target_repo_token: ${{ secrets.GITHUB_TOKEN }}
upstream_pull_args: '--allow-unrelated-histories --strategy=ours'
git_log_format_option: '--oneline'
git_push_args: '--no-verify'
git_commit_args: '--no-verify'

- name: Sync check
if: failure()
run: |
echo "[Error] Due to a change in the workflow file of the upstream repository, GitHub has automatically suspended the scheduled automatic update. You need to manually sync your fork."
exit 1

- name: Delete workflow runs
uses: Mattraks/delete-workflow-runs@main
with:
token: ${{ secrets.GITHUB_TOKEN }}
repository: ${{ github.repository }}
retain_days: 0
keep_minimum_runs: 2
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -197,3 +197,6 @@ cython_debug/

# node
node_modules

report/
logs/
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@

欢迎对AI金融极致热爱的你

携手完善FinGenius,共同探索金融智能分析的技术前沿边界!🌟
携手完善[FinGenius](https://fingenius.cn),共同探索金融智能分析的技术前沿边界!🌟


## 安装指南
Expand Down
53 changes: 0 additions & 53 deletions config/config.example.toml

This file was deleted.

51 changes: 30 additions & 21 deletions src/agent/sentiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,43 +68,52 @@ async def analyze(self, stock_code: str, **kwargs) -> Dict:

# 1. 强制执行新闻搜索
try:
news_result = await self.tool_call("web_search", {
"query": f"{stock_code} 股票 最新消息 舆情",
"max_results": 10
})
if news_result and news_result.success:
analysis_tasks.append(("news_search", news_result.data))
news_result = await self.available_tools.execute(
name="web_search",
tool_input={
"query": f"{stock_code} 股票 最新消息 舆情",
"max_results": 10
}
)
if news_result and not news_result.error:
analysis_tasks.append(("news_search", news_result.output))
logger.info(f"新闻搜索成功: {stock_code}")
else:
logger.warning(f"新闻搜索失败: {stock_code}")
logger.warning(f"新闻搜索失败: {stock_code}, {news_result.error if news_result else 'Unknown error'}")
except Exception as e:
logger.error(f"新闻搜索异常: {stock_code}, {str(e)}")

# 2. 强制执行社交媒体分析
try:
social_result = await self.tool_call("web_search", {
"query": f"{stock_code} 股吧 讨论 情绪",
"max_results": 5
})
if social_result and social_result.success:
analysis_tasks.append(("social_media", social_result.data))
social_result = await self.available_tools.execute(
name="web_search",
tool_input={
"query": f"{stock_code} 股吧 讨论 情绪",
"max_results": 5
}
)
if social_result and not social_result.error:
analysis_tasks.append(("social_media", social_result.output))
logger.info(f"社交媒体分析成功: {stock_code}")
else:
logger.warning(f"社交媒体分析失败: {stock_code}")
logger.warning(f"社交媒体分析失败: {stock_code}, {social_result.error if social_result else 'Unknown error'}")
except Exception as e:
logger.error(f"社交媒体分析异常: {stock_code}, {str(e)}")

# 3. 强制执行舆情分析工具
try:
sentiment_result = await self.tool_call("sentiment_analysis", {
"stock_code": stock_code,
"analysis_type": "comprehensive"
})
if sentiment_result and sentiment_result.success:
analysis_tasks.append(("sentiment_analysis", sentiment_result.data))
sentiment_result = await self.available_tools.execute(
name="sentiment_analysis",
tool_input={
"stock_code": stock_code,
"analysis_type": "comprehensive"
}
)
if sentiment_result and not sentiment_result.error:
analysis_tasks.append(("sentiment_analysis", sentiment_result.output))
logger.info(f"舆情分析工具成功: {stock_code}")
else:
logger.warning(f"舆情分析工具失败: {stock_code}")
logger.warning(f"舆情分析工具失败: {stock_code}, {sentiment_result.error if sentiment_result else 'Unknown error'}")
except Exception as e:
logger.error(f"舆情分析工具异常: {stock_code}, {str(e)}")

Expand Down
16 changes: 0 additions & 16 deletions src/mcp/big_deal_analysis_server.py

This file was deleted.

16 changes: 0 additions & 16 deletions src/mcp/chip_analysis_server.py

This file was deleted.

10 changes: 6 additions & 4 deletions src/mcp/risk_control_server.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
from src.mcp.server import MCPServer
from src.tool import Terminate
from src.tool.risk_control import RiskControlTool
from src.tool.sentiment import SentimentTool
from src.tool.web_search import WebSearch


class RiskControlServer(MCPServer):
def __init__(self, name: str = "RiskControlServer"):
class SentimentServer(MCPServer):
def __init__(self, name: str = "SentimentServer"):
super().__init__(name)

def _initialize_standard_tools(self) -> None:
self.tools.update(
{
"risk_control_tool": RiskControlTool(),
"sentiment_tool": SentimentTool(),
"web_search": WebSearch(),
"terminate": Terminate(),
}
)
128 changes: 107 additions & 21 deletions src/prompt/create_html.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,33 +488,119 @@
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>

<script>
// 页面数据全局变量 - 将被填充实际数据
let reportData = {};

// DOM加载完成后执行
document.addEventListener('DOMContentLoaded', function() {
// 直接渲染页面,数据将在注入时被替换
renderPage();

// 初始化交互功能
initializeInteractions();
});

// 渲染整个页面
function renderPage() {
renderOverview();
renderAnalysis();
renderDebate();
// 页面初始化
function initializePage() {
try {
renderPage();
initializeInteractions();
} catch (error) {
console.error('页面渲染失败:', error);
const errorMessage = `
<div class="alert alert-danger">
<h4 class="alert-heading">页面渲染失败</h4>
<p>很抱歉,在渲染页面时发生错误。错误信息:${error.message}</p>
<hr>
<p class="mb-0">请刷新页面重试,如果问题持续存在,请联系技术支持。</p>
</div>
`;
document.getElementById('overview').innerHTML = errorMessage;
document.getElementById('analysis').innerHTML = '';
document.getElementById('debate').innerHTML = '';
}
}

// DOM加载完成后执行
document.addEventListener('DOMContentLoaded', function() {
// 显示加载状态
document.getElementById('overview').innerHTML = '<div class="alert alert-info">数据加载中...</div>';

// 检查数据加载状态
if (window.dataLoadingState.isLoaded) {
if (reportData && Object.keys(reportData).length > 0) {
initializePage();
} else {
console.error('页面数据未正确加载');
document.getElementById('overview').innerHTML = '<div class="alert alert-danger">数据加载失败</div>';
}
} else {
// 设置超时检查
setTimeout(() => {
if (!window.dataLoadingState.isLoaded) {
console.error('数据加载超时');
document.getElementById('overview').innerHTML = '<div class="alert alert-danger">数据加载超时</div>';
}
}, 5000);
}
});

// 页面数据注入点 - 将被自动替换
let reportData = {};

// 添加数据加载状态指示
window.dataLoadingState = {
isLoaded: false,
error: null
};

// 监听数据加载状态
Object.defineProperty(window.dataLoadingState, 'isLoaded', {
set: function(value) {
this._isLoaded = value;
if (value && reportData && Object.keys(reportData).length > 0) {
initializePage();
}
},
get: function() {
return this._isLoaded;
}
});

// 验证数据完整性
function validateReportData() {
const requiredFields = [
'stock_code',
'battle_results',
'analysis_results',
'debate_results'
];

const missingFields = requiredFields.filter(field => !reportData[field]);

if (missingFields.length > 0) {
throw new Error(`数据不完整,缺少以下字段:${missingFields.join(', ')}`);
}

// 验证具体字段的数据结构
if (!Array.isArray(reportData.battle_results)) {
throw new Error('battle_results 必须是数组类型');
}

if (!Array.isArray(reportData.debate_results)) {
throw new Error('debate_results 必须是数组类型');
}

return true;
}

// 渲染整个页面
function renderPage() {
// 首先验证数据
validateReportData();

// 开始渲染各个部分
renderOverview();
renderAnalysis();
renderDebate();
}

// 渲染概览部分
function renderOverview() {
const overview = document.getElementById('overview');
const stockCode = reportData.stock_code || '未知';
const voteResults = reportData.vote_results || {};
const bullishCount = voteResults.bullish || 0;
const bearishCount = voteResults.bearish || 0;
const finalDecision = voteResults.final_decision || 'unknown';
const battleResults = reportData.battle_results || {};
const bullishCount = battleResults.vote_count?.bullish || 0;
const bearishCount = battleResults.vote_count?.bearish || 0;
const finalDecision = battleResults.final_decision || 'unknown';

const totalVotes = bullishCount + bearishCount;
const bullishPct = totalVotes > 0 ? (bullishCount / totalVotes * 100).toFixed(1) : 0;
Expand Down
Loading