Unable to pass parsed variable from a Mainscript to Model

unfortunately due to limits on SO I am unable to provide full scripts but this should be enough to illustrate the issue..

Main.py

import tkinter as tk
from tkinter import ttk, messagebox
import numpy as np
from model_5_inhalation_exposure_to_spray_spraying import create_parameter_frame as create_model5_frame, ExposureParameters as ExposureParametersModel5

class MainApplication:
    def __init__(self, root):
        self.root = root
        self.root.title("Main Application")

        # Create a canvas to hold the main frame and a scrollbar
        self.canvas = tk.Canvas(self.root)
        self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        self.scrollbar = ttk.Scrollbar(self.root, orient=tk.VERTICAL, command=self.canvas.yview)
        self.scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        self.canvas.configure(yscrollcommand=self.scrollbar.set)
        self.canvas.bind('<Configure>', lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all")))

        self.main_frame = ttk.Frame(self.canvas)
        self.canvas.create_window((0, 0), window=self.main_frame, anchor="nw")

        # Add Frequency and Body Weight entries
        self.add_custom_parameters(self.main_frame)

        # Create and display the Run Model button
        self.run_model_button = ttk.Button(self.main_frame, text="Run Model", command=self.run_model)
        self.run_model_button.pack(pady=10)

        # Create a notebook (tabbed interface)
        self.notebook = ttk.Notebook(self.main_frame)
        self.notebook.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)

        # Create the Inhalation tab
        self.inhalation_tab = ttk.Frame(self.notebook)
        self.notebook.add(self.inhalation_tab, text="Inhalation")

        # Create the exposure parameters frame
        self.exposure_frame = ttk.Frame(self.inhalation_tab)
        self.exposure_frame.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)

        self.ui_instance = create_model5_frame(self.exposure_frame, standalone=False, run_model_callback=self.run_model)

    def add_custom_parameters(self, parent):
        self.custom_params_frame = ttk.Frame(parent)
        self.custom_params_frame.pack(pady=10, fill=tk.X)

        # Frequency parameter
        self.frequency_label = ttk.Label(self.custom_params_frame, text="Frequency")
        self.frequency_label.grid(row=0, column=0, padx=5, pady=5, sticky=tk.W)
        self.frequency_var = tk.StringVar(value="1")
        self.frequency_entry = ttk.Entry(self.custom_params_frame, textvariable=self.frequency_var)
        self.frequency_entry.grid(row=0, column=1, padx=5, pady=5, sticky=tk.EW)
        self.frequency_unit_var = tk.StringVar(value="per year")
        self.frequency_unit_dropdown = ttk.Combobox(self.custom_params_frame, textvariable=self.frequency_unit_var, state='readonly', width=15)
        self.frequency_unit_dropdown['values'] = ["per year", "per day", "per week", "per month"]
        self.frequency_unit_dropdown.grid(row=0, column=2, padx=5, pady=5, sticky=tk.EW)

        # Body Weight parameter
        self.bodyweight_label = ttk.Label(self.custom_params_frame, text="Body weight")
        self.bodyweight_label.grid(row=1, column=0, padx=5, pady=5, sticky=tk.W)
        self.bodyweight_var = tk.StringVar(value="70")
        self.bodyweight_entry = ttk.Entry(self.custom_params_frame, textvariable=self.bodyweight_var)
        self.bodyweight_entry.grid(row=1, column=1, padx=5, pady=5, sticky=tk.EW)
        self.bodyweight_unit_var = tk.StringVar(value="kg")
        self.bodyweight_unit_dropdown = ttk.Combobox(self.custom_params_frame, textvariable=self.bodyweight_unit_var, state='readonly', width=15)
        self.bodyweight_unit_dropdown['values'] = ["kg"]
        self.bodyweight_unit_dropdown.grid(row=1, column=2, padx=5, pady=5, sticky=tk.EW)

    def run_model(self, params=None):
        if params is None:
            params = self.collect_parameters()

        try:
            frequency = float(self.frequency_entry.get())
            body_weight = float(self.bodyweight_entry.get())
        except ValueError:
            print("Error: Invalid frequency or body weight value.")
            return

        try:
            aerosol_diameter_mode = params.get("Aerosol diameter mode")
            if aerosol_diameter_mode == "Log-normal":
                if "Arithmetic coefficient of variation" not in params or params["Arithmetic coefficient of variation"] is None:
                    raise ValueError("Arithmetic coefficient of variation is not set for Log-normal mode.")
            elif aerosol_diameter_mode == "Normal":
                if "Standard deviation" not in params or params["Standard deviation"] is None:
                    raise ValueError("Standard deviation is not set for Normal mode.")
            
            exposure_params = ExposureParametersModel5(
                frequency=(frequency, self.frequency_unit_var.get()),
                body_weight=(body_weight, self.bodyweight_unit_var.get()),
                spray_duration=params["Spray duration"],
                exposure_duration=params["Exposure duration"],
                weight_fraction_substance=params["Weight fraction substance"],
                room_volume=params["Room volume"],
                room_height=params["Room height"],
                ventilation_rate=params["Ventilation rate"],
                inhalation_rate=params["Inhalation rate"],
                spraying_towards_person=params["Spraying towards person"],
                cloud_volume=params.get("Cloud volume"),
                mass_generation_rate=params["Mass generation rate"],
                airborne_fraction=params["Airborne fraction"],
                density_non_volatile=params["Density non volatile"],
                inhalation_cutoff_diameter=params["Inhalation cut off diameter"],
                aerosol_diameter_mode=aerosol_diameter_mode,
                median_diameter=params.get("Median diameter"),
                arithmetic_coefficient_of_variation=params.get("Arithmetic coefficient of variation"),
                mean_diameter=params.get("Mean diameter"),
                standard_deviation=params.get("Standard deviation"),
                maximum_diameter=params["Maximum diameter"]
            )

            self.display_final_results(exposure_params)
            exposure_params.plot_results()
        except KeyError as e:
            print(f"Error: Missing parameter {e}")
            print("Current parameter values:")
            for key, value in params.items():
                print(f"{key}: {value}")
        except Exception as e:
            print(f"An error occurred: {e}")
            import traceback
            traceback.print_exc()

    def collect_parameters(self):
        params = {}
        if self.ui_instance and hasattr(self.ui_instance, 'widgets'):
            for key, widget_info in self.ui_instance.widgets.items():
                if isinstance(widget_info, dict) and 'entry' in widget_info:
                    value = widget_info['entry'].get()
                    unit = widget_info.get('unit')
                    if unit:
                        unit = unit.get()
                    if isinstance(value, str) and value.strip() and value.replace('.', '', 1).isdigit():
                        params[key] = (float(value), unit) if unit else float(value)
                    elif not value.strip():  # If the value is an empty string
                        params[key] = None
                    else:
                        params[key] = (value, unit) if unit else value
                elif isinstance(widget_info, tk.BooleanVar):
                    params[key] = widget_info.get()
                elif isinstance(widget_info, ttk.Combobox):  # For dropdown menus
                    params[key] = widget_info.get()

        # Add Aerosol diameter mode
        if hasattr(self.ui_instance, 'aerosol_diameter_mode_var'):
            params['Aerosol diameter mode'] = self.ui_instance.aerosol_diameter_mode_var.get()

        print("Collected parameters:", params)  # Debug statement

        # Ensure Arithmetic coefficient of variation or Standard deviation is set
        if params.get('Aerosol diameter mode') == 'Log-normal':
            acv_widget = self.ui_instance.widgets.get('Arithmetic coefficient of variation')
            if acv_widget and isinstance(acv_widget, dict) and 'entry' in acv_widget:
                acv_value = acv_widget['entry'].get()
                params['Arithmetic coefficient of variation'] = float(acv_value) if acv_value else None
        elif params.get('Aerosol diameter mode') == 'Normal':
            sd_widget = self.ui_instance.widgets.get('Standard deviation')
            if sd_widget and isinstance(sd_widget, dict) and 'entry' in sd_widget:
                sd_value = sd_widget['entry'].get()
                params['Standard deviation'] = float(sd_value) if sd_value else None

        print("Parameters after setting ACV/SD:", params)  # Debug statement

        return params

    def display_final_results(self, exposure_params):
        # Calculate and display results
        mean_event_concentration = exposure_params.calculate_mean_event_concentration()
        peak_concentration = exposure_params.calculate_peak_concentration()
        mean_concentration_on_day_of_exposure = exposure_params.calculate_mean_concentration_on_day_of_exposure()
        year_average_concentration = exposure_params.calculate_year_average_concentration()
        external_event_dose = exposure_params.calculate_external_event_dose()
        external_dose_on_day_of_exposure = exposure_params.calculate_external_dose_on_day_of_exposure()

        print(f"Mean Event Concentration: {mean_event_concentration:.1e} mg/m³")
        print(f"Peak Concentration (TWA 15 min): {peak_concentration:.1e} mg/m³")
        print(f"Mean Concentration on Day of Exposure: {mean_concentration_on_day_of_exposure:.1e} mg/m³")
        print(f"Year Average Concentration: {year_average_concentration:.1e} mg/m³")
        print(f"External Event Dose: {external_event_dose:.1e} mg/kg bw")
        print(f"External Dose on Day of Exposure: {external_dose_on_day_of_exposure:.1e} mg/kg bw")

if __name__ == "__main__":
    root = tk.Tk()
    app = MainApplication(root)
    root.mainloop()

model_5_inhalation_exposure_to_spray_spraying.py

import tkinter as tk
from tkinter import ttk, messagebox

class ExposureParameters:
    def __init__(self, frequency, body_weight, spray_duration, exposure_duration, weight_fraction_substance, room_volume, room_height, ventilation_rate, inhalation_rate, spraying_towards_person, cloud_volume, mass_generation_rate, airborne_fraction, density_non_volatile, inhalation_cutoff_diameter, aerosol_diameter_mode, median_diameter=None, arithmetic_coefficient_of_variation=None, mean_diameter=None, standard_deviation=None, maximum_diameter=None):
        self.frequency = frequency
        self.body_weight = body_weight
        self.spray_duration = spray_duration
        self.exposure_duration = exposure_duration
        self.weight_fraction_substance = weight_fraction_substance
        self.room_volume = room_volume
        self.room_height = room_height
        self.ventilation_rate = ventilation_rate
        self.inhalation_rate = inhalation_rate
        self.spraying_towards_person = spraying_towards_person
        self.cloud_volume = cloud_volume
        self.mass_generation_rate = mass_generation_rate
        self.airborne_fraction = airborne_fraction
        self.density_non_volatile = density_non_volatile
        self.inhalation_cutoff_diameter = inhalation_cutoff_diameter
        self.aerosol_diameter_mode = aerosol_diameter_mode
        self.median_diameter = median_diameter
        self.arithmetic_coefficient_of_variation = arithmetic_coefficient_of_variation
        self.mean_diameter = mean_diameter
        self.standard_deviation = standard_deviation
        self.maximum_diameter = maximum_diameter

        self.display_parameters()

    def display_parameters(self):
        params = {
            "Frequency": self.frequency,
            "Body weight": self.body_weight,
            "Spray duration": self.spray_duration,
            "Exposure duration": self.exposure_duration,
            "Weight fraction substance": self.weight_fraction_substance,
            "Room volume": self.room_volume,
            "Room height": self.room_height,
            "Ventilation rate": self.ventilation_rate,
            "Inhalation rate": self.inhalation_rate,
            "Spraying towards person": self.spraying_towards_person,
            "Cloud volume": self.cloud_volume,
            "Mass generation rate": self.mass_generation_rate,
            "Airborne fraction": self.airborne_fraction,
            "Density non volatile": self.density_non_volatile,
            "Inhalation cut off diameter": self.inhalation_cutoff_diameter,
            "Aerosol diameter mode": self.aerosol_diameter_mode,
            "Median diameter": self.median_diameter,
            "Arithmetic coefficient of variation": self.arithmetic_coefficient_of_variation,
            "Mean diameter": self.mean_diameter,
            "Standard deviation": self.standard_deviation,
            "Maximum diameter": self.maximum_diameter
        }

        for key, value in params.items():
            print(f"{key}: {value}")

class ExposureUI:
    def __init__(self, root, standalone=True, run_model_callback=None, external_params=None):
        self.root = root
        self.run_model_callback = run_model_callback
        self.standalone = standalone
        self.external_params = external_params if external_params else {}

        if standalone:
            self.root.title("Exposure Parameters - Spraying")

        self.units = {
            "frequency": ["per year"],
            "body_weight": ["kg"],
            "duration": ["minute"],
            "weight_fraction": ["(fraction)"],
            "room_volume": ["m³"],
            "room_height": ["m"],
            "ventilation_rate": ["per hour"],
            "inhalation_rate": ["l/min"],
            "mass_generation_rate": ["g/s"],
            "airborne_fraction": ["(fraction)"],
            "density_non_volatile": ["g/cm³"],
            "inhalation_cutoff_diameter": ["μm"],
            "cloud_volume": ["m³"],
            "aerosol_diameter_mode": ["Log-normal", "Normal"]
        }

        self.widgets = {}

        start_row = 0
        if self.standalone:
            self.create_label_entry_dropdown("Frequency", "1", self.units["frequency"], start_row)
            start_row += 1
            self.create_label_entry_dropdown("Body weight", "65", self.units["body_weight"], start_row)
            start_row += 1

        self.create_label_entry_dropdown("Spray duration", "11.1", self.units["duration"], start_row)
        start_row += 1
        self.create_label_entry_dropdown("Exposure duration", "13", self.units["duration"], start_row)
        start_row += 1
        self.create_label_entry_dropdown("Weight fraction substance", "0.6", self.units["weight_fraction"], start_row)
        start_row += 1
        self.create_label_entry_dropdown("Room volume", "10", self.units["room_volume"], start_row)
        start_row += 1
        self.create_label_entry_dropdown("Room height", "2.5", self.units["room_height"], start_row)
        start_row += 1
        self.create_label_entry_dropdown("Ventilation rate", "2", self.units["ventilation_rate"], start_row)
        start_row += 1
        self.create_label_entry_dropdown("Inhalation rate", "24.1", self.units["inhalation_rate"], start_row)
        start_row += 1

        self.create_boolean_checkbox("Spraying towards person", False, start_row)
        start_row += 1

        self.optional_frame_cloud_volume = tk.Frame(self.root)
        self.create_label_entry_dropdown("Cloud volume", "10", self.units["cloud_volume"], 0, self.optional_frame_cloud_volume)
        self.optional_frame_cloud_volume.grid(row=start_row, columnspan=3, pady=5)
        start_row += 1

        self.create_label_entry_dropdown("Mass generation rate", "0.8", self.units["mass_generation_rate"], start_row)
        start_row += 1
        self.create_label_entry_dropdown("Airborne fraction", "0.008", self.units["airborne_fraction"], start_row)
        start_row += 1
        self.create_label_entry_dropdown("Density non volatile", "1.8", self.units["density_non_volatile"], start_row)
        start_row += 1
        self.create_label_entry_dropdown("Inhalation cut off diameter", "15", self.units["inhalation_cutoff_diameter"], start_row)
        start_row += 1

        self.aerosol_diameter_mode_var = tk.StringVar(value="Log-normal")
        self.create_radio_buttons("Aerosol diameter mode", self.units["aerosol_diameter_mode"], self.aerosol_diameter_mode_var, start_row)
        start_row += 1

        self.aerosol_diameter_frame = tk.Frame(self.root)
        self.create_label_entry_dropdown("Median diameter", "7.7", ["μm"], 0, self.aerosol_diameter_frame)
        self.create_label_entry_entry("Arithmetic coefficient of variation", "1.9", 1, self.aerosol_diameter_frame)
        self.create_label_entry_dropdown("Maximum diameter", "50", ["μm"], 2, self.aerosol_diameter_frame)
        self.aerosol_diameter_frame.grid(row=start_row, columnspan=3, pady=5)

        self.toggle_optional_parameters()
        self.toggle_aerosol_diameter_mode()

        if standalone:
            self.run_model_button = ttk.Button(self.root, text="Run Model", command=self.run_model)
            self.run_model_button.grid(row=start_row + 1, columnspan=3, pady=10)

    def create_label_entry_dropdown(self, text, default_value, unit_options, row, parent=None):
        if parent is None:
            parent = self.root
        label = ttk.Label(parent, text=text)
        label.grid(row=row, column=0, padx=5, pady=5, sticky=tk.W)
        entry = ttk.Entry(parent)
        entry.insert(0, default_value)
        entry.grid(row=row, column=1, padx=5, pady=5)
        unit_dropdown = ttk.Combobox(parent, values=unit_options, state='readonly')
        unit_dropdown.set(unit_options[0])
        unit_dropdown.grid(row=row, column=2, padx=5, pady=5)

        self.widgets[text] = {'entry': entry, 'unit': unit_dropdown}

    def create_label_entry_entry(self, text, default_value, row, parent=None):
        if parent is None:
            parent = self.root
        label = ttk.Label(parent, text=text)
        label.grid(row=row, column=0, padx=5, pady=5, sticky=tk.W)
        entry = ttk.Entry(parent)
        entry.insert(0, default_value)
        entry.grid(row=row, column=1, padx=5, pady=5)

        self.widgets[text] = entry

    def create_boolean_checkbox(self, text, default_value, row, parent=None):
        if parent is None:
            parent = self.root
        var = tk.BooleanVar(value=default_value)
        checkbox = ttk.Checkbutton(parent, text=text, variable=var, command=self.toggle_optional_parameters)
        checkbox.grid(row=row, columnspan=3, sticky=tk.W, pady=5)
        self.widgets[text] = var

    def create_radio_buttons(self, text, options, variable, row, parent=None):
        if parent is None:
            parent = self.root
        label = ttk.Label(parent, text=text)
        label.grid(row=row, column=0, padx=5, pady=5, sticky=tk.W)
        frame = tk.Frame(parent)
        for option in options:
            button = ttk.Radiobutton(frame, text=option, variable=variable, value=option, command=self.toggle_aerosol_diameter_mode)
            button.pack(side=tk.LEFT)
        frame.grid(row=row, column=1, columnspan=2, pady=5)

    def toggle_optional_parameters(self):
        spraying_towards_person = self.widgets["Spraying towards person"].get()
        if spraying_towards_person:
            self.optional_frame_cloud_volume.grid()
        else:
            self.optional_frame_cloud_volume.grid_remove()

    def toggle_aerosol_diameter_mode(self):
        mode = self.aerosol_diameter_mode_var.get()
        for widget in self.aerosol_diameter_frame.winfo_children():
            widget.destroy()
        if mode == "Log-normal":
            self.create_label_entry_dropdown("Median diameter", "7.7", ["μm"], 0, self.aerosol_diameter_frame)
            self.create_label_entry_entry("Arithmetic coefficient of variation", "1.9", 1, self.aerosol_diameter_frame)
        else:
            self.create_label_entry_dropdown("Mean diameter", "7.7", ["μm"], 0, self.aerosol_diameter_frame)
            self.create_label_entry_entry("Standard deviation", "0.5", 1, self.aerosol_diameter_frame)
        self.create_label_entry_dropdown("Maximum diameter", "50", ["μm"], 2, self.aerosol_diameter_frame)
        self.aerosol_diameter_frame.grid()

    def run_model(self):
        parameters = self.get_parameters()

        try:
            exposure_params = ExposureParameters(
                frequency=parameters["Frequency"],
                body_weight=parameters["Body weight"],
                spray_duration=parameters["Spray duration"],
                exposure_duration=parameters["Exposure duration"],
                weight_fraction_substance=parameters["Weight fraction substance"],
                room_volume=parameters["Room volume"],
                room_height=parameters["Room height"],
                ventilation_rate=parameters["Ventilation rate"],
                inhalation_rate=parameters["Inhalation rate"],
                spraying_towards_person=parameters["Spraying towards person"],
                cloud_volume=parameters.get("Cloud volume"),
                mass_generation_rate=parameters["Mass generation rate"],
                airborne_fraction=parameters["Airborne fraction"],
                density_non_volatile=parameters["Density non volatile"],
                inhalation_cutoff_diameter=parameters["Inhalation cut off diameter"],
                aerosol_diameter_mode=parameters["Aerosol diameter mode"],
                median_diameter=parameters.get("Median diameter"),
                arithmetic_coefficient_of_variation=parameters.get("Arithmetic coefficient of variation"),
                mean_diameter=parameters.get("Mean diameter"),
                standard_deviation=parameters.get("Standard deviation"),
                maximum_diameter=parameters["Maximum diameter"]
            )

        except ValueError as e:
            messagebox.showerror("Input Error", str(e))

    def get_parameters(self):
        params = {}
        for key, widget_info in self.widgets.items():
            if isinstance(widget_info, dict):
                value = widget_info['entry'].get()
                unit = widget_info['unit'].get()
                if isinstance(value, str) and value.replace('.', '', 1).isdigit():
                    params[key] = (float(value), unit)
                else:
                    params[key] = (value, unit)
            elif isinstance(widget_info, tk.BooleanVar):
                params[key] = widget_info.get()
            elif isinstance(widget_info, ttk.Entry):
                params[key] = float(widget_info.get())

        params["Aerosol diameter mode"] = self.aerosol_diameter_mode_var.get()
        if params["Aerosol diameter mode"] == "Log-normal":
            acv_widget = self.widgets.get("Arithmetic coefficient of variation")
            if acv_widget:
                acv_value = acv_widget.get()
                params["Arithmetic coefficient of variation"] = float(acv_value) if acv_value else None
        else:
            sd_widget = self.widgets.get("Standard deviation")
            if sd_widget:
                sd_value = sd_widget.get()
                params["Standard deviation"] = float(sd_value) if sd_value else None

        return params

def create_parameter_frame(parent, standalone=False, run_model_callback=None, external_params=None):
    return ExposureUI(parent, standalone, run_model_callback, external_params)

if __name__ == "__main__":
    root = tk.Tk()
    app = ExposureUI(root, standalone=True)
    root.mainloop()

this stripped back version is simply a UI and instead of functionality just prints the values passed to it.

However when I do I am getting the following error:

An error occurred: Arithmetic coefficient of variation is not set for Log-normal mode.
Traceback (most recent call last):
File “/Users/coding/Documents/Python/Work/NEW/testmini3.py”, line 86, in run_model
raise ValueError(“Arithmetic coefficient of variation is not set for Log-normal mode.”)
ValueError: Arithmetic coefficient of variation is not set for Log-normal mode.

My original question showed other models that worked just fine but im unable to show them here.

However effectively I just want to be able to pass the values from mainscript (which displays model5 in a frame) and have it run (print).

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật