首頁 >web前端 >js教程 >使用 Node.js、Express 和 OpenAI API 建立高品質股票報告產生器

使用 Node.js、Express 和 OpenAI API 建立高品質股票報告產生器

Barbara Streisand
Barbara Streisand原創
2024-11-04 14:54:43667瀏覽

Building a High-Quality Stock Report Generator with Node.js, Express, and OpenAI API

在本文中,我們將深入研究使用 Node.js、Express 和 OpenAI API 建立專業級股票報告產生器。我們的重點是編寫高品質、可維護的程式碼,同時保留 OpenAI API 互動中使用的提示訊息的完整性。該應用程式將獲取股票數據,執行情緒和行業分析,並產生全面的投資報告。

目錄

  1. 專案概況
  2. 設定環境
  3. 建立 Express 伺服器
  4. 取得與處理資料
  5. 與 OpenAI API 整合
  6. 產生最終報告
  7. 測試應用程式
  8. 結論

項目概況

我們的目標是建立一個 API 端點,為給定的股票代碼產生詳細的投資報告。該報告將包括:

  • 公司概況
  • 財務表現
  • 管理階層討論與分析(MDA)
  • 情緒分析
  • 產業分析
  • 風險與機會
  • 投資建議

我們將從外部API取得股票數據,並使用OpenAI API進行進階分析,確保提示資訊已準確保留。

設定環境

先決條件

  • Node.js 安裝在您的電腦上
  • OpenAI API 金鑰(如果您沒有,請在 OpenAI 註冊)

初始化專案

建立一個新目錄並初始化 Node.js 專案:

mkdir stock-report-generator
cd stock-report-generator
npm init -y

安裝必要的依賴項:

npm install express axios

設定項目結構:

mkdir routes utils data
touch app.js routes/report.js utils/helpers.js

創建 Express 伺服器

設定 app.js

// app.js
const express = require('express');
const reportRouter = require('./routes/report');

const app = express();

app.use(express.json());
app.use('/api', reportRouter);

const PORT = process.env.PORT || 3000;

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});
  • Express 初始化:導入 Express 並初始化應用程式。
  • 中間件:使用express.json()解析JSON請求體。
  • 路由:將報告路由器掛載到/api路徑上。
  • 伺服器監聽:在指定連接埠啟動伺服器。

取得和處理數據

建立輔助函數

在 utils/helpers.js 中,我們將定義用於資料擷取和處理的實用函數。

mkdir stock-report-generator
cd stock-report-generator
npm init -y
  • getLastYearDates:計算上一年的開始和結束日期。
  • objectToString:將物件轉換為可讀字串,不包括指定的鍵。
  • fetchData:處理對外部 API 的 GET 要求,傳回資料或預設值。
  • readLocalJson:從本機 JSON 檔案讀取資料。

實施股票數據獲取

在routes/report.js中,定義取得股票資料的函數。

npm install express axios
  • fetchStockData:並發取得多個資料點並處理結果。
  • 資料處理:格式化和轉換資料以供後續使用。
  • 錯誤處理:記錄錯誤並重新拋出它們以進行更高級別的處理。

與 OpenAI API 集成

OpenAI API互動功能

mkdir routes utils data
touch app.js routes/report.js utils/helpers.js
  • analyzeWithOpenAI:處理與 OpenAI API 的通訊。
  • API配置:設定模型、溫度等參數。
  • 錯誤處理:記錄並拋出上游處理的錯誤。

執行情緒分析

// app.js
const express = require('express');
const reportRouter = require('./routes/report');

const app = express();

app.use(express.json());
app.use('/api', reportRouter);

const PORT = process.env.PORT || 3000;

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});
  • performSentimentAnalysis:建構提示訊息並呼叫OpenAI API進行分析。
  • 提示設計:確保提示訊息清晰並包含必要的上下文。

產業分析

// utils/helpers.js
const axios = require('axios');
const fs = require('fs');
const path = require('path');

const BASE_URL = 'https://your-data-api.com'; // Replace with your actual data API

/**
 * Get the start and end dates for the last year.
 * @returns {object} - An object containing `start` and `end` dates.
 */
function getLastYearDates() {
  const now = new Date();
  const end = now.toISOString().split('T')[0];
  now.setFullYear(now.getFullYear() - 1);
  const start = now.toISOString().split('T')[0];
  return { start, end };
}

/**
 * Convert an object to a string, excluding specified keys.
 * @param {object} obj - The object to convert.
 * @param {string[]} excludeKeys - Keys to exclude.
 * @returns {string} - The resulting string.
 */
function objectToString(obj, excludeKeys = []) {
  return Object.entries(obj)
    .filter(([key]) => !excludeKeys.includes(key))
    .map(([key, value]) => `${key}: ${value}`)
    .join('\n');
}

/**
 * Fetch data from a specified endpoint with given parameters.
 * @param {string} endpoint - API endpoint.
 * @param {object} params - Query parameters.
 * @param {any} defaultValue - Default value if the request fails.
 * @returns {Promise<any>} - The fetched data or default value.
 */
async function fetchData(endpoint, params = {}, defaultValue = null) {
  try {
    const response = await axios.get(`${BASE_URL}${endpoint}`, { params });
    return response.data || defaultValue;
  } catch (error) {
    console.error(`Error fetching data from ${endpoint}:`, error.message);
    return defaultValue;
  }
}

/**
 * Read data from a local JSON file.
 * @param {string} fileName - Name of the JSON file.
 * @returns {any} - The parsed data.
 */
function readLocalJson(fileName) {
  const filePath = path.join(__dirname, '../data', fileName);
  const data = fs.readFileSync(filePath, 'utf-8');
  return JSON.parse(data);
}

module.exports = {
  fetchData,
  objectToString,
  getLastYearDates,
  readLocalJson,
};
  • analyzeIndustry:與情緒分析類似,但專注於更廣泛的產業背景。
  • 提示保留:保持原始提示訊息的完整性。

產生最終報告

編譯所有數據

// routes/report.js
const express = require('express');
const {
  fetchData,
  objectToString,
  getLastYearDates,
  readLocalJson,
} = require('../utils/helpers');

const router = express.Router();

/**
 * Fetches stock data including historical prices, financials, MDA, and main business info.
 * @param {string} ticker - Stock ticker symbol.
 * @returns {Promise<object>} - An object containing all fetched data.
 */
async function fetchStockData(ticker) {
  try {
    const dates = getLastYearDates();
    const [historicalData, financialData, mdaData, businessData] = await Promise.all([
      fetchData('/stock_zh_a_hist', {
        symbol: ticker,
        period: 'weekly',
        start_date: dates.start,
        end_date: dates.end,
      }, []),

      fetchData('/stock_financial_benefit_ths', {
        code: ticker,
        indicator: '按年度',
      }, [{}]),

      fetchData('/stock_mda', { code: ticker }, []),

      fetchData('/stock_main_business', { code: ticker }, []),
    ]);

    const hist = historicalData[historicalData.length - 1];
    const currentPrice = (hist ? hist['开盘'] : 'N/A') + ' CNY';
    const historical = historicalData
      .map((item) => objectToString(item, ['股票代码']))
      .join('\n----------\n');

    const zsfzJson = readLocalJson('zcfz.json');
    const balanceSheet = objectToString(zsfzJson.find((item) => item['股票代码'] === ticker));

    const financial = objectToString(financialData[0]);

    const mda = mdaData.map(item => `${item['报告期']}\n${item['内容']}`).join('\n-----------\n');

    const mainBusiness = businessData.map(item =>
      `主营业务: ${item['主营业务']}\n产品名称: ${item['产品名称']}\n产品类型: ${item['产品类型']}\n经营范围: ${item['经营范围']}`
    ).join('\n-----------\n');

    return { currentPrice, historical, balanceSheet, mda, mainBusiness, financial };
  } catch (error) {
    console.error('Error fetching stock data:', error.message);
    throw error;
  }
}
  • 提供最終分析:精心製作提示訊息,合併所有收集的資料。
  • 提示完整性:確保原始提示訊息不會被更改或損壞。

測試應用程式

定義路由處理程序

在routes/report.js中加入路由處理程序:

const axios = require('axios');

const OPENAI_API_KEY = 'your-openai-api-key'; // Replace with your OpenAI API key

/**
 * Interacts with the OpenAI API to get completion results.
 * @param {array} messages - Array of messages, including system prompts and user messages.
 * @returns {Promise<string>} - The AI's response.
 */
async function analyzeWithOpenAI(messages) {
  try {
    const headers = {
      'Authorization': `Bearer ${OPENAI_API_KEY}`,
      'Content-Type': 'application/json',
    };
    const requestData = {
      model: 'gpt-4',
      temperature: 0.3,
      messages: messages,
    };

    const response = await axios.post(
      'https://api.openai.com/v1/chat/completions',
      requestData,
      { headers }
    );
    return response.data.choices[0].message.content.trim();
  } catch (error) {
    console.error('Error fetching analysis from OpenAI:', error.message);
    throw error;
  }
}
  • 輸入驗證:檢查是否提供了股票代號。
  • 資料收集:同時取得股票資料並執行分析。
  • 錯誤處理:記錄錯誤並在失敗時發送 500 回應。

啟動伺服器

確保你的app.js和routes/report.js設定正確,然後啟動伺服器:

/**
 * Performs sentiment analysis on news articles using the OpenAI API.
 * @param {string} ticker - Stock ticker symbol.
 * @returns {Promise<string>} - Sentiment analysis summary.
 */
async function performSentimentAnalysis(ticker) {
  const systemPrompt = `You are a sentiment analysis assistant. Analyze the sentiment of the given news articles for ${ticker} and provide a summary of the overall sentiment and any notable changes over time. Be measured and discerning. You are a skeptical investor.`;

  const tickerNewsResponse = await fetchData('/stock_news_specific', { code: ticker }, []);

  const newsText = tickerNewsResponse
    .map(item => `${item['文章来源']} Date: ${item['发布时间']}\n${item['新闻内容']}`)
    .join('\n----------\n');

  const messages = [
    { role: 'system', content: systemPrompt },
    {
      role: 'user',
      content: `News articles for ${ticker}:\n${newsText || 'N/A'}\n----\nProvide a summary of the overall sentiment and any notable changes over time.`,
    },
  ];

  return await analyzeWithOpenAI(messages);
}

發送測試請求

使用curl或Postman發送POST請求:

mkdir stock-report-generator
cd stock-report-generator
npm init -y
  • 回應:伺服器應傳回一個包含產生報表的 JSON 物件。

結論

我們建立了一個高品質的庫存報告產生器,具有以下功能:

  • 從外部 API 取得並處理股票資料
  • 使用 OpenAI API 執行進階分析
  • 產生全面的投資報告,同時確保提示資訊的完整性。

在整個開發過程中,我們專注於編寫專業、可維護的程式碼,並提供了詳細的解釋和註釋。

實施的最佳實踐

  • 模組化程式碼結構:函數被模組化以實現可重複使用性和清晰度。
  • 非同步操作:使用async/await和Promise.all進行高效率的非同步程式設計。
  • 錯誤處理:全面的 try-catch 區塊和錯誤訊息。
  • API 抽象:分離的 API 互動邏輯,以提高可維護性。
  • 提示工程:為OpenAI API精心設計提示訊息,以達到期望的輸出。
  • 輸入驗證:檢查所需的輸入參數,以防止不必要的錯誤。
  • 程式碼文件:新增了JSDoc註釋,以便更好地理解和維護。

下一步

  • 快取:實作快取機制以減少冗餘的API呼叫。
  • 驗證:透過驗證和速率限制來保護 API 端點。
  • 前端開發:建立用於與應用程式互動的使用者介面。
  • 其他分析:納入技術分析或其他財務模型。

參考

  • Node.js 文件
  • Express.js 文件
  • Axios 文件
  • OpenAI API 參考

免責聲明:此應用程式僅用於教育目的。確保遵守所有 API 服務條款並適當處理敏感資料。

以上是使用 Node.js、Express 和 OpenAI API 建立高品質股票報告產生器的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn