#!/usr/bin/env python # -*- coding: utf-8 -*- """ Web API bridge script for handling inputs from the web interface and generating user personas following the logic in generate_profile.py. """ import json import argparse import sys import os from typing import Dict, Any, List, Optional # Import required modules from based_data import ( generate_age_info, generate_gender, generate_career_info, generate_location, generate_personal_values, generate_life_attitude, generate_personal_story, generate_interests_and_hobbies ) from generate_profile import generate_final_summary from select_attributes import get_selected_attributes, save_results def parse_input_data(input_file: str) -> Dict[str, Any]: """ Parse data from the input file Args: input_file: Path to the input JSON file Returns: Dict: Parsed input data """ try: with open(input_file, 'r', encoding='utf-8') as f: data = json.load(f) return data except Exception as e: print(f"Error parsing input file: {e}") return {} def generate_profile_from_input(input_data: Dict[str, Any], attribute_count: int = 200) -> Dict[str, Any]: """ Generate a complete user persona from input data Args: input_data: Input data containing basic information and optional custom values attribute_count: Number of attributes to generate (default: 200) Returns: Dict: Generated complete user persona """ try: # Extract basic information from input data basic_info = input_data.get('basic_info', {}) # Extract custom values if provided custom_values = input_data.get('custom_values', {}) # Use provided basic information or generate new basic information age = basic_info.get('age') if not age: print("✗ Age not provided, generating...") age_info = generate_age_info() age = age_info['age'] else: print(f"✓ Using provided age: {age}") gender = basic_info.get('gender') if not gender: print("✗ Gender not provided, generating...") gender = generate_gender() else: print(f"✓ Using provided gender: {gender}") occupation_info = basic_info.get('occupation', {}) occupation = occupation_info.get('status') if not occupation: print("✗ Occupation not provided, generating...") career_info = generate_career_info(age) occupation = career_info['status'] else: print(f"✓ Using provided occupation: {occupation}") location_info = basic_info.get('location', {}) if not location_info.get('city') or not location_info.get('country'): print("✗ Location not provided, generating...") location_info = generate_location() else: print(f"✓ Using provided location: {location_info.get('city')}, {location_info.get('country')}") # Use custom personal values if provided, otherwise generate them custom_personal_values = custom_values.get('personal_values') if custom_personal_values and custom_personal_values.strip(): print(f"✓ Using provided personal values: {custom_personal_values[:50]}...") values_orientation = custom_personal_values.strip() else: print("✗ Personal values not provided, generating based on inputs...") values_dict = generate_personal_values(age, gender, occupation, location_info) values_orientation = values_dict.get("values_orientation", "") if isinstance(values_dict, dict) else str(values_dict) # Use custom life attitude if provided, otherwise generate it custom_life_attitude = custom_values.get('life_attitude') if custom_life_attitude and custom_life_attitude.strip(): print(f"✓ Using provided life attitude: {custom_life_attitude[:50]}...") life_attitude = { "outlook": custom_life_attitude.strip(), "coping_mechanism": "Custom life attitude provided by user" } else: print("✗ Life attitude not provided, generating based on inputs...") life_attitude = generate_life_attitude(age, gender, occupation, location_info, values_orientation) # Use custom life story if provided, otherwise generate it custom_life_story = custom_values.get('life_story') if custom_life_story and custom_life_story.strip(): print(f"✓ Using provided life story: {custom_life_story[:50]}...") personal_story = {"personal_story": custom_life_story.strip()} else: print("✗ Life story not provided, generating based on inputs...") personal_story = generate_personal_story(age, gender, occupation, location_info, values_orientation, life_attitude) # Use custom interests/hobbies if provided, otherwise generate them custom_interests = custom_values.get('interests_hobbies') if custom_interests and custom_interests.strip(): print(f"✓ Using provided interests: {custom_interests}") # Split by comma and clean up interests_list = [i.strip() for i in custom_interests.split(',') if i.strip()] interests_and_hobbies = {"interests": interests_list} else: print("✗ Interests not provided, generating based on life story...") interests_and_hobbies = generate_interests_and_hobbies(personal_story) # Build complete user persona (matching reference version structure) profile = { "basic_info": { "age": age, "gender": gender, "occupation": {"status": occupation}, "location": location_info }, "values_orientation": values_orientation, "life_attitude": life_attitude, "personal_story": personal_story, "interests_and_hobbies": interests_and_hobbies } # Select attributes print(f"Selecting {attribute_count} attributes...") # Pass the profile directly to get_selected_attributes selected_paths = get_selected_attributes(profile, attribute_count) profile["selected_attributes"] = selected_paths # Save the selected attributes to output files print("Saving selected attributes...") save_results(profile, selected_paths) # Generate final summary print("Generating final summary...") summary = generate_final_summary(profile) profile["Summary"] = summary return profile except Exception as e: print(f"Error generating user persona: {e}") import traceback traceback.print_exc() return {} def main(): """Main function to process command line arguments and execute generation workflow""" parser = argparse.ArgumentParser(description="Generate user persona from input data") parser.add_argument('--input', type=str, required=True, help="Path to input JSON file") parser.add_argument('--attributes', type=int, default=200, help="Number of attributes to generate (default: 200)") args = parser.parse_args() # Parse input data input_data = parse_input_data(args.input) if not input_data: print("Unable to parse input data, exiting") sys.exit(1) # Generate user persona profile = generate_profile_from_input(input_data, attribute_count=args.attributes) if not profile: print("Failed to generate user persona, exiting") sys.exit(1) # Output results if "Summary" in profile: print("\n" + "="*50) print("Generated User Persona Summary:") print("="*50) print(profile["Summary"]) print("="*50) # Output the profile as JSON to stdout for the Next.js API to capture # Clean the summary for JSON output if "Summary" in profile: cleaned_summary = profile["Summary"].replace("`", "") cleaned_summary = cleaned_summary.replace('"', "'") profile["Summary"] = cleaned_summary # Format for API output - clean newlines for JSON compatibility if "Summary" in profile: profile["Summary"] = profile["Summary"].replace('\n', " ") print(f'\n{{"summary": "{profile["Summary"]}"}}\n') else: print("Failed to generate summary") sys.exit(1) # Output the full profile as JSON print(json.dumps(profile, ensure_ascii=False)) if __name__ == "__main__": main()