Sahil Garg commited on
Commit
a9ec4f6
·
1 Parent(s): 2d701b7

agent added, files name changed

Browse files
.dockerignore ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ env/
8
+ venv/
9
+ .venv/
10
+ pip-log.txt
11
+ pip-delete-this-directory.txt
12
+ .tox/
13
+ .coverage
14
+ .pytest_cache/
15
+
16
+ # IDEs
17
+ .vscode/
18
+ .idea/
19
+ *.swp
20
+ *.swo
21
+ *~
22
+
23
+ # OS
24
+ .DS_Store
25
+ .DS_Store?
26
+ ._*
27
+ .Spotlight-V100
28
+ .Trashes
29
+ ehthumbs.db
30
+ Thumbs.db
31
+
32
+ # Git
33
+ .git/
34
+ .gitignore
35
+
36
+ # Documentation
37
+ README.md
38
+ *.md
39
+ docs/
40
+
41
+ # Environment files (these should be mounted or provided separately)
42
+ .env
43
+ .env.local
44
+ .env.example
45
+
46
+ # Data directories (these should be mounted as volumes)
47
+ data/input/*
48
+ data/output*/*
49
+ data/csv_notes_*/*
50
+ data/generated_notes*/*
51
+
52
+ # Logs
53
+ *.log
54
+ logs/
55
+
56
+ # Docker
57
+ Dockerfile
58
+ docker-compose.yml
59
+ .dockerignore
60
+
61
+ # Development
62
+ .pytest_cache/
63
+ .coverage
64
+ htmlcov/
.env.example ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # FinRyver Environment Configuration
2
+ # Copy this file to .env and fill in your actual values
3
+ HFTOKEN=
4
+ OPENROUTER_API_KEY=
5
+ PROJECT_ROOT=
6
+
7
+ # OpenAI API Configuration (required for LangChain agents)
8
+ OPENAI_API_KEY=your_openai_api_key_here
9
+
10
+ # LangChain Configuration
11
+ LANGCHAIN_TRACING_V2=false
12
+ LANGCHAIN_API_KEY=your_langsmith_api_key_here
13
+ LANGCHAIN_PROJECT=finryver-agents
14
+
15
+ # Agent Configuration
16
+ AGENT_MODEL=gpt-4
17
+ AGENT_TEMPERATURE=0.1
18
+ AGENT_MAX_TOKENS=2000
19
+
20
+
21
+ # Application Configuration
22
+ DEBUG=false
23
+ LOG_LEVEL=INFO
24
+
25
+ # File Paths (optional - defaults will be used if not specified)
26
+ DATA_INPUT_PATH=data/input
27
+ DATA_OUTPUT_PATH=data/output
28
+ TEMP_PATH=temp
Dockerfile CHANGED
@@ -1,49 +1,51 @@
1
  # Use Python 3.11 as base image
2
  FROM python:3.11-slim
3
 
4
- # -------------------------------
5
  # Set working directory
6
  WORKDIR /app
7
- COPY . .
8
 
9
- # -------------------------------
10
  # Install system dependencies
11
- RUN ls -l /app
12
  RUN apt-get update && apt-get install -y \
13
  build-essential \
14
  curl \
15
  git \
16
  && rm -rf /var/lib/apt/lists/*
17
 
18
- # -------------------------------
19
- # Copy and install Python dependencies
20
  COPY requirements.txt .
21
  RUN pip install --no-cache-dir -r requirements.txt
22
 
23
- # -------------------------------
24
- # Optional: Create necessary data directories if not bind-mounted
 
 
25
  RUN mkdir -p /app/data/input \
 
26
  /app/data/output1 \
27
  /app/data/output2 \
28
  /app/data/output3 \
29
  /app/data/csv_notes_bs \
30
  /app/data/csv_notes_cfs \
31
  /app/data/csv_notes_pnl \
32
- /app/data/output \
33
- /app/data/output1 \
34
- /app/data/output2 \
35
- /app/data/output3 \
36
  && chmod -R 777 /app/data
37
 
38
- # -------------------------------
39
  # Set environment variables
40
  ENV PYTHONPATH=/app
41
  ENV PYTHONUNBUFFERED=1
42
 
43
- # -------------------------------
 
 
 
 
44
  # Expose the port
45
  EXPOSE 8000
46
 
47
- # -------------------------------
48
- # Start FastAPI app from app.py
 
 
 
49
  CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
 
1
  # Use Python 3.11 as base image
2
  FROM python:3.11-slim
3
 
 
4
  # Set working directory
5
  WORKDIR /app
 
6
 
 
7
  # Install system dependencies
 
8
  RUN apt-get update && apt-get install -y \
9
  build-essential \
10
  curl \
11
  git \
12
  && rm -rf /var/lib/apt/lists/*
13
 
14
+ # Copy and install Python dependencies first (better caching)
 
15
  COPY requirements.txt .
16
  RUN pip install --no-cache-dir -r requirements.txt
17
 
18
+ # Copy application code
19
+ COPY . .
20
+
21
+ # Create necessary data directories for financial processing
22
  RUN mkdir -p /app/data/input \
23
+ /app/data/output \
24
  /app/data/output1 \
25
  /app/data/output2 \
26
  /app/data/output3 \
27
  /app/data/csv_notes_bs \
28
  /app/data/csv_notes_cfs \
29
  /app/data/csv_notes_pnl \
30
+ /app/data/generated_notes \
31
+ /app/data/generated_notes_excel \
 
 
32
  && chmod -R 777 /app/data
33
 
 
34
  # Set environment variables
35
  ENV PYTHONPATH=/app
36
  ENV PYTHONUNBUFFERED=1
37
 
38
+ # Default agent configuration (can be overridden by .env)
39
+ ENV AGENT_MODEL=gpt-3.5-turbo
40
+ ENV AGENT_TEMPERATURE=0.1
41
+ ENV AGENT_MAX_TOKENS=2000
42
+
43
  # Expose the port
44
  EXPOSE 8000
45
 
46
+ # Health check for the API
47
+ HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
48
+ CMD curl -f http://localhost:8000/docs || exit 1
49
+
50
+ # Start FastAPI app
51
  CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
README.md CHANGED
@@ -4,14 +4,18 @@
4
 
5
  FinRyver is an AI-powered financial statement generation platform that automatically converts trial balance data into comprehensive financial reports including balance sheets, cash flow statements, and profit & loss statements. Built with FastAPI and leveraging Large Language Models (LLMs), it streamlines the financial reporting process for accountants, auditors, and financial professionals by automating the generation of detailed financial notes and statements from structured trial balance inputs.
6
 
 
 
7
  ## 🎯 Key Features
8
 
9
  - **Automated Trial Balance Processing**: Upload Excel files containing trial balance data and automatically extract structured financial information
10
  - **AI-Powered Financial Notes Generation**: Utilize LLMs to generate comprehensive financial notes with detailed explanations and context
 
11
  - **Multi-Statement Support**: Generate Balance Sheets, Cash Flow Statements, and Profit & Loss statements from the same data source
12
  - **Excel Output Generation**: Export all generated reports and notes to professional Excel formats
13
  - **RESTful API Architecture**: Easy integration with existing financial systems through well-documented REST endpoints
14
  - **Flexible Note Selection**: Generate specific financial notes by number or create comprehensive reports covering all relevant sections
 
15
 
16
  ## 🏗️ Project Architecture
17
 
@@ -22,6 +26,11 @@ FinRyver/
22
  ├── Dockerfile # Container configuration
23
  ├── docker-compose.yml # Multi-container orchestration
24
  ├──
 
 
 
 
 
25
  ├── bs/ # Balance Sheet processing modules
26
  │ ├── bl_llm.py # Balance sheet LLM integration
27
  │ ├── csv_json_bs.py # Balance sheet data conversion
@@ -80,6 +89,8 @@ Trial Balance Upload → Data Extraction → AI Processing → Financial Stateme
80
 
81
  ### AI/ML Integration
82
  - **Large Language Models (LLMs)**: For intelligent financial note generation and analysis
 
 
83
  - **Custom AI Pipelines**: Specialized processing for financial data interpretation
84
 
85
  ### Infrastructure
@@ -128,6 +139,25 @@ Trial Balance Upload → Data Extraction → AI Processing → Financial Stateme
128
  | `/bs_from_notes` | POST | Generate balance sheet from existing notes |
129
  | `/pnl_from_notes` | POST | Generate P&L statement from existing notes |
130
  | `/cf_from_notes` | POST | Generate cash flow statement from existing notes |
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
 
132
  ## 📊 Results & Examples
133
 
@@ -189,6 +219,27 @@ docker run -p 8000:8000 finryver
189
  2. **Business Rules**: Modify `config/rules1.json` for custom validation rules
190
  3. **Account Mapping**: Update `config/mapping1.json` for account categorization
191
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  ### Usage Examples
193
 
194
  #### Generate Complete Financial Report
@@ -234,12 +285,18 @@ python -m pytest tests/ --verbose
234
 
235
  ## 🔮 Future Roadmap
236
 
 
 
 
 
 
237
  ### Planned Features
238
  - **Multi-Currency Support**: Handle international financial statements
239
  - **Advanced AI Models**: Integration with latest financial AI models
240
  - **Real-time Processing**: WebSocket support for live data updates
241
  - **Audit Trail**: Comprehensive logging and change tracking
242
  - **Custom Templates**: User-defined financial statement templates
 
243
 
244
  ### Known Limitations
245
  - Currently supports Excel input formats only
 
4
 
5
  FinRyver is an AI-powered financial statement generation platform that automatically converts trial balance data into comprehensive financial reports including balance sheets, cash flow statements, and profit & loss statements. Built with FastAPI and leveraging Large Language Models (LLMs), it streamlines the financial reporting process for accountants, auditors, and financial professionals by automating the generation of detailed financial notes and statements from structured trial balance inputs.
6
 
7
+ **New in 2025**: FinRyver now features an intelligent **agentic system** powered by LangChain that provides AI-driven automation, natural language processing, and intelligent decision-making for financial statement generation.
8
+
9
  ## 🎯 Key Features
10
 
11
  - **Automated Trial Balance Processing**: Upload Excel files containing trial balance data and automatically extract structured financial information
12
  - **AI-Powered Financial Notes Generation**: Utilize LLMs to generate comprehensive financial notes with detailed explanations and context
13
+ - **Intelligent Agentic System**: LangChain-powered agents that understand natural language instructions and automate complex financial workflows
14
  - **Multi-Statement Support**: Generate Balance Sheets, Cash Flow Statements, and Profit & Loss statements from the same data source
15
  - **Excel Output Generation**: Export all generated reports and notes to professional Excel formats
16
  - **RESTful API Architecture**: Easy integration with existing financial systems through well-documented REST endpoints
17
  - **Flexible Note Selection**: Generate specific financial notes by number or create comprehensive reports covering all relevant sections
18
+ - **Unified Agent Interface**: Single `/agent/generate` endpoint for intelligent financial statement generation
19
 
20
  ## 🏗️ Project Architecture
21
 
 
26
  ├── Dockerfile # Container configuration
27
  ├── docker-compose.yml # Multi-container orchestration
28
  ├──
29
+ ├── agents/ # Agentic system (LangChain)
30
+ │ ├── base_config.py # Agent configuration and utilities
31
+ │ ├── simple_agent.py # Financial statement agent
32
+ │ └── simple_tools.py # LangChain tools for financial processing
33
+ ├──
34
  ├── bs/ # Balance Sheet processing modules
35
  │ ├── bl_llm.py # Balance sheet LLM integration
36
  │ ├── csv_json_bs.py # Balance sheet data conversion
 
89
 
90
  ### AI/ML Integration
91
  - **Large Language Models (LLMs)**: For intelligent financial note generation and analysis
92
+ - **LangChain Framework**: Agentic system for intelligent financial statement processing
93
+ - **OpenRouter API**: Flexible LLM provider integration for AI-powered analysis
94
  - **Custom AI Pipelines**: Specialized processing for financial data interpretation
95
 
96
  ### Infrastructure
 
139
  | `/bs_from_notes` | POST | Generate balance sheet from existing notes |
140
  | `/pnl_from_notes` | POST | Generate P&L statement from existing notes |
141
  | `/cf_from_notes` | POST | Generate cash flow statement from existing notes |
142
+ | `/agent/generate` | POST | **NEW**: Intelligent agent-based financial statement generation |
143
+
144
+ #### Agentic System Endpoint
145
+
146
+ **`POST /agent/generate`** - Unified intelligent financial statement generation
147
+
148
+ **Parameters:**
149
+ - `file`: Trial balance Excel file
150
+ - `note_numbers`: Optional comma-separated note numbers (empty = all notes)
151
+ - `statement_type`: "all", "notes", "balance_sheet", "pnl", or "cash_flow"
152
+
153
+ **Example Usage:**
154
+ ```bash
155
+ curl -X POST "http://localhost:8000/agent/generate" \
156
+ -H "Content-Type: multipart/form-data" \
157
+ -F "file=@trial_balance.xlsx" \
158
+ -F "note_numbers=2,3,4,5" \
159
+ -F "statement_type=all"
160
+ ```
161
 
162
  ## 📊 Results & Examples
163
 
 
219
  2. **Business Rules**: Modify `config/rules1.json` for custom validation rules
220
  3. **Account Mapping**: Update `config/mapping1.json` for account categorization
221
 
222
+ #### Agentic System Configuration
223
+
224
+ For the intelligent agent features, ensure you have your LLM API key configured:
225
+
226
+ ```env
227
+ # Required for agentic system
228
+ OPENROUTER_API_KEY=your_openrouter_api_key_here
229
+
230
+ # Optional agent configuration
231
+ AGENT_MODEL=gpt-3.5-turbo
232
+ AGENT_TEMPERATURE=0.1
233
+ AGENT_MAX_TOKENS=2000
234
+ ```
235
+
236
+ **Agent Benefits:**
237
+ - Natural language understanding for financial tasks
238
+ - Intelligent workflow orchestration
239
+ - Unified interface for all financial statements
240
+ - Error recovery and retry logic
241
+ - Contextual financial analysis
242
+
243
  ### Usage Examples
244
 
245
  #### Generate Complete Financial Report
 
285
 
286
  ## 🔮 Future Roadmap
287
 
288
+ ### Completed Features ✅
289
+ - **Intelligent Agentic System**: LangChain-powered agents with natural language processing
290
+ - **Unified Agent Interface**: Single endpoint for all financial statement generation
291
+ - **Optional Note Numbers**: Flexible note generation (specific or all notes)
292
+
293
  ### Planned Features
294
  - **Multi-Currency Support**: Handle international financial statements
295
  - **Advanced AI Models**: Integration with latest financial AI models
296
  - **Real-time Processing**: WebSocket support for live data updates
297
  - **Audit Trail**: Comprehensive logging and change tracking
298
  - **Custom Templates**: User-defined financial statement templates
299
+ - **Agent Conversation History**: Multi-turn conversations with financial agents
300
 
301
  ### Known Limitations
302
  - Currently supports Excel input formats only
agents/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ # Agent framework for FinRyver
agents/base_config.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Base configuration and utilities for LangChain agents in FinRyver
3
+ """
4
+ import os
5
+ from typing import Optional
6
+ from langchain_openai import ChatOpenAI
7
+ from langchain.agents import AgentExecutor, create_openai_tools_agent
8
+ from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
9
+ from langchain.tools import Tool
10
+ from langchain_core.messages import HumanMessage, SystemMessage
11
+ import logging
12
+
13
+ # Load environment variables
14
+ try:
15
+ from dotenv import load_dotenv
16
+ load_dotenv()
17
+ except ImportError:
18
+ pass # dotenv is optional
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+ class FinRyverAgentConfig:
23
+ """Configuration class for FinRyver agents"""
24
+
25
+ def __init__(self):
26
+ self.openrouter_api_key = os.getenv("OPENROUTER_API_KEY")
27
+ self.model_name = os.getenv("AGENT_MODEL", "gpt-3.5-turbo")
28
+ self.temperature = float(os.getenv("AGENT_TEMPERATURE", "0.1"))
29
+ self.max_tokens = int(os.getenv("AGENT_MAX_TOKENS", "2000"))
30
+
31
+ def get_llm(self) -> ChatOpenAI:
32
+ """Get configured LLM instance"""
33
+ if not self.openrouter_api_key:
34
+ logger.warning("OPENROUTER_API_KEY not found. Agent functionality may be limited.")
35
+ return None
36
+
37
+ return ChatOpenAI(
38
+ api_key=self.openrouter_api_key,
39
+ base_url="https://openrouter.ai/api/v1",
40
+ model=self.model_name,
41
+ temperature=self.temperature,
42
+ max_tokens=self.max_tokens
43
+ )
44
+
45
+ def create_financial_agent_prompt(role: str, goal: str, context: str = "") -> ChatPromptTemplate:
46
+ """Create a standardized prompt template for financial agents"""
47
+
48
+ system_message = f"""
49
+ You are a {role} working with financial data analysis and reporting.
50
+
51
+ Your primary goal: {goal}
52
+
53
+ Context: {context}
54
+
55
+ You have access to various tools to help you analyze financial data, generate reports,
56
+ and ensure compliance with accounting standards. Always provide clear, accurate, and
57
+ professional responses.
58
+
59
+ When working with financial data:
60
+ - Ensure all calculations are accurate
61
+ - Follow GAAP/IFRS standards where applicable
62
+ - Provide clear explanations for your analysis
63
+ - Flag any anomalies or inconsistencies
64
+ - Always validate data before proceeding
65
+
66
+ If you need clarification or additional information, ask specific questions.
67
+ """
68
+
69
+ return ChatPromptTemplate.from_messages([
70
+ ("system", system_message),
71
+ MessagesPlaceholder(variable_name="chat_history", optional=True),
72
+ ("human", "{input}"),
73
+ MessagesPlaceholder(variable_name="agent_scratchpad")
74
+ ])
75
+
76
+ def create_agent_executor(
77
+ role: str,
78
+ goal: str,
79
+ tools: list,
80
+ context: str = "",
81
+ llm: Optional[ChatOpenAI] = None
82
+ ) -> AgentExecutor:
83
+ """Create a configured agent executor"""
84
+
85
+ if llm is None:
86
+ config = FinRyverAgentConfig()
87
+ llm = config.get_llm()
88
+
89
+ if llm is None:
90
+ raise ValueError("LLM configuration failed. Check your API keys.")
91
+
92
+ prompt = create_financial_agent_prompt(role, goal, context)
93
+
94
+ agent = create_openai_tools_agent(
95
+ llm=llm,
96
+ tools=tools,
97
+ prompt=prompt
98
+ )
99
+
100
+ return AgentExecutor(
101
+ agent=agent,
102
+ tools=tools,
103
+ verbose=True,
104
+ max_iterations=5,
105
+ early_stopping_method="generate"
106
+ )
agents/simple_agent.py ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Simplified financial agent focused only on generating financial statements
3
+ """
4
+ from typing import Dict, Any, Optional
5
+ import logging
6
+ from .base_config import FinRyverAgentConfig, create_agent_executor
7
+ from .simple_tools import FINANCIAL_TOOLS
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+ class FinancialStatementAgent:
12
+ """
13
+ Simple agent that generates: Notes, Balance Sheet, P&L, Cash Flow
14
+ """
15
+
16
+ def __init__(self, config: Optional[FinRyverAgentConfig] = None):
17
+ self.config = config or FinRyverAgentConfig()
18
+ self.llm = self.config.get_llm()
19
+
20
+ # Create agent with financial statement tools
21
+ self.agent_executor = create_agent_executor(
22
+ role="Financial Statement Generator",
23
+ goal="Generate financial statements (notes, balance sheet, P&L, cash flow) from trial balance data",
24
+ tools=FINANCIAL_TOOLS,
25
+ context="You generate financial statements from trial balance files. Available outputs: Notes, Balance Sheet, P&L Statement, Cash Flow Statement.",
26
+ llm=self.llm
27
+ )
28
+
29
+ async def generate_all_statements(self, file_path: str, note_numbers: str) -> Dict[str, Any]:
30
+ """Generate all financial statements from trial balance file"""
31
+ try:
32
+ prompt = f"""
33
+ Generate all financial statements from the trial balance file: {file_path}
34
+ Note numbers to include: {note_numbers}
35
+
36
+ Please generate in this order:
37
+ 1. Financial notes for note numbers: {note_numbers}
38
+ 2. Balance sheet
39
+ 3. P&L statement
40
+ 4. Cash flow statement
41
+
42
+ Use the available tools to generate each statement and provide a summary of what was created.
43
+ """
44
+
45
+ result = await self.agent_executor.ainvoke({"input": prompt})
46
+ return {"status": "success", "result": result["output"]}
47
+
48
+ except Exception as e:
49
+ logger.error(f"Error generating statements: {e}")
50
+ return {"status": "error", "error": str(e)}
51
+
52
+ async def generate_specific_statement(self, file_path: str, statement_type: str, note_numbers: str) -> Dict[str, Any]:
53
+ """Generate a specific financial statement"""
54
+ try:
55
+ prompts = {
56
+ "notes": f"Generate financial notes for note numbers {note_numbers} from {file_path}",
57
+ "balance_sheet": f"Generate balance sheet from {file_path} using note numbers {note_numbers}",
58
+ "pnl": f"Generate P&L statement from {file_path} using note numbers {note_numbers}",
59
+ "cash_flow": f"Generate cash flow statement from {file_path} using note numbers {note_numbers}"
60
+ }
61
+
62
+ prompt = prompts.get(statement_type, prompts["notes"])
63
+
64
+ result = await self.agent_executor.ainvoke({"input": prompt})
65
+ return {"status": "success", "result": result["output"]}
66
+
67
+ except Exception as e:
68
+ logger.error(f"Error generating {statement_type}: {e}")
69
+ return {"status": "error", "error": str(e)}
agents/simple_tools.py ADDED
@@ -0,0 +1,395 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Simplified LangChain tools for FinRyver financial statement generation
3
+ Focus: Notes, Balance Sheet, P&L, Cash Flow generation only
4
+ """
5
+ from langchain_core.tools import tool
6
+ import os
7
+ import subprocess
8
+ import json
9
+ import shutil
10
+ import time
11
+ import uuid
12
+ from typing import Dict, Any
13
+ import logging
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ @tool
19
+ def generate_notes_from_trial_balance(file_path: str, note_numbers: str = "") -> Dict[str, Any]:
20
+ """
21
+ Generate financial notes from trial balance file
22
+ Args:
23
+ file_path: Path to the trial balance Excel file
24
+ note_numbers: Optional comma-separated note numbers (e.g., "2,3,4,5"). If empty, generates all notes.
25
+ """
26
+ execution_id = str(uuid.uuid4())[:8]
27
+ start_time = time.time()
28
+ tool_name = "generate_notes_from_trial_balance"
29
+
30
+ try:
31
+
32
+ # Copy file to input directory
33
+ input_dir = "data/input"
34
+ os.makedirs(input_dir, exist_ok=True)
35
+ input_file = os.path.join(input_dir, "trial_balance.xlsx")
36
+ shutil.copy2(file_path, input_file)
37
+
38
+ file_size = os.path.getsize(input_file)
39
+
40
+
41
+ # Run notes generation using existing endpoint logic
42
+ env = os.environ.copy()
43
+
44
+
45
+ # Use existing notes generation modules
46
+ from notes.data_extraction import extract_trial_balance_data
47
+ from notes.llm_notes_generator import FlexibleFinancialNoteGenerator
48
+ from notes.json_to_excel import json_to_xlsx
49
+
50
+
51
+ # Extract trial balance data
52
+ trial_balance_data = extract_trial_balance_data(file_path)
53
+
54
+
55
+
56
+ # Generate notes
57
+ note_generator = FlexibleFinancialNoteGenerator()
58
+
59
+ if note_numbers.strip():
60
+ # Generate specific notes
61
+ note_list = [int(n.strip()) for n in note_numbers.split(',')]
62
+ generated_notes = {}
63
+ for i, note_num in enumerate(note_list, 1):
64
+ note_content = note_generator.generate_note(note_num, trial_balance_data)
65
+ generated_notes[f"note_{note_num}"] = note_content
66
+ message = f"Notes generated for: {note_numbers}"
67
+ else:
68
+ # Generate all notes
69
+ generated_notes = note_generator.generate_all_notes(trial_balance_data)
70
+ message = "All notes generated successfully"
71
+ # Save notes
72
+ output_path = "data/generated_notes/notes.json"
73
+ os.makedirs(os.path.dirname(output_path), exist_ok=True)
74
+ with open(output_path, 'w') as f:
75
+ json.dump(generated_notes, f, indent=2)
76
+
77
+ execution_time = round(time.time() - start_time, 2)
78
+ output_file_size = os.path.getsize(output_path)
79
+
80
+ return {
81
+ "status": "success",
82
+ "message": message,
83
+ "output_path": output_path,
84
+ "execution_id": execution_id,
85
+ "execution_time": execution_time
86
+ }
87
+
88
+ except Exception as e:
89
+ execution_time = round(time.time() - start_time, 2)
90
+
91
+ return {
92
+ "status": "error",
93
+ "error": str(e),
94
+ "execution_id": execution_id,
95
+ "execution_time": execution_time
96
+ }
97
+
98
+ @tool
99
+ def generate_balance_sheet(file_path: str) -> Dict[str, Any]:
100
+ """
101
+ Generate balance sheet from trial balance file using complete pipeline
102
+ Args:
103
+ file_path: Path to trial balance Excel file
104
+ """
105
+ execution_id = str(uuid.uuid4())[:8]
106
+ start_time = time.time()
107
+ tool_name = "generate_balance_sheet"
108
+
109
+
110
+ try:
111
+ # Use the complete BS pipeline from the existing endpoint
112
+ env = os.environ.copy()
113
+ if os.getenv("OPENROUTER_API_KEY"):
114
+ env["OPENROUTER_API_KEY"] = os.getenv("OPENROUTER_API_KEY")
115
+ env["INPUT_FILE"] = "data/clean_financial_data_bs.json"
116
+ cwd = os.getcwd()
117
+
118
+ # Step 1: Run balance_sheet_data_extractor.py
119
+
120
+ result1 = subprocess.run(
121
+ ["python", "bs/balance_sheet_data_extractor.py", file_path],
122
+ env=env,
123
+ cwd=cwd,
124
+ capture_output=True,
125
+ text=True
126
+ )
127
+
128
+ if result1.returncode != 0:
129
+
130
+ return {"status": "error", "error": f"Balance sheet data extraction failed: {result1.stderr}"}
131
+
132
+ # Step 2: Run balance_sheet_csv_to_json_converter.py
133
+
134
+
135
+ result2 = subprocess.run(
136
+ ["python", "bs/balance_sheet_csv_to_json_converter.py"],
137
+ env=env,
138
+ cwd=cwd,
139
+ capture_output=True,
140
+ text=True
141
+ )
142
+
143
+ if result2.returncode != 0:
144
+
145
+ return {"status": "error", "error": f"CSV to JSON conversion failed: {result2.stderr}"}
146
+
147
+ # Step 3: Run balance_sheet_generator.py
148
+
149
+ result3 = subprocess.run(
150
+ ["python", "bs/balance_sheet_generator.py"],
151
+ env=env,
152
+ cwd=cwd,
153
+ capture_output=True,
154
+ text=True
155
+ )
156
+
157
+ if result3.returncode == 0:
158
+ # Check for output files in data/output directory
159
+ output_files = []
160
+ if os.path.exists("data/output"):
161
+ output_files = [f for f in os.listdir("data/output") if f.endswith('.xlsx')]
162
+
163
+ execution_time = round(time.time() - start_time, 2)
164
+
165
+
166
+ return {
167
+ "status": "success",
168
+ "message": "Balance sheet generated successfully",
169
+ "output_path": "data/output/",
170
+ "output_files": output_files,
171
+ "execution_id": execution_id,
172
+ "execution_time": execution_time
173
+ }
174
+ else:
175
+ execution_time = round(time.time() - start_time, 2)
176
+
177
+ return {
178
+ "status": "error",
179
+ "error": f"Balance sheet generation failed: {result3.stderr}",
180
+ "execution_id": execution_id
181
+ }
182
+
183
+ except Exception as e:
184
+ execution_time = round(time.time() - start_time, 2)
185
+
186
+ return {
187
+ "status": "error",
188
+ "error": str(e),
189
+ "execution_id": execution_id,
190
+ "execution_time": execution_time
191
+ }
192
+
193
+ @tool
194
+ def generate_pnl_statement(file_path: str) -> Dict[str, Any]:
195
+ """
196
+ Generate P&L statement from trial balance file using complete pipeline
197
+ Args:
198
+ file_path: Path to trial balance Excel file
199
+ """
200
+ execution_id = str(uuid.uuid4())[:8]
201
+ start_time = time.time()
202
+ tool_name = "generate_pnl_statement"
203
+
204
+
205
+ try:
206
+ # Use the complete P&L pipeline from existing endpoint
207
+ env = os.environ.copy()
208
+ if os.getenv("OPENROUTER_API_KEY"):
209
+ env["OPENROUTER_API_KEY"] = os.getenv("OPENROUTER_API_KEY")
210
+ env["INPUT_FILE"] = "data/clean_financial_data_pnl.json"
211
+ cwd = os.getcwd()
212
+
213
+ # Step 1: Run profit_loss_data_extractor.py
214
+
215
+ result1 = subprocess.run(
216
+ ["python", "pnl/profit_loss_data_extractor.py", file_path],
217
+ env=env,
218
+ cwd=cwd,
219
+ capture_output=True,
220
+ text=True
221
+ )
222
+
223
+ if result1.returncode != 0:
224
+
225
+ return {"status": "error", "error": f"P&L data extraction failed: {result1.stderr}"}
226
+
227
+ # Step 2: Run profit_loss_csv_to_json_converter.py
228
+
229
+
230
+ result2 = subprocess.run(
231
+ ["python", "pnl/profit_loss_csv_to_json_converter.py"],
232
+ env=env,
233
+ cwd=cwd,
234
+ capture_output=True,
235
+ text=True
236
+ )
237
+
238
+ if result2.returncode != 0:
239
+
240
+ return {"status": "error", "error": f"P&L CSV to JSON conversion failed: {result2.stderr}"}
241
+
242
+ # Step 3: Run profit_loss_statement_generator.py
243
+
244
+ result3 = subprocess.run(
245
+ ["python", "pnl/profit_loss_statement_generator.py", "data/clean_financial_data_pnl.json"],
246
+ env=env,
247
+ cwd=cwd,
248
+ capture_output=True,
249
+ text=True
250
+ )
251
+
252
+ if result3.returncode == 0:
253
+ execution_time = round(time.time() - start_time, 2)
254
+ output_path = "data/pnl_statement.xlsx"
255
+
256
+ return {
257
+ "status": "success",
258
+ "message": "P&L statement generated successfully",
259
+ "output_path": output_path,
260
+ "execution_id": execution_id,
261
+ "execution_time": execution_time
262
+ }
263
+ else:
264
+ execution_time = round(time.time() - start_time, 2)
265
+
266
+ return {
267
+ "status": "error",
268
+ "error": f"P&L generation failed: {result3.stderr}",
269
+ "execution_id": execution_id
270
+ }
271
+
272
+ except Exception as e:
273
+ execution_time = round(time.time() - start_time, 2)
274
+
275
+ return {
276
+ "status": "error",
277
+ "error": str(e),
278
+ "execution_id": execution_id,
279
+ "execution_time": execution_time
280
+ }
281
+
282
+ @tool
283
+ def generate_cash_flow_statement(file_path: str) -> Dict[str, Any]:
284
+ """
285
+ Generate cash flow statement from trial balance file using complete pipeline
286
+ Args:
287
+ file_path: Path to trial balance Excel file
288
+ """
289
+ execution_id = str(uuid.uuid4())[:8]
290
+ start_time = time.time()
291
+ tool_name = "generate_cash_flow_statement"
292
+
293
+
294
+
295
+ try:
296
+ # Use the complete CF pipeline from existing endpoint
297
+ env = os.environ.copy()
298
+ if os.getenv("OPENROUTER_API_KEY"):
299
+ env["OPENROUTER_API_KEY"] = os.getenv("OPENROUTER_API_KEY")
300
+ env["INPUT_FILE"] = "data/clean_financial_data_cfs.json"
301
+ cwd = os.getcwd()
302
+
303
+ # Step 1: Run cash_flow_data_extractor.py
304
+
305
+
306
+ result1 = subprocess.run(
307
+ ["python", "cf/cash_flow_data_extractor.py", file_path],
308
+ env=env,
309
+ cwd=cwd,
310
+ capture_output=True,
311
+ text=True
312
+ )
313
+
314
+ if result1.returncode != 0:
315
+
316
+ return {"status": "error", "error": f"Cash flow data extraction failed: {result1.stderr}"}
317
+
318
+ # Step 2: Run cash_flow_csv_to_json_converter.py
319
+
320
+
321
+ result2 = subprocess.run(
322
+ ["python", "cf/cash_flow_csv_to_json_converter.py"],
323
+ env=env,
324
+ cwd=cwd,
325
+ capture_output=True,
326
+ text=True
327
+ )
328
+
329
+ if result2.returncode != 0:
330
+
331
+ return {"status": "error", "error": f"Cash flow CSV to JSON conversion failed: {result2.stderr}"}
332
+
333
+ # Step 3: Run cash_flow_data_processor.py
334
+
335
+
336
+ result3 = subprocess.run(
337
+ ["python", "cf/cash_flow_data_processor.py"],
338
+ env=env,
339
+ cwd=cwd,
340
+ capture_output=True,
341
+ text=True
342
+ )
343
+
344
+ if result3.returncode != 0:
345
+
346
+ return {"status": "error", "error": f"Cash flow data processing failed: {result3.stderr}"}
347
+
348
+ # Step 4: Run cash_flow_statement_generator.py
349
+
350
+
351
+ result4 = subprocess.run(
352
+ ["python", "cf/cash_flow_statement_generator.py"],
353
+ env=env,
354
+ cwd=cwd,
355
+ capture_output=True,
356
+ text=True
357
+ )
358
+
359
+ if result4.returncode == 0:
360
+ execution_time = round(time.time() - start_time, 2)
361
+ output_path = "data/cash_flow_statements.xlsx"
362
+
363
+ return {
364
+ "status": "success",
365
+ "message": "Cash flow statement generated successfully",
366
+ "output_path": output_path,
367
+ "execution_id": execution_id,
368
+ "execution_time": execution_time
369
+ }
370
+ else:
371
+ execution_time = round(time.time() - start_time, 2)
372
+
373
+ return {
374
+ "status": "error",
375
+ "error": f"Cash flow generation failed: {result4.stderr}",
376
+ "execution_id": execution_id
377
+ }
378
+
379
+ except Exception as e:
380
+ execution_time = round(time.time() - start_time, 2)
381
+
382
+ return {
383
+ "status": "error",
384
+ "error": str(e),
385
+ "execution_id": execution_id,
386
+ "execution_time": execution_time
387
+ }
388
+
389
+ # Simplified tool list - only financial statement generation
390
+ FINANCIAL_TOOLS = [
391
+ generate_notes_from_trial_balance,
392
+ generate_balance_sheet,
393
+ generate_pnl_statement,
394
+ generate_cash_flow_statement
395
+ ]
app.py CHANGED
@@ -17,11 +17,13 @@ from notes.notes_generator import process_json
17
  from notes.json_to_excel import json_to_xlsx
18
  from utils.utils_normalize import normalize_llm_note_json, normalize_llm_notes_json
19
 
20
-
21
  # Configure logging for the application
22
  logging.basicConfig(level=logging.INFO)
23
  logger = logging.getLogger("financial_notes_api")
24
 
 
 
 
25
  app = FastAPI(
26
  title="Financial Notes Generator API",
27
  description="API for generating financial notes, balance sheets, cash flow statements, and P&L reports.",
@@ -213,14 +215,14 @@ async def bs_from_notes(file: UploadFile = File(...)):
213
  env["OPENROUTER_API_KEY"] = os.getenv("OPENROUTER_API_KEY")
214
  env["INPUT_FILE"] = "data/clean_financial_data_bs.json"
215
  cwd = os.getenv("PROJECT_ROOT", os.getcwd())
216
- # Run sircodebs.py
217
- run_subprocess("bs/sircodebs.py", [input_excel_path], env, cwd)
218
  logger.info(f"Files in data/csv_notes_bs/: {os.listdir('data/csv_notes_bs') if os.path.exists('data/csv_notes_bs') else 'data/csv_notes_bs does not exist'}")
219
- # Run csv_json_bs.py
220
- run_subprocess("bs/csv_json_bs.py", [], env, cwd)
221
  logger.info(f"data/clean_financial_data_bs.json exists: {os.path.exists('data/clean_financial_data_bs.json')}")
222
- # Run bl_llm.py
223
- result = run_subprocess("bs/bl_llm.py", [], env, cwd)
224
  output_file = extract_output_file(result.stdout)
225
  if output_file and not os.path.isabs(output_file):
226
  output_file_path = os.path.join(cwd, output_file)
@@ -228,8 +230,8 @@ async def bs_from_notes(file: UploadFile = File(...)):
228
  output_file_path = output_file
229
  if not output_file or not os.path.exists(output_file_path):
230
  debug_msg = f"\nSTDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}"
231
- logger.error(f"Could not determine output file from bl_llm.py output.{debug_msg}")
232
- raise HTTPException(status_code=500, detail=f"Could not determine output file from bl_llm.py output.{debug_msg}")
233
  logger.info(f"Pipeline completed. Output file: {output_file_path}")
234
  return FileResponse(
235
  output_file_path,
@@ -250,16 +252,16 @@ async def pnl_from_notes(file: UploadFile = File(...)):
250
  env["OPENROUTER_API_KEY"] = os.getenv("OPENROUTER_API_KEY")
251
  env["INPUT_FILE"] = "data/clean_financial_data_pnl.json"
252
  cwd = os.getenv("PROJECT_ROOT", os.getcwd())
253
- # Run sircodepnl.py
254
- run_subprocess("pnl/sircodepnl.py", [input_excel_path], env, cwd)
255
  csv_notes_pnl_path = os.path.join(cwd, 'data/csv_notes_pnl')
256
  logger.info(f"Files in {csv_notes_pnl_path}/: {os.listdir(csv_notes_pnl_path) if os.path.exists(csv_notes_pnl_path) else f'{csv_notes_pnl_path} does not exist'}")
257
- # Run csv_json_pnl.py
258
- run_subprocess("pnl/csv_json_pnl.py", [], env, cwd)
259
  json_path = os.path.join(cwd, 'data/clean_financial_data_pnl.json')
260
  logger.info(f"data/clean_financial_data_pnl.json exists: {os.path.exists(json_path)}")
261
- # Run pnl_note.py
262
- run_subprocess("pnl/pnl_note.py", [], env, cwd)
263
  # Use fixed output file path
264
  output_file_path = os.path.join(cwd, "data/pnl_statement.xlsx")
265
  if not os.path.exists(output_file_path):
@@ -282,20 +284,20 @@ async def cf_from_notes(file: UploadFile = File(...)):
282
  logger.info(f"Files in data/input/: {os.listdir('data/input')}")
283
  env = os.environ.copy()
284
  cwd = os.getenv("PROJECT_ROOT", os.getcwd())
285
- # Step 1: Run sircodecf.py
286
- run_subprocess("cf/sircodecf.py", [input_excel_path], env, cwd)
287
  csv_notes_cfs_path = os.path.join(cwd, 'data/csv_notes_cfs')
288
  logger.info(f"Files in {csv_notes_cfs_path}/: {os.listdir(csv_notes_cfs_path) if os.path.exists(csv_notes_cfs_path) else f'{csv_notes_cfs_path} does not exist'}")
289
- # Step 2: Run csv_json_cf.py
290
- run_subprocess("cf/csv_json_cf.py", [], env, cwd)
291
  json_path = os.path.join(cwd, 'data/clean_financial_data_cfs.json')
292
  logger.info(f"data/clean_financial_data_cfs.json exists: {os.path.exists(json_path)}")
293
- # Step 3: Run cf_middlestep.py
294
- run_subprocess("cf/cf_middlestep.py", [], env, cwd)
295
  extracted_json_path = os.path.join(cwd, 'data/extracted_cfs_data.json')
296
  logger.info(f"data/extracted_cfs_data.json exists: {os.path.exists(extracted_json_path)}")
297
- # Step 4: Run cf_generation.py
298
- result = run_subprocess("cf/cf_generation.py", [], env, cwd)
299
  output_file = "data/cash_flow_statements.xlsx"
300
  output_file_path = os.path.join(cwd, output_file)
301
  if not os.path.exists(output_file_path):
@@ -311,6 +313,45 @@ async def cf_from_notes(file: UploadFile = File(...)):
311
  media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
312
  )
313
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
314
  app.include_router(router)
315
 
316
  if __name__ == "__main__":
 
17
  from notes.json_to_excel import json_to_xlsx
18
  from utils.utils_normalize import normalize_llm_note_json, normalize_llm_notes_json
19
 
 
20
  # Configure logging for the application
21
  logging.basicConfig(level=logging.INFO)
22
  logger = logging.getLogger("financial_notes_api")
23
 
24
+ # Import agent system
25
+ from agents.simple_agent import FinancialStatementAgent
26
+
27
  app = FastAPI(
28
  title="Financial Notes Generator API",
29
  description="API for generating financial notes, balance sheets, cash flow statements, and P&L reports.",
 
215
  env["OPENROUTER_API_KEY"] = os.getenv("OPENROUTER_API_KEY")
216
  env["INPUT_FILE"] = "data/clean_financial_data_bs.json"
217
  cwd = os.getenv("PROJECT_ROOT", os.getcwd())
218
+ # Run Balance Sheet Data Extractor
219
+ run_subprocess("bs/balance_sheet_data_extractor.py", [input_excel_path], env, cwd)
220
  logger.info(f"Files in data/csv_notes_bs/: {os.listdir('data/csv_notes_bs') if os.path.exists('data/csv_notes_bs') else 'data/csv_notes_bs does not exist'}")
221
+ # Run Balance Sheet CSV to JSON Converter
222
+ run_subprocess("bs/balance_sheet_csv_to_json_converter.py", [], env, cwd)
223
  logger.info(f"data/clean_financial_data_bs.json exists: {os.path.exists('data/clean_financial_data_bs.json')}")
224
+ # Run Balance Sheet Generator
225
+ result = run_subprocess("bs/balance_sheet_generator.py", [], env, cwd)
226
  output_file = extract_output_file(result.stdout)
227
  if output_file and not os.path.isabs(output_file):
228
  output_file_path = os.path.join(cwd, output_file)
 
230
  output_file_path = output_file
231
  if not output_file or not os.path.exists(output_file_path):
232
  debug_msg = f"\nSTDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}"
233
+ logger.error(f"Could not determine output file from balance_sheet_generator.py output.{debug_msg}")
234
+ raise HTTPException(status_code=500, detail=f"Could not determine output file from balance_sheet_generator.py output.{debug_msg}")
235
  logger.info(f"Pipeline completed. Output file: {output_file_path}")
236
  return FileResponse(
237
  output_file_path,
 
252
  env["OPENROUTER_API_KEY"] = os.getenv("OPENROUTER_API_KEY")
253
  env["INPUT_FILE"] = "data/clean_financial_data_pnl.json"
254
  cwd = os.getenv("PROJECT_ROOT", os.getcwd())
255
+ # Run Profit & Loss Data Extractor
256
+ run_subprocess("pnl/profit_loss_data_extractor.py", [input_excel_path], env, cwd)
257
  csv_notes_pnl_path = os.path.join(cwd, 'data/csv_notes_pnl')
258
  logger.info(f"Files in {csv_notes_pnl_path}/: {os.listdir(csv_notes_pnl_path) if os.path.exists(csv_notes_pnl_path) else f'{csv_notes_pnl_path} does not exist'}")
259
+ # Run Profit & Loss CSV to JSON Converter
260
+ run_subprocess("pnl/profit_loss_csv_to_json_converter.py", [], env, cwd)
261
  json_path = os.path.join(cwd, 'data/clean_financial_data_pnl.json')
262
  logger.info(f"data/clean_financial_data_pnl.json exists: {os.path.exists(json_path)}")
263
+ # Run Profit & Loss Statement Generator
264
+ run_subprocess("pnl/profit_loss_statement_generator.py", [], env, cwd)
265
  # Use fixed output file path
266
  output_file_path = os.path.join(cwd, "data/pnl_statement.xlsx")
267
  if not os.path.exists(output_file_path):
 
284
  logger.info(f"Files in data/input/: {os.listdir('data/input')}")
285
  env = os.environ.copy()
286
  cwd = os.getenv("PROJECT_ROOT", os.getcwd())
287
+ # Step 1: Run Cash Flow Data Extractor
288
+ run_subprocess("cf/cash_flow_data_extractor.py", [input_excel_path], env, cwd)
289
  csv_notes_cfs_path = os.path.join(cwd, 'data/csv_notes_cfs')
290
  logger.info(f"Files in {csv_notes_cfs_path}/: {os.listdir(csv_notes_cfs_path) if os.path.exists(csv_notes_cfs_path) else f'{csv_notes_cfs_path} does not exist'}")
291
+ # Step 2: Run Cash Flow CSV to JSON Converter
292
+ run_subprocess("cf/cash_flow_csv_to_json_converter.py", [], env, cwd)
293
  json_path = os.path.join(cwd, 'data/clean_financial_data_cfs.json')
294
  logger.info(f"data/clean_financial_data_cfs.json exists: {os.path.exists(json_path)}")
295
+ # Step 3: Run Cash Flow Data Processor
296
+ run_subprocess("cf/cash_flow_data_processor.py", [], env, cwd)
297
  extracted_json_path = os.path.join(cwd, 'data/extracted_cfs_data.json')
298
  logger.info(f"data/extracted_cfs_data.json exists: {os.path.exists(extracted_json_path)}")
299
+ # Step 4: Run Cash Flow Statement Generator
300
+ result = run_subprocess("cf/cash_flow_statement_generator.py", [], env, cwd)
301
  output_file = "data/cash_flow_statements.xlsx"
302
  output_file_path = os.path.join(cwd, output_file)
303
  if not os.path.exists(output_file_path):
 
313
  media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
314
  )
315
 
316
+ @router.post("/agent/generate")
317
+ async def agent_generate_statements(
318
+ file: UploadFile = File(...),
319
+ note_numbers: str = Form(""),
320
+ statement_type: str = Form("all") # all, notes, balance_sheet, pnl, cash_flow
321
+ ):
322
+ """
323
+ Use AI agent to generate financial statements (Notes/BS/P&L/CF)
324
+ """
325
+ try:
326
+ # Save uploaded file
327
+ upload_dir = "data/input"
328
+ os.makedirs(upload_dir, exist_ok=True)
329
+ file_path = os.path.join(upload_dir, file.filename)
330
+
331
+ with open(file_path, "wb") as buffer:
332
+ shutil.copyfileobj(file.file, buffer)
333
+
334
+ # Initialize financial statement agent
335
+ agent = FinancialStatementAgent()
336
+
337
+ # Generate requested statements
338
+ if statement_type == "all":
339
+ result = await agent.generate_all_statements(file_path, note_numbers)
340
+ else:
341
+ result = await agent.generate_specific_statement(file_path, statement_type, note_numbers)
342
+
343
+ return JSONResponse(content={
344
+ "message": f"Financial statement generation completed: {statement_type}",
345
+ "file_processed": file.filename,
346
+ "note_numbers": note_numbers,
347
+ "statement_type": statement_type,
348
+ "result": result
349
+ })
350
+
351
+ except Exception as e:
352
+ logger.error(f"Error in agent statement generation: {e}")
353
+ raise HTTPException(status_code=500, detail=f"Agent generation failed: {str(e)}")
354
+
355
  app.include_router(router)
356
 
357
  if __name__ == "__main__":
bs/{csv_json_bs.py → balance_sheet_csv_to_json_converter.py} RENAMED
File without changes
bs/{sircodebs.py → balance_sheet_data_extractor.py} RENAMED
File without changes
bs/{bl_llm.py → balance_sheet_generator.py} RENAMED
File without changes
bs/{temp_bl.py → balance_sheet_template_handler.py} RENAMED
File without changes
cf/{csv_json_cf.py → cash_flow_csv_to_json_converter.py} RENAMED
File without changes
cf/{sircodecf.py → cash_flow_data_extractor.py} RENAMED
File without changes
cf/{cf_middlestep.py → cash_flow_data_processor.py} RENAMED
File without changes
cf/{cf_generation.py → cash_flow_statement_generator.py} RENAMED
File without changes
docker-compose.yml CHANGED
@@ -1,14 +1,37 @@
 
 
1
  services:
2
- app:
3
  build: .
4
- container_name: FinRyver
5
- volumes:
6
- - .:/app
7
  ports:
8
  - "8000:8000"
 
 
 
 
 
9
  environment:
10
  - PYTHONUNBUFFERED=1
11
  - PORT=8000
 
 
 
 
12
  env_file:
13
  - .env
14
- restart: unless-stopped
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3.8'
2
+
3
  services:
4
+ finryver:
5
  build: .
6
+ container_name: finryver-app
 
 
7
  ports:
8
  - "8000:8000"
9
+ volumes:
10
+ # Mount data directory for persistent storage
11
+ - ./data:/app/data
12
+ # Mount config directory for business rules
13
+ - ./config:/app/config
14
  environment:
15
  - PYTHONUNBUFFERED=1
16
  - PORT=8000
17
+ # Default agent settings (override with .env file)
18
+ - AGENT_MODEL=gpt-3.5-turbo
19
+ - AGENT_TEMPERATURE=0.1
20
+ - AGENT_MAX_TOKENS=2000
21
  env_file:
22
  - .env
23
+ restart: unless-stopped
24
+ healthcheck:
25
+ test: ["CMD", "curl", "-f", "http://localhost:8000/docs"]
26
+ interval: 30s
27
+ timeout: 10s
28
+ retries: 3
29
+ start_period: 40s
30
+
31
+ # Optional: Add Redis for caching (future enhancement)
32
+ # redis:
33
+ # image: redis:7-alpine
34
+ # container_name: finryver-redis
35
+ # ports:
36
+ # - "6379:6379"
37
+ # restart: unless-stopped
pnl/{csv_json_pnl.py → profit_loss_csv_to_json_converter.py} RENAMED
File without changes
pnl/{sircodepnl.py → profit_loss_data_extractor.py} RENAMED
File without changes
pnl/{pnl_note.py → profit_loss_statement_generator.py} RENAMED
File without changes
requirements.txt CHANGED
@@ -6,4 +6,11 @@ python-dotenv
6
  pydantic-settings
7
  pydantic
8
  requests
9
- python-multipart
 
 
 
 
 
 
 
 
6
  pydantic-settings
7
  pydantic
8
  requests
9
+ python-multipart
10
+
11
+ # LangChain dependencies
12
+ langchain
13
+ langchain-openai
14
+ langchain-community
15
+ langchain-core
16
+ langsmith