aki f02f848ada feat: Implement full problem generation
This commit marks a major milestone in the problem generator project.

Key systems include:
- Fully functional problem generation for all 23 defined concepts (Simple Interest, Compound Interest, Banker's Discount, Effective Rate, Continuous Compounding, Exact/Ordinary Simple Interest).
- Robust date handling for date-specific interest calculations.
- Improved solution presentation with accurate "Substitute Values" step and complete variable descriptions.
- Interactive problem display in `main.py`: problem statement shown first, question and solution revealed on user input.
- Added plausibility checks for rate calculations to avoid unrealistic negative rates.
- Comprehensive `README.md` update:
    - Detailed system architecture (modules, data files, Mermaid diagram).
    - List of all currently covered financial concepts.
    - Instructions for running and extending the generator.
    - Discussion of scope for future enhancements (Equation of Value, Gradients, etc.).
- Refinements to `value_sampler.py` for better formatting and handling of None values.
- Updates to `text_snippets.json` for complete variable descriptions and improved solution step phrasing.
- Updates to `value_ranges.json` for date generation parameters.
- `problem_engine.py` now systematically tests all concepts when run directly.
- Added `uv.lock` to track resolved dependencies.

The system is capable of generating a wide variety of engineering economy problems with detailed, step-by-step solutions and an interactive user experience.
2025-05-09 11:56:16 +08:00

58 lines
2.3 KiB
Python

import sys
import os
# Ensure the src directory is in the Python path
# This allows running main.py from the project root (e.g., python main.py)
# and having imports like 'from src import ...' work correctly.
project_root = os.path.abspath(os.path.dirname(__file__))
src_path = os.path.join(project_root, 'src')
if src_path not in sys.path:
sys.path.insert(0, src_path)
if project_root not in sys.path: # Also add project root for 'from src import ...' if main is outside src
sys.path.insert(0, project_root)
from src.problem_engine import generate_problem
from src.data_loader import get_text_snippets # For variable descriptions
# Note: problem_engine.generate_problem() handles caching of all necessary data internally.
def main():
print("Generating a financial problem via main.py...\n")
# Load text snippets for variable descriptions
# generate_problem() will load its own cache, but for descriptions here, we need it too.
# A more advanced setup might pass TEXT_SNIPPETS_DATA around or make it a singleton.
text_snippets_data = get_text_snippets()
if not text_snippets_data:
print("Error: Failed to load text snippets for main.py. Exiting.")
return
problem = generate_problem()
if "error" in problem:
print(f"Error generating problem: {problem['error']}")
else:
print(f"--- Problem ---")
print(f"Concept ID: {problem['concept_id']}")
print(f"Topic: {problem['topic']}")
print("\nProblem Statement:")
print(problem['problem_statement'])
input("\nPress Enter to see the question and solution...") # Wait for user interaction
unknown_key_desc = text_snippets_data.get("variable_descriptions", {}).get(problem['target_unknown_key'], problem['target_unknown_key'])
print(f"\nQuestion: What is the {unknown_key_desc}?")
print("\nGuided Solution:")
for i, step in enumerate(problem['solution_steps']):
# The steps from solution_presenter already have numbering.
# If not, add: print(f" {i+1}. {step}")
print(step)
print(f"\nFinal Answer ({problem['target_unknown_key']}): {problem['calculated_answer_formatted']}")
print("---------------------------------------\n")
if __name__ == "__main__":
main()