Moved data from public to backend, fixed Start_date and college_enrollment_status fields, fixed ai-risk saving
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
parent
a8c5ed828b
commit
b33b4ef6d1
@ -1 +1 @@
|
||||
e0de79c21e9b87f23a4da67149cea4e0e979e9e0-803b2c2ecad09a0fbca070296808a53489de891a-e9eccd451b778829eb2f2c9752c670b707e1268b
|
||||
277110e50c0c8ee5c02fee3c1174a225d5593511-803b2c2ecad09a0fbca070296808a53489de891a-e9eccd451b778829eb2f2c9752c670b707e1268b
|
||||
|
||||
@ -16,7 +16,7 @@ RUN npm ci --unsafe-perm --omit=dev
|
||||
COPY --chown=app:app backend/ ./backend/
|
||||
COPY --chown=app:app src/ai/ ./src/ai/
|
||||
COPY --chown=app:app src/assets/ ./src/assets/
|
||||
COPY --chown=app:app public/ ./public/
|
||||
COPY --chown=app:app backend/data/ ./backend/data/
|
||||
|
||||
RUN mkdir -p /run/secrets && chown -R app:app /run/secrets
|
||||
USER app
|
||||
|
||||
@ -16,7 +16,7 @@ RUN npm ci --unsafe-perm --omit=dev
|
||||
COPY --chown=app:app backend/ ./backend/
|
||||
COPY --chown=app:app src/ai/ ./src/ai/
|
||||
COPY --chown=app:app src/assets/ ./src/assets/
|
||||
COPY --chown=app:app public/ ./public/
|
||||
COPY --chown=app:app backend/data/ ./backend/data/
|
||||
|
||||
RUN mkdir -p /run/secrets && chown -R app:app /run/secrets
|
||||
USER app
|
||||
|
||||
@ -16,7 +16,7 @@ RUN npm ci --unsafe-perm --omit=dev
|
||||
COPY --chown=app:app backend/ ./backend/
|
||||
COPY --chown=app:app src/ai/ ./src/ai/
|
||||
COPY --chown=app:app src/assets/ ./src/assets/
|
||||
COPY --chown=app:app public/ ./public/
|
||||
COPY --chown=app:app backend/data/ ./backend/data/
|
||||
|
||||
RUN mkdir -p /run/secrets && chown -R app:app /run/secrets
|
||||
USER app
|
||||
|
||||
77
ai_risk.csv
77
ai_risk.csv
@ -1,77 +0,0 @@
|
||||
soc_code,career_name,job_description,tasks,risk_level,reasoning,created_at
|
||||
25-2022,"Middle School Teachers","Teach one or more subjects to students at the middle, intermediate, or junior high school level.","[object Object]",Moderate,"While AI automation may streamline certain tasks for middle school teachers, the complex nature of teaching and the need for human interaction and empathy make it unlikely to fully replace the role in the next 10 years. However, there may be some impact on administrative tasks and grading.","2025-05-29 13:08:05"
|
||||
25-2012,"Kindergarten Teachers","Teach academic and social skills to kindergarten students.","[object Object]",Low,"AI automation in education is still in its early stages and may not fully replace the role of a kindergarten teacher in the next 10 years. The human touch and personalized instruction are crucial for young learners.","2025-05-29 13:13:59"
|
||||
25-1081,"Education Teachers, Postsecondary","Teach courses pertaining to education, such as counseling, curriculum, guidance, instruction, teacher education, and teaching English as a second language. Includes both teachers primarily engaged in teaching and those who do a combination of teaching and research.","[object Object]",Moderate,"While AI automation may streamline certain tasks like preparing course materials and grading exams, the complex nature of teaching and research in education may require human expertise and judgment. There is a moderate risk of job displacement or changes in the next 10 years.","2025-05-29 13:18:04"
|
||||
29-1129,"Music Therapists","Plan, organize, direct, or assess clinical and evidenced-based music therapy interventions to positively influence individuals' physical, psychological, cognitive, or behavioral status.","[object Object]",Low,"The field of music therapy is highly specialized and relies heavily on human interaction and emotional connection, making it less susceptible to full automation in the next 10 years.","2025-05-29 13:18:15"
|
||||
25-2031,"Secondary School Teachers","Teach one or more subjects to students at the secondary school level.","[object Object]",Moderate,"While AI automation may streamline administrative tasks for secondary school teachers, the complex and nuanced nature of teaching subjects to students requires human interaction and adaptability, which may limit the extent of automation in this field over the next 10 years.","2025-05-29 13:18:23"
|
||||
25-1031,"Architecture Teachers, Postsecondary","Teach courses in architecture and architectural design, such as architectural environmental design, interior architecture/design, and landscape architecture. Includes both teachers primarily engaged in teaching and those who do a combination of teaching and research.","[object Object]",Moderate,"While AI automation may streamline certain aspects of architectural education, the complex and creative nature of the field may limit the extent to which AI can fully replace human teachers in the next 10 years.","2025-05-29 13:18:38"
|
||||
25-1124,"Foreign Language & Literature Teachers, Postsecondary","Teach languages and literature courses in languages other than English. Includes teachers of American Sign Language (ASL). Includes both teachers primarily engaged in teaching and those who do a combination of teaching and research.","[object Object]",Moderate,"While AI automation may streamline administrative tasks like record-keeping and grading, the nuanced and creative aspects of teaching languages and literature may still require human intervention. There may be concerns about job displacement or the impact on the quality of education.","2025-05-29 13:18:45"
|
||||
25-3021,"Self-Enrichment Teachers","Teach or instruct individuals or groups for the primary purpose of self-enrichment or recreation, rather than for an occupational objective, educational attainment, competition, or fitness.","[object Object]",Moderate,"As AI automation continues to advance, there is a moderate risk that self-enrichment teaching roles may be partially automated, leading to potential job displacement or changes in job responsibilities for individuals in this career field.","2025-05-29 13:18:54"
|
||||
15-1252,"Software Developers","","[object Object]",High,"As AI automation continues to advance rapidly, there is a high risk of job displacement for software developers in the next 10 years. It is crucial for professionals in this field to continuously upskill and adapt to stay relevant.","2025-05-29 13:41:14"
|
||||
29-1122,"Occupational Therapists","Assess, plan, and organize rehabilitative programs that help build or restore vocational, homemaking, and daily living skills, as well as general independence, to persons with disabilities or developmental delays. Use therapeutic techniques, adapt the individual's environment, teach skills, and modify specific tasks that present barriers to the individual.","[object Object]",Moderate,"While AI automation has the potential to streamline processes and improve efficiency in occupational therapy, there may be concerns about job displacement and the need for ongoing training and adaptation to new technologies.","2025-06-01 10:33:16"
|
||||
39-9011,Nannies,"Care for children in private households and provide support and expertise to parents in satisfying children's physical, emotional, intellectual, and social needs. Duties may include meal planning and preparation, laundry and clothing care, organization of play activities and outings, discipline, intellectual stimulation, language activities, and transportation.","[object Object]",Moderate,"As AI automation continues to advance in the childcare industry, there may be concerns about the potential impact on job security for nannies. However, the personalized and hands-on nature of childcare may still require human involvement for the foreseeable future.","2025-06-01 10:58:54"
|
||||
15-1299,"Blockchain Engineers","Maintain and support distributed and decentralized blockchain-based networks or block-chain applications such as cryptocurrency exchange, payment processing, document sharing, and digital voting. Design and deploy secure block-chain design patterns and solutions over geographically distributed networks using advanced technologies. May assist with infrastructure setup and testing for application transparency and security.","[object Object]",High,"As AI automation continues to advance rapidly in the next 10 years, there is a high risk of potential security vulnerabilities and threats emerging in blockchain networks due to the complexity and interconnected nature of AI systems.","2025-06-01 11:52:54"
|
||||
25-2022.00,"Middle School Teachers","Teach one or more subjects to students at the middle, intermediate, or junior high school level.","[object Object]",Low,"The role of Middle School Teachers involves complex interactions with students that require human empathy and understanding. AI automation may assist with administrative tasks but is unlikely to fully replace the need for human teachers in the next 10 years.","2025-06-08 13:16:57"
|
||||
29-1129.02,"Music Therapists","Plan, organize, direct, or assess clinical and evidenced-based music therapy interventions to positively influence individuals' physical, psychological, cognitive, or behavioral status.","[object Object]",Moderate,"While AI automation may streamline certain tasks in music therapy, the human element and creativity involved in providing personalized therapy experiences may limit the extent of automation in this field over the next 10 years.","2025-06-08 13:19:02"
|
||||
15-1252.00,"Software Developers","","[object Object]",Moderate,"As AI automation continues to advance rapidly, there is a moderate risk of job displacement for software developers in the next 10 years. However, the demand for skilled developers to create and maintain AI systems will likely remain high.","2025-06-08 13:46:48"
|
||||
15-1299.07,"Blockchain Engineers","","[object Object]",Moderate,"As AI automation continues to advance rapidly, there is a moderate risk of job displacement for Blockchain Engineers in the next 10 years. However, the demand for skilled professionals in this field is also expected to grow, mitigating some of the risk.","2025-06-09 11:59:53"
|
||||
17-1011.00,Architects,"Plan and design structures, such as private residences, office buildings, theaters, factories, and other structural property.","[object Object]",Moderate,"While AI automation may streamline certain tasks for architects, the complexity and creativity required in architectural design may limit the extent of automation in the industry over the next 10 years.","2025-06-09 16:02:55"
|
||||
17-2071.00,"Electrical Engineers","Research, design, develop, test, or supervise the manufacturing and installation of electrical equipment, components, or systems for commercial, industrial, military, or scientific use.","[object Object]",Moderate,"As AI automation continues to advance rapidly in the field of electrical engineering, there is a moderate risk of job displacement for certain roles that can be automated. However, the demand for skilled electrical engineers to design and oversee complex projects will remain high.","2025-06-09 16:05:11"
|
||||
17-2072.00,"Electronics Engineers","Research, design, develop, or test electronic components and systems for commercial, industrial, military, or scientific use employing knowledge of electronic theory and materials properties. Design electronic circuits and components for use in fields such as telecommunications, aerospace guidance and propulsion control, acoustics, or instruments and controls.","[object Object]",Moderate,"As AI automation continues to advance rapidly, there is a moderate risk of job displacement for Electronics Engineers in the next 10 years. However, the demand for skilled professionals in this field is expected to remain strong due to the complexity of the work involved.","2025-06-09 16:11:39"
|
||||
17-3026.01,"Nanotechnology Engineering Technologists & Technicians","Implement production processes and operate commercial-scale production equipment to produce, test, or modify materials, devices, or systems of unique molecular or macromolecular composition. Operate advanced microscopy equipment to manipulate nanoscale objects. Work under the supervision of nanoengineering staff.","[object Object]",Moderate,"As AI automation continues to advance in nanotechnology engineering, there may be potential risks related to job displacement and the need for upskilling or reskilling of workers in this field.","2025-06-09 16:57:51"
|
||||
27-2011.00,Actors,"Play parts in stage, television, radio, video, or film productions, or other settings for entertainment, information, or instruction. Interpret serious or comic role by speech, gesture, and body movement to entertain or inform audience. May dance and sing.","[object Object]",Moderate,"While AI automation may impact certain aspects of the acting industry, such as voiceover work or digital avatars, the creative and emotional depth required for acting roles may still require human actors for the foreseeable future.","2025-06-11 11:53:40"
|
||||
19-3094.00,"Political Scientists","Study the origin, development, and operation of political systems. May study topics, such as public opinion, political decisionmaking, and ideology. May analyze the structure and operation of governments, as well as various political entities. May conduct public opinion surveys, analyze election results, or analyze public documents.","[object Object]",Moderate,"While AI automation may streamline certain tasks for Political Scientists, there is a risk of job displacement as AI technology advances. Political science requires critical thinking and analysis, which may be challenging for AI to fully replicate.","2025-06-11 12:02:07"
|
||||
25-9031.00,"Instructional Coordinators","Develop instructional material, coordinate educational content, and incorporate current technology into instruction in order to provide guidelines to educators and instructors for developing curricula and conducting courses. May train and coach teachers. Includes educational consultants and specialists, and instructional material directors.","[object Object]",Moderate,"While AI automation can enhance instructional coordination tasks, there is a moderate risk of job displacement as AI technology advances. It is important for instructional coordinators to stay updated with technology and adapt to changes in the education sector.","2025-06-13 14:06:04"
|
||||
11-9071.00,"Gambling Managers","Plan, direct, or coordinate gambling operations in a casino. May formulate house rules.","[object Object]",Moderate,"While AI automation can streamline operations and improve efficiency, there is a moderate risk of job displacement for Gambling Managers due to the potential for automation of tasks such as resolving customer complaints and tracking supplies.","2025-06-13 14:06:21"
|
||||
15-1243.00,"Database Architects","","",Moderate,"As AI automation continues to advance, there may be job displacement for Database Architects. However, the demand for skilled professionals in this field is expected to remain strong, mitigating some of the risk.","2025-06-16 13:24:24"
|
||||
11-1011.03,"Chief Sustainability Officers","Communicate and coordinate with management, shareholders, customers, and employees to address sustainability issues. Enact or oversee a corporate sustainability strategy.","[object Object]",Moderate,"As AI automation continues to advance, there may be concerns about job displacement and the need for retraining in the sustainability field. However, the demand for sustainability officers is likely to remain strong due to increasing focus on environmental and social responsibility.","2025-06-17 13:00:30"
|
||||
15-2021.00,Mathematicians,"Conduct research in fundamental mathematics or in application of mathematical techniques to science, management, and other fields. Solve problems in various fields using mathematical methods.","[object Object]",Moderate,"While AI can assist in data analysis and problem-solving, the unique creativity and abstract thinking of mathematicians remain difficult to replicate, leading to a moderate risk of job displacement.","2025-06-27 13:51:33"
|
||||
17-1012.00,"Landscape Architects","Plan and design land areas for projects such as parks and other recreational facilities, airports, highways, hospitals, schools, land subdivisions, and commercial, industrial, and residential sites.","[object Object]",Moderate,"While AI can assist in design and planning, the creative and contextual understanding required for landscape architecture still relies heavily on human expertise and client interaction.","2025-06-27 13:52:24"
|
||||
15-1221.00,"Computer & Information Research Scientists","Conduct research into fundamental computer and information science as theorists, designers, or inventors. Develop solutions to problems in the field of computer hardware and software.","[object Object]",Moderate,"As AI technology advances, the role of Computer & Information Research Scientists may evolve, leading to potential job displacement. However, the need for innovative solutions and human oversight in complex problem-solving will maintain demand for skilled professionals.","2025-06-27 13:52:36"
|
||||
51-9194.00,"Etchers & Engravers","Engrave or etch metal, wood, rubber, or other materials. Includes such workers as etcher-circuit processors, pantograph engravers, and silk screen etchers.","[object Object]",Moderate,"While AI can assist in design and quality inspection, the intricate manual skills required for etching and engraving may limit full automation. However, advancements in robotics could impact job availability.","2025-06-27 13:55:34"
|
||||
15-2051.00,"Data Scientists","Develop and implement a set of techniques or analytics applications to transform raw data into meaningful information using data-oriented programming languages and visualization software. Apply data mining, data modeling, natural language processing, and machine learning to extract and analyze information from large structured and unstructured datasets. Visualize, interpret, and report data findings. May create dynamic data reports.","[object Object]",Moderate,"As AI technologies advance, data scientists may face challenges related to job displacement due to automation of routine tasks. However, the need for human expertise in interpreting complex data and ethical considerations will mitigate this risk.","2025-07-02 12:26:29"
|
||||
53-2012.00,"Commercial Pilots","Pilot and navigate the flight of fixed-wing aircraft on nonscheduled air carrier routes, or helicopters. Requires Commercial Pilot certificate. Includes charter pilots with similar certification, and air ambulance and air tour pilots. Excludes regional, national, and international airline pilots.","[object Object]",Moderate,"While AI can assist in navigation and monitoring systems, the need for human judgment in dynamic environments and emergency situations keeps the risk of full automation moderate.","2025-07-03 13:59:14"
|
||||
15-1211.00,"Computer Systems Analysts","Analyze science, engineering, business, and other data processing problems to develop and implement solutions to complex applications problems, system administration issues, or network concerns. Perform systems management and integration functions, improve existing computer systems, and review computer system capabilities, workflow, and schedule limitations. May analyze or recommend commercially available software.","[object Object]",Moderate,"As AI technologies advance, the role of Computer Systems Analysts may evolve, requiring adaptation to new tools and methodologies. Automation could streamline tasks, but also lead to job displacement in some areas.","2025-07-07 12:04:17"
|
||||
27-1027.00,"Set & Exhibit Designers","Design special exhibits and sets for film, video, television, and theater productions. May study scripts, confer with directors, and conduct research to determine appropriate architectural styles.","[object Object]",Moderate,"While AI can assist in design and rendering, the creative and interpretive aspects of set design require human intuition and collaboration, limiting full automation potential.","2025-07-07 12:11:05"
|
||||
41-9012.00,Models,"Model garments or other apparel and accessories for prospective buyers at fashion shows, private showings, or retail establishments. May pose for photos to be used in magazines or advertisements. May pose as subject for paintings, sculptures, and other types of artistic expression.","[object Object]",Moderate,"While AI can assist in modeling through virtual avatars and augmented reality, the human element of physical presence and emotional expression remains essential in fashion. However, advancements in AI could reduce demand for traditional modeling roles over time.","2025-07-07 12:11:21"
|
||||
39-9032.00,"Recreation Workers","Conduct recreation activities with groups in public, private, or volunteer agencies or recreation facilities. Organize and promote activities, such as arts and crafts, sports, games, music, dramatics, social recreation, camping, and hobbies, taking into account the needs and interests of individual members.","[object Object]",Low,"AI can assist in organizing and promoting activities, but the personal interaction and human judgment required in recreation work remain essential, limiting automation risks.","2025-07-07 12:11:29"
|
||||
43-9021.00,"Data Entry Keyers","Operate data entry device, such as keyboard or photo composing perforator. Duties may include verifying data and preparing materials for printing.","[object Object]",Moderate,"While AI can automate data entry tasks, the need for human oversight in verifying accuracy and handling complex data will maintain a demand for skilled workers. However, efficiency improvements may reduce job opportunities over time.","2025-07-07 12:12:25"
|
||||
27-2042.00,"Musicians & Singers","Play one or more musical instruments or sing. May perform on stage, for broadcasting, or for sound or video recording.","[object Object]",Moderate,"While AI can assist in music composition and production, the unique emotional expression and live performance aspects of musicians and singers are difficult to replicate, maintaining a demand for human talent.","2025-07-07 12:18:16"
|
||||
47-2043.00,"Floor Sanders & Finishers","Scrape and sand wooden floors to smooth surfaces using floor scraper and floor sanding machine, and apply coats of finish.","[object Object]",Moderate,"While automation may enhance efficiency in floor sanding and finishing, the need for skilled craftsmanship and attention to detail in unique spaces will likely preserve job opportunities, albeit with potential shifts in required skills.","2025-07-07 12:23:38"
|
||||
39-5094.00,"Skincare Specialists","Provide skincare treatments to face and body to enhance an individual's appearance. Includes electrologists and laser hair removal specialists.","[object Object]",Moderate,"While AI can assist in skin analysis and treatment recommendations, the personal touch and expertise of skincare specialists remain essential. Automation may reduce demand for routine tasks but won't fully replace the human element in client interactions and customized care.","2025-07-07 12:23:47"
|
||||
27-1014.00,"Special Effects Artists & Animators","Create special effects or animations using film, video, computers, or other electronic tools and media for use in products, such as computer games, movies, music videos, and commercials.","[object Object]",Moderate,"While AI can assist in automating certain tasks like basic design and animation, the creative and nuanced aspects of special effects and animation still require human judgment and creativity, which limits full automation.","2025-07-07 12:23:54"
|
||||
21-2011.00,Clergy,"Conduct religious worship and perform other spiritual functions associated with beliefs and practices of religious faith or denomination. Provide spiritual and moral guidance and assistance to members.","[object Object]",Low,"AI may assist in administrative tasks but cannot replicate the personal, emotional, and spiritual connection essential to clergy roles. Human interaction remains vital in spiritual guidance.","2025-07-07 12:24:01"
|
||||
37-3011.00,"Landscaping & Groundskeeping Workers","Landscape or maintain grounds of property using hand or power tools or equipment. Workers typically perform a variety of tasks, which may include any combination of the following: sod laying, mowing, trimming, planting, watering, fertilizing, digging, raking, sprinkler installation, and installation of mortarless segmental concrete masonry wall units.","[object Object]",Moderate,"While automation can assist with tasks like mowing and planting, many landscaping jobs require human judgment and creativity. However, advancements in robotics and AI may reduce the need for manual labor in the coming years.","2025-07-07 12:24:13"
|
||||
27-2041.00,"Music Directors & Composers","Conduct, direct, plan, and lead instrumental or vocal performances by musical artists or groups, such as orchestras, bands, choirs, and glee clubs; or create original works of music.","[object Object]",Moderate,"While AI can assist in composition and performance analysis, the nuanced creativity and emotional depth required in music direction and composition are challenging to replicate, maintaining a demand for human expertise.","2025-07-07 12:32:20"
|
||||
27-1022.00,"Fashion Designers","Design clothing and accessories. Create original designs or adapt fashion trends.","[object Object]",Moderate,"While AI can assist in design and trend analysis, the creative and subjective nature of fashion design limits full automation. Designers will still be needed for unique concepts and personal expression.","2025-07-07 12:43:57"
|
||||
27-2021.00,"Athletes & Sports Competitors","Compete in athletic events.","[object Object]",Moderate,"While AI can enhance performance analysis and training, the human element of competition and personal coaching remains essential. However, advancements in AI could disrupt traditional roles and training methods over the next decade.","2025-07-07 13:11:35"
|
||||
51-7021.00,"Furniture Finishers","Shape, finish, and refinish damaged, worn, or used furniture or new high-grade furniture to specified color or finish.","[object Object]",Moderate,"While AI can assist in design and finishing processes, the craftsmanship and attention to detail required in furniture finishing are difficult to automate fully. However, advancements in AI tools may reduce the demand for manual labor over time.","2025-07-07 13:18:04"
|
||||
35-2013.00,"Cooks, Private Household","Prepare meals in private homes. Includes personal chefs.","[object Object]",Moderate,"While AI can assist in meal planning and recipe suggestions, the personal touch and customization required in private households limit full automation. However, advancements in kitchen robotics could impact job availability.","2025-07-07 13:34:05"
|
||||
29-1129.01,"Art Therapists","Plan or conduct art therapy sessions or programs to improve clients' physical, cognitive, or emotional well-being.","[object Object]",Low,"Art therapy relies heavily on human empathy, creativity, and personal interaction, which are difficult for AI to replicate. While AI can assist with administrative tasks, the core therapeutic relationship remains human-centric.","2025-07-07 13:58:12"
|
||||
27-1011.00,"Art Directors","Formulate design concepts and presentation approaches for visual productions and media, such as print, broadcasting, video, and film. Direct workers engaged in artwork or layout design.","[object Object]",Moderate,"While AI can assist in design tasks and streamline workflows, the creative and subjective nature of art direction requires human intuition and emotional understanding, which AI may struggle to fully replicate.","2025-07-07 14:28:37"
|
||||
19-3041.00,Sociologists,"Study human society and social behavior by examining the groups and social institutions that people form, as well as various social, religious, political, and business organizations. May study the behavior and interaction of groups, trace their origin and growth, and analyze the influence of group activities on individual members.","[object Object]",Moderate,"While AI can assist in data analysis and report generation, the nuanced understanding of human behavior and social dynamics requires human insight, limiting full automation. However, reliance on AI tools may reduce job opportunities in data collection and preliminary analysis.","2025-07-10 15:59:37"
|
||||
19-1021.00,"Biochemists & Biophysicists","Study the chemical composition or physical principles of living cells and organisms, their electrical and mechanical energy, and related phenomena. May conduct research to further understanding of the complex chemical combinations and reactions involved in metabolism, reproduction, growth, and heredity. May determine the effects of foods, drugs, serums, hormones, and other substances on tissues and vital processes of living organisms.","[object Object]",Low,"AI can assist in data analysis and literature review but lacks the nuanced understanding and creativity required for original research and complex problem-solving in biochemistry and biophysics.","2025-07-10 16:18:16"
|
||||
39-2021.00,"Animal Caretakers","Feed, water, groom, bathe, exercise, or otherwise provide care to promote and maintain the well-being of pets and other animals that are not raised for consumption, such as dogs, cats, race horses, ornamental fish or birds, zoo animals, and mice. Work in settings such as kennels, animal shelters, zoos, circuses, and aquariums. May keep records of feedings, treatments, and animals received or discharged. May clean, disinfect, and repair cages, pens, or fish tanks.","[object Object]",Low,"AI can assist with tasks like record-keeping and monitoring animal health, but the hands-on care and emotional connection required in animal caretaking are difficult to automate fully.","2025-07-11 21:01:40"
|
||||
49-9092.00,"Commercial Divers","Work below surface of water, using surface-supplied air or scuba equipment to inspect, repair, remove, or install equipment and structures. May use a variety of power and hand tools, such as drills, sledgehammers, torches, and welding equipment. May conduct tests or experiments, rig explosives, or photograph structures or marine life.","[object Object]",Moderate,"While automation can enhance safety and efficiency in commercial diving, the complex and unpredictable underwater environment poses challenges. Human judgment and adaptability remain crucial, limiting full automation potential.","2025-07-11 23:56:40"
|
||||
49-9031.00,"Home Appliance Repairers","Repair, adjust, or install all types of electric or gas household appliances, such as refrigerators, washers, dryers, and ovens.","[object Object]",Moderate,"While AI can assist in diagnostics and customer service, the hands-on nature of repairs and the need for human judgment in complex situations limit full automation in this field.","2025-07-13 15:25:24"
|
||||
17-3024.01,"Robotics Technicians","Build, install, test, or maintain robotic equipment or related automated production systems.","[object Object]",Moderate,"While automation may reduce the need for manual repairs and installations, the complexity of robotic systems will require skilled technicians for troubleshooting and maintenance, ensuring job relevance but with potential job displacement in simpler tasks.","2025-07-13 15:29:13"
|
||||
11-9121.00,"Natural Sciences Managers","Plan, direct, or coordinate activities in such fields as life sciences, physical sciences, mathematics, statistics, and research and development in these fields.","[object Object]",Moderate,"While AI can assist in data analysis and project management, the nuanced decision-making and leadership required in natural sciences management are less likely to be fully automated, leading to moderate risk of job displacement.","2025-07-13 15:46:20"
|
||||
15-1255.01,"Video Game Designers","Design core features of video games. Specify innovative game and role-play mechanics, story lines, and character biographies. Create and maintain design documentation. Guide and collaborate with production staff to produce games as designed.","[object Object]",Moderate,"AI may automate certain aspects of game design, such as procedural content generation, but the creative and nuanced elements like storytelling and character development will still require human insight and creativity.","2025-07-13 16:05:12"
|
||||
43-4051.00,"Customer Service Representatives","","",Moderate,"While AI can automate routine inquiries and data processing, the need for human empathy and complex problem-solving in customer service will maintain demand for representatives, albeit with evolving roles.","2025-07-13 17:58:30"
|
||||
15-1243.01,"Data Warehousing Specialists","Design, model, or implement corporate data warehousing activities. Program and configure warehouses of database information and provide support to warehouse users.","[object Object]",Moderate,"AI automation may streamline data warehousing tasks, but the need for human oversight in complex decision-making and data integrity will persist, leading to a moderate risk of job displacement.","2025-07-14 18:12:11"
|
||||
51-9081.00,"Dental Laboratory Technicians","Construct and repair full or partial dentures or dental appliances.","[object Object]",Moderate,"While AI can assist in design and production, the intricate craftsmanship and customization required in dental appliances still necessitate human expertise, limiting full automation potential.","2025-07-17 19:30:09"
|
||||
27-3043.05,"Poets, Lyricists & Creative Writers","Create original written works, such as scripts, essays, prose, poetry or song lyrics, for publication or performance.","[object Object]",Moderate,"While AI can assist in generating content, the unique creativity and emotional depth of human writers remain irreplaceable. However, increased automation in content creation may lead to competition and reduced demand for certain writing roles.","2025-07-17 19:30:36"
|
||||
15-1299.01,"Web Administrators","","",Moderate,"As AI technology evolves, web administrators may face risks from automation of tasks, leading to job displacement. However, the need for oversight and management of AI systems will create new opportunities, balancing the risk.","2025-07-18 15:08:13"
|
||||
15-1299.09,"Information Technology Project Managers","Plan, initiate, and manage information technology (IT) projects. Lead and guide the work of technical staff. Serve as liaison between business and technical aspects of projects. Plan project stages and assess business implications for each stage. Monitor progress to assure deadlines, standards, and cost targets are met.","[object Object]",Moderate,"As AI continues to evolve, IT project managers may face challenges in integrating AI technologies, managing skilled labor shortages, and ensuring data security, which could impact project execution and outcomes.","2025-07-20 13:45:16"
|
||||
25-1022.00,"Mathematical Science Teachers, Postsecondary","Teach courses pertaining to mathematical concepts, statistics, and actuarial science and to the application of original and standardized mathematical techniques in solving specific problems and situations. Includes both teachers primarily engaged in teaching and those who do a combination of teaching and research.","[object Object]",Moderate,"While AI can assist in grading and providing resources, the nuanced understanding and interpersonal skills required for teaching complex mathematical concepts cannot be fully automated, ensuring a continued need for human educators.","2025-07-20 15:22:08"
|
||||
33-3051.00,"Police and Sheriff's Patrol Officers","Maintain order and protect life and property by enforcing local, tribal, state, or federal laws and ordinances. Perform a combination of the following duties: patrol a specific area; direct traffic; issue traffic summonses; investigate accidents; apprehend and arrest suspects, or serve legal processes of courts. Includes police officers working at educational institutions.","[object Object]",Moderate,"While AI can assist in data analysis and crime prediction, the need for human judgment in complex situations and community relations will keep demand for officers stable, albeit with potential job displacement in routine tasks.","2025-07-29 22:36:23"
|
||||
33-2011.00,Firefighters,"Control and extinguish fires or respond to emergency situations where life, property, or the environment is at risk. Duties may include fire prevention, emergency medical service, hazardous material response, search and rescue, and disaster assistance.","[object Object]",Moderate,"While AI can assist in data analysis and predictive modeling for fire prevention, the inherently unpredictable nature of emergencies and the need for human judgment in high-stress situations limits full automation in firefighting roles.","2025-07-29 22:38:29"
|
||||
53-3011.00,"Ambulance Drivers and Attendants, Except Emergency Medical Technicians","Drive ambulance or assist ambulance driver in transporting sick, injured, or convalescent persons. Assist in lifting patients.","[object Object]",Moderate,"While automation may assist in driving and logistics, the human element in patient care and emergency response remains critical, limiting full automation potential.","2025-07-29 22:40:09"
|
||||
19-4099.01,"Quality Control Analysts","Conduct tests to determine quality of raw materials, bulk intermediate and finished products. May conduct stability sample tests.","[object Object]",Moderate,"While AI can automate routine testing and data analysis, the need for human judgment in interpreting results and making recommendations will limit full automation in quality control roles.","2025-08-01 16:16:56"
|
||||
15-2041.00,Statisticians,"Develop or apply mathematical or statistical theory and methods to collect, organize, interpret, and summarize numerical data to provide usable information. May specialize in fields such as biostatistics, agricultural statistics, business statistics, or economic statistics. Includes mathematical and survey statisticians.","[object Object]",Moderate,"As AI technologies advance, the role of statisticians may evolve, with automation handling routine tasks. However, human expertise in interpreting complex data and providing context will remain essential.","2025-08-01 17:32:46"
|
||||
13-2031.00,"Budget Analysts","Examine budget estimates for completeness, accuracy, and conformance with procedures and regulations. Analyze budgeting and accounting reports.","[object Object]",Moderate,"AI may automate data analysis and reporting tasks, reducing the need for manual budget examination. However, human oversight will still be crucial for complex decision-making and regulatory compliance.","2025-08-01 17:33:04"
|
||||
13-2051.00,"Financial & Investment Analysts","Conduct quantitative analyses of information involving investment programs or financial data of public or private institutions, including valuation of businesses.","[object Object]",Moderate,"While AI can enhance analysis and efficiency, the potential for job displacement exists as automation improves. Financial analysts may need to adapt to new technologies and focus on strategic advisory roles.","2025-08-01 18:51:58"
|
||||
13-2011.00,"Accountants & Auditors","Examine, analyze, and interpret accounting records to prepare financial statements, give advice, or audit and evaluate statements prepared by others. Install or advise on systems of recording costs or other financial and budgetary data.","[object Object]",Moderate,"While AI can automate data analysis and reporting, the nuanced judgment required for audits and compliance will still necessitate human oversight, limiting full automation.","2025-08-01 18:52:19"
|
||||
15-2011.00,Actuaries,"Analyze statistical data, such as mortality, accident, sickness, disability, and retirement rates and construct probability tables to forecast risk and liability for payment of future benefits. May ascertain insurance rates required and cash reserves necessary to ensure payment of future benefits.","[object Object]",Moderate,"As AI continues to evolve, actuaries may face challenges in adapting to new technologies and methodologies, potentially impacting accuracy in risk assessment and premium calculations.","2025-08-01 18:52:24"
|
||||
13-1081.02,"Logistics Analysts","Analyze product delivery or supply chain processes to identify or recommend changes. May manage route activity including invoicing, electronic bills, and shipment tracing.","[object Object]",Moderate,"While AI can automate data analysis and tracking, the need for human oversight in complex logistics decisions and communication with service providers will remain, limiting full automation.","2025-08-01 18:52:30"
|
||||
19-4061.00,"Social Science Research Assistants","Assist social scientists in laboratory, survey, and other social science research. May help prepare findings for publication and assist in laboratory analysis, quality control, or data management.","[object Object]",Moderate,"AI can automate data management and analysis tasks, potentially reducing demand for research assistants. However, human oversight and critical thinking remain essential for interpreting results and preparing reports.","2025-08-01 18:52:50"
|
||||
|
|
Can't render this file because it is too large.
|
@ -10,17 +10,17 @@ cron.schedule('*/1 * * * *', async () => {
|
||||
try {
|
||||
// IMPORTANT: use execute() so the param is truly bound
|
||||
|
||||
const [rows] = await pool.execute(
|
||||
`SELECT id,
|
||||
phone_e164 AS toNumber,
|
||||
message_body AS body
|
||||
FROM reminders
|
||||
WHERE status = 'pending'
|
||||
AND send_at_utc <= UTC_TIMESTAMP()
|
||||
ORDER BY send_at_utc ASC
|
||||
LIMIT ?`,
|
||||
[BATCH_SIZE] // must be a number
|
||||
);
|
||||
const sql = `
|
||||
SELECT id,
|
||||
phone_e164 AS toNumber,
|
||||
message_body AS body
|
||||
FROM reminders
|
||||
WHERE status = 'pending'
|
||||
AND send_at_utc <= UTC_TIMESTAMP()
|
||||
ORDER BY send_at_utc ASC
|
||||
LIMIT ${BATCH_SIZE}
|
||||
`;
|
||||
const [rows] = await pool.query(sql);
|
||||
|
||||
if (!rows.length) return;
|
||||
|
||||
|
||||
@ -34,9 +34,9 @@ const envPath = path.resolve(rootPath, `.env.${env}`);
|
||||
dotenv.config({ path: envPath, override: false }); // don't clobber compose-injected env
|
||||
|
||||
const ROOT_DIR = path.resolve(__dirname, '..');
|
||||
const PUBLIC_DIR = path.join(ROOT_DIR, 'public');
|
||||
const CIP_TO_SOC_PATH = path.join(PUBLIC_DIR, 'CIP_to_ONET_SOC.xlsx');
|
||||
const INSTITUTION_DATA_PATH= path.join(PUBLIC_DIR, 'Institution_data.json');
|
||||
const DATA_DIR = path.join(__dirname, 'data');
|
||||
const CIP_TO_SOC_PATH = path.join(DATA_DIR, 'CIP_to_ONET_SOC.xlsx');
|
||||
const INSTITUTION_DATA_PATH = path.join(DATA_DIR, 'Institution_data.json');
|
||||
const SALARY_DB_PATH = path.join(ROOT_DIR, 'salary_info.db');
|
||||
const USER_PROFILE_DB_PATH = path.join(ROOT_DIR, 'user_profile.db');
|
||||
|
||||
@ -264,15 +264,6 @@ app.use((req, res, next) => {
|
||||
'GET, POST, OPTIONS'
|
||||
);
|
||||
|
||||
/* 4b — Public JSON exception */
|
||||
} else if (req.path.includes('Institution_data')) {
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
||||
res.setHeader(
|
||||
'Access-Control-Allow-Headers',
|
||||
'Content-Type, Accept, Origin, X-Requested-With'
|
||||
);
|
||||
|
||||
/* 4c — Default permissive fallback (same as your original) */
|
||||
} else {
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
@ -294,11 +285,59 @@ app.use((req, res, next) => {
|
||||
|
||||
/* 5 — JSON parsing & static assets */
|
||||
app.use(express.json());
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
|
||||
/* 6 — No-op pass-through (kept for completeness) */
|
||||
app.use((req, res, next) => next());
|
||||
|
||||
|
||||
// ──────────────────────────────── Data endpoints ───────────────────────────────
|
||||
|
||||
// /api/data/careers-with-ratings → backend/data/careers_with_ratings.json
|
||||
app.get('/api/data/careers-with-ratings', (req, res) => {
|
||||
const p = path.join(DATA_DIR, 'careers_with_ratings.json');
|
||||
fs.access(p, fs.constants.R_OK, (err) => {
|
||||
if (err) return res.status(404).json({ error: 'careers_with_ratings.json not found' });
|
||||
res.type('application/json');
|
||||
res.sendFile(p);
|
||||
});
|
||||
});
|
||||
|
||||
// /api/data/cip-institution-map → backend/data/cip_institution_mapping_new.json (or fallback)
|
||||
app.get('/api/data/cip-institution-map', (req, res) => {
|
||||
const candidates = [
|
||||
'cip_institution_mapping_new.json',
|
||||
'cip_institution_mapping_fixed.json',
|
||||
'cip_institution_mapping.json'
|
||||
].map(f => path.join(DATA_DIR, f));
|
||||
|
||||
const found = candidates.find(f => fs.existsSync(f));
|
||||
if (!found) {
|
||||
return res.status(404).json({ error: 'CIP institution map not found', tried: candidates.map(p => path.basename(p)) });
|
||||
}
|
||||
res.type('application/json');
|
||||
res.sendFile(found);
|
||||
});
|
||||
|
||||
// /api/data/ic2023 → backend/data/ic2023_ay.csv
|
||||
app.get('/api/data/ic2023', (req, res) => {
|
||||
const p = path.join(DATA_DIR, 'ic2023_ay.csv');
|
||||
fs.access(p, fs.constants.R_OK, (err) => {
|
||||
if (err) return res.status(404).json({ error: 'ic2023_ay.csv not found' });
|
||||
res.type('text/csv');
|
||||
res.sendFile(p);
|
||||
});
|
||||
});
|
||||
|
||||
app.get('/api/data/career-clusters', (req, res) => {
|
||||
const p = path.join(DATA_DIR, 'career_clusters.json');
|
||||
fs.access(p, fs.constants.R_OK, (err) => {
|
||||
if (err) return res.status(404).json({ error: 'career_clusters.json not found' });
|
||||
res.type('application/json');
|
||||
res.sendFile(p);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
/**************************************************
|
||||
* Load CIP->SOC mapping
|
||||
**************************************************/
|
||||
@ -316,7 +355,7 @@ if (socToCipMapping.length === 0) {
|
||||
* Load single JSON with all states + US
|
||||
* Replaces old GA-only approach
|
||||
**************************************************/
|
||||
const singleProjFile = path.resolve(__dirname, '..', 'public', 'economicproj.json');
|
||||
const singleProjFile = path.join(DATA_DIR, 'economicproj.json');
|
||||
let allProjections = [];
|
||||
try {
|
||||
const raw = fs.readFileSync(singleProjFile, 'utf8');
|
||||
|
||||
@ -41,6 +41,7 @@ if (!process.env.FROM_SECRETS_MANAGER) {
|
||||
|
||||
const PORT = process.env.SERVER3_PORT || 5002;
|
||||
const API_BASE = `http://localhost:${PORT}/api`;
|
||||
const DATA_DIR = path.join(__dirname, 'data');
|
||||
|
||||
/* ─── helper: canonical public origin ─────────────────────────── */
|
||||
const PUBLIC_BASE = (
|
||||
@ -164,6 +165,25 @@ function internalFetch(req, urlPath, opts = {}) {
|
||||
|
||||
const auth = (req, urlPath, opts = {}) => internalFetch(req, urlPath, opts);
|
||||
|
||||
function parseJSONLoose(text) {
|
||||
if (!text || typeof text !== 'string') return null;
|
||||
|
||||
// fenced ```json ... ```
|
||||
const fence = text.match(/```json\s*([\s\S]+?)```/i) || text.match(/```\s*([\s\S]+?)```/i);
|
||||
if (fence) { try { return JSON.parse(fence[1].trim()); } catch {} }
|
||||
|
||||
// slice between first {/[ and last }/]
|
||||
const start = text.search(/[{\[]/);
|
||||
const end = Math.max(text.lastIndexOf('}'), text.lastIndexOf(']'));
|
||||
if (start !== -1 && end > start) {
|
||||
try { return JSON.parse(text.slice(start, end + 1).trim()); } catch {}
|
||||
}
|
||||
|
||||
// last chance: strip backticks
|
||||
try { return JSON.parse(text.trim().replace(/^`+|`+$/g, '')); } catch {}
|
||||
return null;
|
||||
}
|
||||
|
||||
// AI Risk Analysis Helper Functions
|
||||
async function getRiskAnalysisFromDB(socCode) {
|
||||
const [rows] = await pool.query(
|
||||
@ -512,7 +532,7 @@ app.get('/api/premium/career-profile/latest', authenticatePremiumUser, async (re
|
||||
const sql = `
|
||||
SELECT
|
||||
*,
|
||||
DATE_FORMAT(start_date, '%Y-%m-%d') AS start_date
|
||||
start_date AS start_date
|
||||
FROM career_profiles
|
||||
WHERE user_id = ?
|
||||
ORDER BY start_date DESC
|
||||
@ -532,7 +552,7 @@ app.get('/api/premium/career-profile/all', authenticatePremiumUser, async (req,
|
||||
const sql = `
|
||||
SELECT
|
||||
*,
|
||||
DATE_FORMAT(start_date, '%Y-%m-%d') AS start_date
|
||||
start_date AS start_date
|
||||
FROM career_profiles
|
||||
WHERE user_id = ?
|
||||
ORDER BY start_date ASC
|
||||
@ -552,7 +572,7 @@ app.get('/api/premium/career-profile/:careerProfileId', authenticatePremiumUser,
|
||||
const sql = `
|
||||
SELECT
|
||||
*,
|
||||
DATE_FORMAT(start_date, '%Y-%m-%d') AS start_date
|
||||
start_date AS start_date
|
||||
FROM career_profiles
|
||||
WHERE id = ?
|
||||
AND user_id = ?
|
||||
@ -2126,7 +2146,7 @@ app.post('/api/premium/ai-risk-analysis', authenticatePremiumUser, async (req, r
|
||||
Tasks: ${tasks.join('; ')}
|
||||
|
||||
Provide AI automation risk analysis for the next 10 years.
|
||||
Return JSON in exactly this format:
|
||||
Return ONLY a JSON object (no markdown/code fences), exactly in this format:
|
||||
|
||||
{
|
||||
"riskLevel": "Low|Moderate|High",
|
||||
@ -2143,25 +2163,21 @@ app.post('/api/premium/ai-risk-analysis', authenticatePremiumUser, async (req, r
|
||||
});
|
||||
|
||||
const aiText = completion?.choices?.[0]?.message?.content?.trim() || '';
|
||||
let parsed;
|
||||
try {
|
||||
parsed = JSON.parse(aiText);
|
||||
} catch (err) {
|
||||
console.error('Error parsing AI JSON:', err);
|
||||
return res.status(500).json({ error: 'Invalid AI JSON response.' });
|
||||
}
|
||||
const parsed = parseJSONLoose(aiText);
|
||||
if (!parsed) {
|
||||
console.error('Error parsing AI JSON (loose):', aiText);
|
||||
return res.status(500).json({ error: 'Invalid AI JSON response.' });
|
||||
}
|
||||
const { riskLevel, reasoning } = parsed;
|
||||
|
||||
// 3) Store in DB
|
||||
await storeRiskAnalysisInDB({
|
||||
socCode,
|
||||
careerName,
|
||||
jobDescription,
|
||||
tasks,
|
||||
riskLevel: parsed.riskLevel,
|
||||
reasoning: parsed.reasoning
|
||||
|
||||
});
|
||||
const tasksStr =
|
||||
Array.isArray(tasks) ? tasks.map(t => (typeof t === 'string' ? t : String(t))).join('; ')
|
||||
: (typeof tasks === 'string' ? tasks : '');
|
||||
await storeRiskAnalysisInDB({
|
||||
socCode, careerName, jobDescription, tasks: tasksStr,
|
||||
riskLevel: parsed.riskLevel, reasoning: parsed.reasoning
|
||||
});
|
||||
|
||||
// 4) Return the new analysis
|
||||
res.json({
|
||||
@ -2214,13 +2230,11 @@ app.post('/api/public/ai-risk-analysis', async (req, res) => {
|
||||
});
|
||||
|
||||
const aiText = completion?.choices?.[0]?.message?.content?.trim() || '';
|
||||
let parsed;
|
||||
try {
|
||||
parsed = JSON.parse(aiText);
|
||||
} catch (err) {
|
||||
console.error('Error parsing AI JSON:', err);
|
||||
return res.status(500).json({ error: 'Invalid AI JSON response.' });
|
||||
}
|
||||
const parsed = parseJSONLoose(aiText);
|
||||
if (!parsed) {
|
||||
console.error('Error parsing AI JSON (loose):', aiText);
|
||||
return res.status(500).json({ error: 'Invalid AI JSON response.' });
|
||||
}
|
||||
const { riskLevel, reasoning } = parsed;
|
||||
|
||||
res.json({
|
||||
@ -3671,21 +3685,20 @@ app.delete('/api/premium/milestone-impacts/:impactId', authenticatePremiumUser,
|
||||
let onetKsaData = []; // entire array from ksa_data.json
|
||||
let allKsaNames = []; // an array of unique KSA names (for fuzzy matching)
|
||||
|
||||
|
||||
(async function loadKsaJson() {
|
||||
try {
|
||||
const filePath = path.join(__dirname, '..', 'public', 'ksa_data.json');
|
||||
const raw = await fs.readFile(filePath, 'utf8');
|
||||
const filePath = path.join(DATA_DIR, 'ksa_data.json');
|
||||
const raw = await readFile(filePath, 'utf8'); // ← use fs/promises.readFile
|
||||
onetKsaData = JSON.parse(raw);
|
||||
|
||||
// Build a set of unique KSA names for fuzzy search
|
||||
const nameSet = new Set();
|
||||
for (const row of onetKsaData) {
|
||||
nameSet.add(row.elementName);
|
||||
}
|
||||
const nameSet = new Set(onetKsaData.map(r => r.elementName));
|
||||
allKsaNames = Array.from(nameSet);
|
||||
console.log(`Loaded ksa_data.json with ${onetKsaData.length} rows; ${allKsaNames.length} unique KSA names.`);
|
||||
} catch (err) {
|
||||
console.error('Error loading ksa_data.json:', err);
|
||||
onetKsaData = [];
|
||||
allKsaNames = [];
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@ import Fuse from "fuse.js";
|
||||
/* resolve …/backend/utils → …/public/careers_with_ratings.json */
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const careersPath = path.join(__dirname, "..", "..", "public", "careers_with_ratings.json");
|
||||
const careersPath = path.join(__dirname, "..", "data", "careers_with_ratings.json");
|
||||
|
||||
const CAREERS = JSON.parse(fs.readFileSync(careersPath, "utf-8"));
|
||||
|
||||
|
||||
@ -54,10 +54,11 @@ http {
|
||||
location ^~ /api/tuition/ { proxy_pass http://backend5001; }
|
||||
location ^~ /api/projections/ { proxy_pass http://backend5001; }
|
||||
location ^~ /api/skills/ { proxy_pass http://backend5001; }
|
||||
location ^~ /api/ai-risk { proxy_pass http://backend5001; }
|
||||
location ^~ /api/ai-risk { proxy_pass http://backend5002; }
|
||||
location ^~ /api/maps/distance { proxy_pass http://backend5001; }
|
||||
location ^~ /api/schools { proxy_pass http://backend5001; }
|
||||
location ^~ /api/support { proxy_pass http://backend5001; }
|
||||
location ^~ /api/data/ { proxy_pass http://backend5001; }
|
||||
|
||||
location ^~ /api/premium/ { proxy_pass http://backend5002; }
|
||||
location ^~ /api/public/ { proxy_pass http://backend5002; }
|
||||
|
||||
@ -81,12 +81,20 @@ Create three milestones that expand professional connections.
|
||||
${planPrompt()}
|
||||
`.trim(),
|
||||
|
||||
jobSearch: ({ careerName, goalsText }) => `
|
||||
jobSearch: ({ careerName, goalsText }) => `
|
||||
MODE : job_search_plan
|
||||
ROLE : ${careerName}
|
||||
GOALS: ${goalsText || "N/A"}
|
||||
|
||||
Draft three milestones that accelerate the job hunt.
|
||||
Draft three milestones that directly advance a job hunt.
|
||||
Each milestone must focus ONLY on job-search execution:
|
||||
– finding postings
|
||||
– tailoring applications / resume
|
||||
– submitting applications
|
||||
– scheduling / attending interviews
|
||||
– following up with recruiters or companies
|
||||
|
||||
Do NOT include skill improvement, networking, or AI-growth items.
|
||||
${planPrompt()}
|
||||
`.trim(),
|
||||
|
||||
@ -138,28 +146,13 @@ export default function CareerCoach({
|
||||
const [draftGoals, setDraftGoals] = useState(scenarioRow?.career_goals || "");
|
||||
const [saving , setSaving ] = useState(false);
|
||||
const [threadId, setThreadId] = useState(null);
|
||||
const historyLoadedRef = useRef(false);
|
||||
|
||||
/* -------------- scroll --------------- */
|
||||
useEffect(() => {
|
||||
if (chatRef.current) chatRef.current.scrollTop = chatRef.current.scrollHeight;
|
||||
}, [messages]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
const id = await ensureCoachThread();
|
||||
setThreadId(id);
|
||||
const r3 = await authFetch(`/api/premium/coach/chat/threads/${id}`);
|
||||
if (r3.ok && (r3.headers.get('content-type') || '').includes('application/json')) {
|
||||
const { messages: msgs = [] } = await r3.json();
|
||||
setMessages(msgs);
|
||||
}
|
||||
} catch {
|
||||
// keep UI usable; callAi will create on first send
|
||||
}
|
||||
})();
|
||||
}, [careerProfileId]);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
|
||||
@ -167,35 +160,40 @@ useEffect(() => {
|
||||
if (!careerProfileId) return;
|
||||
|
||||
try {
|
||||
// ensure or create a thread
|
||||
const newId = await ensureCoachThread();
|
||||
const id = await ensureCoachThread();
|
||||
if (cancelled) return;
|
||||
|
||||
setThreadId(newId);
|
||||
setThreadId(id);
|
||||
|
||||
// preload history (best-effort)
|
||||
const r3 = await authFetch(`/api/premium/coach/chat/threads/${newId}`);
|
||||
// preload history
|
||||
const r3 = await authFetch(`/api/premium/coach/chat/threads/${id}`);
|
||||
if (cancelled) return;
|
||||
|
||||
if (r3.ok && (r3.headers.get('content-type') || '').includes('application/json')) {
|
||||
const { messages: msgs = [] } = await r3.json();
|
||||
if (!cancelled) setMessages(msgs);
|
||||
const data = await r3.json();
|
||||
const msgs = Array.isArray(data.messages) ? data.messages : [];
|
||||
if (!cancelled) setMessages(msgs.length ? msgs : [generatePersonalizedIntro()]);
|
||||
} else {
|
||||
if (!cancelled) setMessages([generatePersonalizedIntro()]);
|
||||
}
|
||||
} catch (e) {
|
||||
if (!cancelled) setThreadId(null); // UI stays usable; callAi will create on first send
|
||||
console.error("Coach thread preload failed:", e);
|
||||
if (!cancelled) {
|
||||
setThreadId(null);
|
||||
setMessages([generatePersonalizedIntro()]);
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
return () => { cancelled = true; };
|
||||
}, [careerProfileId]);
|
||||
|
||||
|
||||
/* -------------- intro ---------------- */
|
||||
useEffect(() => {
|
||||
if (!scenarioRow) return;
|
||||
setMessages(prev =>
|
||||
prev.length ? prev // keep what we loaded
|
||||
: [generatePersonalizedIntro()] );
|
||||
}, [scenarioRow?.id]);
|
||||
useEffect(() => {
|
||||
if (!scenarioRow || !historyLoadedRef.current) return;
|
||||
setMessages(prev => (prev.length ? prev : [generatePersonalizedIntro()]));
|
||||
}, [scenarioRow?.id]);
|
||||
|
||||
/* ---------- helpers you already had ---------- */
|
||||
function buildStatusSituationMessage(status, situation, careerName) {
|
||||
|
||||
@ -247,7 +247,7 @@ function CareerExplorer() {
|
||||
|
||||
return {
|
||||
...career,
|
||||
job_zone: jobZoneData[stripSoc(career.code)]?.job_zone || null,
|
||||
job_zone: jobZoneData[strippedSoc]?.job_zone || null,
|
||||
limitedData: isLimitedData,
|
||||
};
|
||||
});
|
||||
@ -480,15 +480,17 @@ const handleCareerClick = useCallback(
|
||||
// ------------------------------------------------------
|
||||
// Load careers_with_ratings for CIP arrays
|
||||
// ------------------------------------------------------
|
||||
useEffect(() => {
|
||||
fetch('/careers_with_ratings.json')
|
||||
.then((res) => {
|
||||
if (!res.ok) throw new Error('Failed to fetch ratings JSON');
|
||||
return res.json();
|
||||
})
|
||||
.then((data) => setMasterCareerRatings(data))
|
||||
.catch((err) => console.error('Error fetching career ratings:', err));
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
const { data } = await api.get('/api/data/careers-with-ratings'); // server2 route
|
||||
setMasterCareerRatings(data || []);
|
||||
} catch (err) {
|
||||
console.error('Error fetching career ratings:', err);
|
||||
setMasterCareerRatings([]);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
// ------------------------------------------------------
|
||||
// Derived data / Helpers
|
||||
|
||||
@ -5,8 +5,7 @@ import isAllOther from '../utils/isAllOther.js';
|
||||
|
||||
|
||||
function CareerModal({ career, careerDetails, closeModal, addCareerToList }) {
|
||||
const [error, setError] = useState(null);
|
||||
const [loadingRisk, setLoadingRisk] = useState(false);
|
||||
const [error] = useState(null);
|
||||
const aiRisk = careerDetails?.aiRisk || null;
|
||||
const fmt = (v) =>
|
||||
typeof v === 'number'
|
||||
|
||||
@ -182,10 +182,9 @@ export default function CareerProfileForm() {
|
||||
onChange={handleChange}
|
||||
>
|
||||
<option value="">-- select --</option>
|
||||
<option value="not_applicable">Not Applicable</option>
|
||||
<option value="prospective_student">Prospective Student</option>
|
||||
<option value="not_enrolled">Not Enrolled / Not Planning</option>
|
||||
<option value="currently_enrolled">Currently Enrolled</option>
|
||||
<option value="completed">Completed</option>
|
||||
<option value="prospective_student">Planning to Enroll (Prospective)</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
|
||||
@ -34,10 +34,7 @@ import FinancialDisclaimer from './FinancialDisclaimer.js';
|
||||
import { Button } from './ui/button.js';
|
||||
import { Pencil } from 'lucide-react';
|
||||
import ScenarioEditModal from './ScenarioEditModal.js';
|
||||
import parseAIJson from "../utils/parseAIJson.js"; // your shared parser
|
||||
import InfoTooltip from "./ui/infoTooltip.js";
|
||||
import differenceInMonths from 'date-fns/differenceInMonths';
|
||||
|
||||
|
||||
import "../styles/legacy/MilestoneTimeline.legacy.css";
|
||||
|
||||
@ -684,16 +681,19 @@ useEffect(() => {
|
||||
}, [recommendations]);
|
||||
|
||||
|
||||
// 2) load local JSON => masterCareerRatings
|
||||
// 2) load JSON => masterCareerRatings
|
||||
useEffect(() => {
|
||||
fetch('/careers_with_ratings.json')
|
||||
.then((res) => {
|
||||
if (!res.ok) throw new Error('Failed to load local career data');
|
||||
return res.json();
|
||||
})
|
||||
.then((data) => setMasterCareerRatings(data))
|
||||
.catch((err) => console.error('Error loading local career data =>', err));
|
||||
}, []);
|
||||
(async () => {
|
||||
try {
|
||||
const { data } = await api.get('/api/data/careers-with-ratings');
|
||||
setMasterCareerRatings(data || []);
|
||||
} catch (err) {
|
||||
console.error('Error loading career ratings via API =>', err);
|
||||
setMasterCareerRatings([]);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
|
||||
// 3) fetch user’s career-profiles
|
||||
// utilities you already have in this file
|
||||
@ -1308,59 +1308,6 @@ const DAILY_CLICK_LIMIT = 10; // example limit per day
|
||||
|
||||
const yearsInCareer = getYearsInCareer(scenarioRow?.start_date);
|
||||
|
||||
// -- AI Handler --
|
||||
async function handleAiClick() {
|
||||
if (aiLoading || clickCount >= DAILY_CLICK_LIMIT) {
|
||||
alert('You have reached the daily limit for suggestions.');
|
||||
return;
|
||||
}
|
||||
|
||||
setAiLoading(true);
|
||||
setSelectedIds([]);
|
||||
|
||||
const oldRecTitles = recommendations.map(r => r.title.trim()).filter(Boolean);
|
||||
const acceptedTitles = scenarioMilestones.map(m => (m.title || '').trim()).filter(Boolean);
|
||||
const allToAvoid = [...oldRecTitles, ...acceptedTitles];
|
||||
|
||||
try {
|
||||
const payload = {
|
||||
userProfile,
|
||||
scenarioRow,
|
||||
financialProfile,
|
||||
collegeProfile,
|
||||
previouslyUsedTitles: allToAvoid
|
||||
};
|
||||
|
||||
const res = await authFetch('/api/premium/ai/next-steps', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
|
||||
if (!res.ok) throw new Error('AI request failed');
|
||||
|
||||
const data = await res.json();
|
||||
const rawText = data.recommendations || '';
|
||||
const arr = parseAIJson(rawText);
|
||||
|
||||
setRecommendations(arr);
|
||||
localStorage.setItem('aiRecommendations', JSON.stringify(arr));
|
||||
|
||||
// Update click count
|
||||
setClickCount(prev => {
|
||||
const newCount = prev + 1;
|
||||
localStorage.setItem('aiClickCount', newCount);
|
||||
return newCount;
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
console.error('Error fetching AI next steps =>', err);
|
||||
} finally {
|
||||
setAiLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function handleSimulationYearsChange(e) {
|
||||
setSimulationYearsInput(e.target.value);
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Check } from 'lucide-react'; // any icon lib you use
|
||||
import { Check } from 'lucide-react'; // (unused here, keep/remove as you like)
|
||||
import { Button } from './ui/button.js';
|
||||
import api from '../auth/apiClient.js';
|
||||
|
||||
/* ---------- helpers ---------- */
|
||||
const normalize = (s = '') =>
|
||||
@ -18,11 +19,11 @@ const CareerSearch = ({ onCareerSelected, required, disabled: externallyDisabled
|
||||
const [selectedObj, setSelectedObj] = useState(null); // ✓ state
|
||||
const computedDisabled = externallyDisabled || !!selectedObj;
|
||||
|
||||
/* fetch & de-dupe once */
|
||||
/* fetch & de-dupe once (now via backend) */
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
const raw = await fetch('/careers_with_ratings.json').then(r => r.json());
|
||||
const { data: raw = [] } = await api.get('/api/data/careers-with-ratings');
|
||||
const map = new Map();
|
||||
for (const c of raw) {
|
||||
if (c.title && c.soc_code && c.cip_codes) {
|
||||
@ -41,6 +42,7 @@ const CareerSearch = ({ onCareerSelected, required, disabled: externallyDisabled
|
||||
setCareerObjects([...map.values()]);
|
||||
} catch (err) {
|
||||
console.error('Career list load failed:', err);
|
||||
setCareerObjects([]);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
@ -52,13 +54,13 @@ const CareerSearch = ({ onCareerSelected, required, disabled: externallyDisabled
|
||||
);
|
||||
if (match && match !== selectedObj) {
|
||||
setSelectedObj(match);
|
||||
onCareerSelected(match); // notify parent immediately
|
||||
onCareerSelected?.(match); // notify parent immediately
|
||||
}
|
||||
}, [searchInput, careerObjects, selectedObj, onCareerSelected]);
|
||||
|
||||
/* allow “Enter” to commit first suggestion */
|
||||
const handleKeyDown = (e) => {
|
||||
if (computedDisabled) return;
|
||||
if (computedDisabled) return;
|
||||
if (e.key === 'Enter') {
|
||||
const first = careerObjects.find(o =>
|
||||
normalize(o.title).startsWith(normalize(searchInput))
|
||||
@ -76,6 +78,8 @@ const CareerSearch = ({ onCareerSelected, required, disabled: externallyDisabled
|
||||
setSearchInput('');
|
||||
};
|
||||
|
||||
const listId = 'career-titles';
|
||||
|
||||
return (
|
||||
<div className="mb-4">
|
||||
<label className="block font-medium mb-1">
|
||||
@ -85,7 +89,7 @@ const CareerSearch = ({ onCareerSelected, required, disabled: externallyDisabled
|
||||
<div className="relative">
|
||||
<input
|
||||
type="text"
|
||||
list="career-titles"
|
||||
list={listId}
|
||||
value={searchInput}
|
||||
required={required}
|
||||
disabled={computedDisabled} // lock when chosen
|
||||
@ -97,20 +101,20 @@ const CareerSearch = ({ onCareerSelected, required, disabled: externallyDisabled
|
||||
/>
|
||||
|
||||
{!computedDisabled && (
|
||||
<datalist id="career-titles">
|
||||
{careerObjects.map((o) => (
|
||||
<option key={o.soc_code} value={o.title} />
|
||||
))}
|
||||
</datalist>
|
||||
)}
|
||||
<datalist id={listId}>
|
||||
{careerObjects.map((o) => (
|
||||
<option key={o.soc_code} value={o.title} />
|
||||
))}
|
||||
</datalist>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* PSA message */}
|
||||
{!selectedObj && (
|
||||
<datalist id="career-titles">
|
||||
{careerObjects.map((o) => (
|
||||
<option key={o.soc_code} value={o.title} />
|
||||
))}
|
||||
</datalist>
|
||||
<p className="mt-2 text-sm text-blue-700">
|
||||
Please pick from the dropdown when performing search. Our database is very comprehensive but can’t
|
||||
accommodate every job title—choose the closest match to what you’re searching for.
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* change / clear link */}
|
||||
|
||||
@ -219,66 +219,37 @@ function normalizeCipList(arr) {
|
||||
if (newSoc || navCareer) setShowSearch(false);
|
||||
}, [location.state]);
|
||||
|
||||
// Load KSA data once
|
||||
useEffect(() => {
|
||||
async function loadKsaData() {
|
||||
setLoadingKsa(true);
|
||||
setKsaError(null);
|
||||
try {
|
||||
const resp = await fetch('/ksa_data.json');
|
||||
if (!resp.ok) {
|
||||
throw new Error('Failed to fetch ksa_data.json');
|
||||
}
|
||||
let data = await resp.json();
|
||||
|
||||
// skip possible header row
|
||||
data = data.filter((item) => item.onetSocCode !== 'O*NET-SOC Code');
|
||||
|
||||
setAllKsaData(data);
|
||||
} catch (err) {
|
||||
console.error('Error loading ksa_data.json:', err);
|
||||
setKsaError('Could not load KSA data');
|
||||
} finally {
|
||||
setLoadingKsa(false);
|
||||
}
|
||||
}
|
||||
loadKsaData();
|
||||
}, []);
|
||||
|
||||
|
||||
|
||||
|
||||
// Filter: only IM >=3, then combine IM+LV
|
||||
useEffect(() => {
|
||||
if (!socCode) {
|
||||
// no career => no KSA
|
||||
setKsaForCareer([]);
|
||||
return;
|
||||
}
|
||||
|
||||
// No local blob anymore → ask server3 (local/DB/GPT) for this SOC.
|
||||
if (!allKsaData.length) {
|
||||
return;
|
||||
}
|
||||
fetchKsaFallback(socCode, careerTitle);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, we have local data loaded:
|
||||
// If you keep allKsaData around for dev, this path still works:
|
||||
let filtered = allKsaData.filter((r) => r.onetSocCode === socCode);
|
||||
filtered = filtered.filter((r) => r.recommendSuppress !== 'Y');
|
||||
filtered = filtered.filter((r) => ['IM', 'LV'].includes(r.scaleID));
|
||||
|
||||
let combined = combineIMandLV(filtered);
|
||||
combined = combined.filter((item) => {
|
||||
return item.importanceValue !== null && item.importanceValue >= 3;
|
||||
});
|
||||
combined.sort((a, b) => (b.importanceValue || 0) - (a.importanceValue || 0));
|
||||
let combined = combineIMandLV(filtered)
|
||||
.filter((i) => i.importanceValue != null && i.importanceValue >= 3)
|
||||
.sort((a, b) => (b.importanceValue || 0) - (a.importanceValue || 0));
|
||||
|
||||
if (combined.length === 0) {
|
||||
// We found ZERO local KSA records for this socCode => fallback
|
||||
fetchKsaFallback(socCode, careerTitle);
|
||||
fetchKsaFallback(socCode, careerTitle);
|
||||
} else {
|
||||
// We found local KSA data => just use it
|
||||
setKsaForCareer(combined);
|
||||
}
|
||||
}, [socCode, allKsaData, careerTitle]);
|
||||
|
||||
|
||||
// Load user profile
|
||||
// Load user profile (cookie-based auth via api client)
|
||||
useEffect(() => {
|
||||
|
||||
@ -40,7 +40,6 @@ const CareerOnboarding = ({ nextStep, prevStep, data, setData, finishNow }) => {
|
||||
setCareerObj(navCareerObj);
|
||||
localStorage.setItem('selectedCareer', JSON.stringify(navCareerObj));
|
||||
|
||||
|
||||
setData(prev => ({
|
||||
...prev,
|
||||
career_name : navCareerObj.title,
|
||||
@ -49,7 +48,6 @@ const CareerOnboarding = ({ nextStep, prevStep, data, setData, finishNow }) => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [navCareerObj]); // ← run once per navigation change
|
||||
|
||||
|
||||
// Called whenever other <inputs> change
|
||||
const handleChange = (e) => {
|
||||
setData(prev => ({ ...prev, [e.target.name]: e.target.value }));
|
||||
@ -62,8 +60,6 @@ const CareerOnboarding = ({ nextStep, prevStep, data, setData, finishNow }) => {
|
||||
setData(prev => ({ ...prev, career_name: obj.title, soc_code: obj.soc_code || '' }));
|
||||
}
|
||||
|
||||
|
||||
|
||||
function handleSubmit() {
|
||||
if (!ready) return alert('Fill all required fields.');
|
||||
const inCollege = ['currently_enrolled', 'prospective_student'].includes(collegeStatus);
|
||||
@ -87,7 +83,6 @@ function handleSubmit() {
|
||||
? inCollege ? 'College →' : 'Finish →'
|
||||
: inCollege ? 'College →' : 'Financial →';
|
||||
|
||||
|
||||
return (
|
||||
<div className="max-w-md mx-auto p-6 space-y-4">
|
||||
<h2 className="text-2xl font-semibold">Career Details</h2>
|
||||
|
||||
@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
|
||||
import Modal from '../../components/ui/modal.js';
|
||||
import FinancialAidWizard from '../../components/FinancialAidWizard.js';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import authFetch from '../../utils/authFetch.js';
|
||||
|
||||
const Req = () => <span className="text-red-600 ml-0.5">*</span>;
|
||||
|
||||
@ -15,24 +16,16 @@ function CollegeOnboarding({ nextStep, prevStep, data, setData }) {
|
||||
const [schoolValid, setSchoolValid] = useState(false);
|
||||
const [programValid, setProgramValid] = useState(false);
|
||||
const [enrollmentDate, setEnrollmentDate] = useState(
|
||||
data.enrollment_date || '' // carry forward if the user goes back
|
||||
data.enrollment_date || ''
|
||||
);
|
||||
const [expectedGraduation, setExpectedGraduation] = useState(data.expected_graduation || '');
|
||||
|
||||
|
||||
|
||||
// Show/hide the financial aid wizard
|
||||
const [showAidWizard, setShowAidWizard] = useState(false);
|
||||
|
||||
|
||||
const location = useLocation();
|
||||
const navSelectedSchoolRaw = location.state?.selectedSchool;
|
||||
const navSelectedSchool = toSchoolName(navSelectedSchoolRaw);
|
||||
|
||||
|
||||
function dehydrate(schObj) {
|
||||
if (!schObj || typeof schObj !== 'object') return null;
|
||||
/* keep only the fields you really need */
|
||||
const { INSTNM, CIPDESC, CREDDESC, ...rest } = schObj;
|
||||
return { INSTNM, CIPDESC, CREDDESC, ...rest };
|
||||
}
|
||||
@ -47,7 +40,6 @@ function toSchoolName(objOrStr) {
|
||||
return objOrStr; // already a string
|
||||
}
|
||||
|
||||
|
||||
const infoIcon = (msg) => (
|
||||
<span
|
||||
className="ml-1 inline-flex h-4 w-4 items-center justify-center rounded-full bg-blue-500 text-white text-xs cursor-help"
|
||||
@ -101,7 +93,6 @@ function toSchoolName(objOrStr) {
|
||||
}));
|
||||
}
|
||||
}, [selectedSchool, setData]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (data.expected_graduation && !expectedGraduation)
|
||||
@ -162,15 +153,25 @@ useEffect(() => {
|
||||
useEffect(() => {
|
||||
async function fetchCipData() {
|
||||
try {
|
||||
const res = await fetch('/cip_institution_mapping_new.json');
|
||||
const text = await res.text();
|
||||
const lines = text.split('\n');
|
||||
const parsed = lines.map(line => {
|
||||
try { return JSON.parse(line); } catch { return null; }
|
||||
}).filter(Boolean);
|
||||
setSchoolData(parsed);
|
||||
// Preferred: backend returns JSON array
|
||||
const res = await authFetch('/api/data/cip-institution-map');
|
||||
if (!res.ok) throw new Error(`CIP map error (${res.status})`);
|
||||
const ct = res.headers.get('content-type') || '';
|
||||
if (ct.includes('application/json')) {
|
||||
const json = await res.json();
|
||||
setSchoolData(Array.isArray(json) ? json : []);
|
||||
} else {
|
||||
// Fallback: line-delimited JSON (if you keep that format)
|
||||
const text = await res.text();
|
||||
const parsed = text
|
||||
.split('\n')
|
||||
.map(line => { try { return JSON.parse(line); } catch { return null; } })
|
||||
.filter(Boolean);
|
||||
setSchoolData(parsed);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Failed to load CIP data:", err);
|
||||
console.error('Failed to load CIP data:', err);
|
||||
setSchoolData([]);
|
||||
}
|
||||
}
|
||||
fetchCipData();
|
||||
@ -180,16 +181,18 @@ useEffect(() => {
|
||||
useEffect(() => {
|
||||
async function fetchIpedsData() {
|
||||
try {
|
||||
const res = await fetch('/ic2023_ay.csv');
|
||||
const res = await authFetch('/api/data/ic2023'); // serves CSV from backend
|
||||
if (!res.ok) throw new Error(`iPEDS error (${res.status})`);
|
||||
const text = await res.text();
|
||||
const rows = text.split('\n').map(line => line.split(','));
|
||||
const headers = rows[0];
|
||||
const headers = rows[0] || [];
|
||||
const dataRows = rows.slice(1).map(row =>
|
||||
Object.fromEntries(row.map((val, idx) => [headers[idx], val]))
|
||||
);
|
||||
setIcTuitionData(dataRows);
|
||||
} catch (err) {
|
||||
console.error("Failed to load iPEDS data:", err);
|
||||
console.error('Failed to load iPEDS data:', err);
|
||||
setIcTuitionData([]);
|
||||
}
|
||||
}
|
||||
fetchIpedsData();
|
||||
|
||||
@ -6,9 +6,9 @@ import parseFloatOrZero from '../utils/ParseFloatorZero.js';
|
||||
import InfoTooltip from "./ui/infoTooltip.js";
|
||||
|
||||
// Data paths
|
||||
const CIP_URL = '/cip_institution_mapping_new.json';
|
||||
const IPEDS_URL = '/ic2023_ay.csv';
|
||||
const CAREER_CLUSTERS_URL = '/career_clusters.json';
|
||||
const CIP_URL = '/api/data/cip-institution-map';
|
||||
const IPEDS_URL = '/api/data/ic2023';
|
||||
const CAREER_CLUSTERS_URL = '/api/data/career_clusters.json';
|
||||
|
||||
export default function ScenarioEditModal({
|
||||
show,
|
||||
@ -182,7 +182,7 @@ export default function ScenarioEditModal({
|
||||
is_in_state: safe(!!c.is_in_state),
|
||||
is_in_district: safe(!!c.is_in_district),
|
||||
is_online: safe(!!c.is_online),
|
||||
college_enrollment_status_db: safe(c.college_enrollment_status || 'not_enrolled'),
|
||||
college_enrollment_status: safe(c.college_enrollment_status || 'not_enrolled'),
|
||||
|
||||
annual_financial_aid : safe(c.annual_financial_aid),
|
||||
existing_college_debt : safe(c.existing_college_debt),
|
||||
|
||||
@ -1,29 +0,0 @@
|
||||
/**
|
||||
* parseAiJson
|
||||
* Attempts to extract a JSON array or object from a string that may include
|
||||
* extra text or a fenced code block (```json ... ```).
|
||||
*
|
||||
* @param {string} rawText - The raw string from the AI response.
|
||||
* @returns {any} - The parsed JSON (object or array).
|
||||
* @throws Will throw an error if parsing fails.
|
||||
*/
|
||||
function parseAIJson(rawText) {
|
||||
if (!rawText || typeof rawText !== 'string') {
|
||||
throw new Error('No valid text provided for parseAiJson.');
|
||||
}
|
||||
|
||||
// 1) Look for a fenced code block with "```json" ... "```"
|
||||
const fencedRegex = /```json\s*([\s\S]*?)\s*```/i;
|
||||
const match = rawText.match(fencedRegex);
|
||||
if (match && match[1]) {
|
||||
// parse the fenced code block
|
||||
const jsonStr = match[1].trim();
|
||||
return JSON.parse(jsonStr);
|
||||
}
|
||||
|
||||
// 2) Fallback: try parsing the entire string directly
|
||||
// Sometimes the AI might return just a raw JSON array without fences
|
||||
return JSON.parse(rawText);
|
||||
}
|
||||
|
||||
export default parseAIJson;
|
||||
Loading…
Reference in New Issue
Block a user