Dmitry Beresnev commited on
Commit
bba1099
Β·
1 Parent(s): 6df4a0a

add openrouter client, promt generator, etc

Browse files
.env.example CHANGED
@@ -1,4 +1,5 @@
1
  TELEGRAM_TOKEN=
2
  FINNHUB_API_TOKEN=
3
  ACCESS_TOKEN=
4
- SPACE_ID=
 
 
1
  TELEGRAM_TOKEN=
2
  FINNHUB_API_TOKEN=
3
  ACCESS_TOKEN=
4
+ SPACE_ID=
5
+ OPENROUTER_API_TOKEN=
src/api/finnhub/__init__.py ADDED
File without changes
src/api/{financial_news_requester.py β†’ finnhub/financial_news_requester.py} RENAMED
File without changes
src/api/openrouter/__init__.py ADDED
File without changes
src/api/openrouter/openrouter_client.py ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import time
3
+ import requests
4
+ import json
5
+ import os
6
+
7
+ from api.finnhub.financial_news_requester import fetch_comp_financial_news
8
+ from api.openrouter.prompt_generator import PromptGenerator
9
+
10
+
11
+ class OpenRouterClient:
12
+ def __init__(self, model: str = "tngtech/deepseek-r1t2-chimera:free", api_key: str | None = None):
13
+ self._api_key = api_key or os.getenv("OPENROUTER_API_KEY")
14
+ if not self._api_key:
15
+ raise ValueError("OpenRouter API key is required")
16
+ self._api_url = "https://openrouter.ai/api/v1/chat/completions"
17
+ self.model = model
18
+
19
+ def chat(self, user_message: str, role: str = "user") -> str:
20
+ """
21
+ Sends a message to the OpenRouter API and returns the response.
22
+ Raises RuntimeError for HTTP errors and ValueError for unexpected response formats.
23
+
24
+ Args:
25
+ user_message (str): The message to send to the model.
26
+ Returns:
27
+ str: The response from the model.
28
+ Raises:
29
+ RuntimeError: If the API request fails.
30
+ ValueError: If the response format is unexpected.
31
+ """
32
+ headers = {
33
+ "Authorization": f"Bearer {self._api_key}",
34
+ "Content-Type": "application/json"
35
+ }
36
+ payload = {
37
+ "model": self.model,
38
+ "messages": [
39
+ {
40
+ "role": role,
41
+ "content": user_message
42
+ }
43
+ ]
44
+ }
45
+ try:
46
+ response = requests.post(
47
+ url=self._api_url,
48
+ headers=headers,
49
+ data=json.dumps(payload),
50
+ timeout=10
51
+ )
52
+ response.raise_for_status()
53
+ except requests.exceptions.RequestException as e:
54
+ logging.error(f"OpenRouter request error: {e}")
55
+ raise RuntimeError(f"Request error: {e}")
56
+ response_json = response.json()
57
+ try:
58
+ return response_json["choices"][0]["message"]["content"]
59
+ except (KeyError, IndexError):
60
+ logging.error(f"Unexpected response format: {response_json}")
61
+ raise ValueError(f"Unexpected response format: {response_json}")
62
+
63
+
64
+ if __name__ == "__main__":
65
+ sample_news = fetch_comp_financial_news(ticker='NVDA', date_from='2025-08-04', date_to='2025-08-05')
66
+ print(sample_news)
67
+ print(len(sample_news))
68
+ # Example usage
69
+ client = OpenRouterClient()
70
+ try:
71
+ for news in sample_news:
72
+ start_time = time.perf_counter()
73
+ prompt = PromptGenerator.format_prompt(news)
74
+ print(f"Prompt: {prompt}")
75
+ response = client.chat(prompt)
76
+ print(f"Response: {response}")
77
+ elapsed = time.perf_counter() - start_time
78
+ print(f"Processing time: {elapsed:.2f} seconds")
79
+ except (RuntimeError, ValueError) as e:
80
+ print(f"Error: {e}")
src/api/openrouter/prompt_generator.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ from src.api.openrouter.system_prompt import system_prompt_template
2
+
3
+
4
+ class PromptGenerator:
5
+ @staticmethod
6
+ def format_prompt(news_text: str) -> str:
7
+ return system_prompt_template.format(news_text=news_text).strip()
src/api/openrouter/system_prompt.py ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ system_prompt_template = """
2
+ You are an experienced trader and long-term investor holding NVDA stock.
3
+
4
+ Analyze the following financial news from the perspective of its potential impact on NVDA (ticker: NVDA). Consider direct and indirect effects, including market sentiment, sector influence, regulatory risks, macroeconomic context, and technological competition.
5
+
6
+ ---
7
+
8
+ News:
9
+ "{news_text}"
10
+
11
+ ---
12
+
13
+ Answer in one of the following categories only: **Positive**, **Negative**, or **Neutral** β€” depending on the implications for NVDA.
14
+
15
+ Also include a very short explanation (1-2 sentences) why you classified it that way.
16
+ """
src/core/news_analysis/lexicon_based_sentiment_analyzer.py CHANGED
@@ -47,7 +47,7 @@ from nltk.stem import WordNetLemmatizer
47
  from src.core.news_analysis.data.news_item import NewsItem
48
  from src.core.news_analysis.data.sentiment_result import SentimentResult
49
  from src.core.news_analysis.data.news_analysis import NewsAnalysis
50
- from src.api.financial_news_requester import fetch_comp_financial_news
51
 
52
 
53
  class FinnhubSentimentAnalyzer:
 
47
  from src.core.news_analysis.data.news_item import NewsItem
48
  from src.core.news_analysis.data.sentiment_result import SentimentResult
49
  from src.core.news_analysis.data.news_analysis import NewsAnalysis
50
+ from api.finnhub.financial_news_requester import fetch_comp_financial_news
51
 
52
 
53
  class FinnhubSentimentAnalyzer:
src/core/news_analysis/llm_based_analyzer.py ADDED
File without changes
src/telegram_bot.py CHANGED
@@ -5,7 +5,7 @@ from typing import Any
5
  from telegram import Update
6
  from telegram.ext import Application, CommandHandler, ContextTypes
7
  from dotenv import load_dotenv
8
- from api.financial_news_requester import fetch_comp_financial_news
9
  from fastapi import FastAPI, Request
10
  import uvicorn
11
  import httpx
 
5
  from telegram import Update
6
  from telegram.ext import Application, CommandHandler, ContextTypes
7
  from dotenv import load_dotenv
8
+ from api.finnhub.financial_news_requester import fetch_comp_financial_news
9
  from fastapi import FastAPI, Request
10
  import uvicorn
11
  import httpx