| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887 |
- /**
- * 将 v6.1.2.8 的 run_context.json 转换成按 Round > 步骤 > 数据 组织的图结构
- */
- function convertV8ToGraphV2(runContext, searchResults) {
- const nodes = {};
- const edges = [];
- const iterations = {};
- const o = runContext.o || '原始问题';
- const rounds = runContext.rounds || [];
- // 添加原始问题根节点
- const rootId = 'root_o';
- nodes[rootId] = {
- type: 'root',
- query: o,
- level: 0,
- relevance_score: 1.0,
- strategy: '原始问题',
- iteration: 0,
- is_selected: true
- };
- iterations[0] = [rootId];
- // 处理每一轮
- rounds.forEach((round, roundIndex) => {
- if (round.type === 'initialization') {
- // Round 0: 初始化阶段
- const roundNum = 0;
- const roundId = `round_${roundNum}`;
- // 创建 Round 节点
- nodes[roundId] = {
- type: 'round',
- query: `Round ${roundNum} (初始化)`,
- level: roundNum,
- relevance_score: 0,
- strategy: '初始化',
- iteration: roundNum,
- is_selected: true
- };
- edges.push({
- from: rootId,
- to: roundId,
- edge_type: 'root_to_round',
- strategy: '初始化'
- });
- if (!iterations[roundNum]) iterations[roundNum] = [];
- iterations[roundNum].push(roundId);
- // 创建分词步骤节点
- const segStepId = `step_seg_r${roundNum}`;
- nodes[segStepId] = {
- type: 'step',
- query: `步骤:分词 (${round.seg_list?.length || 0}个分词)`,
- level: roundNum,
- relevance_score: 0,
- strategy: '分词',
- iteration: roundNum,
- is_selected: true
- };
- edges.push({
- from: roundId,
- to: segStepId,
- edge_type: 'round_to_step',
- strategy: '分词'
- });
- iterations[roundNum].push(segStepId);
- // 添加分词结果作为步骤的子节点
- round.seg_list?.forEach((seg, segIndex) => {
- const segId = `seg_${seg.text}_${roundNum}_${segIndex}`;
- nodes[segId] = {
- type: 'seg',
- query: seg.text,
- level: roundNum + 1,
- relevance_score: seg.score || 0,
- evaluationReason: seg.reason || '',
- strategy: '分词结果',
- iteration: roundNum,
- is_selected: true
- };
- edges.push({
- from: segStepId,
- to: segId,
- edge_type: 'step_to_data',
- strategy: '分词结果'
- });
- if (!iterations[roundNum + 1]) iterations[roundNum + 1] = [];
- iterations[roundNum + 1].push(segId);
- });
- } else {
- // 普通轮次
- const roundNum = round.round_num;
- const roundId = `round_${roundNum}`;
- // 创建 Round 节点
- nodes[roundId] = {
- type: 'round',
- query: `Round ${roundNum}`,
- level: roundNum * 10, // 使用10的倍数作为层级
- relevance_score: 0,
- strategy: `第${roundNum}轮`,
- iteration: roundNum,
- is_selected: true
- };
- edges.push({
- from: rootId,
- to: roundId,
- edge_type: 'root_to_round',
- strategy: `第${roundNum}轮`
- });
- if (!iterations[roundNum * 10]) iterations[roundNum * 10] = [];
- iterations[roundNum * 10].push(roundId);
- // 步骤1: 请求&评估推荐词
- if (round.sug_details && Object.keys(round.sug_details).length > 0) {
- const sugStepId = `step_sug_r${roundNum}`;
- const totalSugs = Object.values(round.sug_details).reduce((sum, list) => sum + list.length, 0);
- nodes[sugStepId] = {
- type: 'step',
- query: `步骤1: 请求&评估推荐词 (${totalSugs}个)`,
- level: roundNum * 10 + 1,
- relevance_score: 0,
- strategy: '请求&评估推荐词',
- iteration: roundNum,
- is_selected: true
- };
- edges.push({
- from: roundId,
- to: sugStepId,
- edge_type: 'round_to_step',
- strategy: '推荐词'
- });
- iterations[roundNum * 10].push(sugStepId);
- // 为每个 Q 创建节点
- Object.keys(round.sug_details).forEach((qText, qIndex) => {
- // 从q_list_1中查找对应的q获取分数和理由
- // Round 0: 从q_list_1查找; Round 1+: 从input_q_list查找
- let qData = {};
- if (roundNum === 0) {
- qData = round.q_list_1?.find(q => q.text === qText) || {};
- } else {
- // 从当前轮的input_q_list中查找
- qData = round.input_q_list?.find(q => q.text === qText) || {};
- }
- const qId = `q_${qText}_r${roundNum}_${qIndex}`;
- nodes[qId] = {
- type: 'q',
- query: qText,
- level: roundNum * 10 + 2,
- relevance_score: qData.score || 0,
- evaluationReason: qData.reason || '',
- strategy: 'Query',
- iteration: roundNum,
- is_selected: true
- };
- edges.push({
- from: sugStepId,
- to: qId,
- edge_type: 'step_to_q',
- strategy: 'Query'
- });
- if (!iterations[roundNum * 10 + 2]) iterations[roundNum * 10 + 2] = [];
- iterations[roundNum * 10 + 2].push(qId);
- // 为每个 Q 的 sug 创建节点
- const sugs = round.sug_details[qText] || [];
- sugs.forEach((sug, sugIndex) => {
- const sugId = `sug_${sug.text}_r${roundNum}_q${qIndex}_${sugIndex}`;
- nodes[sugId] = {
- type: 'sug',
- query: sug.text,
- level: roundNum * 10 + 3,
- relevance_score: sug.score || 0,
- evaluationReason: sug.reason || '',
- strategy: '推荐词',
- iteration: roundNum,
- is_selected: true
- };
- edges.push({
- from: qId,
- to: sugId,
- edge_type: 'q_to_sug',
- strategy: '推荐词'
- });
- if (!iterations[roundNum * 10 + 3]) iterations[roundNum * 10 + 3] = [];
- iterations[roundNum * 10 + 3].push(sugId);
- });
- });
- }
- // 步骤2: 筛选并执行搜索
- const searchStepId = `step_search_r${roundNum}`;
- const searchCountText = round.search_count > 0
- ? `筛选${round.high_score_sug_count}个高分词,搜索${round.search_count}次,${round.total_posts}个帖子`
- : `无高分推荐词,未执行搜索`;
- nodes[searchStepId] = {
- type: 'step',
- query: `步骤2: 筛选并执行搜索 (${searchCountText})`,
- level: roundNum * 10 + 1,
- relevance_score: 0,
- strategy: '筛选并执行搜索',
- iteration: roundNum,
- is_selected: true
- };
- edges.push({
- from: roundId,
- to: searchStepId,
- edge_type: 'round_to_step',
- strategy: '搜索'
- });
- iterations[roundNum * 10].push(searchStepId);
- // 只有在有搜索结果时才添加搜索词和帖子
- // 优先使用 round.search_results(新格式),否则使用外部传入的 searchResults(兼容旧版本)
- const roundSearchResults = round.search_results || searchResults;
- if (round.search_count > 0 && roundSearchResults) {
- if (Array.isArray(roundSearchResults)) {
- roundSearchResults.forEach((search, searchIndex) => {
- const searchWordId = `search_${search.text}_r${roundNum}_${searchIndex}`;
- nodes[searchWordId] = {
- type: 'search_word',
- query: search.text,
- level: roundNum * 10 + 2,
- relevance_score: search.score_with_o || 0,
- strategy: '搜索词',
- iteration: roundNum,
- is_selected: true
- };
- edges.push({
- from: searchStepId,
- to: searchWordId,
- edge_type: 'step_to_search_word',
- strategy: '搜索词'
- });
- if (!iterations[roundNum * 10 + 2]) iterations[roundNum * 10 + 2] = [];
- iterations[roundNum * 10 + 2].push(searchWordId);
- // 添加帖子
- if (search.post_list && search.post_list.length > 0) {
- search.post_list.forEach((post, postIndex) => {
- const postId = `post_${post.note_id}_${searchIndex}_${postIndex}`;
- // 准备图片列表,将URL字符串转换为对象格式供轮播图使用
- const imageList = (post.images || []).map(url => ({
- image_url: url
- }));
- nodes[postId] = {
- type: 'post',
- query: post.title,
- level: roundNum * 10 + 3,
- relevance_score: 0,
- strategy: '帖子',
- iteration: roundNum,
- is_selected: true,
- note_id: post.note_id,
- note_url: post.note_url,
- body_text: post.body_text || '',
- images: post.images || [],
- image_list: imageList,
- interact_info: post.interact_info || {}
- };
- edges.push({
- from: searchWordId,
- to: postId,
- edge_type: 'search_word_to_post',
- strategy: '搜索结果'
- });
- if (!iterations[roundNum * 10 + 3]) iterations[roundNum * 10 + 3] = [];
- iterations[roundNum * 10 + 3].push(postId);
- });
- }
- });
- }
- }
- // 步骤3: 加词生成新查询
- if (round.add_word_details && Object.keys(round.add_word_details).length > 0) {
- const addWordStepId = `step_add_r${roundNum}`;
- const totalAddWords = Object.values(round.add_word_details).reduce((sum, list) => sum + list.length, 0);
- nodes[addWordStepId] = {
- type: 'step',
- query: `步骤3: 加词生成新查询 (${totalAddWords}个)`,
- level: roundNum * 10 + 1,
- relevance_score: 0,
- strategy: '加词生成新查询',
- iteration: roundNum,
- is_selected: true
- };
- edges.push({
- from: roundId,
- to: addWordStepId,
- edge_type: 'round_to_step',
- strategy: '加词'
- });
- iterations[roundNum * 10].push(addWordStepId);
- // 为每个 Seed 创建节点
- Object.keys(round.add_word_details).forEach((seedText, seedIndex) => {
- const seedId = `seed_${seedText}_r${roundNum}_${seedIndex}`;
- // 查找seed的来源信息 - 从Round 0的seed_list查找基础种子的from_type
- const round0 = rounds.find(r => r.round_num === 0 || r.type === 'initialization');
- const seedInfo = round0?.seed_list?.find(s => s.text === seedText) || {};
- const fromType = seedInfo.from_type || 'unknown';
- // 根据来源设置strategy
- let strategy;
- if (fromType === 'seg') {
- strategy = '初始分词';
- } else if (fromType === 'add') {
- strategy = '加词';
- } else if (fromType === 'sug') {
- strategy = '调用sug';
- } else {
- strategy = 'Seed'; // 默认灰色
- }
- nodes[seedId] = {
- type: 'seed',
- query: seedText,
- level: roundNum * 10 + 2,
- relevance_score: 0,
- strategy: strategy,
- iteration: roundNum,
- is_selected: true
- };
- edges.push({
- from: addWordStepId,
- to: seedId,
- edge_type: 'step_to_seed',
- strategy: 'Seed'
- });
- if (!iterations[roundNum * 10 + 2]) iterations[roundNum * 10 + 2] = [];
- iterations[roundNum * 10 + 2].push(seedId);
- // 为每个 Seed 的组合词创建节点
- const combinedWords = round.add_word_details[seedText] || [];
- combinedWords.forEach((word, wordIndex) => {
- const wordId = `add_${word.text}_r${roundNum}_seed${seedIndex}_${wordIndex}`;
- nodes[wordId] = {
- type: 'add_word',
- query: word.text,
- level: roundNum * 10 + 3,
- relevance_score: word.score || 0,
- evaluationReason: word.reason || '',
- strategy: '加词生成',
- iteration: roundNum,
- is_selected: true,
- selected_word: word.selected_word
- };
- edges.push({
- from: seedId,
- to: wordId,
- edge_type: 'seed_to_add_word',
- strategy: '组合词'
- });
- if (!iterations[roundNum * 10 + 3]) iterations[roundNum * 10 + 3] = [];
- iterations[roundNum * 10 + 3].push(wordId);
- });
- });
- }
- // 步骤4: 筛选推荐词进入下轮
- const filteredSugs = round.output_q_list?.filter(q => q.from === 'sug') || [];
- if (filteredSugs.length > 0) {
- const filterStepId = `step_filter_r${roundNum}`;
- nodes[filterStepId] = {
- type: 'step',
- query: `步骤4: 筛选推荐词进入下轮 (${filteredSugs.length}个)`,
- level: roundNum * 10 + 1,
- relevance_score: 0,
- strategy: '筛选推荐词进入下轮',
- iteration: roundNum,
- is_selected: true
- };
- edges.push({
- from: roundId,
- to: filterStepId,
- edge_type: 'round_to_step',
- strategy: '筛选'
- });
- iterations[roundNum * 10].push(filterStepId);
- // 添加筛选出的sug
- filteredSugs.forEach((sug, sugIndex) => {
- const sugId = `filtered_sug_${sug.text}_r${roundNum}_${sugIndex}`;
- nodes[sugId] = {
- type: 'filtered_sug',
- query: sug.text,
- level: roundNum * 10 + 2,
- relevance_score: sug.score || 0,
- strategy: '进入下轮',
- iteration: roundNum,
- is_selected: true
- };
- edges.push({
- from: filterStepId,
- to: sugId,
- edge_type: 'step_to_filtered_sug',
- strategy: '进入下轮'
- });
- if (!iterations[roundNum * 10 + 2]) iterations[roundNum * 10 + 2] = [];
- iterations[roundNum * 10 + 2].push(sugId);
- });
- }
- // 步骤5: 构建下一轮
- const nextRoundStepId = `step_next_round_r${roundNum}`;
- const nextQCount = round.output_q_list?.length || 0;
- const nextSeedCount = round.seed_list_next_size || 0;
- nodes[nextRoundStepId] = {
- type: 'step',
- query: `步骤5: 构建下一轮 (${nextQCount}个查询, ${nextSeedCount}个种子)`,
- level: roundNum * 10 + 1,
- relevance_score: 0,
- strategy: '构建下一轮',
- iteration: roundNum,
- is_selected: true
- };
- edges.push({
- from: roundId,
- to: nextRoundStepId,
- edge_type: 'round_to_step',
- strategy: '构建下一轮'
- });
- iterations[roundNum * 10].push(nextRoundStepId);
- // 5.1: 构建下轮查询
- if (round.output_q_list && round.output_q_list.length > 0) {
- const nextQStepId = `step_next_q_r${roundNum}`;
- nodes[nextQStepId] = {
- type: 'step',
- query: `构建下轮查询 (${nextQCount}个)`,
- level: roundNum * 10 + 2,
- relevance_score: 0,
- strategy: '下轮查询',
- iteration: roundNum,
- is_selected: true
- };
- edges.push({
- from: nextRoundStepId,
- to: nextQStepId,
- edge_type: 'step_to_step',
- strategy: '查询'
- });
- if (!iterations[roundNum * 10 + 2]) iterations[roundNum * 10 + 2] = [];
- iterations[roundNum * 10 + 2].push(nextQStepId);
- // 添加下轮查询列表
- round.output_q_list.forEach((q, qIndex) => {
- const nextQId = `next_q_${q.text}_r${roundNum}_${qIndex}`;
- // 根据来源设置strategy
- let strategy;
- if (q.from === 'seg') {
- strategy = '初始分词';
- } else if (q.from === 'add') {
- strategy = '加词';
- } else if (q.from === 'sug') {
- strategy = '调用sug';
- } else {
- strategy = 'Query'; // 默认
- }
- nodes[nextQId] = {
- type: 'next_q',
- query: q.text,
- level: roundNum * 10 + 3,
- relevance_score: q.score || 0,
- evaluationReason: q.reason || '',
- strategy: strategy,
- iteration: roundNum,
- is_selected: true,
- from_source: q.from
- };
- edges.push({
- from: nextQStepId,
- to: nextQId,
- edge_type: 'step_to_next_q',
- strategy: strategy
- });
- if (!iterations[roundNum * 10 + 3]) iterations[roundNum * 10 + 3] = [];
- iterations[roundNum * 10 + 3].push(nextQId);
- });
- }
- // 5.2: 构建下轮种子(如果有数据的话)
- if (nextSeedCount > 0 && round.seed_list_next) {
- const nextSeedStepId = `step_next_seed_r${roundNum}`;
- nodes[nextSeedStepId] = {
- type: 'step',
- query: `构建下轮种子 (${nextSeedCount}个)`,
- level: roundNum * 10 + 2,
- relevance_score: 0,
- strategy: '下轮种子',
- iteration: roundNum,
- is_selected: true
- };
- edges.push({
- from: nextRoundStepId,
- to: nextSeedStepId,
- edge_type: 'step_to_step',
- strategy: '种子'
- });
- if (!iterations[roundNum * 10 + 2]) iterations[roundNum * 10 + 2] = [];
- iterations[roundNum * 10 + 2].push(nextSeedStepId);
- // 添加下轮种子列表
- round.seed_list_next.forEach((seed, seedIndex) => {
- const nextSeedId = `next_seed_${seed.text}_r${roundNum}_${seedIndex}`;
- // 根据来源设置strategy
- let strategy;
- if (seed.from === 'seg') {
- strategy = '初始分词';
- } else if (seed.from === 'add') {
- strategy = '加词';
- } else if (seed.from === 'sug') {
- strategy = '调用sug';
- } else {
- strategy = 'Seed'; // 默认
- }
- nodes[nextSeedId] = {
- type: 'next_seed',
- query: seed.text,
- level: roundNum * 10 + 3,
- relevance_score: seed.score || 0,
- strategy: strategy,
- iteration: roundNum,
- is_selected: true,
- from_source: seed.from
- };
- edges.push({
- from: nextSeedStepId,
- to: nextSeedId,
- edge_type: 'step_to_next_seed',
- strategy: strategy
- });
- if (!iterations[roundNum * 10 + 3]) iterations[roundNum * 10 + 3] = [];
- iterations[roundNum * 10 + 3].push(nextSeedId);
- });
- }
- }
- });
- return {
- nodes,
- edges,
- iterations
- };
- }
- /**
- * 简化版转换:专注于query和post的演化
- * - 合并所有query节点(不区分seg/sug/add_word)
- * - 合并相同的帖子节点
- * - 步骤信息放在边上
- * - 隐藏Round/Step节点
- */
- function convertV8ToGraphSimplified(runContext, searchResults) {
- const mergedNodes = {};
- const edges = [];
- const iterations = {};
- const o = runContext.o || '原始问题';
- const rounds = runContext.rounds || [];
- // 添加原始问题根节点
- const rootId = 'root_o';
- mergedNodes[rootId] = {
- type: 'root',
- query: o,
- level: 0,
- relevance_score: 1.0,
- strategy: '原始问题',
- iteration: 0,
- is_selected: true,
- occurrences: [{round: 0, role: 'root', score: 1.0}]
- };
- iterations[0] = [rootId];
- // 用于记录节点之间的演化关系
- const queryEvolution = {}; // {text: {occurrences: [], parentTexts: [], childTexts: []}}
- const postMap = {}; // {note_id: {...}}
- // 第一遍:收集所有query和post
- rounds.forEach((round, roundIndex) => {
- const roundNum = round.round_num || roundIndex;
- if (round.type === 'initialization') {
- // Round 0: 收集分词结果
- (round.q_list_1 || []).forEach(q => {
- if (!queryEvolution[q.text]) {
- queryEvolution[q.text] = {
- occurrences: [],
- parentTexts: new Set([o]), // 来自原始问题
- childTexts: new Set()
- };
- }
- queryEvolution[q.text].occurrences.push({
- round: roundNum,
- role: 'segmentation',
- strategy: '分词',
- score: q.score,
- reason: q.reason
- });
- });
- } else {
- // Round 1+
- // 收集sug_details (推荐词)
- Object.entries(round.sug_details || {}).forEach(([parentText, sugs]) => {
- sugs.forEach(sug => {
- if (!queryEvolution[sug.text]) {
- queryEvolution[sug.text] = {
- occurrences: [],
- parentTexts: new Set(),
- childTexts: new Set()
- };
- }
- queryEvolution[sug.text].occurrences.push({
- round: roundNum,
- role: 'sug',
- strategy: '调用sug',
- score: sug.score,
- reason: sug.reason
- });
- queryEvolution[sug.text].parentTexts.add(parentText);
- if (queryEvolution[parentText]) {
- queryEvolution[parentText].childTexts.add(sug.text);
- }
- });
- });
- // 收集add_word_details (加词结果)
- Object.entries(round.add_word_details || {}).forEach(([seedText, words]) => {
- words.forEach(word => {
- if (!queryEvolution[word.text]) {
- queryEvolution[word.text] = {
- occurrences: [],
- parentTexts: new Set(),
- childTexts: new Set()
- };
- }
- queryEvolution[word.text].occurrences.push({
- round: roundNum,
- role: 'add_word',
- strategy: '加词',
- score: word.score,
- reason: word.reason,
- selectedWord: word.selected_word
- });
- queryEvolution[word.text].parentTexts.add(seedText);
- if (queryEvolution[seedText]) {
- queryEvolution[seedText].childTexts.add(word.text);
- }
- });
- });
- // 收集搜索结果和帖子
- const roundSearchResults = round.search_results || searchResults;
- if (roundSearchResults && Array.isArray(roundSearchResults)) {
- roundSearchResults.forEach(search => {
- const searchText = search.text;
- // 标记这个query被用于搜索
- if (queryEvolution[searchText]) {
- queryEvolution[searchText].occurrences.push({
- round: roundNum,
- role: 'search',
- strategy: '执行搜索',
- score: search.score_with_o,
- postCount: search.post_list ? search.post_list.length : 0
- });
- }
- // 收集帖子
- if (search.post_list && search.post_list.length > 0) {
- search.post_list.forEach(post => {
- if (!postMap[post.note_id]) {
- postMap[post.note_id] = {
- ...post,
- foundByQueries: new Set(),
- foundInRounds: new Set()
- };
- }
- postMap[post.note_id].foundByQueries.add(searchText);
- postMap[post.note_id].foundInRounds.add(roundNum);
- // 建立query到post的关系
- if (!queryEvolution[searchText].posts) {
- queryEvolution[searchText].posts = new Set();
- }
- queryEvolution[searchText].posts.add(post.note_id);
- });
- }
- });
- }
- }
- });
- // 第二遍:创建合并后的节点
- Object.entries(queryEvolution).forEach(([text, data]) => {
- const nodeId = `query_${text}`;
- // 获取最新的分数
- const latestOccurrence = data.occurrences[data.occurrences.length - 1] || {};
- const hasSearchResults = data.posts && data.posts.size > 0;
- mergedNodes[nodeId] = {
- type: 'query',
- query: text,
- level: Math.max(...data.occurrences.map(o => o.round), 0) * 10 + 2,
- relevance_score: latestOccurrence.score || 0,
- evaluationReason: latestOccurrence.reason || '',
- strategy: data.occurrences.map(o => o.strategy).join(' + '),
- primaryStrategy: latestOccurrence.strategy || '未知', // 添加主要策略字段
- iteration: Math.max(...data.occurrences.map(o => o.round), 0),
- is_selected: true,
- occurrences: data.occurrences,
- hasSearchResults: hasSearchResults,
- postCount: data.posts ? data.posts.size : 0,
- selectedWord: data.occurrences.find(o => o.selectedWord)?.selectedWord || ''
- };
- // 添加到对应的轮次
- const maxRound = Math.max(...data.occurrences.map(o => o.round), 0);
- const iterKey = maxRound * 10 + 2;
- if (!iterations[iterKey]) iterations[iterKey] = [];
- iterations[iterKey].push(nodeId);
- });
- // 创建帖子节点
- Object.entries(postMap).forEach(([noteId, post]) => {
- const postId = `post_${noteId}`;
- const imageList = (post.images || []).map(url => ({
- image_url: url
- }));
- mergedNodes[postId] = {
- type: 'post',
- query: post.title,
- level: 100, // 放在最后
- relevance_score: 0,
- strategy: '帖子',
- iteration: Math.max(...Array.from(post.foundInRounds)),
- is_selected: true,
- note_id: post.note_id,
- note_url: post.note_url,
- body_text: post.body_text || '',
- images: post.images || [],
- image_list: imageList,
- interact_info: post.interact_info || {},
- foundByQueries: Array.from(post.foundByQueries),
- foundInRounds: Array.from(post.foundInRounds)
- };
- if (!iterations[100]) iterations[100] = [];
- iterations[100].push(postId);
- });
- // 第三遍:创建边
- // 1. 原始问题 -> 分词结果
- Object.entries(queryEvolution).forEach(([text, data]) => {
- const nodeId = `query_${text}`;
- const segOccurrence = data.occurrences.find(o => o.role === 'segmentation');
- if (segOccurrence && data.parentTexts.has(o)) {
- edges.push({
- from: rootId,
- to: nodeId,
- edge_type: 'segmentation',
- strategy: '分词',
- label: '分词',
- round: 0
- });
- }
- });
- // 2. Query演化关系
- Object.entries(queryEvolution).forEach(([text, data]) => {
- const nodeId = `query_${text}`;
- data.parentTexts.forEach(parentText => {
- if (parentText === o) return; // 跳过原始问题(已处理)
- const parentNodeId = `query_${parentText}`;
- if (!mergedNodes[parentNodeId]) return;
- // 找到这个演化的策略和轮次
- const occurrence = data.occurrences.find(o =>
- o.role === 'sug' || o.role === 'add_word'
- );
- edges.push({
- from: parentNodeId,
- to: nodeId,
- edge_type: occurrence?.role || 'evolution',
- strategy: occurrence?.strategy || '演化',
- label: `${occurrence?.strategy || '演化'} (R${occurrence?.round || 0})`,
- round: occurrence?.round || 0
- });
- });
- });
- // 3. Query -> Post (搜索关系)
- Object.entries(queryEvolution).forEach(([text, data]) => {
- const nodeId = `query_${text}`;
- if (data.posts && data.posts.size > 0) {
- const searchOccurrence = data.occurrences.find(o => o.role === 'search');
- data.posts.forEach(noteId => {
- const postId = `post_${noteId}`;
- edges.push({
- from: nodeId,
- to: postId,
- edge_type: 'search',
- strategy: '搜索',
- label: `搜索 (${data.posts.size}个帖子)`,
- round: searchOccurrence?.round || 0
- });
- });
- }
- });
- return {
- nodes: mergedNodes,
- edges,
- iterations
- };
- }
- module.exports = { convertV8ToGraphV2, convertV8ToGraphSimplified };
|