Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 

Repository files navigation

🗃️ Restaurant Data Management — IBM Granite + LLM-Powered CRUD

Language LLM Pattern Testing Storage Status


📌 Project Overview

A CLI-based restaurant data management system where IBM Granite 3 8B acts as a data extraction engine — converting unstructured restaurant descriptions (paragraphs) into structured JSON records automatically, with built-in JSON auto-repair if the LLM output is malformed.

Full CRUD operations (Browse, View, Add, Edit, Delete) with security confirmation prompts, automatic backup before every write, and unittest coverage with mocked inputs and LLM calls.

Domain: LLM-Powered Data Engineering + CLI App
LLM: ibm/granite-3-8b-instruct (IBM Watsonx.ai)
Companion project to: california-culinary-mcp-server


📂 Project Structure

restaurant-data-management/
│
├── restaurant_data_management.py   # Full app — LLM extraction + CRUD + tests
├── structured_restaurant_data.json # Persistent restaurant records
└── structured_restaurant_data.json.bak  # Auto-backup before every write

🛠️ Tech Stack

Component Technology
LLM ibm/granite-3-8b-instruct (IBM Watsonx)
API ibm_watsonx_ai.foundation_models.ModelInference
Data Validation Pydantic BaseModel + Field
Storage JSON file + .bak automatic backup
Testing Python unittest + unittest.mock.patch

🤖 LLM-Powered Data Entry Pipeline

# Exercise 1 — Prompt generation
def restaurant_data_structure_prompt_generation(paragraph):
    system_msg = "You are a data engineer. Extract restaurant details into valid JSON."
    prompt_txt = f"""
    Extract: name, location, cuisine, style, rating, description, price_range
    Paragraph: {paragraph}
    Return ONLY the JSON object.
    """
    return system_msg, prompt_txt

# Auto-repair if JSON is malformed
def JSON_auto_repair_prompts(response, error_message):
    """Sends broken JSON back to LLM with error for repair"""

# Full new entry pipeline with fallback repair
def new_data_entry_process(paragraph, itemId):
    sys_msg, p_txt = restaurant_data_structure_prompt_generation(paragraph)
    raw_response = llm_model(sys_msg, p_txt)

    try:
        structured_data = json.loads(raw_response)
    except Exception as e:
        # Auto-repair loop
        repair_sys, repair_p = JSON_auto_repair_prompts(raw_response, str(e))
        repaired = llm_model(repair_sys, repair_p)
        structured_data = json.loads(repaired)

    structured_data['itemId'] = 1000000 + len(data) + 1
    return structured_data

📋 CLI Menu — 6 Operations

Records: 12
1. Browse     → List all restaurant names with index
2. View       → Pretty-print full restaurant card (JSON)
3. Add        → Paste a paragraph → LLM extracts → saves to JSON
4. Edit       → Update fields of an existing record
5. Delete     → Remove a record by index
6. Exit

Security: Operations 3/4/5 require yes confirmation before execution.


💾 Auto-Backup System

def save_data(data, file_path, backup_path):
    # Always backup before overwriting
    if os.path.exists(file_path):
        shutil.copy(file_path, backup_path)  # → .json.bak

    with open(file_path, "w") as f:
        json.dump(data, f, indent=4)

✅ Unit Tests with Mocked Inputs & LLM

class TestRestaurantDatabase(unittest.TestCase):

    def test_add_and_delete_restaurant_success(self, mock_stdout, mock_input):
        # Simulate: Add → confirm → enter paragraph → Exit
        mock_input.side_effect = ['3', 'yes', mock_restaurant, '6']
        manage_restaurants(self.test_file, self.test_file_backup)
        self.assertEqual(len(data), 2)  # One more record added
        self.assertIn("✅ Restaurant added.", mock_stdout.getvalue())

        # Simulate: Delete → confirm → index → Exit
        mock_input.side_effect = ['5', 'yes', '1', '6']
        self.assertEqual(len(data), 1)  # Back to original

    def test_delete_security_cancel(self, mock_stdout, mock_input):
        # Simulate: Delete → 'no' → Exit (no changes)
        mock_input.side_effect = ['5', 'no', '6']
        self.assertEqual(len(data), 1)  # Unchanged
        self.assertIn("Operation cancelled.", mock_stdout.getvalue())

LLM is mocked — unit tests run without API keys via safe fallback JSON.


🎓 Skills Demonstrated

  • IBM Granite 3 8B text-to-JSON extraction via ModelInference.chat()
  • LLM prompt engineering for structured data extraction
  • JSON auto-repair loop — broken LLM output → repair prompt → retry
  • Full CRUD CLI application with menu-driven interface
  • Automatic file backup before every write (shutil.copy)
  • Python unittest with @patch('builtins.input') and @patch('sys.stdout')
  • Mock-safe LLM fallback — tests run without live API
  • Security confirmation prompts for destructive operations
  • Pydantic for data validation schema

📜 Certifications

Certification Issuer Platform
IBM Data Science Professional Certificate IBM Coursera
IBM Generative AI Professional Certificate IBM Coursera
IBM RAG and Agentic AI Professional Certificate IBM Coursera

🤝 Connect with Me

LinkedIn Gmail GitHub

About

LLM-powered restaurant CRUD — IBM Granite 3 8B extracts structured JSON from text paragraphs with auto-repair loop, CLI menu, auto-backup & unittest coverage with mocked inputs

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages