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.
- package/git-user-log.js +159 -128
- 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📨 发送给
|
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('🔄 正在向
|
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
|
-
|
757
|
+
// 创建请求
|
758
|
+
const req = protocol.request(options, (res) => {
|
790
759
|
// 检查状态码
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
|
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
|
-
|
799
|
-
|
767
|
+
try {
|
768
|
+
const parsedError = JSON.parse(errorData);
|
800
769
|
errorMessage += `: ${JSON.stringify(parsedError)}`;
|
801
|
-
|
770
|
+
} catch (e) {
|
802
771
|
errorMessage += `: ${errorData}`;
|
803
772
|
}
|
804
773
|
if (spinner) spinner.fail(`❌ ${errorMessage}`);
|
805
774
|
reject(new Error(errorMessage));
|
806
|
-
|
807
|
-
|
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
|
-
|
819
|
-
let
|
820
|
-
const dataRegex = /data: (.*?)\n\n/gs;
|
779
|
+
let fullContent = '';
|
780
|
+
let buffer = '';
|
821
781
|
|
822
|
-
|
823
|
-
|
782
|
+
// 处理数据
|
783
|
+
res.on('data', (chunk) => {
|
784
|
+
// 将新的数据添加到缓冲区
|
785
|
+
const data = chunk.toString();
|
786
|
+
buffer += data;
|
824
787
|
|
825
|
-
//
|
826
|
-
|
788
|
+
// 尝试从缓冲区中提取完整的SSE消息
|
789
|
+
const messages = buffer.split('\n\n');
|
827
790
|
|
828
|
-
|
829
|
-
|
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
|
-
|
833
|
-
|
834
|
-
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
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
|
-
|
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
|
-
|
857
|
-
|
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('🔄
|
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
|
-
|
960
|
+
const data = chunk.toString();
|
961
|
+
buffer += data;
|
961
962
|
|
962
963
|
// 尝试从缓冲区中提取完整的SSE消息
|
963
|
-
|
964
|
-
const dataRegex = /data: (.*?)\n\n/gs;
|
964
|
+
const messages = buffer.split('\n\n');
|
965
965
|
|
966
|
-
|
967
|
-
|
966
|
+
// 处理除了最后一个可能不完整的消息之外的所有消息
|
967
|
+
for (let i = 0; i < messages.length - 1; i++) {
|
968
|
+
const message = messages[i].trim();
|
969
|
+
if (!message) continue; // 跳过空消息
|
968
970
|
|
969
|
-
//
|
970
|
-
if (data
|
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 (
|
977
|
-
|
978
|
-
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
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
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
|
1000
|
-
|
1001
|
-
|
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
|
-
|
1045
|
+
req.end();
|
1015
1046
|
} catch (error) {
|
1016
1047
|
if (spinner) spinner.fail(`❌ DeepSeek API错误: ${error.message}`);
|
1017
1048
|
reject(error);
|