Files
Orchestrator/privat/CV/src/linkedin/experience-generator.ts
T
ankn a5f8fb49ab Migrate all repos into monorepo context folders
Bahn: aisupport, Analyse-O2C-C2S, awesome-bahn-mcp-servers, beam-mcp,
      Confluence_Bot, db-planet-mcp-server, O2C-Harness, project-audit,
      Projekt-KIQ-HP, teamlandkarte-mcp
Dhive: Jury-Voting
Privat: CV, NoteGraph (NOTE: NoteGraph needs complete redo after consolidation)
Shared: AI-Orchestrator, OrgMyLife, power_skills_and_more
Shared/references: symphony (read-only)

Bahn repos remain available as independent remotes - this monorepo
pulls them in via subtree, the originals are untouched.
2026-06-30 20:39:52 +02:00

400 lines
14 KiB
TypeScript

/**
* LinkedIn Experience Generator
*
* Generates result-oriented LinkedIn experience descriptions from KB data.
* Reads person experiences, skills, and projects, then produces optimized
* descriptions with measurable achievements and relevant keywords.
*/
import type { Person, Experience, Organization, Skill, Project } from '../schemas/types';
import type { ExperienceOptions, ExperienceResult } from './types';
import { validateExperience, EXPERIENCE_CHAR_LIMIT } from './constraints';
import { readEntity } from '../io/entity-files';
// --- Internal Types ---
interface ExperienceData {
experience: Experience;
orgName: string;
skills: Skill[];
projects: Project[];
}
// --- Experience Positioning Strategies ---
/**
* Maps experience IDs to positioning strategies that generate
* result-oriented descriptions instead of task lists.
*/
const POSITIONING_STRATEGIES: Record<string, (data: ExperienceData, keywords: string[]) => PositionedContent> = {
'db-infrago-digitalisierung': positionDbInfraGo,
'data-hive-cassel-gruender': positionDataHive,
'db-netz-einfachbahn-jobsharing': positionJobSharing,
'db-netz-einfachbahn-leiter': positionEinfachbahnLeiter,
'uni-kassel-teilgruppenleiter': positionAcademicLeader,
'uni-kassel-doktorand': positionAcademicFoundation,
'uni-kassel-dozent-physik': positionAcademicTeaching,
'hochschule-fresenius-dozent': positionFreseniusDozent,
};
interface PositionedContent {
description: string;
achievements: string[];
keywords: string[];
}
// --- Public API ---
/**
* Generates LinkedIn experience descriptions from KB data.
*
* Reads the person's experiences, enriches them with skills and projects,
* and produces result-oriented descriptions validated against LinkedIn constraints.
*/
export async function generateExperiences(options: ExperienceOptions): Promise<ExperienceResult[]> {
const { personId, experienceIds, keywords = [] } = options;
const person = (await readEntity('person', personId)) as Person;
const targetIds = experienceIds ?? person.experiences ?? [];
const results: ExperienceResult[] = [];
for (const expId of targetIds) {
try {
const data = await loadExperienceData(expId);
const positioned = generatePositionedContent(data, keywords);
const description = truncateToLimit(positioned.description);
const validation = validateExperience(description);
results.push({
experienceId: expId,
title: data.experience.title,
organization: data.orgName,
description,
keywords: positioned.keywords,
achievements: positioned.achievements,
validation,
});
} catch {
// Skip experiences that cannot be loaded
}
}
return results;
}
// --- Data Loading ---
async function loadExperienceData(expId: string): Promise<ExperienceData> {
const experience = (await readEntity('experience', expId)) as Experience;
let orgName = experience.organization;
try {
const org = (await readEntity('organization', experience.organization)) as Organization;
orgName = org.name;
} catch {
// Use raw org ID as fallback
}
const skills: Skill[] = [];
for (const skillId of experience.skillsUsed ?? []) {
try {
const skill = (await readEntity('skill', skillId)) as Skill;
skills.push(skill);
} catch {
// Skip missing skills
}
}
const projects: Project[] = [];
for (const projId of experience.projects ?? []) {
try {
const project = (await readEntity('project', projId)) as Project;
projects.push(project);
} catch {
// Skip missing projects
}
}
return { experience, orgName, skills, projects };
}
// --- Content Generation ---
function generatePositionedContent(data: ExperienceData, requestedKeywords: string[]): PositionedContent {
const strategy = POSITIONING_STRATEGIES[data.experience.id];
if (strategy) {
return strategy(data, requestedKeywords);
}
return generateDefaultContent(data, requestedKeywords);
}
// --- Positioning Strategies ---
function positionDbInfraGo(data: ExperienceData, requestedKeywords: string[]): PositionedContent {
const description = [
'Digitalen Kundennutzen schaffen — mit einem Blick für Technologie und Menschen.',
'',
'Als Experte für Digitalisierung bei DB InfraGO treibe ich die digitale Transformation der Schieneninfrastruktur voran. Mein Fokus: Projekte effizient zum Abschluss bringen und das System Schiene zukunftsfähig machen.',
'',
'Schwerpunkte:',
'→ Digitale Transformation großer Infrastrukturprojekte',
'→ Change Management an der Schnittstelle von IT und Fachbereichen',
'→ Teamführung mit Fokus auf Ergebnisse und Wirkung',
].join('\n');
const achievements = [
'Digitale Transformation der Schieneninfrastruktur vorangetrieben',
'Effiziente Projektsteuerung in komplexem Konzernumfeld',
];
const keywords = mergeKeywords(
['Digitalisierung', 'Digitale Transformation', 'Change Management', 'Infrastruktur', 'DB', 'Schienenverkehr'],
requestedKeywords,
);
return { description, achievements, keywords };
}
function positionDataHive(data: ExperienceData, requestedKeywords: string[]): PositionedContent {
const description = [
'Wir hassen Verschwendung und lieben Wandel.',
'',
'Als Gründer von Data Hive Cassel verbinde ich KI-Expertise mit echtem Veränderungswillen. Mein Anspruch: nicht nur technische Lösungen liefern, sondern nachhaltigen Wandel ermöglichen.',
'',
'Ergebnisse:',
'→ 50+ Projekte erfolgreich umgesetzt',
'→ 15+ Kunden aus Mittelstand und öffentlichem Sektor',
'→ ROI > 2 für Kunden durch datengetriebene Optimierung',
'→ KI praxistauglich gemacht — von der Strategie bis zur Implementierung',
'',
'Schwerpunkte: KI-Beratung, Prozessautomatisierung, Energieeffizienz, Change Management',
].join('\n');
const achievements = [
'50+ Projekte erfolgreich umgesetzt',
'15+ Kunden aus Mittelstand und öffentlichem Sektor',
'ROI > 2 für Kunden durch datengetriebene Optimierung',
'KI praxistauglich gemacht — von der Strategie bis zur Implementierung',
];
const keywords = mergeKeywords(
['Künstliche Intelligenz', 'KI-Beratung', 'Startup', 'Gründer', 'Prozessautomatisierung', 'Change Management', 'Energieeffizienz', 'ROI'],
requestedKeywords,
);
return { description, achievements, keywords };
}
function positionJobSharing(data: ExperienceData, requestedKeywords: string[]): PositionedContent {
const description = [
'Führung ist keine One-Man-Show — und das haben wir bewiesen.',
'',
'Im JobSharing-Tandem mit Claudia Froldi haben wir geteilte Führung auf Augenhöhe im Konzernumfeld etabliert. Ein bewusstes Experiment: Gehaltsverzicht für ein innovatives Führungsmodell.',
'',
'Ergebnisse:',
'→ Shared Leadership als Führungsinnovation im DB-Konzern etabliert',
'→ Komplementäre Stärken: Fachliche Führung + disziplinarische Führung',
'→ Team #Einfachbahn erfolgreich durch Transformation begleitet',
'→ Vorbild für neue Arbeitsmodelle in der Bahnbranche',
].join('\n');
const achievements = [
'Shared Leadership als Führungsinnovation im DB-Konzern etabliert',
'Bewusster Gehaltsverzicht für geteilte Führung auf Augenhöhe',
'Team erfolgreich durch Transformation begleitet',
];
const keywords = mergeKeywords(
['Shared Leadership', 'JobSharing', 'Führungsinnovation', 'New Work', 'Tandem-Führung', 'Transformation'],
requestedKeywords,
);
return { description, achievements, keywords };
}
function positionEinfachbahnLeiter(data: ExperienceData, requestedKeywords: string[]): PositionedContent {
const description = [
'Die Digitalisierung auf die Schiene bringen — eines der ambitioniertesten Vorhaben im Konzernumfeld.',
'',
'Als Leiter #Einfachbahn habe ich ein interdisziplinäres Team aufgebaut und zu Höchstleistungen geführt. Agile Methoden und innovative Arbeitsformen etabliert, Silos aufgebrochen.',
'',
'Ergebnisse:',
'→ Interdisziplinäres Team aufgebaut und agile Methoden etabliert',
'→ Kultur des offenen Lernens geschaffen',
'→ Technische und kulturelle Transformation nachhaltig vorangetrieben',
].join('\n');
const achievements = data.experience.achievements ?? [
'Interdisziplinäres Team aufgebaut und agile Methoden etabliert',
'Silos aufgebrochen und Kultur des offenen Lernens geschaffen',
];
const keywords = mergeKeywords(
['Digitalisierung', 'Agile Führung', 'Transformation', 'Teamaufbau', 'Change Management'],
requestedKeywords,
);
return { description, achievements, keywords };
}
function positionAcademicLeader(data: ExperienceData, requestedKeywords: string[]): PositionedContent {
const description = [
'Vom Labor in die Praxis — hier wurde das Fundament für meine KI-Expertise gelegt.',
'',
'Als Teilgruppenleiter Spektroskopie habe ich Forschung, Teamführung und Technologieentwicklung vereint. Machine Learning seit 2012 in der Praxis angewandt — lange bevor es Mainstream wurde.',
'',
'Ergebnisse:',
'→ 50+ wissenschaftliche Veröffentlichungen, 2.000+ Zitationen',
'→ 12 Mio. € Drittmittel eingeworben (DFG, BMBF, EU)',
'→ Internationale Forschungsteams aufgebaut und geführt',
'→ ML/PyTorch seit 2012 für Datenanalyse eingesetzt',
].join('\n');
const achievements = [
'50+ wissenschaftliche Veröffentlichungen, 2.000+ Zitationen',
'12 Mio. € Drittmittel eingeworben (DFG, BMBF, EU)',
'Internationale Forschungsteams aufgebaut und geführt',
'ML/PyTorch seit 2012 für Datenanalyse eingesetzt',
];
const keywords = mergeKeywords(
['Machine Learning', 'Forschung', 'Künstliche Intelligenz', 'Teamführung', 'Drittmittel', 'Publikationen'],
requestedKeywords,
);
return { description, achievements, keywords };
}
function positionAcademicFoundation(data: ExperienceData, requestedKeywords: string[]): PositionedContent {
const description = [
'Wissenschaftliche Exzellenz als Grundlage für praxisnahe KI-Anwendungen.',
'',
'Promotion in Atom- und Molekülphysik mit Fokus auf experimentelle Methoden und Datenanalyse. Die analytische Denkweise und der systematische Ansatz prägen bis heute meine Arbeit mit KI und Digitalisierung.',
'',
'Ergebnisse:',
'→ 10 wissenschaftliche Paper und 10 internationale Konferenzbeiträge',
'→ Elektronenstrahlquelle von Simulation bis Konstruktion aufgebaut',
'→ Grundstein für 13+ Jahre KI-Erfahrung gelegt',
].join('\n');
const achievements = [
'10 wissenschaftliche Paper und 10 internationale Konferenzbeiträge',
'Elektronenstrahlquelle von Simulation bis Konstruktion aufgebaut',
'Grundstein für 13+ Jahre KI-Erfahrung gelegt',
];
const keywords = mergeKeywords(
['Promotion', 'Physik', 'Forschung', 'Datenanalyse', 'Wissenschaft'],
requestedKeywords,
);
return { description, achievements, keywords };
}
function positionAcademicTeaching(data: ExperienceData, requestedKeywords: string[]): PositionedContent {
const description = [
'Komplexe Themen verständlich machen — eine Kompetenz, die von der Physik bis zur KI-Beratung trägt.',
'',
'Als Dozent für experimentelle Atom- und Molekülphysik habe ich gelernt, anspruchsvolle Inhalte so aufzubereiten, dass sie begeistern und verstanden werden.',
].join('\n');
const achievements = [
'Komplexe wissenschaftliche Inhalte verständlich vermittelt',
];
const keywords = mergeKeywords(
['Lehre', 'Wissensvermittlung', 'Physik', 'Universität'],
requestedKeywords,
);
return { description, achievements, keywords };
}
function positionFreseniusDozent(data: ExperienceData, requestedKeywords: string[]): PositionedContent {
const description = [
'Agilität, Change und Innovation erlebbar machen — nicht nur theoretisch, sondern am eigenen Leib.',
'',
'Als Dozent an der Hochschule Fresenius habe ich MBA-Studierenden gezeigt, warum Agilität, Change, Innovation und Führung zusammengehören. Praxisnah, interaktiv und mit echten Erfahrungen aus Konzern und Startup.',
].join('\n');
const achievements = [
'MBA-Studierende für Agilität und Innovation begeistert',
'Praxiswissen aus Konzern und Startup in die Lehre eingebracht',
];
const keywords = mergeKeywords(
['Agilität', 'Change Management', 'Innovation', 'Führung', 'Lehre', 'MBA'],
requestedKeywords,
);
return { description, achievements, keywords };
}
// --- Default Content Generation ---
function generateDefaultContent(data: ExperienceData, requestedKeywords: string[]): PositionedContent {
const description = data.experience.description?.trim() ?? data.experience.title;
const achievements = data.experience.achievements ?? [];
const keywords = mergeKeywords(
extractSkillKeywords(data.skills),
requestedKeywords,
);
return { description, achievements, keywords };
}
// --- Keyword Helpers ---
const SKILL_KEYWORD_MAP: Record<string, string> = {
'kuenstliche-intelligenz': 'Künstliche Intelligenz',
'change-management': 'Change Management',
'digitale-transformation': 'Digitale Transformation',
'shared-leadership': 'Shared Leadership',
'agilitaet': 'Agilität',
'coaching': 'Coaching',
'team-management': 'Teamführung',
'it-strategie': 'IT-Strategie',
};
function extractSkillKeywords(skills: Skill[]): string[] {
const keywords: string[] = [];
for (const skill of skills) {
const mapped = SKILL_KEYWORD_MAP[skill.id];
if (mapped) {
keywords.push(mapped);
} else {
keywords.push(skill.name);
}
}
return keywords;
}
function mergeKeywords(base: string[], requested: string[]): string[] {
const merged = new Set<string>(base);
for (const kw of requested) {
merged.add(kw);
}
return Array.from(merged);
}
// --- Constraint Helpers ---
function truncateToLimit(text: string): string {
if (text.length <= EXPERIENCE_CHAR_LIMIT) {
return text;
}
const truncated = text.slice(0, EXPERIENCE_CHAR_LIMIT - 1);
const lastNewline = truncated.lastIndexOf('\n');
if (lastNewline > EXPERIENCE_CHAR_LIMIT * 0.7) {
return truncated.slice(0, lastNewline);
}
const lastSpace = truncated.lastIndexOf(' ');
if (lastSpace > EXPERIENCE_CHAR_LIMIT * 0.7) {
return truncated.slice(0, lastSpace) + '…';
}
return truncated + '…';
}