g2log 1.4.1 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/git-user-log.js +159 -128
  2. package/package.json +1 -1
package/git-user-log.js CHANGED
@@ -676,6 +676,12 @@ Git提交记录:
676
676
  let aiResponse = '';
677
677
  const providerLower = apiProvider.toLowerCase();
678
678
 
679
+ // 输出AI总结的标题信息
680
+ console.log(`\n${colorize('📊 ' + author + ' 的工作总结', 'bright')}`);
681
+ console.log(`${colorize('📅 时间范围: ' + since + ' 至 ' + until, 'green')}`);
682
+ console.log(`${colorize('🤖 使用模型: ' + modelName, 'cyan')}`);
683
+ console.log(`${colorize('=' .repeat(30), 'bright')}\n`);
684
+
679
685
  // 根据提供商名称选择对应的实现
680
686
  if (providerLower === 'openai') {
681
687
  aiResponse = await getOpenAIResponse(apiKey, prompt, modelName, apiBaseURL, spinner);
@@ -687,43 +693,6 @@ Git提交记录:
687
693
  // 停止spinner并显示成功消息
688
694
  if (spinner) spinner.stop('✅ AI总结已生成');
689
695
 
690
- // 格式化并输出AI总结
691
- console.log(`\n${colorize('📊 ' + author + ' 的工作总结', 'bright')}`);
692
- console.log(`${colorize('📅 时间范围: ' + since + ' 至 ' + until, 'green')}`);
693
- console.log(`${colorize('🤖 使用模型: ' + modelName, 'cyan')}`);
694
- console.log(`${colorize('=' .repeat(30), 'bright')}\n`);
695
-
696
- // 分段输出并优化格式
697
- const lines = aiResponse.split('\n');
698
- for (let i = 0; i < lines.length; i++) {
699
- const line = lines[i];
700
-
701
- // 为标题添加颜色
702
- if (line.startsWith('# ')) {
703
- console.log(colorize(line, 'bright'));
704
- }
705
- // 为子标题添加颜色
706
- else if (line.startsWith('## ')) {
707
- console.log(colorize(line, 'yellow'));
708
- }
709
- // 为列表项添加图标和颜色
710
- else if (line.trim().startsWith('- ')) {
711
- console.log(colorize(' • ' + line.trim().substring(2), 'reset'));
712
- }
713
- // 为数字列表添加颜色
714
- else if (/^\d+\.\s/.test(line.trim())) {
715
- console.log(colorize(' ' + line.trim(), 'reset'));
716
- }
717
- // 为分隔线添加颜色
718
- else if (line.trim().startsWith('---')) {
719
- console.log(colorize(' ' + '─'.repeat(30), 'dim'));
720
- }
721
- // 普通文本
722
- else {
723
- console.log(colorize(line, 'reset'));
724
- }
725
- }
726
-
727
696
  return aiResponse;
728
697
  } catch (error) {
729
698
  if (spinner) spinner.fail(`❌ AI总结失败: ${error.message}`);
@@ -758,7 +727,7 @@ async function getOpenAIResponse(apiKey, prompt, modelName, apiBaseURL, spinner
758
727
  };
759
728
 
760
729
  // 打印请求内容
761
- console.log(colorize('\n📨 发送给OpenAI的请求:', 'cyan'));
730
+ console.log(colorize('\n📨 发送给AI的请求:', 'cyan'));
762
731
  console.log(colorize(`📌 API端点: ${url}`, 'dim'));
763
732
  console.log(colorize(`🤖 使用模型: ${data.model}`, 'dim'));
764
733
  console.log(colorize(`🌡️ 温度: ${data.temperature}`, 'dim'));
@@ -766,7 +735,7 @@ async function getOpenAIResponse(apiKey, prompt, modelName, apiBaseURL, spinner
766
735
  console.log(colorize('📄 系统角色: ' + data.messages[0].content, 'dim'));
767
736
  console.log(colorize('💬 提示内容预览: ' + data.messages[1].content.substring(0, 150) + '...', 'dim'));
768
737
 
769
- if (spinner) spinner.update('🔄 正在向OpenAI发送请求...');
738
+ if (spinner) spinner.update('🔄 正在向AI发送请求...\n');
770
739
 
771
740
  return new Promise((resolve, reject) => {
772
741
  try {
@@ -785,76 +754,107 @@ async function getOpenAIResponse(apiKey, prompt, modelName, apiBaseURL, spinner
785
754
  // 确定使用http还是https
786
755
  const protocol = urlObj.protocol === 'https:' ? require('https') : require('http');
787
756
 
788
- // 创建请求
789
- const req = protocol.request(options, (res) => {
757
+ // 创建请求
758
+ const req = protocol.request(options, (res) => {
790
759
  // 检查状态码
791
- if (res.statusCode !== 200) {
792
- let errorData = '';
793
- res.on('data', chunk => {
794
- errorData += chunk.toString();
795
- });
796
- res.on('end', () => {
760
+ if (res.statusCode !== 200) {
761
+ let errorData = '';
762
+ res.on('data', chunk => {
763
+ errorData += chunk.toString();
764
+ });
765
+ res.on('end', () => {
797
766
  let errorMessage = `OpenAI API请求失败 (${res.statusCode})`;
798
- try {
799
- const parsedError = JSON.parse(errorData);
767
+ try {
768
+ const parsedError = JSON.parse(errorData);
800
769
  errorMessage += `: ${JSON.stringify(parsedError)}`;
801
- } catch (e) {
770
+ } catch (e) {
802
771
  errorMessage += `: ${errorData}`;
803
772
  }
804
773
  if (spinner) spinner.fail(`❌ ${errorMessage}`);
805
774
  reject(new Error(errorMessage));
806
- });
807
- return;
808
- }
809
-
810
- let fullContent = '';
811
- let buffer = '';
812
-
813
- // 处理数据
814
- res.on('data', (chunk) => {
815
- // 将新的数据添加到缓冲区
816
- buffer += chunk.toString();
775
+ });
776
+ return;
777
+ }
817
778
 
818
- // 尝试从缓冲区中提取完整的SSE消息
819
- let match;
820
- const dataRegex = /data: (.*?)\n\n/gs;
779
+ let fullContent = '';
780
+ let buffer = '';
821
781
 
822
- while ((match = dataRegex.exec(buffer)) !== null) {
823
- const data = match[1];
782
+ // 处理数据
783
+ res.on('data', (chunk) => {
784
+ // 将新的数据添加到缓冲区
785
+ const data = chunk.toString();
786
+ buffer += data;
824
787
 
825
- // 跳过 [DONE] 消息
826
- if (data === '[DONE]') continue;
788
+ // 尝试从缓冲区中提取完整的SSE消息
789
+ const messages = buffer.split('\n\n');
827
790
 
828
- try {
829
- const parsedData = JSON.parse(data);
791
+ // 处理除了最后一个可能不完整的消息之外的所有消息
792
+ for (let i = 0; i < messages.length - 1; i++) {
793
+ const message = messages[i].trim();
794
+ if (!message) continue; // 跳过空消息
830
795
 
831
- // 获取内容增量
832
- if (parsedData.choices &&
833
- parsedData.choices[0] &&
834
- parsedData.choices[0].delta &&
835
- parsedData.choices[0].delta.content) {
836
- const content = parsedData.choices[0].delta.content;
837
- fullContent += content;
838
-
839
- // 直接输出内容增量到控制台
840
- process.stdout.write(content);
796
+ // 处理SSE格式的消息
797
+ if (message.startsWith('data: ')) {
798
+ const content = message.substring(6); // 移除 'data: ' 前缀
799
+
800
+ // 跳过[DONE]消息
801
+ if (content === '[DONE]') continue;
802
+
803
+ try {
804
+ const parsed = JSON.parse(content);
805
+ if (parsed.choices &&
806
+ parsed.choices[0] &&
807
+ parsed.choices[0].delta &&
808
+ parsed.choices[0].delta.content) {
809
+ const contentPart = parsed.choices[0].delta.content;
810
+ fullContent += contentPart;
811
+
812
+ // 直接输出内容增量到控制台
813
+ process.stdout.write(contentPart);
814
+ }
815
+ } catch (err) {
816
+ // 忽略解析错误,但在调试模式下输出
817
+ if (process.argv.includes('--debug')) {
818
+ console.error(`解析错误: ${err.message} for content: ${content}`);
819
+ }
841
820
  }
842
- } catch (err) {
843
- // 忽略解析错误
844
821
  }
845
822
  }
846
823
 
847
- // 保留可能不完整的最后一部分
848
- const lastIndex = buffer.lastIndexOf('\n\n');
849
- if (lastIndex !== -1) {
850
- buffer = buffer.substring(lastIndex + 2);
851
- }
824
+ // 保留最后一个可能不完整的消息
825
+ buffer = messages[messages.length - 1];
852
826
  });
853
827
 
854
- // 处理结束
828
+ // 处理响应结束
855
829
  res.on('end', () => {
856
- if (spinner) spinner.stop('✅ OpenAI响应已接收');
857
- console.log(); // 添加换行符
830
+ // 处理缓冲区中可能剩余的内容
831
+ if (buffer.trim()) {
832
+ const lines = buffer.split('\n');
833
+ for (const line of lines) {
834
+ if (line.startsWith('data: ') && line.substring(6) !== '[DONE]') {
835
+ try {
836
+ const parsed = JSON.parse(line.substring(6));
837
+ if (parsed.choices &&
838
+ parsed.choices[0] &&
839
+ parsed.choices[0].delta &&
840
+ parsed.choices[0].delta.content) {
841
+ const contentPart = parsed.choices[0].delta.content;
842
+ fullContent += contentPart;
843
+
844
+ // 直接输出内容增量到控制台
845
+ process.stdout.write(contentPart);
846
+ }
847
+ } catch (err) {
848
+ // 忽略解析错误
849
+ }
850
+ }
851
+ }
852
+ }
853
+
854
+ // 确保输出后有换行符
855
+ console.log(); // 强制添加换行符
856
+
857
+ if (spinner) spinner.stop('✅ AI响应已结束');
858
858
  resolve(fullContent);
859
859
  });
860
860
  });
@@ -910,7 +910,7 @@ async function getDeepSeekResponse(apiKey, prompt, modelName, apiBaseURL, spinne
910
910
  console.log(colorize('📄 系统角色: ' + data.messages[0].content, 'dim'));
911
911
  console.log(colorize('💬 提示内容预览: ' + data.messages[1].content.substring(0, 150) + '...', 'dim'));
912
912
 
913
- if (spinner) spinner.update('🔄 正在AI发送请求...\n');
913
+ if (spinner) spinner.update('🔄 正在向AI发送请求...\n');
914
914
 
915
915
  return new Promise((resolve, reject) => {
916
916
  try {
@@ -957,52 +957,83 @@ async function getDeepSeekResponse(apiKey, prompt, modelName, apiBaseURL, spinne
957
957
  // 处理数据
958
958
  res.on('data', (chunk) => {
959
959
  // 将新的数据添加到缓冲区
960
- buffer += chunk.toString();
960
+ const data = chunk.toString();
961
+ buffer += data;
961
962
 
962
963
  // 尝试从缓冲区中提取完整的SSE消息
963
- let match;
964
- const dataRegex = /data: (.*?)\n\n/gs;
964
+ const messages = buffer.split('\n\n');
965
965
 
966
- while ((match = dataRegex.exec(buffer)) !== null) {
967
- const data = match[1];
966
+ // 处理除了最后一个可能不完整的消息之外的所有消息
967
+ for (let i = 0; i < messages.length - 1; i++) {
968
+ const message = messages[i].trim();
969
+ if (!message) continue; // 跳过空消息
968
970
 
969
- // 跳过 [DONE] 消息
970
- if (data === '[DONE]') continue;
971
-
972
- try {
973
- const parsedData = JSON.parse(data);
971
+ // 处理SSE格式的消息
972
+ if (message.startsWith('data: ')) {
973
+ const content = message.substring(6); // 移除 'data: ' 前缀
974
974
 
975
- // 获取内容增量
976
- if (parsedData.choices &&
977
- parsedData.choices[0] &&
978
- parsedData.choices[0].delta &&
979
- parsedData.choices[0].delta.content) {
980
- const content = parsedData.choices[0].delta.content;
981
- fullContent += content;
982
-
983
- // 直接输出内容增量到控制台
984
- process.stdout.write(content);
975
+ // 跳过[DONE]消息
976
+ if (content === '[DONE]') continue;
977
+
978
+ try {
979
+ const parsed = JSON.parse(content);
980
+ if (parsed.choices &&
981
+ parsed.choices[0] &&
982
+ parsed.choices[0].delta &&
983
+ parsed.choices[0].delta.content) {
984
+ const contentPart = parsed.choices[0].delta.content;
985
+ fullContent += contentPart;
986
+
987
+ // 直接输出内容增量到控制台
988
+ process.stdout.write(contentPart);
989
+ }
990
+ } catch (err) {
991
+ // 忽略解析错误,但在调试模式下输出
992
+ if (process.argv.includes('--debug')) {
993
+ console.error(`解析错误: ${err.message} for content: ${content}`);
994
+ }
995
+ }
985
996
  }
986
- } catch (err) {
987
- // 忽略解析错误
988
997
  }
989
- }
998
+
999
+ // 保留最后一个可能不完整的消息
1000
+ buffer = messages[messages.length - 1];
1001
+ });
990
1002
 
991
- // 保留可能不完整的最后一部分
992
- const lastIndex = buffer.lastIndexOf('\n\n');
993
- if (lastIndex !== -1) {
994
- buffer = buffer.substring(lastIndex + 2);
995
- }
996
- });
997
-
998
- // 处理结束
999
- res.on('end', () => {
1000
- if (spinner) spinner.stop('✅ AI响应已接收');
1001
- console.log(); // 添加换行符
1003
+ // 处理响应结束
1004
+ res.on('end', () => {
1005
+ // 处理缓冲区中可能剩余的内容
1006
+ if (buffer.trim()) {
1007
+ const lines = buffer.split('\n');
1008
+ for (const line of lines) {
1009
+ if (line.startsWith('data: ') && line.substring(6) !== '[DONE]') {
1010
+ try {
1011
+ const parsed = JSON.parse(line.substring(6));
1012
+ if (parsed.choices &&
1013
+ parsed.choices[0] &&
1014
+ parsed.choices[0].delta &&
1015
+ parsed.choices[0].delta.content) {
1016
+ const contentPart = parsed.choices[0].delta.content;
1017
+ fullContent += contentPart;
1018
+
1019
+ // 直接输出内容增量到控制台
1020
+ process.stdout.write(contentPart);
1021
+ }
1022
+ } catch (err) {
1023
+ // 忽略解析错误
1024
+ }
1025
+ }
1026
+ }
1027
+ }
1028
+
1029
+ // 确保输出后有换行符
1030
+ console.log(); // 强制添加换行符
1031
+
1032
+ if (spinner) spinner.stop('✅ AI响应已结束');
1002
1033
  resolve(fullContent);
1034
+ });
1003
1035
  });
1004
- });
1005
-
1036
+
1006
1037
  // 处理请求错误
1007
1038
  req.on('error', (error) => {
1008
1039
  if (spinner) spinner.fail(`❌ DeepSeek API网络错误: ${error.message}`);
@@ -1011,7 +1042,7 @@ async function getDeepSeekResponse(apiKey, prompt, modelName, apiBaseURL, spinne
1011
1042
 
1012
1043
  // 发送请求体
1013
1044
  req.write(JSON.stringify(data));
1014
- req.end();
1045
+ req.end();
1015
1046
  } catch (error) {
1016
1047
  if (spinner) spinner.fail(`❌ DeepSeek API错误: ${error.message}`);
1017
1048
  reject(error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "g2log",
3
- "version": "1.4.1",
3
+ "version": "1.4.3",
4
4
  "description": "查询特定用户和时间范围的Git提交记录并通过AI进行总结,可通过npx直接运行",
5
5
  "main": "git-user-log.js",
6
6
  "bin": {