update
This commit is contained in:
188
cmd/main.go
Normal file
188
cmd/main.go
Normal file
@@ -0,0 +1,188 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"wasm-go/internal/api"
|
||||
"wasm-go/internal/excel"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("========== Excel转JSON ==========")
|
||||
|
||||
excelFile := "yst郑州惠兴财务报表2021(3).xlsx"
|
||||
|
||||
// 检查Excel文件是否存在
|
||||
if _, err := os.Stat(excelFile); os.IsNotExist(err) {
|
||||
fmt.Printf("❌ Excel文件不存在: %s\n", excelFile)
|
||||
return
|
||||
}
|
||||
|
||||
// 读取Excel文件为bytes
|
||||
excelBytes, err := os.ReadFile(excelFile)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 读取Excel文件失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("✓ 读取Excel文件为字节成功")
|
||||
|
||||
// 使用NewXLSXReaderFromBytes从bytes创建读取器
|
||||
reader, err := excel.NewXLSXReaderFromBytes(excelBytes)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 创建XLSX读取器失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Println("✓ 创建XLSX读取器成功")
|
||||
|
||||
// 读取所有的sheets并转换为markdown格式
|
||||
var allMarkdownTables strings.Builder
|
||||
allMarkdownTables.WriteString("以下是Excel表格的数据:\n\n")
|
||||
|
||||
sheets, err := reader.GetSheetNames()
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 获取工作表名称失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, sheetName := range sheets {
|
||||
fmt.Printf("\n========== 工作表: %s ==========\n", sheetName)
|
||||
|
||||
data, err := reader.GetSheetData(sheetName)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 读取工作表失败: %v\n", err)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(data) == 0 {
|
||||
fmt.Println("⚠️ 工作表为空")
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("找到 %d 行数据\n", len(data))
|
||||
|
||||
// 转换为markdown格式
|
||||
markdown := excel.ConvertToMarkdown(data)
|
||||
allMarkdownTables.WriteString(fmt.Sprintf("## 工作表: %s\n", sheetName))
|
||||
allMarkdownTables.WriteString(markdown)
|
||||
allMarkdownTables.WriteString("\n\n")
|
||||
}
|
||||
|
||||
fmt.Println("\n✅ 所有工作表已转换为Markdown格式!")
|
||||
|
||||
// 读取quarterly1.txt的prompt
|
||||
promptBytes, err := os.ReadFile("./quarterly1.txt")
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 读取quarterly1.txt失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
prompt := string(promptBytes)
|
||||
|
||||
// 合并prompt和markdown表格
|
||||
finalPrompt := fmt.Sprintf("%s\n\n%s", prompt, allMarkdownTables.String())
|
||||
|
||||
// 尝试连接到不同的LLM提供商
|
||||
var response *api.ChatResponse
|
||||
var llmErr error
|
||||
|
||||
// 首先尝试Ollama
|
||||
fmt.Println("\n🔄 尝试连接到Ollama服务...")
|
||||
if ollamaClient := api.NewOllamaClient("http://localhost:11434", "qwen3.5:9b"); ollamaClient != nil {
|
||||
response, llmErr = ollamaClient.Chat([]api.ChatMessage{
|
||||
{Role: "user", Content: finalPrompt},
|
||||
})
|
||||
if llmErr == nil {
|
||||
fmt.Println("✓ 成功使用Ollama生成响应")
|
||||
} else {
|
||||
fmt.Printf("⚠ Ollama调用失败: %v\n", llmErr)
|
||||
|
||||
// 检查是否是连接问题
|
||||
if strings.Contains(llmErr.Error(), "connection refused") || strings.Contains(llmErr.Error(), "404") {
|
||||
fmt.Println("💡 提示:Ollama服务可能未启动,或模型未安装")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println("\n========== LLM生成的JSON ==========")
|
||||
// 解析LLM返回的响应,提取```json{内容}```中的JSON部分
|
||||
parsedJSON := extractJSONFromResponse(response.Choices[0].Message.Content)
|
||||
fmt.Println(parsedJSON)
|
||||
fmt.Println("==================================")
|
||||
|
||||
// 使用解析出的JSON调用税务健康API
|
||||
fmt.Println("\n🔄 正在使用解析的JSON调用税务健康API...")
|
||||
|
||||
// 创建税务健康服务客户端
|
||||
// 注意:这里需要替换为实际的用户ID和私钥
|
||||
taxHealthService := api.NewTaxHealthService("1560142251348287489", "")
|
||||
|
||||
// 将解析的JSON解析为map结构
|
||||
var companyData map[string]interface{}
|
||||
if err := json.Unmarshal([]byte(parsedJSON), &companyData); err != nil {
|
||||
fmt.Printf("❌ 解析JSON数据失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 构建税务评估请求
|
||||
request := api.TaxEvalRequest{
|
||||
ReqNo: fmt.Sprintf("REQ%v", time.Now().Unix()), // 使用时间戳生成请求号
|
||||
Detail: api.TaxEvalDetail{
|
||||
CompanyName: "企业名称", // 可以从数据中提取公司名称
|
||||
Data: companyData,
|
||||
},
|
||||
}
|
||||
|
||||
// 调用税务健康API
|
||||
taxResponse, err := taxHealthService.EvaluateTaxHealth(request)
|
||||
if err != nil {
|
||||
fmt.Printf("❌ 调用税务健康API失败: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("\n========== 税务健康API反馈结果 ==========")
|
||||
fmt.Printf("API响应: %+v\n", taxResponse)
|
||||
fmt.Println("======================================")
|
||||
}
|
||||
|
||||
// extractJSONFromResponse 从LLM响应中提取JSON内容
|
||||
// 查找并提取 ```json {...} ``` 或 ``` {...} ``` 中的内容
|
||||
func extractJSONFromResponse(response string) string {
|
||||
// 首先尝试匹配 ```json 开头的代码块
|
||||
start := strings.Index(response, "```json")
|
||||
if start != -1 {
|
||||
start += 7 // 跳过 "```json"
|
||||
end := strings.Index(response[start:], "```")
|
||||
if end != -1 {
|
||||
jsonContent := strings.TrimSpace(response[start : start+end])
|
||||
return jsonContent
|
||||
}
|
||||
}
|
||||
|
||||
// 然后尝试匹配 ``` 开头的代码块(假设是JSON)
|
||||
start = strings.Index(response, "```")
|
||||
if start != -1 {
|
||||
start += 3 // 跳过 "```"
|
||||
end := strings.Index(response[start:], "```")
|
||||
if end != -1 {
|
||||
jsonContent := strings.TrimSpace(response[start : start+end])
|
||||
// 检查是否看起来像JSON
|
||||
jsonContent = strings.TrimSpace(jsonContent)
|
||||
if strings.HasPrefix(jsonContent, "{") || strings.HasPrefix(jsonContent, "[") {
|
||||
return jsonContent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有找到代码块,尝试直接解析整个响应是否为JSON
|
||||
response = strings.TrimSpace(response)
|
||||
if strings.HasPrefix(response, "{") && strings.HasSuffix(response, "}") ||
|
||||
strings.HasPrefix(response, "[") && strings.HasSuffix(response, "]") {
|
||||
return response
|
||||
}
|
||||
|
||||
// 如果以上都失败,返回原内容
|
||||
return response
|
||||
}
|
||||
55
cmd/test/main.go
Normal file
55
cmd/test/main.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"wasm-go/internal/api"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("=== 企业行业分类示例 ===")
|
||||
|
||||
// 创建LLM客户端 - 这里使用Ollama作为示例
|
||||
// 如果Ollama不可用,也可以使用OpenAI
|
||||
var llmClient *api.LLMClient
|
||||
|
||||
// 尝试连接到Ollama
|
||||
fmt.Println("尝试连接到Ollama服务...")
|
||||
llmClient = api.NewOllamaClient("http://localhost:11434", "qwen3.5:9b")
|
||||
|
||||
// 如果需要使用OpenAI,取消下面的注释并替换API KEY
|
||||
/*
|
||||
llmClient = api.NewOpenAIClient("your-openai-api-key", "gpt-3.5-turbo")
|
||||
*/
|
||||
|
||||
// 创建企业行业分类器
|
||||
classifier := api.NewCompanyIndustryClassifier(llmClient)
|
||||
|
||||
// 示例公司名称 - 可以从命令行参数获取
|
||||
companyName := "深圳市致远速联信息技术有限公司"
|
||||
|
||||
fmt.Printf("正在分析公司: %s\n", companyName)
|
||||
|
||||
// 分析企业行业
|
||||
result, err := classifier.ClassifyCompany(companyName)
|
||||
if err != nil {
|
||||
log.Printf("分析失败: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 输出结果
|
||||
fmt.Printf("\n✅ 企业行业分析完成!\n")
|
||||
fmt.Printf("公司名称: %s\n", result.CompanyName)
|
||||
fmt.Printf("主要行业: %s - %s\n", result.Primary.Code, result.Primary.Name)
|
||||
fmt.Printf("判断依据: %s\n", result.Primary.Reason)
|
||||
|
||||
if len(result.Secondary) > 0 {
|
||||
fmt.Printf("次要行业:\n")
|
||||
for _, sec := range result.Secondary {
|
||||
fmt.Printf(" %s - %s\n", sec.Code, sec.Name)
|
||||
fmt.Printf(" 判断依据: %s\n", sec.Reason)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("次要行业: 无\n")
|
||||
}
|
||||
}
|
||||
334
cmd/wasm/main.go
Normal file
334
cmd/wasm/main.go
Normal file
@@ -0,0 +1,334 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"syscall/js"
|
||||
"wasm-go/internal/api"
|
||||
"wasm-go/internal/excel"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// 注册各种功能函数
|
||||
js.Global().Set("analyzeCompanyIndustryAsync", js.FuncOf(analyzeCompanyIndustryAsync))
|
||||
js.Global().Set("parseExcelAsync", js.FuncOf(parseExcelAsync))
|
||||
js.Global().Set("callLLMAsync", js.FuncOf(callLLMAsync))
|
||||
js.Global().Set("callTaxHealthAsync", js.FuncOf(callTaxHealthAsync))
|
||||
|
||||
// 保持程序运行
|
||||
select {} // 无限循环,保持程序运行
|
||||
}
|
||||
|
||||
// analyzeCompanyIndustryAsync 异步版本的函数,返回Promise
|
||||
func analyzeCompanyIndustryAsync(this js.Value, args []js.Value) interface{} {
|
||||
// 获取公司名称参数
|
||||
companyName := args[0].String()
|
||||
|
||||
// 创建一个通道来处理结果
|
||||
resultChan := make(chan interface{}, 1)
|
||||
errorChan := make(chan error, 1) // 使用error类型而不是interface{}
|
||||
|
||||
// 在goroutine中执行异步操作
|
||||
go func() {
|
||||
// 创建LLM客户端
|
||||
llmClient := api.NewOllamaClient("http://localhost:11434", "qwen3.5:9b")
|
||||
|
||||
// 创建企业行业分类器
|
||||
classifier := api.NewCompanyIndustryClassifier(llmClient)
|
||||
|
||||
// 分析企业行业
|
||||
result, err := classifier.ClassifyCompany(companyName)
|
||||
if err != nil {
|
||||
// 发送错误到错误通道
|
||||
errorChan <- err
|
||||
} else {
|
||||
// 发送结果到结果通道
|
||||
resultChan <- result
|
||||
}
|
||||
}()
|
||||
|
||||
// 创建Promise
|
||||
promise := js.Global().Get("Promise").New(js.FuncOf(func(this js.Value, promiseArgs []js.Value) interface{} {
|
||||
if len(promiseArgs) < 2 {
|
||||
// 如果参数不足,返回一个立即拒绝的Promise
|
||||
return nil
|
||||
}
|
||||
|
||||
resolve := promiseArgs[0]
|
||||
reject := promiseArgs[1]
|
||||
|
||||
// 启动一个goroutine来处理结果
|
||||
go func() {
|
||||
select {
|
||||
case result := <-resultChan:
|
||||
// 将复杂结构体序列化为JSON
|
||||
jsonResult, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
// 序列化失败,返回错误
|
||||
reject.Invoke(js.ValueOf(map[string]string{
|
||||
"error": "JSON序列化失败: " + err.Error(),
|
||||
}))
|
||||
return
|
||||
}
|
||||
|
||||
// 将JSON字符串解析为JavaScript对象
|
||||
jsResult := js.Global().Get("JSON").Call("parse", string(jsonResult))
|
||||
resolve.Invoke(jsResult)
|
||||
case err := <-errorChan:
|
||||
// 将错误转换为JavaScript值
|
||||
reject.Invoke(js.ValueOf(map[string]string{
|
||||
"error": err.Error(),
|
||||
}))
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}))
|
||||
|
||||
return promise
|
||||
}
|
||||
|
||||
// parseExcelAsync 解析Excel文件的异步函数
|
||||
func parseExcelAsync(this js.Value, args []js.Value) interface{} {
|
||||
// 获取Excel文件的ArrayBuffer
|
||||
arrayBuffer := args[0]
|
||||
uint8Array := js.Global().Get("Uint8Array").New(arrayBuffer)
|
||||
|
||||
// 创建字节切片
|
||||
length := uint8Array.Get("length").Int()
|
||||
excelBytes := make([]byte, length)
|
||||
|
||||
// 将数据复制到Go字节切片
|
||||
for i := 0; i < length; i++ {
|
||||
excelBytes[i] = byte(uint8Array.Index(i).Int())
|
||||
}
|
||||
|
||||
// 创建一个通道来处理结果
|
||||
resultChan := make(chan interface{}, 1)
|
||||
errorChan := make(chan error, 1)
|
||||
|
||||
// 在goroutine中执行异步操作
|
||||
go func() {
|
||||
// 创建Excel读取器
|
||||
reader, err := excel.NewXLSXReaderFromBytes(excelBytes)
|
||||
if err != nil {
|
||||
errorChan <- err
|
||||
return
|
||||
}
|
||||
|
||||
// 读取所有工作表
|
||||
sheetNames, err := reader.GetSheetNames()
|
||||
if err != nil {
|
||||
errorChan <- err
|
||||
return
|
||||
}
|
||||
|
||||
// 创建一个map来存储所有工作表的数据
|
||||
sheets := make(map[string][][]string)
|
||||
|
||||
// 读取每个工作表的数据
|
||||
for _, sheetName := range sheetNames {
|
||||
sheetData, err := reader.GetSheetData(sheetName)
|
||||
if err != nil {
|
||||
// 记录错误但继续处理其他工作表
|
||||
continue
|
||||
}
|
||||
sheets[sheetName] = sheetData
|
||||
}
|
||||
|
||||
// 将结果转换为适当的格式
|
||||
result := map[string]interface{}{
|
||||
"sheets": sheets,
|
||||
}
|
||||
|
||||
resultChan <- result
|
||||
}()
|
||||
|
||||
// 创建Promise
|
||||
promise := js.Global().Get("Promise").New(js.FuncOf(func(this js.Value, promiseArgs []js.Value) interface{} {
|
||||
if len(promiseArgs) < 2 {
|
||||
// 如果参数不足,返回一个立即拒绝的Promise
|
||||
return nil
|
||||
}
|
||||
|
||||
resolve := promiseArgs[0]
|
||||
reject := promiseArgs[1]
|
||||
|
||||
// 启动一个goroutine来处理结果
|
||||
go func() {
|
||||
select {
|
||||
case result := <-resultChan:
|
||||
// 将复杂结构体序列化为JSON
|
||||
jsonResult, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
// 序列化失败,返回错误
|
||||
reject.Invoke(js.ValueOf(map[string]string{
|
||||
"error": "JSON序列化失败: " + err.Error(),
|
||||
}))
|
||||
return
|
||||
}
|
||||
|
||||
// 将JSON字符串解析为JavaScript对象
|
||||
jsResult := js.Global().Get("JSON").Call("parse", string(jsonResult))
|
||||
resolve.Invoke(jsResult)
|
||||
case err := <-errorChan:
|
||||
// 将错误转换为JavaScript值
|
||||
reject.Invoke(js.ValueOf(map[string]string{
|
||||
"error": err.Error(),
|
||||
}))
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}))
|
||||
|
||||
return promise
|
||||
}
|
||||
|
||||
// callLLMAsync 调用大模型的异步函数
|
||||
func callLLMAsync(this js.Value, args []js.Value) interface{} {
|
||||
// 获取提示词参数
|
||||
prompt := args[0].String()
|
||||
|
||||
// 创建一个通道来处理结果
|
||||
resultChan := make(chan interface{}, 1)
|
||||
errorChan := make(chan error, 1)
|
||||
|
||||
// 在goroutine中执行异步操作
|
||||
go func() {
|
||||
// 创建LLM客户端(可以根据需要选择不同的模型)
|
||||
llmClient := api.NewOllamaClient("http://localhost:11434", "qwen3.5:9b")
|
||||
|
||||
// 调用大模型
|
||||
response, err := llmClient.SimpleChat(prompt)
|
||||
if err != nil {
|
||||
errorChan <- err
|
||||
return
|
||||
}
|
||||
|
||||
result := map[string]string{
|
||||
"response": response,
|
||||
}
|
||||
|
||||
resultChan <- result
|
||||
}()
|
||||
|
||||
// 创建Promise
|
||||
promise := js.Global().Get("Promise").New(js.FuncOf(func(this js.Value, promiseArgs []js.Value) interface{} {
|
||||
if len(promiseArgs) < 2 {
|
||||
// 如果参数不足,返回一个立即拒绝的Promise
|
||||
return nil
|
||||
}
|
||||
|
||||
resolve := promiseArgs[0]
|
||||
reject := promiseArgs[1]
|
||||
|
||||
// 启动一个goroutine来处理结果
|
||||
go func() {
|
||||
select {
|
||||
case result := <-resultChan:
|
||||
// 将复杂结构体序列化为JSON
|
||||
jsonResult, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
// 序列化失败,返回错误
|
||||
reject.Invoke(js.ValueOf(map[string]string{
|
||||
"error": "JSON序列化失败: " + err.Error(),
|
||||
}))
|
||||
return
|
||||
}
|
||||
|
||||
// 将JSON字符串解析为JavaScript对象
|
||||
jsResult := js.Global().Get("JSON").Call("parse", string(jsonResult))
|
||||
resolve.Invoke(jsResult)
|
||||
case err := <-errorChan:
|
||||
// 将错误转换为JavaScript值
|
||||
reject.Invoke(js.ValueOf(map[string]string{
|
||||
"error": err.Error(),
|
||||
}))
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}))
|
||||
|
||||
return promise
|
||||
}
|
||||
|
||||
// callTaxHealthAsync 调用税务健康API的异步函数
|
||||
// 注意:由于WASM环境的CORS限制,我们在这里提供模拟实现
|
||||
func callTaxHealthAsync(this js.Value, args []js.Value) interface{} {
|
||||
// 获取公司信息参数
|
||||
companyInfoJSON := args[0].String()
|
||||
|
||||
// 创建一个通道来处理结果
|
||||
resultChan := make(chan interface{}, 1)
|
||||
errorChan := make(chan error, 1)
|
||||
|
||||
// 在goroutine中执行异步操作
|
||||
go func() {
|
||||
// 由于WASM环境无法直接调用外部API(CORS限制)
|
||||
// 我们返回一个模拟的响应
|
||||
simulatedResponse := map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": map[string]interface{}{
|
||||
"req_no": "REQ" + fmt.Sprint(js.Global().Get("Date").New().Call("getTime").Int()),
|
||||
"order_no": "ORDER" + fmt.Sprint(js.Global().Get("Date").New().Call("getTime").Int()),
|
||||
},
|
||||
"message": "模拟的税务健康评估结果",
|
||||
}
|
||||
|
||||
// 解析输入的JSON以获取一些信息用于模拟
|
||||
var companyInfo map[string]interface{}
|
||||
err := json.Unmarshal([]byte(companyInfoJSON), &companyInfo)
|
||||
if err != nil {
|
||||
errorChan <- err
|
||||
return
|
||||
}
|
||||
|
||||
// 根据输入数据添加一些模拟的评估结果
|
||||
simulatedResponse["company_data"] = companyInfo
|
||||
|
||||
resultChan <- simulatedResponse
|
||||
}()
|
||||
|
||||
// 创建Promise
|
||||
promise := js.Global().Get("Promise").New(js.FuncOf(func(this js.Value, promiseArgs []js.Value) interface{} {
|
||||
if len(promiseArgs) < 2 {
|
||||
// 如果参数不足,返回一个立即拒绝的Promise
|
||||
return nil
|
||||
}
|
||||
|
||||
resolve := promiseArgs[0]
|
||||
reject := promiseArgs[1]
|
||||
|
||||
// 启动一个goroutine来处理结果
|
||||
go func() {
|
||||
select {
|
||||
case result := <-resultChan:
|
||||
// 将复杂结构体序列化为JSON
|
||||
jsonResult, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
// 序列化失败,返回错误
|
||||
reject.Invoke(js.ValueOf(map[string]string{
|
||||
"error": "JSON序列化失败: " + err.Error(),
|
||||
}))
|
||||
return
|
||||
}
|
||||
|
||||
// 将JSON字符串解析为JavaScript对象
|
||||
jsResult := js.Global().Get("JSON").Call("parse", string(jsonResult))
|
||||
resolve.Invoke(jsResult)
|
||||
case err := <-errorChan:
|
||||
// 将错误转换为JavaScript值
|
||||
reject.Invoke(js.ValueOf(map[string]string{
|
||||
"error": err.Error(),
|
||||
}))
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}))
|
||||
|
||||
return promise
|
||||
}
|
||||
Reference in New Issue
Block a user