From 98805838e929480078300a43a553317eca3d7bac Mon Sep 17 00:00:00 2001 From: Runxi Yu Date: Thu, 10 Apr 2025 19:49:00 +0800 Subject: [PATCH] Initial commit --- .gitignore | 2 ++ go.mod | 3 +++ main.go | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++ static/index.html | 470 +++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..23fb135f7d4a962e6f05f01e599f300690db2732 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/tiff +/responses diff --git a/go.mod b/go.mod new file mode 100644 index 0000000000000000000000000000000000000000..938ac4e672b7d9a7795ac2acdcc811193c76e206 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module tiff + +go 1.24.1 diff --git a/main.go b/main.go new file mode 100644 index 0000000000000000000000000000000000000000..e3fdd93e3bf2a1b3f23415307cc84f7dea1019c7 --- /dev/null +++ b/main.go @@ -0,0 +1,152 @@ +package main + +import ( + "embed" + "encoding/csv" + "encoding/json" + "fmt" + "io/fs" + "log" + "net" + "net/http" + "os" + "path/filepath" + "sort" + "strings" + "time" +) + +//go:embed static/* +var embeddedStatic embed.FS + +func main() { + fs, err := fs.Sub(embeddedStatic, "static") + if err != nil { + panic(err) + } + + http.Handle("/", http.FileServer(http.FS(fs))) + http.HandleFunc("/submit", handleForm) + http.HandleFunc("/responses.csv", serveCSV) + + if err := os.MkdirAll("responses", 0755); err != nil { + log.Fatalf("unable to create responses folder: %v", err) + } + + log.Println("listening 127.0.0.1:9074") + log.Fatal(http.ListenAndServe("127.0.0.1:9074", nil)) +} + +func handleForm(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) + return + } + + if err := r.ParseForm(); err != nil { + http.Error(w, "Unable to parse form", http.StatusBadRequest) + return + } + + data := make(map[string]string) + for key, values := range r.PostForm { + if len(values) > 0 { + data[key] = values[0] + } else { + data[key] = "" + } + } + + ip := r.Header.Get("X-Forwarded-For") + if ip != "" { + ip = strings.Split(ip, ",")[0] + ip = strings.TrimSpace(ip) + } else { + ip, _, _ = net.SplitHostPort(r.RemoteAddr) + } + data["ip_address"] = ip + + filename := time.Now().Format("20060102_150405.000") + ".json" + filePath := filepath.Join("responses", filename) + + file, err := os.Create(filePath) + if err != nil { + http.Error(w, "无法打开保存文件:"+err.Error(), http.StatusInternalServerError) + return + } + defer file.Close() + + encoder := json.NewEncoder(file) + encoder.SetIndent("", "\t") + if err := encoder.Encode(data); err != nil { + http.Error(w, "无法写入保存文件:"+err.Error(), http.StatusInternalServerError) + return + } + + fmt.Fprintf(w, "感谢您的提交!您的数据已成功保存。") +} + +func serveCSV(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/csv") + w.Header().Set("Content-Disposition", "attachment;filename=responses.csv") + + writer := csv.NewWriter(w) + defer writer.Flush() + + fieldOrder := []string{ + "gender", "age", "dialect", "wuyu_details", "guanhua_details", "other_details", + "usage_frequency", "fluency", "foreign_language", "music_training", + "absolute_pitch", "music_freq", + } + for i := 1; i <= 20; i++ { + fieldOrder = append(fieldOrder, fmt.Sprintf("q%d", i)) + } + fieldOrder = append(fieldOrder, "cadence1", "cadence2", "cadence3", "cadence4") + fieldOrder = append(fieldOrder, + "style1trap", "style2drill", "style3drumbass", "style4reggaetton", "style5rb", + ) + + if err := writer.Write(fieldOrder); err != nil { + http.Error(w, "Failed to write header", http.StatusInternalServerError) + return + } + + files, err := os.ReadDir("responses") + if err != nil { + http.Error(w, "Failed to read responses", http.StatusInternalServerError) + return + } + + sort.Slice(files, func(i, j int) bool { + return files[i].Name() < files[j].Name() + }) + + for _, file := range files { + if !strings.HasSuffix(file.Name(), ".json") { + continue + } + path := filepath.Join("responses", file.Name()) + + f, err := os.Open(path) + if err != nil { + log.Printf("Failed to open file %s: %v", path, err) + continue + } + + var data map[string]string + if err := json.NewDecoder(f).Decode(&data); err != nil { + log.Printf("Failed to decode %s: %v", path, err) + f.Close() + continue + } + f.Close() + + var row []string + for _, key := range fieldOrder { + row = append(row, data[key]) + } + if err := writer.Write(row); err != nil { + log.Printf("Failed to write row: %v", err) + } + } +} diff --git a/static/index.html b/static/index.html new file mode 100644 index 0000000000000000000000000000000000000000..e61739260da241d97c4e2b11248d360d8b551e44 --- /dev/null +++ b/static/index.html @@ -0,0 +1,470 @@ + + + + + 方言背景对音乐感知与音乐学习能力的影响:实验问卷 + + + + +
+

方言背景对音乐感知与音乐学习能力的影响:实验问卷

+

您好!非常感谢您抽出宝贵时间参加本实验。

+

填写此份问卷即说明您同意将以下个人信息和测试得分作为实验数据供后续分析。我们将不会泄露您的个人信息。

+

为了音频能顺利播放,请使用电脑浏览器打开问卷链接。

+

如您在测试过程中感到不适可随时退出,您的数据将不会被记录。

+

感谢您的配合!

+ +

您的性别?

+ + + + +

您的年龄段?

+ + + + + + + + +

您的母语方言是?只要您家中使用除标准普通话以外的方言,就填写相应的方言。如果完全不使用方言,填写“普通话”。

+
+
+
+ + +

您使用方言的频率是?

+
+
+
+ + +

您认为自己的方言流利程度是?

+ + + + + + +

您是否学习过外国语言(如英语、日语等,不包含中文或汉语方言)?如有,学过多少门?

+ + + + + + +

您是否接受过系统的音乐训练(学习乐器/作曲等)?如有,接受训练的时间是?

+ + + + + + + +

您是否有绝对音感?

+ + + +

您平常听音乐的频率是?

+ + + + + + +

任务 1: 请判断下列音频中的两条旋律/节奏是否相同。

+

音频加载可能需要一些时间。请注意,每一个音频只能听一遍。

+

旋律

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
序号音频选项
旋律 1
旋律 2
旋律 3
旋律 4
旋律 5
旋律 6
旋律 7
旋律 8
旋律 9
旋律 10
+

节奏

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
序号音频选项
节奏 1
节奏 2
节奏 3
节奏 4
节奏 5
节奏 6
节奏 7
节奏 8
节奏 9
节奏 10
+

任务 2: 终止式配对

+

请先听 C 大调主和弦并学习 4 种终止式的名称和音响效果。

+ + + + + + + + + + + + + + + + + + + + + + +
C大调主和弦
完全终止
变格终止
导音终止
阻碍终止
+

然后,将在 F♯ 大调上演奏的这 4 种终止式和其名称进行配对。

+ + + + + + + + + + + + + + + + + + + + + + +
F♯ 大调主和弦
1
2
3
4
+ +

请将以上终止式音频的数字序号填入其相对应的终止式序号。

+ + + + + +
+ +

任务 3: 音乐风格识别

+

请聆听并学习 5 种音乐风格的鼓组节奏型和音色特点。

+ + + + + + + + + + + + + + + + + + + + + +
Trap 陷阱
Drill 钻头
Drum & Bass 鼓与贝斯
Reggaetton 雷击顿
R&B 节奏蓝调
+ +

然后,将 5 个真实音乐片段与其风格相对应。

+ + + + + + + + + + + + + + + + + + + + + +
1
2
3
4
5
+ + +

请将以上片段的序号与其风格相对应(只填阿拉伯数字)。

+ + + + + + +
+ +

恭喜您完成所有测试并衷心感谢您的参与!

+

如有兴趣了解实验数据分析结果,请关注微信公众号 @WIT studio。

+ +
+ + -- 2.48.1