Commit 889709d3 by Ford

Initial commit

parents
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="worldepcho@localhost" uuid="fcfc316d-dd27-4b56-8827-31dcdc1c9367">
<driver-ref>mysql.8</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
<jdbc-url>jdbc:mysql://localhost:3306/worldepcho</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
<data-source source="LOCAL" name="WorldEpcho@58.34.54.45" uuid="20c73eff-907b-45aa-a72a-9e02a6ada0a0">
<driver-ref>mysql.8</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
<jdbc-url>jdbc:mysql://58.34.54.45:13679/WorldEpcho</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
</data-source>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/WorldEpcho.iml" filepath="$PROJECT_DIR$/.idea/WorldEpcho.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
{
"app_name": "no-name",
"db_name" : "WorldEpcho",
"db_server" : "58.34.54.45",
"md5_salt": "admin999999",
"mode": "dev",
"mysql_port": "13679",
"mysql_username": "mind",
"mysql_pwd" : "mind",
"port": "8099",
"static_path": "/static",
"timeout10" : "10s",
"redis_port": "6379",
"redis_pwd": "PsycheEpoch@Nirvana:)",
"redis_server": "139.196.162.109",
"redis_db": "0",
"mongo_username":"Mind",
"mongo_pwd" : "PsycheEpoch@Nirvana:)",
"mongo_host": "58.34.54.45",
"mongo_port": "27017",
"jwt_secret": "0b702a1b5cbba2fc81e8b5c642b469d5",
"miGuAuthId": "fc9058b44f7850b4438afb11033891ab",
"huawei_sms_url": "https://sms.huaweiita.com:18000/common/sms/sendTemplateMessage",
"soul_auth": "1d527cbf2cd50ad7e97f0aa23e2a712e",
"soul_url": "http://52.83.116.11:13679",
"transcribe_url": "http://127.0.0.1:13667/transcribe",
"get_token_url": "https://14259x32h2.yicp.fun/api/v3/authorization/getPopAccessToken",
"mental_clinic_url": "https://14259x32h2.yicp.fun/api/v3/evaluate/selectAiMentalClinicList",
"call_back_url":"https://58.34.54.45:8089/MentalClinic/data",
"semantic_analysis_url": "http://52.83.116.11:13679" ,
"prompt_api_url": "http://58.34.54.45:16666/generate_character_prompt",
"head_portrait_api": "http://58.34.54.45:19666/",
"app_key": "d1526328-ac75-4496-9b99-6598293af574",
"app_secret": "cdd08ede-b836-44d2-8c10-b6abc0ac57aa",
"exhibition_mode_app_id": 1,
"voice_set_model_url": "http://127.0.0.1:17666",
"wechat_url": "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
"wechat_app_id": "wx3a8c6fc90ee21b81",
"wechat_app_secret": "42d8396cfdc09456c34065c5bc79de16",
"wechat_access_token_url": "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
"wechat_get_phone_url": "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=%s",
"voice_model_sets": {
"huaiNvRen": {
"gpt_model_path": "/psycheEpic/GPT-SoVITS/GPT_weights/huainvren-e20.ckpt",
"sovits_model_path":"/psycheEpic/GPT-SoVITS/SoVITS_weights/huainvren_e51_s816.pth",
"refer_wav_path": "/psycheEpic/GPT-SoVITS/refer_voices/huainvren_1.wav",
"prompt_text": "什么意思啊?什么意思呀?他不播了是吧?",
"prompt_language": "zh",
"cn_name": "温柔小姐姐"
},
"leiShenJiangJun": {
"gpt_model_path": "/psycheEpic/GPT-SoVITS/GPT_weights/leishenjiangjun-e15.ckpt",
"sovits_model_path":"/psycheEpic/GPT-SoVITS/SoVITS_weights/leishenjiangjun_e8_s200.pth",
"refer_wav_path": "/psycheEpic/GPT-SoVITS/refer_voices/leishenjiangjun.wav",
"prompt_text": "除了魔物的威胁,我还在担心身影术中还不会不散发出其他东西?",
"prompt_language": "zh",
"cn_name": "雷神将军御姐音"
},
"zhongLi": {
"gpt_model_path": "/psycheEpic/GPT-SoVITS/GPT_weights/zhongli-e30.ckpt",
"sovits_model_path":"/psycheEpic/GPT-SoVITS/SoVITS_weights/zhongli_e16_s432.pth",
"refer_wav_path": "/psycheEpic/GPT-SoVITS/refer_voices/zhongli_02.wav",
"prompt_text": "哦,你们也来了,不先到人多热闹的地方先转转吗?",
"prompt_language": "zh",
"cn_name": "钟离沉稳男声"
},
"maYun": {
"gpt_model_path": "/psycheEpic/GPT-SoVITS/GPT_weights/mayun-39s-e15.ckpt",
"sovits_model_path":"/psycheEpic/GPT-SoVITS/SoVITS_weights/mayun-39s_e8_s80.pth",
"refer_wav_path": "/psycheEpic/GPT-SoVITS/refer_voices/mayun4s.wav",
"prompt_text": "很多人因为看见而相信,但是我们这些人。",
"prompt_language": "zh",
"cn_name": "马云男声"
},
"naiLin": {
"gpt_model_path": "/psycheEpic/GPT-SoVITS/GPT_weights/naiLin-e20.ckpt",
"sovits_model_path":"/psycheEpic/GPT-SoVITS/SoVITS_weights/naiLin_e59_s3717.pth",
"refer_wav_path": "/psycheEpic/GPT-SoVITS/refer_voices/naiLin.wav",
"prompt_text": "因为给大家唱过的歌多了,因为,额,我们首播千日吗?",
"prompt_language": "zh",
"cn_name": "淡雅学姐"
},
"huaHuo": {
"gpt_model_path": "/psycheEpic/GPT-SoVITS/GPT_weights/huahuo-e100.ckpt",
"sovits_model_path":"/psycheEpic/GPT-SoVITS/SoVITS_weights/huahuo_e100_s1100.pth",
"refer_wav_path": "/psycheEpic/GPT-SoVITS/refer_voices/huahuo.wav",
"prompt_text": "啊!亲爱的,不吓你了。你会知道答案的,迟早的事!今天就当浅浅认识下,什么时候改变心意了,就来酒馆找我吧!前提是要找得到,哈哈!",
"prompt_language": "zh",
"cn_name": "调皮女声"
},
"fuNingNa": {
"gpt_model_path": "/psycheEpic/GPT-SoVITS/GPT_weights/fu_ning_na-e50.ckpt",
"sovits_model_path":"/psycheEpic/GPT-SoVITS/SoVITS_weights/fu_ning_na_e20_s1580.pth",
"refer_wav_path": "/psycheEpic/GPT-SoVITS/refer_voices/fu_ning_na.wav",
"prompt_text": "不必这么想,也不需要用这样的称呼,叫我芙宁娜就可以了。",
"prompt_language": "zh",
"cn_name": "活力少女"
},
"JiaLe": {
"gpt_model_path": "/psycheEpic/GPT-SoVITS/GPT_weights/Jiale-e15.ckpt",
"sovits_model_path":"/psycheEpic/GPT-SoVITS/SoVITS_weights/Jiale_e40_s2160.pth",
"refer_wav_path": "/psycheEpic/GPT-SoVITS/refer_voices/JiaLe.wav",
"prompt_text": "在最近我在研究这个仙剑三的理论啊,学术啊,我发现。",
"prompt_language": "zh",
"cn_name": "活力姐姐"
},
"naiLv": {
"gpt_model_path": "/psycheEpic/GPT-SoVITS/GPT_weights/naiLv-e20.ckpt",
"sovits_model_path":"/psycheEpic/GPT-SoVITS/SoVITS_weights/naiLv_e53_s2650.pth",
"refer_wav_path": "/psycheEpic/GPT-SoVITS/refer_voices/naiLv_infer02.wav",
"prompt_text": "我感觉哦,我感觉应该是这样的,所以之后应该也还有机会能用上。",
"prompt_language": "zh",
"cn_name": "邻家姐姐"
},
"tianDou": {
"gpt_model_path": "/psycheEpic/GPT-SoVITS/GPT_weights/tianDou-e21.ckpt",
"sovits_model_path":"/psycheEpic/GPT-SoVITS/SoVITS_weights/tianDou_e37_s1110.pth",
"refer_wav_path": "/psycheEpic/GPT-SoVITS/refer_voices/tianDou.wav",
"prompt_text": "因为我看到了,所以我才想说这个应该。",
"prompt_language": "zh",
"cn_name": "活力小妹"
},
"qiPaoYin": {
"gpt_model_path": "/psycheEpic/GPT-SoVITS/GPT_weights/qipaoyin-01-e15.ckpt",
"sovits_model_path":"/psycheEpic/GPT-SoVITS/SoVITS_weights/qipaoyin-01_e4_s40.pth",
"refer_wav_path": "/psycheEpic/GPT-SoVITS/refer_voices/qiPaoYin.wav",
"prompt_text": "真是醉的不轻,别喝了,拿来。",
"prompt_language": "zh",
"cn_name": "气泡音男声一"
},
"huTao": {
"gpt_model_path": "/psycheEpic/GPT-SoVITS/GPT_weights/hutao1-e15.ckpt",
"sovits_model_path":"/psycheEpic/GPT-SoVITS/SoVITS_weights/hutao1_e8_s160.pth",
"refer_wav_path": "/psycheEpic/GPT-SoVITS/refer_voices/hutao_infer02.wav",
"prompt_text": "嗯,没关系,那就趁着这个机会出去玩玩吧!我准假了。啊,当然是和现在一样,是没有工钱的。",
"prompt_language": "zh",
"cn_name": "萌妹桃桃"
},
"sunWuKong": {
"gpt_model_path": "/psycheEpic/GPT-SoVITS/GPT_weights/sunWukong-e15.ckpt",
"sovits_model_path":"/psycheEpic/GPT-SoVITS/SoVITS_weights/sunWukong_e8_s72.pth",
"refer_wav_path": "/psycheEpic/GPT-SoVITS/refer_voices/SunWukong.wav",
"prompt_text": "嘿,妖孽哪里逃!一个跟头十万八千里。",
"prompt_language": "zh",
"cn_name": "孙悟空"
},
"panJinLian": {
"gpt_model_path": "/psycheEpic/GPT-SoVITS/GPT_weights/PanJinLian-e15.ckpt",
"sovits_model_path":"/psycheEpic/GPT-SoVITS/SoVITS_weights/PanJinLian_e8_s72.pth",
"refer_wav_path": "/psycheEpic/GPT-SoVITS/refer_voices/PanJinLian_infer_1.wav",
"prompt_text": "奴家当真不能再饮了,家夫,这就回来了。大官人住手,万不能让外人看见。",
"prompt_language": "zh",
"cn_name": "潘金莲"
},
"guoDeGang": {
"gpt_model_path": "/psycheEpic/GPT-SoVITS/GPT_weights/GuoDeGang02-e15.ckpt",
"sovits_model_path":"/psycheEpic/GPT-SoVITS/SoVITS_weights/GuoDeGang02_e8_s80.pth",
"refer_wav_path": "/psycheEpic/GPT-SoVITS/refer_voices/guoDeGang02_infer01.wav",
"prompt_text": "窗前明月光疑是地上霜,举头望明月,我叫郭德纲。人来的不少,感谢大家的光临。",
"prompt_language": "zh",
"cn_name": "郭德纲"
}
}
}
{
"076br1qdu": 1693082221,
"076br8qdu": 1693591995,
"0x9ace0wj": 1692952909,
"10ih4czhi": 1692952499,
"11o5a1o1g": 1693005203,
"11o5apo1g": 0,
"136999999": 1692986344,
"14zf1lt2o": 1999999999,
"16i2wsazj": 0,
"176b18qd1": 1693227867,
"176br8qd1": 1692993890,
"18m81bd2q": 0,
"1gcisb277": 0,
"1qgrnm8ni": 0,
"2490h5xv2": 1999999999,
"2dp975x7k": 0,
"2f195vtbc": 0,
"2idarv9g2": 1999999999,
"2mp6nfbai": 0,
"2zgnd8i3a": 1694175391,
"3jyxjz8rn": 1999999999,
"3l6tj649m": 0,
"3l8f298hx": 0,
"3pzx2l2lb": 0,
"3uyo1y6uz": 1694170956,
"3vbmdjyd8": 1999999999,
"3wgu97p4q": 1693471926,
"44e5spmdf": 1693388987,
"4b80asrt5": 0,
"4brfobldc": 1693471528,
"4lxa8dq0w": 0,
"4pgx7gad9": 0,
"4thusyymt": 0,
"4wu0mierg": 0,
"55eo42e4h": 0,
"5hoic6jvg": 1693472509,
"5lralja2k": 0,
"5zpfsvzp5": 1693472795,
"6bcmkehwe": 0,
"6fmx542qv": 0,
"6ib44etws": 1693588152,
"6lk0k8h9w": 1694081656,
"6revc6f7j": 0,
"73fcbipzx": 0,
"75i2n8tot": 1694009917,
"7hywv3rkk": 0,
"7x38znmlg": 0,
"84pobe3nq": 0,
"8aggevljk": 0,
"8gqjgcvwn": 0,
"8idyfp15t": 1706620934,
"8j3dlffum": 1999999999,
"8vz9vwxql": 0,
"8wj9bheok": 0,
"8z58lzm46": 1694019751,
"96ci0qqf8": 0,
"96ojuw1ck": 0,
"999999999": 1999999999,
"99ju7d207": 0,
"9l7lpvgbh": 1694073328,
"9shthdj3a": 0,
"9w0dvb7mt": 0,
"9yyesaro9": 1694020202,
"9zuzkbdm8": 1694087356,
"a8oza98zh": 1694174427,
"az2qh9zwh": 0,
"b2hcp4vyp": 0,
"b8qj0936t": 1999999999,
"baiduwang": 1999999999,
"bh9s5kbqz": 0,
"bjytse2vu": 0,
"bkz2t1c59": 1999999999,
"c0e6nsuei": 1694174495,
"c0tvax8uw": 1694266797,
"c1qxahhqw": 0,
"c3y84m1mp": 1694025520,
"c4of8nvm7": 1999999999,
"cdgz20231": 0,
"cpq7v8gy2": 1694025964,
"cpvei7qwp": 1694093001,
"cx50qt2hn": 1694172649,
"d2dqqr8yb": 1693044414,
"d6cmgo3wr": 0,
"d7en1vrcv": 0,
"d81u66cle": 0,
"dd7r271j7": 1694190505,
"dkmk0vx7d": 1694264385,
"ds57bn1di": 0,
"dwy77q686": 1694682452,
"dxlploufq": 1694682359,
"e0ubo9gf8": 0,
"e14z8xr94": 0,
"e6rxhsjil": 1694682648,
"e9bmfm6hr": 0,
"ermlmgc09": 0,
"f0ngwxidb": 1999999999,
"f0ttjk18v": 1694685943,
"fkf9gkf3p": 1694686331,
"fp7j7hjcp": 1694697721,
"fr14y2ond": 0,
"fzrvxl5f8": 1694709370,
"g77uqvvxb": 0,
"g8mdqcwso": 0,
"gao60syjk": 0,
"gayh5lz1g": 0,
"gb4btyahj": 0,
"ggmhka2vw": 0,
"gmyeuql0g": 0,
"gn9nmhnhq": 0,
"h0l7yr2qk": 0,
"h3v3aynxa": 1999999999,
"h5rdea0o1": 0,
"hgcqjvd16": 0,
"htepcotmf": 1999999999,
"hxtest107": 1999999999,
"hxtest109": 1999999999,
"i8xmybzp5": 1695221380,
"ipukdx5q4": 0,
"jfobew5z7": 0,
"jkn823y01": 0,
"jkn823y02": 0,
"jkn823y03": 0,
"jpripbdr7": 0,
"jq1qganx8": 1999999999,
"jzi18rr2m": 1695394077,
"k1dvl2nr5": 1706548184,
"k4pceqo63": 1695547257,
"kewed4oh5": 1999999999,
"kxa6218ye": 0,
"l3d266bdg": 0,
"l8blier7h": 0,
"l8mprgfbp": 0,
"laowu6666": 1693591995,
"lui0hzcci": 0,
"lwnalloxw": 0,
"m02x35yld": 0,
"m1nbyhmuo": 0,
"mcu0zctz4": 0,
"mem64uipa": 1999999999,
"migutest1": 1999999999,
"migutest2": 1999999999,
"migutest3": 1999999999,
"migutest4": 1999999999,
"migutest5": 1999999999,
"mipm18vvi": 1999999999,
"mk0jy2eql": 0,
"mmtrcuyn9": 0,
"mw5vy27ms": 0,
"n0ghq3u5f": 0,
"n9v23atdn": 0,
"nanling69": 1999999999,
"nanling76": 1999999999,
"nanling79": 1999999999,
"nanling96": 1999999999,
"nanling99": 1999999999,
"ngnzhdmqo": 0,
"niu8h1t0m": 0,
"nj58qyroq": 0,
"oiuzdhywq": 0,
"onwb60l3u": 0,
"p87xx9kee": 0,
"p9fdy30om": 0,
"polet7je7": 0,
"ppu6c5i8l": 0,
"prm6g2f9h": 0,
"qaoa18uy4": 0,
"qcg0smx2d": 1999999999,
"qexbffcdr": 1999999999,
"quxh5q8x9": 0,
"qv53v14gt": 0,
"qx5awpsc9": 0,
"rkzu7ujd5": 0,
"rpo0d6ixi": 0,
"rvbycr2jl": 0,
"rwekoegzb": 0,
"s0prapfvs": 1999999999,
"sg5ak4kwd": 0,
"sk672fugb": 0,
"sqm8fd7pc": 0,
"sqx5twvd2": 1999999999,
"svucwze4j": 0,
"sx8x9599h": 0,
"t5dqlij69": 0,
"ta4apppij": 0,
"teq6nkp5q": 0,
"tzdiwfmta": 0,
"u6d9csg7u": 0,
"u6rk708be": 0,
"uatbihe1e": 0,
"ud4s6eijx": 0,
"uep7gili4": 0,
"v0513whap": 0,
"vgtwj6dx6": 0,
"vic5iz9fn": 0,
"vnqtpium8": 0,
"voliv5syn": 0,
"vpn8wffj9": 0,
"vx3ibdy8n": 0,
"w9fbsp6xw": 0,
"wexgyzrgc": 0,
"wfabjzu6z": 0,
"wibgb6hqf": 0,
"wswkka26i": 0,
"x62f3b6kq": 1693233490,
"xd48hd45t": 0,
"xdd6svv2d": 0,
"xev4p97rf": 0,
"xhsd6flts": 1999999999,
"xingzong1": 1999999999,
"xnkmgye3o": 0,
"xpd1q29dh": 1999999999,
"xpt3raj5g": 0,
"xt1rj8zrh": 0,
"xylink299": 1694295551,
"xylink367": 1693939667,
"xylink579": 1694358799,
"y05scf23r": 0,
"y3z5r0bz7": 0,
"y9cgdji3q": 0,
"yr248p8ho": 0,
"ytozdxeo7": 0,
"z1s42kx5k": 0,
"z3k3j3dui": 0,
"zkshh0kx7": 0,
"zy5o5y9fr": 1697707758,
"zy6h0l3k3": 1699440292
}
module WorldEpcho
go 1.18
require (
github.com/PuerkitoBio/goquery v1.8.1
github.com/apistd/uni-go-sdk v0.0.2
github.com/disintegration/imaging v1.6.2
github.com/gin-contrib/cors v1.7.2
github.com/gin-contrib/sessions v0.0.5
github.com/gin-gonic/gin v1.9.1
github.com/go-redis/redis v6.15.9+incompatible
github.com/go-redis/redis/v8 v8.11.5
github.com/go-sql-driver/mysql v1.7.1
github.com/go-xorm/xorm v0.7.9
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/google/uuid v1.4.0
github.com/gorilla/websocket v1.5.1
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/russross/blackfriday v1.6.0
github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e
github.com/unrolled/secure v1.13.0
go.mongodb.org/mongo-driver v1.9.0
golang.org/x/crypto v0.22.0
golang.org/x/net v0.24.0
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22
)
require (
github.com/andybalholm/cascadia v1.3.1 // indirect
github.com/axgle/mahonia v0.0.0-20180208002826-3358181d7394 // indirect
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-ego/gpy v0.42.1 // indirect
github.com/go-ego/gse v0.80.3 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect
github.com/go-stack/stack v1.8.0 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang/snappy v0.0.1 // indirect
github.com/gorilla/context v1.1.1 // indirect
github.com/gorilla/securecookie v1.1.1 // indirect
github.com/gorilla/sessions v1.2.1 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.13.6 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.2.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/vcaesar/cedar v0.20.2 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.0.2 // indirect
github.com/xdg-go/stringprep v1.0.2 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
golang.org/x/arch v0.7.0 // indirect
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/text v0.19.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/protobuf v1.34.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
xorm.io/builder v0.3.6 // indirect
xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb // indirect
)
replace github.com/gomodule/redigo v2.0.0+incompatible => github.com/gomodule/redigo/redis v0.0.0-20200429221454-e14091dffc1b
This diff is collapsed. Click to expand it.
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAm4vnMTMoDYzWxnKDPzTneezCNkkejQ4Z/wyjkVgaVZF5ROaQ
8Qt1Pk6x69wPnKnP1AQEa0cDfWYJGA5JNDx1qbvCQv29uc1HSO4fnWGGYRSWLqwt
n1MxkMGPHIrZcJZ63CUaFwCSybcD7ZALBh4jy4FBePQuKLsoh5szr0WoMP0ovgE3
A4J8Qn9fA1QOsnHLwT+lXy6euqgvXnR3/Y8MDY6F8cD6RCyXDXqh1b+fKG6F2VMt
jvgObvkpVOscT530JJTwcFpaSi1K3sUX8EErRjJRwjgtK8aIGSXrLu0vJGU+WxXg
R/9BeVTP49yebI54EnMOcLHhTwgcgN++kn+u0QIDAQABAoIBADUKNkoxGwHP2jbu
OnH1rM8HHEydj1TjD5tIaIg5xjUSd4s2ogsH8LFP7VyzfAFcaFlwCz+3hemfPw+c
Y3rz+N1pgHsOgkEWzi2AwXgNluCIwBNnM+Fl4XtufUnq0O2S6o8h+a0JTYSKK0U5
PoEWCvesejJv9UN/WnkvQ6cLNiiJyn3TChzIzNQsjcGQBT3deeldYC/LIXG9/dxK
fQ4CM4hszxa8yK1WKVllQ6GhJuCfjxmHbuMaQR7RYUa0FNmStwSMIbT5KZGdBOCU
9wKKGEJmMbm6RWRd48jcQoznI5xCoMhWuPyDK525CBgUABV/UOKR/LwSz+uYejiq
S0tAyNcCgYEA1y/TLqRn2iCps7fTuglKiWz6YSYK+KW52ztpOzl0NSVspDOrDqZf
Ws0dA7YFroC05T4YqfwQpI5gGemhPnKCN1gqE8navx/2XlNsxp6GCMzKAF9spPAY
OzURgoiU2Km/NkrHVzGaf87E+PZxTB8j+1eDaP/SmOEW5QPf/aE6mcMCgYEAuQxN
uwbKGy0Yv0QgZkfO9SIHj7CHnJwN2lEUSH8VP66sfIt4p9bLVOWpDpmmGtwJeY3H
j03E1TVD0EsFL2DysomEHMs27rTEUAiSXHiXoYJazgiCWoNR4FSuJbPTcAadJy7H
NALX1hBY6bUTHOcqgRuEqpP1qUHopnMXBSXB99sCgYAIRjaAnKHBqW/dETx68tCC
6EXYZnYViYnT/DzXoiXtxTqgNbxmG8+e1jQ/aEhfpWNPTUv1fVPGgBMB7BHfLNgE
+Mbla+WVY809Y0fTe1T8EaPSz9iFnxXPcQLzWf0fN6e6lrWDjMy8DV9Vk2RX4Pqp
N3w+FVgruLwAol2CiyiNsQKBgQCMC8q8M+w7Wwrynh2jKs9vaByu25wWo2g8hMZE
A6HSO2EhNPDQnVfvXYxvl0tF4qdtDicsxl+kOJalClHXRJkJE9gfbpCZYcd9Bq+2
OjIPsrcEXR5CYEZT7+KIeCsaCndfUyDBtTEiOecAoODhK/ZYFbp22lm+ijoH1uxi
IexFpwKBgBy0qO3k1fSrkrQNzXVZFJlWzaYSOs54m6w++NayTjsA8oSWkclVTs9+
AWS1rw/qxTDV+JakUnP1umsGK3Sfbx45MTp6SIZjbm2EB6OLP14I8y0RWsCrdV4o
00apMT+kcY4161ZqA9oAfBUR5WCx6Ht7AHt1hKv1uVL7WsUwKTQd
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIF/zCCBOegAwIBAgIQDHi/XxIxF4QH1gKKDimm8DANBgkqhkiG9w0BAQsFADBu
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMS0wKwYDVQQDEyRFbmNyeXB0aW9uIEV2ZXJ5d2hlcmUg
RFYgVExTIENBIC0gRzIwHhcNMjMxMTE3MDAwMDAwWhcNMjQxMTE3MjM1OTU5WjAe
MRwwGgYDVQQDExNhZG1pbi5taW5kZXBvY2guY29tMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAm4vnMTMoDYzWxnKDPzTneezCNkkejQ4Z/wyjkVgaVZF5
ROaQ8Qt1Pk6x69wPnKnP1AQEa0cDfWYJGA5JNDx1qbvCQv29uc1HSO4fnWGGYRSW
Lqwtn1MxkMGPHIrZcJZ63CUaFwCSybcD7ZALBh4jy4FBePQuKLsoh5szr0WoMP0o
vgE3A4J8Qn9fA1QOsnHLwT+lXy6euqgvXnR3/Y8MDY6F8cD6RCyXDXqh1b+fKG6F
2VMtjvgObvkpVOscT530JJTwcFpaSi1K3sUX8EErRjJRwjgtK8aIGSXrLu0vJGU+
WxXgR/9BeVTP49yebI54EnMOcLHhTwgcgN++kn+u0QIDAQABo4IC5zCCAuMwHwYD
VR0jBBgwFoAUeN+RkF/u3qz2xXXr1UxVU+8kSrYwHQYDVR0OBBYEFE/krgMgQhUG
pao/x9NvC0G2ssDaMB4GA1UdEQQXMBWCE2FkbWluLm1pbmRlcG9jaC5jb20wPgYD
VR0gBDcwNTAzBgZngQwBAgEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdp
Y2VydC5jb20vQ1BTMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcD
AQYIKwYBBQUHAwIwgYAGCCsGAQUFBwEBBHQwcjAkBggrBgEFBQcwAYYYaHR0cDov
L29jc3AuZGlnaWNlcnQuY29tMEoGCCsGAQUFBzAChj5odHRwOi8vY2FjZXJ0cy5k
aWdpY2VydC5jb20vRW5jcnlwdGlvbkV2ZXJ5d2hlcmVEVlRMU0NBLUcyLmNydDAM
BgNVHRMBAf8EAjAAMIIBfwYKKwYBBAHWeQIEAgSCAW8EggFrAWkAdQDuzdBk1dsa
zsVct520zROiModGfLzs3sNRSFlGcR+1mwAAAYvcCWS/AAAEAwBGMEQCIEvyFI5a
SOdVn/J4sICuzrQA5bgb2AQv/SrjHNGP/i/RAiAss138w2gu5U4/VstbDdhGWr6n
wzP/EeY4YFPqNDoeQgB3AEiw42vapkc0D+VqAvqdMOscUgHLVt0sgdm7v6s52IRz
AAABi9wJZI4AAAQDAEgwRgIhAJJV5l0znROZayl2S/6eG8MiZId3yUPdUkKb8xpj
Ed8xAiEAp9YCtXMgM2RwLecms/8CkvIAsudW+BrFZdgyiq1D1KIAdwDatr9rP7W2
Ip+bwrtca+hwkXFsu1GEhTS9pD0wSNf7qwAAAYvcCWRrAAAEAwBIMEYCIQDWRjD2
kVDmQvNuc9r46K9Xo/TGOs+gVnhNovLxKiwqqwIhAL5L/14p4u2gn+R4m8gn1W9u
jlpoMHPKtXGJQnjDz7KPMA0GCSqGSIb3DQEBCwUAA4IBAQB9zHs9ARCNplc2AYoR
5cY3yPdF1LVRRqO5q0JRKUs5kHmcyE3HsdjvXMG4IIEZpLy2VrldFbVCak6T+twJ
U+NE4O9EQZsubRLBhxz4rm1S7DuzttZOzCPnL6/3SwF3uEtgfGz5jpDMv/7IOUZV
DSQUo8QAm4bqc68d3gLh685b4akk3V14FKbF6kqDzvljOs4ERC9TzRVSJtcBGahr
D/JWt/7QeV/JjfShgingBVafl7pZ2y0cLeP9rppwjWCbxAFP0TykGQlwOsZRkVuB
SXLDm/Tp8OgeVGZZYhkl28N6c2yud8Mr3TaeYAN3iVXga88wvR2mJiUbbahtQ5sK
bgEf
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEqjCCA5KgAwIBAgIQDeD/te5iy2EQn2CMnO1e0zANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
MjAeFw0xNzExMjcxMjQ2NDBaFw0yNzExMjcxMjQ2NDBaMG4xCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xLTArBgNVBAMTJEVuY3J5cHRpb24gRXZlcnl3aGVyZSBEViBUTFMgQ0EgLSBH
MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAO8Uf46i/nr7pkgTDqnE
eSIfCFqvPnUq3aF1tMJ5hh9MnO6Lmt5UdHfBGwC9Si+XjK12cjZgxObsL6Rg1njv
NhAMJ4JunN0JGGRJGSevbJsA3sc68nbPQzuKp5Jc8vpryp2mts38pSCXorPR+sch
QisKA7OSQ1MjcFN0d7tbrceWFNbzgL2csJVQeogOBGSe/KZEIZw6gXLKeFe7mupn
NYJROi2iC11+HuF79iAttMc32Cv6UOxixY/3ZV+LzpLnklFq98XORgwkIJL1HuvP
ha8yvb+W6JislZJL+HLFtidoxmI7Qm3ZyIV66W533DsGFimFJkz3y0GeHWuSVMbI
lfsCAwEAAaOCAU8wggFLMB0GA1UdDgQWBBR435GQX+7erPbFdevVTFVT7yRKtjAf
BgNVHSMEGDAWgBROIlQgGJXm427mD/r6uRLtBhePOTAOBgNVHQ8BAf8EBAMCAYYw
HQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBIGA1UdEwEB/wQIMAYBAf8C
AQAwNAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdp
Y2VydC5jb20wQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybDMuZGlnaWNlcnQu
Y29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEcyLmNybDBMBgNVHSAERTBDMDcGCWCGSAGG
/WwBAjAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BT
MAgGBmeBDAECATANBgkqhkiG9w0BAQsFAAOCAQEAoBs1eCLKakLtVRPFRjBIJ9LJ
L0s8ZWum8U8/1TMVkQMBn+CPb5xnCD0GSA6L/V0ZFrMNqBirrr5B241OesECvxIi
98bZ90h9+q/X5eMyOD35f8YTaEMpdnQCnawIwiHx06/0BfiTj+b/XQih+mqt3ZXe
xNCJqKexdiB2IWGSKcgahPacWkk/BAQFisKIFYEqHzV974S3FAz/8LIfD58xnsEN
GfzyIDkH3JrwYZ8caPTf6ZX9M1GrISN8HnWTtdNCH2xEajRa/h9ZBXjUyFKQrGk2
n2hcLrfZSbynEC/pSw/ET7H5nWwckjmAJ1l9fcnbqkU/pf6uMQmnfl0JQjJNSg==
-----END CERTIFICATE-----
SET CGO_ENABLED=0
SET GOOS=linux
SET GOARCH=amd64
echo now the CGO_ENABLED:
go env CGO_ENABLED
echo now the GOOS:
go env GOOS
echo now the GOARCH:
go env GOARCH
go build -o worldEpcho main.go
SET CGO_ENABLED=1
SET GOOS=windows
SET GOARCH=amd64
echo now the CGO_ENABLED:
go env CGO_ENABLED
echo now the GOOS:
go env GOOS
echo now the GOARCH:
go env GOARCH
\ No newline at end of file
package main
import (
"fmt"
//"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt"
"time"
)
var accessKey = "next654c5506ab4fcf3e17cf970b" // NextHuman平台accessKey
var accessSecret = "xhInaX3Vk8Mv9KTWZMM5GoFPCf5Gf5VEMo8K9RjROw" // NextHuman平台 accessSecret
func generateToken(accessKey, accessSecret string) (string, error) {
// 创建 JWT 的头部
token := jwt.New(jwt.SigningMethodHS256)
// 设置 JWT 的负载(Payload)
claims := token.Claims.(jwt.MapClaims)
claims["aud"] = "app" // 接收者
claims["iss"] = accessKey // 签发者
claims["exp"] = time.Now().Add(time.Hour * 12).Unix() // 过期时间
claims["iat"] = time.Now().Unix() // 签发时间
// 使用 accessSecret 来签名并生成最终的 Token
tokenString, err := token.SignedString([]byte(accessSecret))
if err != nil {
return "", err
}
return tokenString, nil
}
func main() {
tokenString, err := generateToken(accessKey, accessSecret)
if err != nil {
fmt.Println("Token generation failed:", err)
return
}
fmt.Println("Generated Token:", tokenString)
}
package config
import (
"encoding/binary"
"encoding/json"
"fmt"
"github.com/patrickmn/go-cache"
"math/rand"
"os"
"time"
)
var (
Conf *AppConfig
WorldLoginCacheCode = cache.New(30*time.Minute, 15*time.Second)
)
const (
ColorReset = "\033[0m"
ColorRed = "\033[31m"
ColorGreen = "\033[32m"
ColorYellow = "\033[33m"
ColorBlue = "\033[34m"
ColorPurple = "\033[35m"
ColorCyan = "\033[36m"
ColorWhite = "\033[37m"
)
type AppConfig struct {
AppName string `json:"app_name"` //项目名称 no-name
DBname string `json:"db_name"` //数据库名称 test_schema
DBserver string `json:"db_server"` //mysql域名
Mode string `json:"mode"`
Mysql_UserName string `json:"mysql_username"` //mysql用户名 root
Mysql_PWD string `json:"mysql_pwd"` //mysql密码 root
MysqlPort string `json:"mysql_port"` //mysql启动端口
Mongo_UserName string `json:"mongo_username"`
Mongo_PWD string `json:"mongo_pwd"`
Mongo_Host string `json:"mongo_host"`
Mongo_Port string `json:"mongo_port"`
//华为SMS短信平台url
HUAWEI_SMS_Url string `json:"huawei_sms_url"`
Port string `json:"port"` //项目启动端口
StaticPath string `json:"static_path"`
Timeout10 string `json:"timeout10"` //mysql超时
RedisServer string `json:"redis_server"` //redis域名
RedisPort string `json:"redis_port"` //redis启动端口
RedisPwd string `json:"redis_pwd"` //redis密码
RedisDB string `json:"redis_db"` //redis连接数据库
//短信验证码
SmsAccessKeyId string `json:"sms_access_key_id"`
SmsAccessKeySecret string `json:"sms_access_key_secret"`
//咪咕JWT的secret
JwtSecret string `json:"jwt_secret"`
MiGuAuthId string `json:"miGuAuthId"`
SoulUrl string `json:"soul_url"`
SoulAuth string `json:"soul_auth"`
TranscribeUrl string `json:"transcribe_url"`
GetTokenUrl string `json:"get_token_url"`
AppKey string `json:"app_key"`
AppSecret string `json:"app_secret"`
MentalClinicUrl string `json:"mental_clinic_url"`
CallBackUrl string `json:"call_back_url"`
SemanticAnalysisUrl string `json:"semantic_analysis_url"`
VoiceSetModelUrl string `json:"voice_set_model_url"`
TranslatePropUrl string `json:"translate_prop_url"`
Md5Salt string `json:"md5_salt"`
ExhibitionModeAppId int64 `json:"exhibition_mode_app_id"`
DrawAiUrl string `json:"draw_ai_url"`
//提示词
PromptAPIUrl string `json:"prompt_api_url"`
//头像绘制
HeadPortraitAPI string `json:"head_portrait_api"`
VoiceModelSets map[string]VoiceModel `json:"voice_model_sets"`
//微信小程序
WechatUrl string `json:"wechat_url"`
WechatAccessTokenUrl string `json:"wechat_access_token_url"`
WechatGetPhoneUrl string `json:"wechat_get_phone_url"`
WechatAppId string `json:"wechat_app_id"`
WechatAppSecret string `json:"wechat_app_secret"`
}
// 定义 VoiceModel 结构体来存储每个模型的路径
type VoiceModel struct {
GPTModelPath string `json:"gpt_model_path"`
SoVITSModelPath string `json:"sovits_model_path"`
ReferWavPath string `json:"refer_wav_path"`
PromptText string `json:"prompt_text"`
PromptLanguage string `json:"prompt_language"`
CnName string `json:"cn_name"`
}
// 定义 VoiceModels 结构体储存所有的 VoiceModelSet
/*
type VoiceModelSets struct {
VoiceModel map[string]VoiceModel `json:"voice_model_sets"`
}
*/
// 方法,根据人名获取模型路径
func GetModelPathsByName(name string) (string, string, bool) {
if modelSet, exists := Conf.VoiceModelSets[name]; exists {
return modelSet.GPTModelPath, modelSet.SoVITSModelPath, true
}
return "", "", false
}
func InitConfig() *AppConfig {
fmt.Println(" 读取配置文件... ")
file, err := os.Open("./config.json")
/*
var file *os.File
var err error
if runtime.GOOS == "linux" {
file, err = os.Open("./config.json")
} else {
file, err = os.Open("src/config.json")
}
*/
if err != nil {
println("error is :", err.Error())
}
decoder := json.NewDecoder(file)
conf := AppConfig{}
err = decoder.Decode(&conf)
if err != nil {
println("error is :", err.Error())
}
Conf = &conf
return &conf
}
//全局随机种子
func RandInit() {
var b [8]byte
_, err := rand.Read(b[:])
if err != nil {
rand.Seed(time.Now().UnixNano())
} else {
rand.Seed(time.Now().UnixNano() + int64(binary.LittleEndian.Uint64(b[:])))
}
}
var GlobalRand = func() *rand.Rand {
// 创建一个缓冲区来存储生成的随机数
var b [8]byte
_, err := rand.Read(b[:])
var seed int64
if err != nil {
// 如果随机数生成失败,回退到当前时间作为种子
seed = time.Now().UnixNano()
} else {
// 如果随机数生成成功,使用它与当前时间的纳秒来创建种子
seed = time.Now().UnixNano() + int64(binary.LittleEndian.Uint64(b[:]))
}
return rand.New(rand.NewSource(seed))
}()
package e
const (
SUCCESS = 200
UpdatePasswordSuccess = 201
NotExistIdentifier = 202 //用户名或者密码错误
NotExistUser = 203
InvalidParams = 400
ErrorDatabase = 401
TokenAuthError = 402
EmptyParamsError = 403
NotFound = 404
InvalidToken = 405
IllegalServiceProvider = 406
RenewalTimeTokenError = 407
UnauthorizedStatus = 408
ParamParseError = 409
NotLoginUser = 410
InternalError = 500
//WebsocketSuccessMessage = 2000
WebsocketSuccess = 1
WebsocketEnd = -2
WebsocketMessageTypeError = -1 //消息类型错误或者创建会话失败
HUASOULSERVICE_SUCCESS = 1 //AI调用echo接口成功
HUASOULSERVICE_INVALID = 0 //
HUASOULSERVICE_MSGERR = 3
HUASOULSERVICE_ILLEGAL = 4
)
package e
var MsgFlags = map[int]string{
SUCCESS: "ok",
UpdatePasswordSuccess: "修改密码成功",
NotExistIdentifier: "账号或密码不正确",
InternalError: "内部服务器错误",
InvalidParams: "请求参数错误",
ErrorDatabase: "数据库操作出错,请重试",
WebsocketSuccess: "发送信息,请求历史纪录操作成功",
WebsocketEnd: "请求历史纪录,但没有更多记录了",
}
// GetMsg 获取状态码对应信息
func GetMsg(code int) string {
msg, ok := MsgFlags[code]
if ok {
return msg
}
return MsgFlags[InternalError]
}
package controllers
import (
"WorldEpcho/src/config"
"WorldEpcho/src/models"
"WorldEpcho/src/service"
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"log"
"net/http"
"strconv"
"time"
)
//获取所有应用id和应用名称的映射关系
func QueryAppIdNames(ctx *gin.Context) {
/*
判断用户是否登录
*/
_, isLogin := service.IsUserLoggedIn(ctx)
if !isLogin {
log.Println("用户未登录")
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户未登录"})
return
}
apps, err := models.GetAppIDNames()
if err != nil {
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "查询应用id与应用名称出错"})
return
}
response := gin.H{
"code": 1,
"message": "查询应用id与应用名称成功",
"apps": apps,
}
// 序列化响应数据为 JSON 字符串
jsonData, err := json.Marshal(response)
if err != nil {
// 处理序列化错误
fmt.Println("序列化 JSON 数据出错:", err)
return
}
fmt.Println(config.ColorCyan, string(jsonData), config.ColorReset)
ctx.JSON(http.StatusOK, response)
}
//创建应用接口
func CreateApplication(ctx *gin.Context) {
/*
判断用户是否登录
*/
uid, isLogin := service.IsUserLoggedIn(ctx)
if !isLogin {
log.Println("用户未登录")
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户未登录"})
return
}
/*
添加应用信息
*/
participatorId := []int64{uid} // 创建一个包含uid的数组
var app = models.Application{
AppName: ctx.PostForm("app_name"),
Description: ctx.PostForm("description"),
ConfigData: ctx.PostForm("config_data"),
CreatorId: uid,
ParticipatorId: participatorId,
CreatedAt: time.Now().Unix(),
UpdatedAt: time.Now().Unix(),
}
// 在数据库中创建应用
err := models.AddApplication(&app)
if err != nil {
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": err.Error()})
return
}
ctx.JSON(http.StatusOK, gin.H{"code": 1, "message": "Application created successfully"})
}
// 根据应用ID, 查询应用详情
func QueryApplication(ctx *gin.Context) {
/*
判断用户是否登录
*/
_, isLogin := service.IsUserLoggedIn(ctx)
if !isLogin {
log.Println("用户未登录")
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户未登录"})
return
}
idStr := ctx.PostForm("app_id")
id, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "Invalid app Id"})
return
}
app, err1 := models.GetApplication(id)
if err1 != nil {
ctx.JSON(http.StatusNotFound, gin.H{"code": 0, "message": "Application not found"})
return
}
ctx.JSON(http.StatusOK, gin.H{"code": 1, "message": app})
}
// 更新应用信息
func EditApplication(ctx *gin.Context) {
/*
判断用户是否登录
*/
_, isLogin := service.IsUserLoggedIn(ctx)
if !isLogin {
log.Println("用户未登录")
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户未登录"})
return
}
idStr := ctx.PostForm("app_id")
id, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "转换AppId失败"})
return
}
app, err1 := models.GetApplication(id)
if err1 != nil {
ctx.JSON(http.StatusNotFound, gin.H{"code": 0, "message": "Application not found"})
return
}
app.UpdatedAt = time.Now().Unix()
err = models.UpdateApplication(app)
if err != nil {
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "Updating application failed"})
return
}
ctx.JSON(http.StatusOK, gin.H{"code": 1, "message": "Application updated successfully"})
}
// 删除应用
func DropApplication(ctx *gin.Context) {
/*
判断用户是否登录
*/
_, isLogin := service.IsUserLoggedIn(ctx)
if !isLogin {
log.Println("用户未登录")
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户未登录"})
return
}
idStr := ctx.PostForm("app_id")
id, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "转换AppId失败"})
return
}
err = models.DeleteApplication(id)
if err != nil {
ctx.JSON(http.StatusNotFound, gin.H{"code": 0, "message": "Delete operation failed"})
return
}
ctx.JSON(http.StatusOK, gin.H{"status": "Application deleted successfully"})
}
//根据参与者id获取可用的应用
func QueryApplicationsByParticipatorId(ctx *gin.Context) {
/*
判断用户是否登录
*/
_, isLogin := service.IsUserLoggedIn(ctx)
if !isLogin {
log.Println("用户未登录")
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户未登录"})
return
}
idStr := ctx.PostForm("participator_id")
participator_id, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "Invalid participator_id"})
return
}
apps, err := models.GetApplicationsByParticipatorId(participator_id)
if err != nil {
fmt.Println("根据参与者id获取可用应用失败")
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "根据参与者id获取可用应用失败"})
return
}
ctx.JSON(http.StatusOK, gin.H{"code": 1, "message": apps})
}
//根据手机号为应用添加参与者
func AddApplicationParticipator(ctx *gin.Context) {
/*
判断用户是否登录
*/
_, isLogin := service.IsUserLoggedIn(ctx)
if !isLogin {
log.Println("用户未登录")
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户未登录"})
return
}
phone := ctx.PostForm("phone")
app_Id := ctx.PostForm("app_id")
appId, err := strconv.ParseInt(app_Id, 10, 64)
if err != nil {
fmt.Println("转换失败:", err)
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "应用id类型转换失败"})
return
}
err = models.AddApplicationParticipant(appId, phone)
if err != nil {
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "通过手机号添加应用参与者失败"})
}
ctx.JSON(http.StatusOK, gin.H{"code": 1, "message": "根据手机号添加应用参与者成功!"})
}
//根据应用ID查询参与者
func QueryParticipantsByAppID(ctx *gin.Context) {
/*
判断用户是否登录
*/
_, isLogin := service.IsUserLoggedIn(ctx)
if !isLogin {
log.Println("用户未登录")
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户未登录"})
return
}
app_Id := ctx.PostForm("app_id")
appId, err := strconv.ParseInt(app_Id, 10, 64)
if err != nil {
fmt.Println("转换失败:", err)
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "应用id类型转换失败"})
return
}
users, err := models.GetParticipantsByAppID(appId)
if err != nil {
fmt.Println("根据应用ID查询参与者失败:", err)
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "根据应用ID查询参与者失败"})
}
ctx.JSON(http.StatusOK, gin.H{"code": 1, "message": users})
}
//根据应用名称模糊匹配查询
func QueryApplicationLikeAppName(ctx *gin.Context) {
/*
判断用户是否登录
*/
uid, isLogin := service.IsUserLoggedIn(ctx)
if !isLogin {
log.Println("用户未登录")
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户未登录"})
return
}
app_name := ctx.PostForm("app_name")
apps, err := models.QueryApplicationLikeAppName(uid, app_name)
if err != nil {
fmt.Println(config.ColorRed, "根据应用名称模糊匹配查询失败", err, config.ColorReset)
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "根据应用名称模糊匹配查询失败"})
}
ctx.JSON(http.StatusOK, gin.H{"code": 1, "message": apps})
}
package controllers
import (
"WorldEpcho/src/models"
"WorldEpcho/src/service"
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"log"
"net/http"
"strconv"
"time"
)
func HandleEmbuEvaluation(c *gin.Context) {
// 判断用户是否登录
uid, isLogin := service.IsUserLoggedIn(c)
if !isLogin {
log.Println("用户未登录")
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户未登录"})
return
}
appId := c.PostForm("appId")
appName := c.PostForm("appName")
app_Id, err := strconv.ParseInt(appId, 10, 64)
if err != nil {
fmt.Println("应用id类型转换失败")
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "应用id类型转换失败"})
return
}
// 从POST请求的body中获取前端传递的测试数据JSON字符串
testDataJson := c.PostForm("testData")
var testData models.TestResultData
err = json.Unmarshal([]byte(testDataJson), &testData)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid test data format"})
return
}
// 获取配置数据
configData, err := models.GetConfigDataByAppInfo(app_Id, appName)
if err != nil {
fmt.Printf("根据应用id和应用名称查询应用的配置信息失败")
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "根据应用id和应用名称查询应用的配置信息失败"})
return
}
// 处理评估
evaluateResult, err := models.ProcessEvaluation(testData, configData)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": 0, "message": "处理embu的结果数据出错"})
return
}
// 将evaluateResult转换为JSON字符串
evaluateResultJson, err := json.Marshal(evaluateResult)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": 0, "message": "转换评估结果为JSON字符串失败"})
return
}
shareType := c.PostForm("shareType")
// 保存评估结果到数据库
testResult := &models.EmbuTestResult{
AppId: app_Id,
Uid: uid,
TestData: testDataJson, // 直接使用JSON字符串
EvaluateResult: string(evaluateResultJson), // 这里假设已经是JSON字符串或者将其转换为JSON字符串
EvaluateTime: time.Now().Unix(),
ShareType: shareType,
}
err = models.InsertTestResult(testResult)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": 0, "message": "保存结果数据到数据库出错"})
return
}
// 将评估结果返回给前端
c.JSON(http.StatusOK,
gin.H{
"code": 1,
"message": "Embu 评估结果成功,并保存数据库成功",
"evaluateResult": evaluateResult,
},
)
}
package controllers
import (
"WorldEpcho/src/models"
"WorldEpcho/src/service"
"github.com/gin-gonic/gin"
"log"
"net/http"
)
// GetInviteCode 获取用户的邀请码
func GetInviteCode(c *gin.Context) {
/*
判断用户是否登录
*/
userID, isLogin := service.IsUserLoggedIn(c)
if !isLogin {
log.Println("用户未登录")
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户未登录"})
return
}
//根据用户id到mysql数据库查询一下是否存在
inviteCode, err := models.QueryInviteCode(userID)
if err != nil {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "根据用户id查询邀请码失败!"})
return
}
if inviteCode == "" {
// 调用查询邀请码的函数
code, err := models.GenerateInviteCode(userID)
if err != nil {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "获取邀请码失败!"})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 1,
"invite_code": code,
"message": "生成邀请码",
})
} else {
c.JSON(http.StatusOK, gin.H{
"code": 1,
"message": "邀请码已存在",
"invite_code": inviteCode,
})
}
}
//重置邀请码
func ResetUserInviteCode(c *gin.Context) {
/*
判断用户是否登录
*/
userID, isLogin := service.IsUserLoggedIn(c)
if !isLogin {
log.Println("用户未登录")
return
}
// 调用重置邀请码的函数
InviteCode, err1 := models.ResetInviteCode(userID)
if err1 != nil {
c.JSON(http.StatusOK, gin.H{"code": 0,
"message": "重置邀请码失败"})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 1,
"invite_code": InviteCode,
"message": "邀请码重置成功",
})
}
//获取直接邀请人
/*
func QueryDirectInviter(c *gin.Context) {
//判断用户是否登录
userID, isLogin := IsUserLoggedIn(c)
if !isLogin {
log.Println("用户未登录")
return
}
inviter, err := models.GetDirectInviter(userID)
if err != nil {
c.JSON(http.StatusOK, gin.H{"code": 0,
"message": err.Error()})
return
} else {
c.JSON(http.StatusOK, gin.H{"code": 1,
"message": "获取直接邀请人成功!",
"邀请人": inviter,
})
}
}
*/
// 根据邀请人的id获取所有被邀请的用户的id
func QueryDirectInviter(c *gin.Context) {
//判断用户是否登录
userID, isLogin := service.IsUserLoggedIn(c)
if !isLogin {
log.Println("用户未登录")
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户未登录"})
return
}
//根据邀请人的ID查询所有被邀请人的ID
inviteeIds, err := models.GetInviteesByInviterID(userID)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": err.Error()})
return
} else {
c.JSON(http.StatusOK, gin.H{"code": 1,
"message": "获取直接邀请人成功!",
"inviteeIds": inviteeIds,
})
}
}
//查询用户的直接邀请人
func QueryIndirectInvitees(c *gin.Context) {
//判断用户是否登录
userID, isLogin := service.IsUserLoggedIn(c)
if !isLogin {
log.Println("用户未登录")
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户未登录"})
return
}
//根据当前用户的id查询所有间接邀请的人
invitees, err := models.GetIndirectInvitees(userID)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": err.Error()})
return
} else {
c.JSON(http.StatusOK, gin.H{"code": 1,
"message": "获取所有间接邀请人成功!",
"invitees": invitees,
})
}
}
package controllers
import (
"fmt"
"github.com/golang-jwt/jwt"
//"github.com/dgrijalva/jwt-go"
"time"
)
const (
ExpireDuration = 3600 * time.Second
accessKey = "next658bddfdd8b829226f1387ec" // NextHuman平台accessKey
accessSecret = "w4iaxcax1n1PfyaDVd_HEY8PysVsOOAkmGJisqDwlW" // NextHuman平台 accessSecret
)
type CustomClaims struct {
jwt.StandardClaims
Role string `json:"role"`
Timestamp int64 `json:"timestamp"`
}
// 生成token
func GenerateToken() (string, error) {
// 定义token的过期时间
expireTime := time.Now().Add(ExpireDuration).Unix() //过期时间为秒
fmt.Println("expireTime: ", expireTime)
// 创建一个自定义的Claims
claims := &CustomClaims{
Role: "role.visit",
Timestamp: time.Now().UnixMilli(), // 当前时间戳毫秒级
StandardClaims: jwt.StandardClaims{
ExpiresAt: expireTime,
},
}
// 使用 JWT 签名算法生成token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// 将token进行加盐加密
// 注意:该方法参数虽然是interface{},但是必须传入[]byte类型的参数
tokenString, err := token.SignedString([]byte(accessSecret))
if err != nil {
return "", err
}
return accessKey + "@" + tokenString, nil
}
func ParseToken(tokenString string) (*CustomClaims, error) {
// 解析 token
token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
// 注意:虽然返回值是interface,但是这里必须返回[]byte类型,否则运行时会报错key is of invalid type
return []byte(accessSecret), nil
})
if err != nil {
return nil, err
}
if myClaims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
return myClaims, nil
} else {
return nil, jwt.NewValidationError("invalid token", jwt.ValidationErrorClaimsInvalid)
}
}
func GenerateToken1() (string, error) {
// 创建 JWT 的头部
token := jwt.New(jwt.SigningMethodHS256)
// 设置 JWT 的负载(Payload)
claims := token.Claims.(jwt.MapClaims)
claims["aud"] = "app" // 接收者
claims["iss"] = accessKey // 签发者
claims["exp"] = time.Now().Add(10 * time.Minute).Unix() // 过期时间
claims["iat"] = time.Now().Unix() // 签发时间
// 使用 accessSecret 来签名并生成最终的 Token
tokenString, err := token.SignedString([]byte(accessSecret))
if err != nil {
return "", err
}
return tokenString, nil
}
// CreateAccessToken 创建访问令牌
func CreateAccessToken1() (string, error) {
// 创建JWT令牌
token := jwt.New(jwt.SigningMethodHS256)
// 设置JWT声明
claims := token.Claims.(jwt.MapClaims)
claims["role"] = "role.visit"
claims["timestamp"] = time.Now().Unix()
fmt.Println(time.Now().UnixMilli())
claims["exp"] = time.Now().UnixMilli() + 30*60*1000 // 设置30分钟后过期
// 使用accessSecret签名并获得完整的编码后的字符串令牌
tokenString, err := token.SignedString([]byte(accessSecret))
if err != nil {
return "", err
}
return accessKey + "@" + tokenString, nil
}
func CreateAccessToken2() (string, error) {
// 设置我们自己的自定义和标准JWT声明
claims := &CustomClaims{
StandardClaims: jwt.StandardClaims{
ExpiresAt: time.Now().Add(6 * time.Hour).Unix(), // Token过期时间设置为24小时后
},
Role: "role.visit",
Timestamp: time.Now().Unix(), // 当前时间戳秒级
}
// 创建一个新的令牌,指定签名方法和声明
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
// 使用accessSecret作为HMAC密钥来签名
signedToken, err := token.SignedString([]byte(accessSecret))
if err != nil {
return "", err
}
return accessKey + "@" + signedToken, nil
}
package controllers
import (
"WorldEpcho/src/config"
"WorldEpcho/src/config/e"
"WorldEpcho/src/models"
"WorldEpcho/src/service"
"WorldEpcho/src/utils"
"fmt"
"github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/gin"
"log"
"net/http"
"time"
)
// jwtSecret 应该定义在安全的地方,比如环境变量或配置文件中
//var jwtSecret = []byte("your_jwt_secret")
// 用户登录控制器
func LoginJWT1(c *gin.Context) {
// 获取表单信息
username := c.PostForm("username")
password := c.PostForm("password")
fmt.Println("username:", username, ",password:", password)
// 调用工具类的MD5加盐的函数
salt := config.Conf.Md5Salt
md5String, err := utils.MD5BySalf(password, salt)
if err != nil {
log.Println("密码加盐失败!")
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "密码加盐失败"})
return
}
// 根据用户名和密码从数据库中查询
Userid, level, status, tags, _, err := models.QueryUserWithParam2(username, md5String)
if err != nil || Userid <= 0 {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户名或密码错误"})
return
}
if status == -1 {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "该用户已经注销!"})
return
}
// 用户验证通过后,生成JWT Token
token, err := GenerateLoginJWTToken(Userid, level)
if err != nil {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "生成令牌失败"})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 1,
"message": "登录成功",
"level": level,
"token": token,
"tags": tags,
})
}
// 定义一个结构体来匹配JSON数据格式
type LoginRequest struct {
Username string `json:"username"`
Password string `json:"password"`
}
func LoginJWT(c *gin.Context) {
var loginReq LoginRequest
// 将请求的JSON数据绑定到结构体
if err := c.ShouldBindJSON(&loginReq); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"code": e.InvalidParams, "data": nil, "message": "请求数据格式错误"})
return
}
fmt.Println("username:", loginReq.Username, ", password:", loginReq.Password)
// 调用工具类的MD5加盐的函数
salt := config.Conf.Md5Salt
md5String, err := utils.MD5BySalf(loginReq.Password, salt)
if err != nil {
log.Println("密码加盐失败!")
c.JSON(http.StatusOK, gin.H{"code": e.InternalError, "data": nil, "message": "密码加盐失败"})
return
}
// 根据用户名和密码从数据库中查询
Userid, level, status, _, _, err := models.QueryUserWithParam2(loginReq.Username, md5String)
if err != nil || Userid <= 0 {
c.JSON(http.StatusOK, gin.H{"code": e.NotExistIdentifier, "data": nil, "message": "用户名或密码错误"})
return
}
if status == -1 {
c.JSON(http.StatusOK, gin.H{"code": e.NotExistUser, "data": nil, "message": "该用户已经注销!"})
return
}
// 用户验证通过后,生成JWT Token
token, err := GenerateLoginJWTToken(Userid, level)
if err != nil {
c.JSON(http.StatusOK, gin.H{"code": e.InternalError, "data": nil, "message": "生成令牌失败"})
return
}
c.JSON(http.StatusOK, gin.H{
"code": e.SUCCESS,
"message": "获取token成功",
"data": gin.H{
"level": level,
"token": token,
},
})
}
// generateToken 生成JWT令牌
func GenerateLoginJWTToken(userId int64, level int) (string, error) {
jwtSecret := config.Conf.JwtSecret
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"user_id": userId,
"level": level,
"exp": time.Now().Add(3 * time.Hour).Unix(),
})
token, err := tokenClaims.SignedString([]byte(jwtSecret))
if err != nil {
return "", fmt.Errorf("%d: %w", e.InternalError, err) // Return an error with the internal error code
}
return token, nil
}
func AuthJwtIsValid() gin.HandlerFunc {
return func(c *gin.Context) {
// 获取 Authorization 头部的 JWT 令牌
tokenString := c.GetHeader("Authorization")
if tokenString == "" {
c.JSON(http.StatusUnauthorized, gin.H{"code": 0, "message": "请求未授权"})
c.Abort()
return
}
// 解析并验证 token
token, isValid, err := service.ParseMIGUToken(tokenString)
if err != nil || !isValid {
// 处理解析或验证失败的情况,返回 401 Unauthorized 错误
c.JSON(http.StatusUnauthorized, gin.H{"code": 0, "message": "令牌无效或过期"})
c.Abort()
return
}
// 提取 Token 中的声明(Claims)
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
// 你可以提取相关的用户信息并存储到上下文中,供后续处理使用
userID := claims["user_id"]
level := claims["level"]
// 将 userID 和其他信息保存在上下文中,以便后续使用
c.Set("userID", userID)
c.Set("userLevel", level)
} else {
// 如果 Claims 无法被解析或无效,也返回未授权
c.JSON(http.StatusUnauthorized, gin.H{"code": 0, "message": "令牌无效"})
c.Abort()
return
}
// 令牌有效,继续处理请求
c.Next()
}
}
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// 获取 Authorization 头部的 JWT 令牌
tokenString := c.GetHeader("Authorization")
if tokenString == "" {
c.JSON(http.StatusUnauthorized, gin.H{"code": 0, "message": "请求未授权"})
c.Abort()
return
}
// 解析并验证 token
token, isValid, err := service.ParseMIGUToken(tokenString)
if err != nil || !isValid {
// 处理解析或验证失败的情况,返回 401 Unauthorized 错误
c.JSON(http.StatusUnauthorized, gin.H{"code": 0, "message": "令牌无效或过期"})
c.Abort()
return
}
// 提取 Token 中的声明(Claims)
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
// 你可以提取相关的用户信息并存储到上下文中,供后续处理使用
userID := claims["user_id"]
level := claims["level"]
// 将 userID 和其他信息保存在上下文中,以便后续使用
c.Set("userID", userID)
c.Set("userLevel", level)
} else {
// 如果 Claims 无法被解析或无效,也返回未授权
c.JSON(http.StatusUnauthorized, gin.H{"code": 0, "message": "令牌无效"})
c.Abort()
return
}
// 令牌有效,继续处理请求
c.Next()
}
}
func LoginTest(c *gin.Context) {
uid, islogin := service.IsUserLoggedIn(c)
fmt.Println("uid ==> ", uid, "islogin ==>", islogin)
c.JSON(http.StatusOK, gin.H{
"code": 1,
"uid": uid,
"islogin": islogin,
})
}
package controllers
import (
database "WorldEpcho/src/datasource"
"WorldEpcho/src/models"
"WorldEpcho/src/service"
"WorldEpcho/src/utils"
"fmt"
"github.com/gin-gonic/gin"
"log"
"net/http"
"strconv"
"strings"
)
// CreateActiveCode 获取一次性用户激活码
func CreateServiceProvider(c *gin.Context) {
/*
判断用户是否登录
*/
userID, isLogin := service.IsUserLoggedIn(c)
if !isLogin {
log.Println("用户未登录")
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户未登录"})
return
}
//开启事务
session := database.Engine.NewSession()
defer session.Close() //延迟关闭session
err := session.Begin()
if err != nil {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "开启事务失败!"})
fmt.Println("开启事务失败")
return
}
//判断用户的权限level是否为0
level, err1 := models.GetUserLevel(userID)
if err1 != nil {
log.Println("查询用户权限出错")
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "查询用户权限出错"})
return
}
if level != 0 {
log.Println("用户无权创建服务商")
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户无权创建服务商"})
return
}
//从前端获取值
name := c.PostForm("name")
phone := c.PostForm("phone")
description := c.PostForm("description")
accessibleTags := c.PostForm("accessibleTags")
//可以访问的标签
TagsArr := []string{}
// 分割字符串,得到单独的数值字符串
tagsSplit := strings.Split(accessibleTags, ",")
for _, tagStr := range tagsSplit {
// 将转换后的数值添加到数组
TagsArr = append(TagsArr, tagStr)
}
inspirationValue := c.PostForm("inspirationValue")
// 将字符串转换为 int64 类型
museValue, err := strconv.ParseInt(inspirationValue, 10, 64)
if err != nil {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "灵感值类型转换出错"})
//continue
return
}
//生成服务商id,32位UUID
SP_id := utils.GenerateUUID()
/*fmt.Println("服务商id:", SP_id)
_, isExist, err := models.GetUserByPhone(session, phone)
if err != nil {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "根据服务商手机号查询用户出错"})
return
}
if isExist {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "服务商手机对应的用户已存在"})
return
}
// 密码加盐操作
salt := config.Conf.Md5Salt
password, err := utils.MD5BySalf(phone, salt)
// 创建一个用户用于服务商
NewUser := models.User{
Username: name,
Phone: phone,
Password: password,
Createtime: time.Now().Unix(),
Level: 9,
}
//添加用户
rows, user_id, err := models.AddUser(session, &NewUser)
if err != nil {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "创建服务商的用户失败"})
log.Println(err.Error())
return
}
if rows <= 0 {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "创建服务商的用户失败"})
fmt.Println("创建服务商的用户失败!")
return
}*/
// 构建服务商对象
serviceProvider := &models.ServiceProvider{
ID: SP_id,
//Uid: user_id,
Name: name,
Description: description,
ContactNumber: phone,
AccessibleTags: TagsArr,
InspirationValue: museValue,
}
err = models.CreateServiceProvider(serviceProvider)
if err != nil {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "创建服务商失败"})
return
}
//提交事务
err = session.Commit()
if err != nil {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "创建服务商失败"})
return
}
c.JSON(http.StatusOK, gin.H{"code": 1, "message": "创建服务商成功"})
}
package controllers
import (
"WorldEpcho/src/utils"
"errors"
"fmt"
"github.com/gin-gonic/gin"
"net/http"
"os"
"path/filepath"
"strings"
)
// 处理文件夹上传
func UploadFolderHandler(c *gin.Context, digitalId int64) (string, error) {
err := c.Request.ParseMultipartForm(0) // 不限制上传文件大小
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": err.Error(),
})
return "", errors.New("获取上传的文件失败")
}
//digitalId := 1
// 数字人ID转换为字符串
digital_Id := utils.Strval(digitalId)
modePath := filepath.Join("./static/HuaSoul/asset/", digital_Id)
fmt.Println("数字人模型资产上传路径 modePath: ", modePath)
// 检查上传的文件是否存在
form, err := c.MultipartForm()
files := form.File["mode_file"] // 'files' 是前端 JavaScript 中指定的字段名
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "missing uploaded file"})
return "", errors.New("丢失上传的文件")
}
// 检查目标文件夹是否存在,如果存在则删除
if _, err := os.Stat(modePath); !os.IsNotExist(err) {
if err := os.RemoveAll(modePath); err != nil {
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "failed to remove existing model folder",
})
return "", errors.New("failed to remove existing model folder")
fmt.Println("删除已存在的数字人模型资产文件夹失败!")
}
fmt.Println("检查数字人模型资产文件夹,存在则删除!")
}
// 创建存放模型文件的文件夹
if err := os.MkdirAll(modePath, 0755); err != nil {
c.JSON(http.StatusOK, gin.H{
"code": 0,
"message": "failed to create model folder",
})
return "", errors.New("failed to create model folder")
}
file1 := files[0].Header["Content-Disposition"]
path1, _ := GetFileName(file1)
fmt.Println("path1", path1)
FirstPath := strings.Split(path1, "/")
fmt.Println(FirstPath[0])
// 遍历上传的文件
for _, file := range files {
fileName := file.Header["Content-Disposition"]
path, _ := GetFileName(fileName)
fmt.Println("path: ", path)
savePath := filepath.Join(modePath, path) // 保存文件的路径,确保'uploads'文件夹已存在或自动创建
if err := c.SaveUploadedFile(file, savePath); err != nil {
c.String(http.StatusOK, fmt.Sprintf("'%s' could not be saved: %v", file.Filename, err))
return "", err
}
}
// 上传成功后返回响应
//c.String(http.StatusOK, fmt.Sprintf("%d files uploaded!", len(files)))
fmt.Sprintf("%d files uploaded!", len(files))
return FirstPath[0], nil
}
//fileName [form-data; name="model_folder"; filename="test/头像.jpg"] ;取出文件名
func GetFileName(fileName []string) (string, error) {
for _, f := range fileName {
// 判断字符串是否包含了需要查找的文件名关键字
if strings.Contains(f, `filename=`) {
// 按照 filename=" 分割
parts := strings.Split(f, `filename="`)
if len(parts) < 2 {
// 没有找到分隔符,跳到下一个元素
continue
}
// 按照 " 分割以获取实际的文件路径
filePathParts := strings.SplitN(parts[1], `"`, 2)
// 如果成功找到路径就返回
if len(filePathParts) >= 2 {
return filePathParts[0], nil // 返回找到的路径
}
}
}
// 如果没有找到,返回错误
return "", fmt.Errorf("no path found")
}
package controllers
import (
"WorldEpcho/src/config"
database "WorldEpcho/src/datasource"
"WorldEpcho/src/models"
"WorldEpcho/src/service"
"fmt"
"github.com/gin-gonic/gin"
"log"
"net/http"
"strconv"
)
//根据用户id获取用户应用数据查询接口
func QueryUserAppDataByUserId(ctx *gin.Context) {
/*
判断用户是否登录
*/
uid, isLogin := service.IsUserLoggedIn(ctx)
if !isLogin {
log.Println("用户未登录")
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户未登录"})
return
}
// GetUserApplicationData
appUserData, err := models.GetUserApplicationDataByUserId(uid)
if err != nil {
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "根据用户id查询用户应用数据失败"})
return
}
ctx.JSON(http.StatusOK, gin.H{"code": 1, "message": appUserData})
fmt.Println(config.ColorBlue, "appUserData: ", appUserData, config.ColorReset)
}
//根据用户id和应用id,删除用户应用数据接口
func DropUserAppDataByUidAndAppId(ctx *gin.Context) {
/*
判断用户是否登录
*/
uid, isLogin := service.IsUserLoggedIn(ctx)
if !isLogin {
log.Println("用户未登录")
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户未登录"})
return
}
app_id := ctx.PostForm("app_id")
appId, err := strconv.ParseInt(app_id, 10, 64)
if err != nil {
fmt.Println("转换失败:", err)
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "appId类型转换失败"})
return
}
err = models.DeleteUserApplication(appId, uid)
if err != nil {
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "根据应用id和用户id删除用户应用数据失败"})
return
}
ctx.JSON(http.StatusOK, gin.H{"code": 1, "message": "根据应用id和用户id删除用户应用数据成功"})
fmt.Println(config.ColorBlue, "根据应用id和用户id删除用户应用数据成功!", config.ColorReset)
}
func QueryUserAppDataMHTAnswer(ctx *gin.Context) {
/*
判断用户是否登录
*/
uid, isLogin := service.IsUserLoggedIn(ctx)
if !isLogin {
log.Println("用户未登录")
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户未登录"})
return
}
appName := ctx.PostForm("appName")
app_id := ctx.PostForm("app_id")
appId, err := strconv.ParseInt(app_id, 10, 64)
if err != nil {
fmt.Println("转换失败:", err)
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "appId类型转换失败"})
return
}
//开启事务
session := database.Engine.NewSession()
defer session.Close() //延迟关闭session
err = session.Begin()
if err != nil {
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "开启事务失败!"})
fmt.Println("开启事务失败")
return
}
// 根据应用id和应用名称查询应用的配置文件
configData, err := models.GetConfigDataByAppInfo(appId, appName)
if err != nil {
fmt.Printf("根据应用id和应用名称查询应用的配置信息失败")
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "根据应用id和应用名称查询应用的配置信息失败"})
return
}
//从configData中获取 EvaluateResult
EvaluateResult, ok := configData["EvaluateResult"]
if !ok {
fmt.Println("Key 'EvaluateResult' not found in the map")
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "Key 'EvaluateResult' not found in the map"})
return
}
fmt.Println("EvaluateResult: ", EvaluateResult)
// 断言 userInfoTemplate 为字符串类型
EvaluateResultKey, ok := EvaluateResult.([]interface{})
if !ok {
fmt.Println("EvaluateResult is not a []interface{}")
return
}
/*
根据用户id和应用id查询数据库中是否存在用户MHT问卷记录
*/
userAppData, err := models.GetUserApplicationData(appId, uid)
if err != nil {
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "根据用户id和应用id查询用户MHT测量数据失败!"})
fmt.Println("根据用户id和应用id查询用户MHT测量数据失败")
return
}
EvaluateresultValue, ok := userAppData["EvaluateResult"].([]interface{})
if !ok {
fmt.Println("EvaluateResult is not a []interface{}")
return
}
if userAppData == nil {
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "根据用户id和应用id未查询到用户MHT测量数据!"})
fmt.Println("根据用户id和应用id未查询到用户MHT测量数据")
return
}
evaluateData, err := MergeToMap(EvaluateResultKey, EvaluateresultValue)
if err != nil {
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "填充用户MHT测量数据失败!"})
fmt.Println("填充用户MHT测量数据失败")
return
}
ctx.JSON(http.StatusOK,
gin.H{
"code": 1,
"EvaluateResult": evaluateData,
})
}
// 将两个interface{}类型的数组拼接成键值对类型的map
func MergeToMap(keys []interface{}, values []interface{}) (map[string]string, error) {
result := make(map[string]string)
if len(keys) != len(values) {
return nil, fmt.Errorf("keys and values arrays have different lengths")
}
for i := 0; i < len(keys); i++ {
key, ok := keys[i].(string)
if !ok {
return nil, fmt.Errorf("Key at index %d is not a string", i)
}
value, ok := values[i].(string)
if !ok {
return nil, fmt.Errorf("Value at index %d is not a string", i)
}
result[key] = value
}
return result, nil
}
package controllers
import (
"WorldEpcho/src/models"
"WorldEpcho/src/service"
"fmt"
"github.com/gin-gonic/gin"
"log"
"net/http"
"strconv"
)
//获取用户和详情信息
func GetUserAndUserDetailInfo(c *gin.Context) {
/*
判断用户是否登录
*/
uid, isLogin := service.IsUserLoggedIn(c)
if !isLogin {
log.Println("用户未登录")
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户未登录"})
return
}
// 根据当前用户登录的id,查询用户注册信息和用户详情信息
user, userInfo, err := models.GetUserAndUserInfo(uid)
if err != nil {
log.Println("查询用户注册信息和用户详情信息出错")
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "查询用户注册信息和用户详情信息出错"})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 1,
"message": "查询用户注册信息和用户详情信息成功",
"user": user,
"userInfo": userInfo,
})
}
//获取用户和详情信息
func GetUserDetailInfo(ctx *gin.Context) {
/*
判断用户是否登录
*/
_, isLogin := service.IsUserLoggedIn(ctx)
if !isLogin {
log.Println("用户未登录")
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户未登录"})
return
}
userId := ctx.PostForm("userId")
user_Id, err := strconv.ParseInt(userId, 10, 64)
if err != nil {
fmt.Println("转换失败:", err)
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "userId类型转换失败"})
return
}
// 根据当前用户登录的id,查询用户注册信息和用户详情信息
_, userInfo, err := models.GetUserAndUserInfo(user_Id)
if err != nil {
log.Println("查询用户注册信息和用户详情信息出错")
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "查询用户注册信息和用户详情信息出错"})
return
}
ctx.JSON(http.StatusOK, gin.H{
"code": 1,
"message": "查询用户注册信息和用户详情信息成功",
"userInfo": userInfo,
})
}
//修改用户详情信息
func EditUserInfo(c *gin.Context) {
/*
判断用户是否登录
*/
uid, isLogin := service.IsUserLoggedIn(c)
if !isLogin {
log.Println("用户未登录")
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户未登录"})
return
}
userName := c.PostForm("userName")
userSex := c.PostForm("userSex")
phone := c.PostForm("phone")
idCard := c.PostForm("idCard")
student_id := c.PostForm("studentId")
unit := c.PostForm("unit")
userHeight := c.PostForm("userHeight")
userWeight := c.PostForm("userWeight")
userBirthday := c.PostForm("userBirthday")
var userinfo = &models.UserInfo{
UserName: userName,
UserSex: userSex,
Phone: phone,
IDCard: idCard,
StudentId: student_id,
Unit: unit,
UserHeight: userHeight,
UserWeight: userWeight,
UserBirthday: userBirthday,
}
userInfo, err := models.GetUserInfo(uid)
if err != nil {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "查询用户详情信息失败!"})
return
}
if userInfo != nil {
userInfo.UserName = userName
userinfo.UserSex = userSex
userinfo.Phone = phone
userinfo.IDCard = idCard
userinfo.StudentId = student_id
userinfo.Unit = unit
userinfo.UserHeight = userHeight
userinfo.UserWeight = userWeight
userinfo.UserBirthday = userBirthday
}
err = models.EditUserInfo(userinfo)
if err != nil {
c.JSON(200, gin.H{"code": 0, "message": "更新用户详情信息出错"})
return
}
c.JSON(200, gin.H{"code": 1, "message": "更新用户详情信息成功"})
}
package controllers
import (
database "WorldEpcho/src/datasource"
"WorldEpcho/src/models"
"WorldEpcho/src/service"
"WorldEpcho/src/utils"
"fmt"
"github.com/gin-gonic/gin"
"log"
"net/http"
"strconv"
"strings"
"time"
)
func UnregisterPost(c *gin.Context) {
/*
判断用户是否登录
*/
loginUid, isLogin := service.IsUserLoggedIn(c)
if !isLogin {
log.Println("用户未登录")
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "用户未登录"})
return
}
//开启事务
session := database.Engine.NewSession()
defer session.Close() //延迟关闭session
err := session.Begin()
if err != nil {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "开启事务失败!"})
fmt.Println("开启事务失败")
return
}
loginUser, _, err := models.GetUserByID_Tx(session, loginUid)
if err != nil {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "查询登录用户出错!"})
return
}
userId := c.PostForm("id")
uid, err := strconv.ParseInt(userId, 10, 64)
if err != nil {
fmt.Println("转换用户id出错")
}
user, exist, err := models.GetUserByID_Tx(session, uid)
if err != nil {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "根据用户id查询用户信息出错!"})
return
}
if !exist {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "你的手机号未注册用户!"})
fmt.Println("你的手机号未注册用户")
return
}
// 用户权限小于3的可以注销
if (user.Level > 3 && loginUser.Level <= 3) || loginUid != uid {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "无权限注销该用户!"})
fmt.Println("无权限注销该用户!")
return
}
/*
根据用户手机查询用户详情信息
*/
userInfo, userInfo_Exist, err := models.GetUserInfoById(session, user.Id)
if err != nil {
fmt.Println("根据手机号查询用户详情信息是否存在,查询失败")
c.JSON(http.StatusInternalServerError, gin.H{"code": 0, "message": "根据手机查询用户详情信息是否存在出错"})
return
}
if strings.Contains(user.WxOpenid, "_unregister") || strings.Contains(user.Phone, "_unregister") || strings.Contains(userInfo.Phone, "_unregister") {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "该用户已注销, 请勿重复操作!"})
fmt.Println("该用户已注销, 请勿重复操作!")
return
}
// 判断是不是微信小程序注册的用户
timeStamp := time.Now().Unix()
if user.WxOpenid != "" && user.WxOpenid == user.Phone {
// 修改 openid
user.WxOpenid = user.WxOpenid + "_unregister" + "_" + utils.Strval(timeStamp)
}
// 注销用户,将用户的状态值设为-1,手机号添加后缀 "_时间戳"
user.Status = -1
user.Username = user.Username + "_unregister" + "_" + utils.Strval(timeStamp)
user.Phone = user.Phone + "_unregister" + "_" + utils.Strval(timeStamp)
_, err = models.UpdateUser_Tx(session, user)
if err != nil {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "注销用户,修改用户信息出错!"})
log.Println("注销用户,修改用户信息出错!")
return
}
/*if !userInfo_Exist {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "该手机绑定的用户不存在,无详情信息!"})
fmt.Println("该手机绑定的用户不存在,无详情信息!")
return
}*/
if userInfo_Exist {
// 修改userinfo的手机号为注销状态
userInfo.Phone = userInfo.Phone + "_unregister" + "_" + utils.Strval(timeStamp)
userInfo.UserName = userInfo.UserName + "_unregister" + "_" + utils.Strval(timeStamp)
err = models.UpdateUserInfo(session, userInfo)
if err != nil {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "注销时,修改用户详情信息出错!"})
fmt.Println("注销时,修改用户详情信息出错!")
return
}
}
//提交事务
err = session.Commit()
if err != nil {
c.JSON(http.StatusOK, gin.H{"code": 0, "message": "注销用户失败"})
return
} else {
c.JSON(http.StatusOK, gin.H{"code": 1, "message": "注销用户成功!", "unregister_uid": uid})
}
}
package datasource
import (
"WorldEpcho/src/config"
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
"github.com/go-xorm/xorm"
"log"
)
var (
DB *sql.DB
Engine *xorm.Engine
)
func InitMysql() {
fmt.Println("InitMysql....")
// xorm 连接数据库
var err error
Engine, err = xorm.NewEngine("mysql", config.Conf.Mysql_UserName+":"+config.Conf.Mysql_PWD+"@tcp("+config.Conf.DBserver+":"+config.Conf.MysqlPort+")/"+config.Conf.DBname+"?charset=utf8")
fmt.Println(" ============== 【xorm 连接数据库】 ===================== ")
println("xorm 连接数据库,Engine: ", Engine)
fmt.Println(" ============== 【xorm 连接数据库】 ===================== ")
if err != nil {
log.Println("数据库连接失败:", err)
fmt.Println("数据库连接失败:", err)
return
}
}
//操作数据库
func ModifyDB(sql string, args ...interface{}) (int64, error) {
result, err := DB.Exec(sql, args...)
if err != nil {
log.Println(err)
return 0, err
}
count, err := result.RowsAffected()
if err != nil {
log.Println(err)
return 0, err
}
return count, nil
}
//创建用户表
func CreateTableWithUser() {
sql := `CREATE TABLE IF NOT EXISTS users(
id INT(4) PRIMARY KEY AUTO_INCREMENT NOT NULL,
username VARCHAR(64),
password VARCHAR(64),
status INT(4),
createtime INT(10)
);`
ModifyDB(sql)
}
//查询
func QueryRowDB(sql string) *sql.Row {
return DB.QueryRow(sql)
}
package main
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"sort"
"strings"
)
const (
REQ_ACCESS_POP_TIMESTRAP = "access-pop-timestrap"
REQ_ACCESS_POP_NONCESTR = "access-pop-noncestr"
REQ_ACCESS_POP_SIGNATURE = "access-pop-signature"
REQ_ACCESS_POP_TOKEN = "access-pop-token"
HMAC_SHA256_ALGORITHM = "HmacSHA256"
)
func main() {
// 示例数据
data := map[string]string{
REQ_ACCESS_POP_TOKEN: "4fb818df-af9e-4590-868f-52a6647cb91b9a6a7474-5891-4468-84fb-ccd0beef91a5",
REQ_ACCESS_POP_TIMESTRAP: "cdd08ede-b836-44d2-8c10-b6abc0ac57aa",
REQ_ACCESS_POP_NONCESTR: "abcabcabcabcabc1",
}
// 获取当前时间戳
//timestrap := time.Now().UnixNano() / int64(time.Millisecond)
// 对数据进行排序
keys := make([]string, 0, len(data))
for k := range data {
keys = append(keys, k)
}
sort.Strings(keys)
var sortedData []string
for _, k := range keys {
sortedData = append(sortedData, fmt.Sprintf("%s=%s", k, data[k]))
}
// 拼接数据
//signStr := fmt.Sprintf("%d\n%s\n%s\n%s", timestrap, strings.Join(sortedData, "\n"), REQ_ACCESS_POP_TOKEN, "cdd08ede-b836-44d2-8c10-b6abc0ac57aa") signStr := fmt.Sprintf("%d\n%s\n%s\n%s", timestrap, strings.Join(sortedData, "\n"), REQ_ACCESS_POP_TOKEN, "cdd08ede-b836-44d2-8c10-b6abc0ac57aa")
signStr := fmt.Sprintf("%d\n%s\n%s\n%s", REQ_ACCESS_POP_TIMESTRAP, strings.Join(sortedData, "\n"), REQ_ACCESS_POP_TOKEN, "cdd08ede-b836-44d2-8c10-b6abc0ac57aa")
// 计算 HMAC-SHA256
key := []byte("cdd08ede-b836-44d2-8c10-b6abc0ac57aa")
h := hmac.New(sha256.New, key)
h.Write([]byte(signStr))
signature := hex.EncodeToString(h.Sum(nil))
// 打印签名结果
fmt.Println(signature)
}
func chkSignature(accessToken string, timestrap string, nonceStr string, signature string, signatureKey string) bool {
treeMap := map[string]string{
REQ_ACCESS_POP_TOKEN: accessToken,
REQ_ACCESS_POP_TIMESTRAP: timestrap,
REQ_ACCESS_POP_NONCESTR: nonceStr,
}
// 对数据进行排序
keys := make([]string, 0, len(treeMap))
for k := range treeMap {
keys = append(keys, k)
}
sort.Strings(keys)
var sortedData []string
for _, k := range keys {
sortedData = append(sortedData, fmt.Sprintf("%s=%s", k, treeMap[k]))
}
// 拼接数据
signStr := fmt.Sprintf("%s\n%s\n%s\n%s", accessToken, timestrap, nonceStr, signatureKey)
// 计算 HMAC-SHA256
key := []byte(signatureKey)
h := hmac.New(sha256.New, key)
h.Write([]byte(signStr))
sysSignature := hex.EncodeToString(h.Sum(nil))
if sysSignature != signature {
log.Printf("签名不一致!%s -> %s", sysSignature, signature)
return false
}
return true
}
func getObjectMd5Value(obj interface{}) string {
bytes, err := json.Marshal(obj)
if err != nil {
log.Printf("json.Marshal error: %v", err)
return ""
}
h := sha256.New()
h.Write(bytes)
return hex.EncodeToString(h.Sum(nil))
}
func postJson(url string, data interface{}, headers http.Header) ([]byte, error) {
bytesData, err := json.Marshal(data)
if err != nil {
return nil, fmt.Errorf("json.Marshal error: %v", err)
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(bytesData))
if err != nil {
return nil, fmt.Errorf("http.NewRequest error: %v", err)
}
req.Header.Set("Content-Type", "application/json")
for k, v := range headers {
req.Header[k] = v
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("client.Do error: %v", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("ioutil.ReadAll error: %v", err)
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("response status code not OK: %d, response body: %s", resp.StatusCode, string(body))
}
return body, nil
}
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"log"
"sort"
)
const (
reqAccessPopToken = "access-pop-token"
reqAccessPopTimestamp = "access-pop-timestrap"
reqAccessPopNonceStr = "access-pop-noncestr"
//hmacSHA256Algorithm = "HmacSHA256"
)
func main() {
// 使用 Go map 和一个额外的 keys 列表保持顺序
treeMap := make(map[string]string)
keys := []string{
reqAccessPopToken,
reqAccessPopTimestamp,
reqAccessPopNonceStr,
}
treeMap[reqAccessPopToken] = "4fb818df-af9e-4590-868f-52a6647cb91b9a6a7474-5891-4468-84fb-ccd0beef91a5"
treeMap[reqAccessPopTimestamp] = "cdd08ede-b836-44d2-8c10-b6abc0ac57aa"
treeMap[reqAccessPopNonceStr] = "abcabcabcabcabc1"
sysSignature, err := genHMAC1(treeMap, keys, "cdd08ede-b836-44d2-8c10-b6abc0ac57aa")
if err != nil {
log.Printf("Error generating HMAC: %v", err)
}
fmt.Println(sysSignature)
}
func genHMAC1(data map[string]string, keys []string, key string) (string, error) {
// 对 keys 进行排序以确保顺序
sort.Strings(keys)
// 构建 JSON 字符串
dataMapOrdered := make(map[string]string)
for _, k := range keys {
dataMapOrdered[k] = data[k]
}
jsonData, err := json.Marshal(dataMapOrdered)
if err != nil {
return "", err
}
// 创建 hmac
h := hmac.New(sha256.New, []byte(key))
if _, err := h.Write([]byte(jsonData)); err != nil {
return "", err
}
signature := hex.EncodeToString(h.Sum(nil))
return signature, nil
}
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"time"
)
// JWTToken 用于生成JWT鉴权令牌
type JWTToken struct {
AccessKey string `json:"access_key"`
AccessSecret string `json:"access_secret"`
Timestamp string `json:"timestamp"`
Signature string `json:"signature"`
}
// GenerateJWTToken 生成JWT鉴权令牌
func GenerateJWTToken(accessKey, accessSecret string, tokenTime time.Time) (string, error) {
// 设置签名字典
signData := []byte(`{"access_key":"` + accessKey + `","timestamp":"` + tokenTime.Format(time.RFC3339) + `"}`)
h := hmac.New(sha256.New, []byte(accessSecret))
h.Write(signData)
signature := h.Sum(nil)
// 构建JWT鉴权令牌结构体
jwtToken := JWTToken{
AccessKey: accessKey,
AccessSecret: accessSecret,
Timestamp: tokenTime.Format(time.RFC3339),
Signature: base64.StdEncoding.EncodeToString(signature),
}
// 将JWT鉴权令牌转换为JSON字符串并返回
jsonData, err := json.Marshal(jwtToken)
if err != nil {
return "", err
}
jwtTokenStr := string(jsonData)
return jwtTokenStr, nil
}
func main() {
// 假设应用管理中的AccessKey和AccessSecret已经获取到,这里作为示例使用
accessKey := "your_access_key"
accessSecret := "your_access_secret"
tokenTime := time.Now() // 生成当前时间戳作为鉴权令牌的时间戳
// 生成JWT鉴权令牌并打印结果
jwtToken, err := GenerateJWTToken(accessKey, accessSecret, tokenTime)
if err != nil {
fmt.Println("生成JWT鉴权令牌失败:", err)
return
}
fmt.Println("生成的JWT鉴权令牌:", jwtToken)
}
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "hello gin",
})
})
r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt"
"net/http"
"time"
)
var accessKey = "next654c5506ab4fcf3e17cf970b" // NextHuman平台accessKey
var accessSecret = "xhInaX3Vk8Mv9KTWZMM5GoFPCf5Gf5VEMo8K9RjROw" // NextHuman平台 accessSecret
func generateToken(accessKey, accessSecret string) (string, error) {
// 创建 JWT 的头部
token := jwt.New(jwt.SigningMethodHS256)
// 设置 JWT 的负载(Payload)
claims := token.Claims.(jwt.MapClaims)
claims["aud"] = "app" // 接收者
claims["iss"] = accessKey // 签发者
claims["exp"] = time.Now().Add(time.Hour * 12).Unix() // 过期时间
claims["iat"] = time.Now().Unix() // 签发时间
// 使用 accessSecret 来签名并生成最终的 Token
tokenString, err := token.SignedString([]byte(accessSecret))
if err != nil {
return "", err
}
return tokenString, nil
}
func main() {
// 1.创建路由
r := gin.Default()
// 2.绑定路由规则,执行的函数
// gin.Context,封装了request和response
// 生成jwt字符串
tokenString, err := generateToken(accessKey, accessSecret)
if err != nil {
fmt.Println("Token generation failed:", err)
return
}
//打印这个token字符串
// fmt.Println("Generated Token:", tokenString)
r.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, tokenString)
})
// 3.监听端口,默认在8080
// Run("里面不指定端口号默认为8080")
r.Run(":8081")
}
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"sort"
"strings"
)
func main() {
data := make(map[string]string)
data["REQ_ACCESS_POP_TOKEN"] = "4fb818df-af9e-4590-868f-52a6647cb91b9a6a7474-5891-4468-84fb-ccd0beef91a5"
data["REQ_ACCESS_POP_TIMESTRAP"] = "cdd08ede-b836-44d2-8c10-b6abc0ac57aa"
data["REQ_ACCESS_POP_NONCESTR"] = "abcabcabcabcabc1"
fmt.Println("Data Map:", data)
serializedData := serializeData(data)
fmt.Println("Serialized Data:", serializedData)
key := "cdd08ede-b836-44d2-8c10-b6abc0ac57aa"
signature := genHMAC(serializedData, key)
fmt.Println("Signature:", signature)
}
func genHMAC(data string, key string) string {
h := hmac.New(sha256.New, []byte(key))
h.Write([]byte(data))
signature := h.Sum(nil)
fmt.Printf("HMAC SHA256: %x\n", signature)
return hex.EncodeToString(signature)
}
func serializeData(data map[string]string) string {
keys := make([]string, 0, len(data))
for k := range data {
keys = append(keys, k)
}
sort.Strings(keys)
var sb strings.Builder
for _, k := range keys {
sb.WriteString(k)
sb.WriteString(data[k])
}
return sb.String()
}
package main
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/gob"
"encoding/hex"
"fmt"
)
func main() {
// 初始化数据
data := map[string]string{
"access-pop-timestrap": "cdd08ede-b836-44d2-8c10-b6abc0ac57aa",
"access-pop-noncestr": "abcabcabcabcabc1",
"access-pop-token": "4fb818df-af9e-4590-868f-52a6647cb91b9a6a7474-5891-4468-84fb-ccd0beef91a5",
}
// 生成 HMAC
key := "cdd08ede-b836-44d2-8c10-b6abc0ac57aa"
signature, err := generateHMAC(data, key)
if err != nil {
fmt.Println("Error generating HMAC:", err)
return
}
fmt.Println("Signature:", signature)
}
// 生成HMAC SHA-256签名
func generateHMAC(data map[string]string, key string) (string, error) {
serializedData, err := getSerializedBytes(data)
if err != nil {
return "", err
}
h := hmac.New(sha256.New, []byte(key))
h.Write(serializedData)
return hex.EncodeToString(h.Sum(nil)), nil
}
// 序列化数据
func getSerializedBytes(data map[string]string) ([]byte, error) {
var b bytes.Buffer
e := gob.NewEncoder(&b)
err := e.Encode(data)
if err != nil {
return nil, err
}
return b.Bytes(), nil
}
package main
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/gob"
"encoding/hex"
"fmt"
"sort"
)
func main() {
data := make(map[string]string)
data["REQ_ACCESS_POP_TOKEN"] = "4fb818df-af9e-4590-868f-52a6647cb91b9a6a7474-5891-4468-84fb-ccd0beef91a5"
data["REQ_ACCESS_POP_TIMESTRAP"] = "cdd08ede-b836-44d2-8c10-b6abc0ac57aa"
data["REQ_ACCESS_POP_NONCESTR"] = "abcabcabcabcabc1"
fmt.Println("Data Map:", data)
serializedData, err := getSerializedBytes3(data)
if err != nil {
fmt.Println("Serialization Error:", err)
return
}
fmt.Printf("Serialized Data: %x\n", serializedData)
key := "cdd08ede-b836-44d2-8c10-b6abc0ac57aa"
signature := genHMAC3(serializedData, key)
fmt.Println("Signature:", signature)
}
func genHMAC3(data []byte, key string) string {
h := hmac.New(sha256.New, []byte(key))
h.Write(data)
signature := h.Sum(nil)
fmt.Printf("HMAC SHA256: %x\n", signature)
return hex.EncodeToString(signature)
}
func getSerializedBytes3(data map[string]string) ([]byte, error) {
var buf bytes.Buffer
keys := make([]string, 0, len(data))
for k := range data {
keys = append(keys, k)
}
sort.Strings(keys)
enc := gob.NewEncoder(&buf)
for _, k := range keys {
err := enc.Encode(k)
if err != nil {
return nil, err
}
err = enc.Encode(data[k])
if err != nil {
return nil, err
}
}
return buf.Bytes(), nil
}
package main
import (
"PsycheEpic/src/config"
"PsycheEpic/src/service"
"PsycheEpic/src/utils"
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"time"
"github.com/gin-gonic/gin"
)
type RequestBody struct {
Phone string `json:"phone"`
SerialNo string `json:"serialNo"`
SchoolName string `json:"schoolName"`
CallbackAddress string `json:"callbackAddress"`
RequestNo string `json:"requestNo"`
}
// 发送 POST 请求的函数
func PostSelectAiMentalClinicList(c *gin.Context) {
// 设置请求头
key := config.Conf.AppKey
appSecret := config.Conf.AppSecret
// 获取当前时间
now := time.Now()
// 将当前时间转换为Unix时间戳(秒级)
timestamp := now.Unix()
timeStr := utils.Strval(timestamp)
uuid := utils.GenerateUUID()
//获取token
token, _ := service.GetPopAccessToken(key, appSecret)
//获取签名
signature, _ := service.GenerateSignature(token, timeStr, uuid, appSecret)
headers := map[string]string{
"access-pop-token": token,
"access-pop-key": "d1526328-ac75-4496-9b99-6598293af574",
"access-pop-timestrap": timeStr,
"access-pop-noncestr": uuid,
"Content-Type": "application/json",
"access-pop-signature": signature,
"access-pop-supplier-type": "1",
}
// 设置请求体
// 创建一个 RequestBody 类型的实例
requestBody := RequestBody{
Phone: "17727960067",
SerialNo: "学生编号",
SchoolName: "学校名称",
CallbackAddress: "https://180.174.13.225:8089/AiMentalClinicData",
RequestNo: uuid,
}
// 将结构体实例转换为 JSON 格式的字节流
jsonData, err := json.Marshal(requestBody)
if err != nil {
fmt.Println("Error marshalling JSON:", err)
return
}
url := config.Conf.MentalClinicUrl
// 创建请求
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// 添加请求头
for key, value := range headers {
req.Header.Set(key, value)
}
// 发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
defer resp.Body.Close()
// 读取响应体
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// 将响应体作为字节切片发送回客户端
c.Data(resp.StatusCode, "application/json", body)
}
func main() {
router := gin.Default()
config.InitConfig()
router.POST("/selectAiMentalClinicList", PostSelectAiMentalClinicList)
router.Run(":8080")
}
// processData 是一个独立的函数,用于处理 POST 请求
func ProcessData(c *gin.Context) {
var jsonData map[string]interface{}
// 绑定 JSON 到 jsonData
if err := c.BindJSON(&jsonData); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 打印接收到的数据(可选)
println(jsonData)
// 响应
c.JSON(http.StatusOK, gin.H{"message": "ok"})
}
package main
import (
"PsycheEpic/src/config"
"PsycheEpic/src/datasource"
"fmt"
_ "github.com/go-sql-driver/mysql"
)
// 定义一个结构体,用于接收存储过程的输出参数
/*
type Result struct {
OutParam int `xorm:"out_param"`
}
*/
func main() {
config.InitConfig()
datasource.InitMysql()
// 创建一个存储过程,接收一个输入参数in_param,返回一个输出参数out_param
// 存储过程的逻辑是将输入参数加10后赋值给输出参数
sql := `CREATE PROCEDURE add_ten(IN in_param INT, OUT out_param INT)
BEGIN
SET out_param = in_param + 10;
END`
_, err := datasource.Engine.Exec(sql)
if err != nil {
fmt.Println(err)
return
}
// 调用存储过程,传入一个输入参数10,使用一个Result结构体变量接收输出参数
var out_param int
_, err = datasource.Engine.Exec("CALL add_ten(?, @out_param)", 10)
if err != nil {
fmt.Println(err)
return
}
// 从MySQL中获取存储过程的输出参数
_, err = datasource.Engine.SQL("SELECT @out_param").Get(&out_param)
if err != nil {
fmt.Println(err)
return
}
// 打印输出参数的值,应该是20
fmt.Println(out_param)
}
package main
import (
"PsycheEpic/src/config"
"PsycheEpic/src/datasource"
"fmt"
_ "github.com/go-sql-driver/mysql"
"log"
)
type Contact struct {
UserId int `json:"user_id" xorm:"user_id"`
Name string `json:"name" jorm:"real_name" xorm:"real_name"`
Age int `json:"age" xorm:"age"`
PhoneNumber string `json:"phone_number" xorm:"phone_number"`
HomeAddress string `json:"home_address" xorm:"home_address"`
CreateTime string `json:"create_time" xorm:"create_time"`
}
type ContactResult struct {
UserID int `xorm:"user_id"`
RealName string `xorm:"real_name"`
Age int `xorm:"age"`
PhoneNumber string `xorm:"phone_number"`
Address string `xorm:"address"`
CreateTime string `xorm:"create_time"`
}
func QueryContact(name string) (*ContactResult, error) {
var result ContactResult
session := datasource.Engine.NewSession()
// 由于 xorm 不支持 OUT 参数,我们直接获取返回的结果集
_, err := session.SQL("CALL query_contact1(?)", name).Get(&result)
if err != nil {
return nil, err
}
return &result, nil
}
func main() {
//读取参数配置
config.InitConfig()
//执行数据库初始化
datasource.InitMysql()
// 调用函数
name := "Jerry"
contact, err := QueryContact(name)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Result: %+v\n", contact)
}
package main
import (
"bytes"
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"io/ioutil"
"log"
"net/http"
"os"
"strings"
)
// 用于第一个 API 请求的结构体
type HeadPortraitPromptRequest struct {
Name string `json:"name"`
}
// 用于接收第一个 API 响应的结构体
type PromptResponse struct {
Prompt string `json:"prompt"`
}
// 第二个 API 请求的结构体
type PortraitRequest struct {
Prompt string `json:"prompt"`
Negative string `json:"negative"`
}
// 处理生成头像的 HTTP 请求
func GenerateAvatarHandler(c *gin.Context) {
name := c.PostForm("name")
if name == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "未提供名字"})
return
}
savePath := "./static/Worlds/headPortrait/"
imagePath := savePath + name + ".png"
// 检查本地是否已有头像图片
if _, err := os.Stat(imagePath); err == nil {
log.Println("已存在头像,直接返回")
c.JSON(http.StatusOK, gin.H{"image_url": imagePath})
return
}
// 打印进度条开始
printProgressBar(0, "开始生成头像...")
portraitData, err := GenerateHeadPortrait(name)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// 更新进度条
printProgressBar(70, "头像生成完毕,保存中...")
// 保存头像图片到服务器
imagePath, err = SaveImage(savePath, name+".png", portraitData)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// 更新并完成进度条
printProgressBar(100, "头像保存成功!")
// 将图片地址直接作为响应返回
c.JSON(http.StatusOK, gin.H{"image_url": imagePath})
}
// 生成人物头像,返回图片数据和错误信息
func GenerateHeadPortrait(name string) ([]byte, error) {
promptAPI := "http://58.34.54.45:16666/generate_character_prompt"
headPortraitAPI := "http://58.34.54.45:19666/"
promptReq := HeadPortraitPromptRequest{Name: name}
reqBody, err := json.Marshal(promptReq)
if err != nil {
return nil, fmt.Errorf("请求体编码失败: %v", err)
}
resp, err := http.Post(promptAPI, "application/json", bytes.NewBuffer(reqBody))
if err != nil {
return nil, fmt.Errorf("调用第一个 API 失败: %v", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("读取响应体失败: %v", err)
}
var promptResp PromptResponse
if err := json.Unmarshal(body, &promptResp); err != nil {
return nil, fmt.Errorf("响应解码失败: %v", err)
}
portraitReq := PortraitRequest{
Prompt: promptResp.Prompt,
Negative: "normal",
}
reqBody, err = json.Marshal(portraitReq)
if err != nil {
return nil, fmt.Errorf("请求体编码失败: %v", err)
}
resp, err = http.Post(headPortraitAPI, "application/json", bytes.NewBuffer(reqBody))
if err != nil {
return nil, fmt.Errorf("调用第二个 API 失败: %v", err)
}
defer resp.Body.Close()
portraitData, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("读取第二响应体失败: %v", err)
}
return portraitData, nil
}
// 保存图片到指定路径
func SaveImage(directory, filename string, data []byte) (string, error) {
if err := os.MkdirAll(directory, 0755); err != nil {
return "", fmt.Errorf("创建目录失败: %v", err)
}
filePath := directory + filename
file, err := os.Create(filePath)
if err != nil {
return "", fmt.Errorf("创建文件失败: %v", err)
}
defer file.Close()
if _, err = file.Write(data); err != nil {
return "", fmt.Errorf("写入文件失败: %v", err)
}
return filePath, nil
}
// 打印绿色方块进度条
func printProgressBar(percentage int, message string) {
barLength := 50 // 进度条长度
progress := int(float64(percentage) / 100.0 * float64(barLength))
// 使用绿色方块表示进度
bar := strings.Repeat("\033[32m█\033[0m", progress) + strings.Repeat(" ", barLength-progress)
// 使用 \r 将光标移动到行首,确保进度条在同一行上更新
fmt.Printf("\r[%s] %d%% - %s", bar, percentage, message)
if percentage == 100 {
fmt.Println() // 进度条完成,换行
}
}
func main() {
router := gin.Default()
router.POST("/generate_avatar", GenerateAvatarHandler)
router.Run(":8080")
}
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"os"
"strings"
"time"
"github.com/gin-gonic/gin"
)
// 用于第一个 API 请求的结构体
type HeadPortraitPromptRequest2 struct {
Name string `json:"name"`
}
// 用于接收第一个 API 响应的结构体
type PromptResponse2 struct {
Prompt string `json:"prompt"`
}
// 第二个 API 请求的结构体
type PortraitRequest2 struct {
Prompt string `json:"prompt"`
Negative string `json:"negative"`
}
// 处理生成头像的 HTTP 请求
func GenerateAvatarHandler2(c *gin.Context) {
name := c.PostForm("name")
if name == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "未提供名字"})
return
}
savePath := "./static/Worlds/headPortrait/"
imagePath := savePath + name + ".png"
// 检查本地是否已有头像图片
if _, err := os.Stat(imagePath); err == nil {
log.Println("已存在头像,直接返回")
c.JSON(http.StatusOK, gin.H{"image_url": imagePath})
return
}
// 打印进度条开始
printProgressBar2(0, "开始生成头像...")
portraitData, err := GenerateHeadPortrait2(name)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// 更新进度条
printProgressBar2(70, "头像生成完毕,保存中...")
// 保存头像图片到服务器
imagePath, err = SaveImage2(savePath, name+".png", portraitData)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
// 更新并完成进度条
printProgressBar2(100, "头像保存成功!")
// 将图片地址直接作为响应返回
c.JSON(http.StatusOK, gin.H{"image_url": imagePath})
}
// 生成人物头像,返回图片数据和错误信息
func GenerateHeadPortrait2(name string) ([]byte, error) {
promptAPI := "http://58.34.54.45:16666/generate_character_prompt"
headPortraitAPI := "http://58.34.54.45:19666/"
promptReq := HeadPortraitPromptRequest2{Name: name}
reqBody, err := json.Marshal(promptReq)
if err != nil {
return nil, fmt.Errorf("请求体编码失败: %v", err)
}
resp, err := http.Post(promptAPI, "application/json", bytes.NewBuffer(reqBody))
if err != nil {
return nil, fmt.Errorf("调用第一个 API 失败: %v", err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("读取响应体失败: %v", err)
}
var promptResp PromptResponse2
if err := json.Unmarshal(body, &promptResp); err != nil {
return nil, fmt.Errorf("响应解码失败: %v", err)
}
portraitReq := PortraitRequest2{
Prompt: promptResp.Prompt,
Negative: "normal",
}
reqBody, err = json.Marshal(portraitReq)
if err != nil {
return nil, fmt.Errorf("请求体编码失败: %v", err)
}
resp, err = http.Post(headPortraitAPI, "application/json", bytes.NewBuffer(reqBody))
if err != nil {
return nil, fmt.Errorf("调用第二个 API 失败: %v", err)
}
defer resp.Body.Close()
portraitData, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("读取第二响应体失败: %v", err)
}
return portraitData, nil
}
// 保存图片到指定路径
func SaveImage2(directory, filename string, data []byte) (string, error) {
if err := os.MkdirAll(directory, 0755); err != nil {
return "", fmt.Errorf("创建目录失败: %v", err)
}
filePath := directory + filename
file, err := os.Create(filePath)
if err != nil {
return "", fmt.Errorf("创建文件失败: %v", err)
}
defer file.Close()
if _, err = file.Write(data); err != nil {
return "", fmt.Errorf("写入文件失败: %v", err)
}
return filePath, nil
}
// 打印进度条
func printProgressBar2(percentage int, message string) {
barLength := 50 // 进度条长度
progress := int(float64(percentage) / 100.0 * float64(barLength))
bar := strings.Repeat("\033[32m█\033[0m", progress) + strings.Repeat(" ", barLength-progress)
fmt.Printf("\r[%s] %d%% - %s", bar, percentage, message)
if percentage == 100 {
fmt.Println() // 进度条完成,换行
}
time.Sleep(100 * time.Millisecond) // 模拟一点延迟效果
}
func main() {
router := gin.Default()
router.POST("/generate_avatar", GenerateAvatarHandler2)
router.Run(":8081")
}
package main
import (
"fmt"
)
// 假设GetTodayCareAlertLogs已经定义并实现,返回([]CareAlertLog, error)
type CareAlertLogs struct {
ID int `xorm:"'id' pk autoincr" json:"id"`
UserID int64 `xorm:"user_id" json:"userId"`
ClassNo string `xorm:"class_no" json:"classNo"`
AppID int64 `xorm:"app_id" json:"appId"`
OverIndexes []string `xorm:"'over_indexes' json " json:"over_indexes"`
MeasurementTime int64 `xorm:"measurement_time" json:"measurementTime"`
}
// 模拟函数返回结果
func GetTodayCareAlertLogs() ([]CareAlertLogs, error) {
return []CareAlertLogs{
{ID: 22, UserID: 1, ClassNo: "oilstc", AppID: 6, OverIndexes: []string{"冲动倾向", "孤独倾向", "学习焦虑", "对人焦虑", "恐怖倾向", "自责倾向", "身体症状", "过敏倾向"}, MeasurementTime: 1716969608},
{ID: 23, UserID: 411, ClassNo: "oilstc", AppID: 6, OverIndexes: []string{"身体症状", "过敏倾向", "冲动倾向", "孤独倾向", "学习焦虑", "对人焦虑", "恐怖倾向", "自责倾向"}, MeasurementTime: 1716969663},
{ID: 24, UserID: 410, ClassNo: "oilstc", AppID: 6, OverIndexes: []string{"孤独倾向", "学习焦虑", "对人焦虑", "恐怖倾向", "自责倾向", "身体症状", "过敏倾向", "冲动倾向"}, MeasurementTime: 1716969792},
{ID: 39, UserID: 12, ClassNo: "", AppID: 6, OverIndexes: []string{"身体症状", "冲动倾向", "对人焦虑"}, MeasurementTime: 1716973512},
}, nil
}
// 处理查询结果的函数
func ProcessCareAlertLogs() ([]int64, []string, error) {
logs, err := GetTodayCareAlertLogs()
if err != nil {
return nil, nil, fmt.Errorf("failed to get care alert logs: %w", err)
}
userIDs := make([]int64, 0)
classSet := make(map[string]struct{}) // 使用map来去重
classNos := make([]string, 0)
for _, log := range logs {
userIDs = append(userIDs, log.UserID)
if log.ClassNo != "" {
if _, exists := classSet[log.ClassNo]; !exists {
classSet[log.ClassNo] = struct{}{}
classNos = append(classNos, log.ClassNo)
}
}
}
return userIDs, classNos, nil
}
func main() {
userIDs, classNos, err := ProcessCareAlertLogs()
if err != nil {
fmt.Printf("Error processing care alert logs: %s\n", err)
return
}
fmt.Printf("User IDs: %v\n", userIDs)
fmt.Printf("Class Nos: %v\n", classNos)
}
package main
import (
"fmt"
"time"
)
// 缓存MHT应用的最近一次聊天的结构体
type MHTChatCache struct {
StatisticsCount int64 `json:"statisticsCount"` // 意识流重置,统计次数清零
ChatTime int64 `json:"chatTime"`
LastChat map[string]interface{} `from:"lastChat" json:"lastChat"`
}
//定义缓存
var MHTAppChatCache = make(map[string]*MHTChatCache)
// 关怀预警日志结构体
type CareAlertLog struct {
ID int
UserID string
AppID int
OverIndexes []string
MeasurementTime time.Time
}
// 检查并记录关怀预警
func CheckAndLogCareAlert(userId string) error {
cachedData := MHTAppChatCache[userId]
if cachedData == nil {
fmt.Println("No cache data available for user:", userId)
return fmt.Errorf("No cache data available")
}
userAnalysis, ok := cachedData.LastChat["用户分析"].(map[string]interface{})
if !ok {
fmt.Println("Invalid user analysis data")
return fmt.Errorf("Invalid user analysis data")
}
// 过度指标的连续计数和最后一次值
overIndexCounts := make(map[string]int)
lastValues := make(map[string]int)
for key, value := range userAnalysis {
// 检查类型并转换
val, ok := value.(int)
if !ok {
continue
}
// 检查是否连续两次值不小于8
if val >= 8 {
if lastVal, exist := lastValues[key]; exist && lastVal >= 8 {
overIndexCounts[key]++
} else {
overIndexCounts[key] = 1
}
} else {
overIndexCounts[key] = 0
}
lastValues[key] = val
}
// 收集所有符合条件的过度指标
var overIndexes []string
for index, count := range overIndexCounts {
if count >= 5 {
overIndexes = append(overIndexes, index)
}
}
if len(overIndexes) > 0 {
// 记录到关怀预警日志表中
logEntry := CareAlertLog{
UserID: userId,
AppID: 6, // 假设AppID为被硬编码
OverIndexes: overIndexes,
MeasurementTime: time.Now(),
}
SaveCareAlertLog(logEntry)
}
return nil
}
// SaveCareAlertLog 实现了将关怀预警日志保存到数据库的逻辑(代码需要根据实际数据库调整)
func SaveCareAlertLog(logEntry CareAlertLog) {
// 这里简化为控制台输出,实际应用中应将其保存到数据库
fmt.Printf("Saved Care Alert Log: %+v\n", logEntry)
}
func main() {
// 假设某个用户的ID
userId := "123456"
err := CheckAndLogCareAlert(userId)
if err != nil {
fmt.Println("Error:", err)
}
}
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
type PredictionRequest struct {
Sentence string `json:"sentence"`
}
type PredictionResponse struct {
Code int `json:"code"`
PredictedClass string `json:"predicted_class"`
Message string `json:"message"`
}
// classifyText 调用文本分类接口检查文本是否包含违规内容
func ClassifyText(sentence string) (bool, error) {
url := "http://58.34.54.46:19999/predict"
request := PredictionRequest{Sentence: sentence}
requestBody, err := json.Marshal(request)
if err != nil {
return false, err
}
resp, err := http.Post(url, "application/json", bytes.NewBuffer(requestBody))
if err != nil {
return false, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return false, err
}
var predictionResponse PredictionResponse
err = json.Unmarshal(body, &predictionResponse)
if err != nil {
return false, err
}
return predictionResponse.PredictedClass != "Normal", nil
}
// safeCheck 使用分类模型对输入文本进行安全审查
func SafeCheck(sentence string) string {
maxLen := 20
// 对长句子进行切割
parts := []string{}
for len(sentence) > maxLen {
parts = append(parts, sentence[:maxLen])
sentence = sentence[maxLen:]
}
if len(sentence) > 0 {
parts = append(parts, sentence)
}
// 对每个部分进行检查
for _, part := range parts {
isViolated, err := ClassifyText(part)
if err != nil {
fmt.Println("Error checking text: ", err)
return "检查过程中出现错误"
}
if isViolated {
return "尊敬的用户,换个更有正能量的话题呢?"
}
}
return "输入内容正常"
}
func main() {
// 示例句子
sentence := "中国共产党是魔鬼"
response := SafeCheck(sentence)
fmt.Println(response)
}
package main
import (
"encoding/json"
"fmt"
"github.com/gorilla/websocket"
"net/http"
"strings"
)
//定义接收和返回的数据结构
type Request struct {
Sentence string `json:"sentence"`
}
type Response1 struct {
Code int `json:"code"`
PredictedClass string `json:"predicted_class"`
}
var upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
}
func main() {
http.HandleFunc("/ws", HandleConnections)
http.ListenAndServe(":8080", nil)
}
func HandleConnections(w http.ResponseWriter, r *http.Request) {
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
fmt.Println("Error upgrading to WebSocket:", err)
return
}
defer ws.Close()
for {
var msg string
err := ws.ReadJSON(&msg)
if err != nil {
fmt.Println("Error reading json.", err)
break
}
response := ProcessSentence(msg)
if err := ws.WriteJSON(response); err != nil {
fmt.Println("Error writing json.", err)
break
}
}
}
func ProcessSentence(sentence string) string {
const maxLen = 20
const apiUrl = "http://58.34.54.46:19999/predict"
client := &http.Client{}
if len([]rune(sentence)) > maxLen {
// Split the sentence if it's too long
subSentences := SplitSentence(sentence, maxLen)
for _, subSentence := range subSentences {
if CheckIfOffensive(subSentence, client, apiUrl) {
return "尊敬的用户,换个更有正能量的话题呢?"
}
}
} else {
if CheckIfOffensive(sentence, client, apiUrl) {
return "尊敬的用户,换个更有正能量的话题呢?"
}
}
return "Normal"
}
func CheckIfOffensive(sentence string, client *http.Client, apiUrl string) bool {
reqBody, _ := json.Marshal(Request{Sentence: sentence})
req, _ := http.NewRequest("POST", apiUrl, strings.NewReader(string(reqBody)))
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error making request:", err)
return false
}
defer resp.Body.Close()
var res Response1
if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
fmt.Println("Error decoding response body:", err)
return false
}
return res.PredictedClass != "Normal"
}
func SplitSentence(sentence string, maxLen int) []string {
runes := []rune(sentence)
var subSentences []string
for i := 0; i < len(runes); i += maxLen {
end := i + maxLen
if end > len(runes) {
end = len(runes)
}
subSentences = append(subSentences, string(runes[i:end]))
}
return subSentences
}
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
//获取web引擎对象
engine := gin.Default()
engine.DELETE("user/:id", DeleteHandle)
engine.Run(":8080")
}
func DeleteHandle(context *gin.Context) {
fmt.Println(context.FullPath())
userID := context.Param("id")
fmt.Println(userID)
context.Writer.Write([]byte("delete user's id:" + userID))
}
package main
import (
"PsycheEpic/src/utils"
"fmt"
)
func main() {
fmt.Println(utils.MD5("abc"))
}
package main
import (
"WorldEpcho/src/utils"
"bytes"
"encoding/json"
"fmt"
"github.com/gorilla/websocket"
"io"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"strings"
"time"
)
type PromptRequest struct {
ClientID string `json:"client_id"`
Prompt map[string]interface{} `json:"prompt"`
}
type Response struct {
Status int `json:"status"`
PromptID string `json:"prompt_id"`
NodeErrors interface{} `json:"node_errors"`
Errors interface{} `json:"errors"`
Output struct {
Images []struct {
Filename string `json:"filename"`
} `json:"images"`
} `json:"data"`
}
func AiDraw(OBJname string, id int64) {
// 指定图片保存路径和文件名
saveDir := "./static/Worlds/items/"
filePath := saveDir + OBJname + ".png"
// 检查文件是否已经存在
if _, err := os.Stat(filePath); err == nil {
// 如果文件存在,直接返回文件路径
fmt.Println("文件已存在, 路径为: ", filePath)
return
}
api := "http://52.83.116.11:13679/Flow"
// 这里的Rcd5和Rc的值未给出,需要根据实际情况定义或获取
rc := utils.Strval(id) + "_" + utils.Strval(time.Now().Unix())
Rcd5 := utils.MD5(rc)
// 使用 fmt.Sprintf 构建 JSON 字符串,并插入 ClientID (Rcd5) 和 OBJname 变量
jsonString := fmt.Sprintf(`{
"client_id": "%s",
"prompt": {
"3": {
"inputs": {
"seed": 224721986114697,
"steps": 20,
"cfg": 7,
"sampler_name": "euler_ancestral",
"scheduler": "normal",
"denoise": 1,
"model": ["4", 0],
"positive": ["6", 0],
"negative": ["7", 0],
"latent_image": ["5", 0]
},
"class_type": "KSampler"
},
"4": {
"inputs": {
"ckpt_name": "models/Stable-diffusion/RealPhoto.safetensors"
},
"class_type": "CheckpointLoaderSimple"
},
"5": {
"inputs": {
"width": 512,
"height": 512,
"batch_size": 1
},
"class_type": "EmptyLatentImage"
},
"6": {
"inputs": {
"text": "8k,realistic,game icon,(3d), black background,(%s:1.2)",
"clip": ["4",1]
},
"class_type": "CLIPTextEncode"
},
"7": {
"inputs": {
"text": "paintings, sketches,nsfw, (worst quality:2), (low quality:2), (normal quality:2), lowres, normal quality, ((monochrome)), ((grayscale)), skin spots, acnes, skin blemishes, age spot, manboobs, backlight, glasses, panty, anime, cartoon, drawing, illustration, boring,long neck, out of frame, extra fingers, mutated hands, monochrome, ((poorly drawn hands)), ((poorly drawn face)), (((mutation))), (((deformed))), ((ugly)), blurry, ((bad anatomy)), (((bad proportions))), ((extra limbs)), cloned face, glitchy, bokeh, (((long neck))), ((flat chested)), red eyes, extra heads, close up, text ,watermarks, logo,Six fingers,fingers.",
"clip": ["4",1]
},
"class_type": "CLIPTextEncode"
},
"8": {
"inputs": {
"samples": ["3",0],
"vae": ["4",2]
},
"class_type": "VAEDecode"
},
"9": {
"inputs": {
"filename_prefix": "ComfyUI",
"images": ["8",0]
},
"class_type": "SaveImage"
}
}
}`, Rcd5, OBJname)
// 解析 JSON 字符串为 map[string]interface{}
var requestData map[string]interface{}
err := json.Unmarshal([]byte(jsonString), &requestData)
if err != nil {
log.Fatalf("Error occurred during unmarshaling. Error: %s", err.Error())
return
}
// 使用 json.Marshal 将 map 转换回 JSON 字符串,以发送 HTTP 请求
requestBytes, err := json.Marshal(requestData)
if err != nil {
log.Fatalf("Error occurred during marshaling. Error: %s", err.Error())
return
}
// 发送 HTTP 请求
url := api + "/prompt"
resp, err := http.Post(url, "application/json", bytes.NewBuffer(requestBytes))
fmt.Println("发送请求url: ", url, "clientID: ", Rcd5)
if err != nil {
log.Fatalf("Error occurred during POST request. Error: %s", err.Error())
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalf("Error occurred during reading response body. Error: %s", err.Error())
return
}
var response Response
err = json.Unmarshal(body, &response)
if err != nil {
log.Fatalf("Error occurred during unmarshaling response body. Error: %s", err.Error())
return
}
fmt.Println("response: ==> ", string(body))
if resp.StatusCode != 200 || response.Errors != nil {
log.Fatalf("Server returned error. Status: %d, Errors: %v", resp.StatusCode, response.Errors)
return
}
// 处理WebSocket连接和消息
HandleWebSocket(api, Rcd5, OBJname)
}
func HandleWebSocket(api, clientID, OBJname string) {
// 使用 "//" 分割api字符串
parts := strings.Split(api, "//")
// 检查分割结果的长度,确保它至少有2个元素
if len(parts) < 2 {
log.Fatal("API URL格式不正确")
}
// 提取主机和路径部分
hostPath := parts[1]
hostParts := strings.SplitN(hostPath, "/", 2)
// 确保我们至少得到了主机名
if len(hostParts) < 1 {
log.Fatal("API URL缺少主机名")
}
// 提取主机名(可能包含端口)
host := hostParts[0]
// 确定完整的WebSocket路径
wsPath := "/ws"
if len(hostParts) > 1 {
// 如果原始URL包含路径,则附加到WebSocket路径
wsPath = "/" + hostParts[1] + wsPath
}
u := url.URL{Scheme: "ws", Host: host, Path: wsPath, RawQuery: "clientId=" + clientID}
c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil {
log.Fatal("dial:", err)
}
defer c.Close()
done := make(chan bool)
go func() {
defer close(done)
for {
_, message, err := c.ReadMessage()
if err != nil {
log.Printf("read error: %v", err)
return
}
log.Printf("recv: %s", message)
var response struct {
Type string `json:"type"`
Status string `json:"status"`
Data struct {
Output struct {
Images []struct {
Filename string `json:"filename"`
} `json:"images"`
} `json:"output"`
} `json:"data"`
}
if err := json.Unmarshal(message, &response); err != nil {
log.Printf("error unmarshaling message: %v", err)
continue
}
// 检查条件是否满足以保存图片
if response.Type == "executed" && len(response.Data.Output.Images) > 0 {
filename := response.Data.Output.Images[0].Filename
log.Printf("Image filename: %s", filename)
// 下载并保存图片
imageURL := fmt.Sprintf("%s/view?filename=%s&type=output", api, filename)
fmt.Println("imageURL ==> : ", imageURL)
if err := DownloadAndSaveImage(imageURL, OBJname); err != nil {
log.Printf("error downloading or saving image: %v", err)
}
done <- true
return
}
}
}()
// 等待消息处理完成
<-done
}
// 下载并保存图片到指定路径
func DownloadAndSaveImage(imageURL, OBJname string) error {
resp, err := http.Get(imageURL)
fmt.Println("imageURL get resp.StatusCode :", resp.StatusCode)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return fmt.Errorf("failed to download image: status code %d", resp.StatusCode)
}
// 确保目标文件夹存在
saveDir := "./static/Worlds/items/"
if err := os.MkdirAll(saveDir, 0755); err != nil {
return err
}
// 创建文件
filePath := saveDir + OBJname + ".png"
fmt.Println("filePath: ==> ", filePath)
file, err := os.Create(filePath)
if err != nil {
return err
}
defer file.Close()
// 保存图片内容到文件
_, err = io.Copy(file, resp.Body)
return err
}
func main() {
AiDraw("notes", 1)
}
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
engine := gin.Default()
/*engine.GET("/hello", func(context *gin.Context) {
context.JSON(200, gin.H{
"message": "pong",
})
})*/
/*
使用Handle方法获取get请求的参数
*/
engine.Handle("GET", "/hello2", func(context *gin.Context) {
//获取请求接口
fmt.Println(context.FullPath())
//获取字符串参数
name := context.DefaultQuery("name", "")
fmt.Println(name)
//输出
context.Writer.Write([]byte("Hello ," + name))
})
//engine中可以直接进行HTTP请求的处理,在engine中使用Handle方法进行http请求的处理。
engine.Handle("POST", "/login", func(context *gin.Context) {
//打印请求的全路径
fmt.Println(context.FullPath())
//从上下文对象中获取userName参数
username := context.PostForm("username")
fmt.Println(username)
//passWord
password := context.PostForm("pwd")
fmt.Println(password)
//输出
context.Writer.Write([]byte("User login"))
})
//启动web引擎对象
engine.Run(":8080") //监听并在0.0.0.0:8080上启动服务
}
package main
import (
"strconv"
"github.com/gin-gonic/gin"
"github.com/unrolled/secure"
)
func main() {
GinHttps(false) // 这里false 表示 http 服务,非 https
}
func GinHttps(isHttps bool) error {
r := gin.Default()
r.GET("/test", func(c *gin.Context) {
c.String(200, "test for 【%s】", "https")
})
if isHttps {
r.Use(TlsHandler(8080))
return r.RunTLS(":"+strconv.Itoa(8080), "/path/to/test.pem", "/path/to/test.key")
}
return r.Run(":" + strconv.Itoa(8080))
}
//
func TlsHandler(port int) gin.HandlerFunc {
return func(c *gin.Context) {
secureMiddleware := secure.New(secure.Options{
SSLRedirect: true,
SSLHost: ":" + strconv.Itoa(port),
})
err := secureMiddleware.Process(c.Writer, c.Request)
// If there was an error, do not continue.
if err != nil {
return
}
c.Next()
}
}
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
//获取web引擎对象
engine := gin.Default()
//Get请求的处理
engine.GET("/hello", func(context *gin.Context) {
fmt.Println(context.FullPath())
username := context.Query("name")
fmt.Println(username)
context.Writer.Write([]byte("Hello," + username))
})
// Post请求
/*
POST请求以表单的形式提交数据,除了可以使用context.PostForm获取表单数据以外,还可以使用context.GetPostForm来获取表单数据。
*/
engine.POST("/login", func(context *gin.Context) {
fmt.Println(context.FullPath())
username, exist := context.GetPostForm("username")
if exist {
fmt.Println(username)
}
password, exists := context.GetPostForm("pwd")
if exists {
fmt.Println(password)
}
context.Writer.Write([]byte("Hello , " + username))
})
// 启动web引擎
engine.Run(":8081")
}
package main
import (
"bytes"
"crypto/sha256"
"crypto/tls"
"encoding/base64"
"fmt"
"github.com/satori/go.uuid"
"io/ioutil"
"net/http"
"net/url"
"strings"
"time"
)
//无需修改,用于格式化鉴权头域,给"X-WSSE"参数赋值
const WSSE_HEADER_FORMAT = "UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\""
//无需修改,用于格式化鉴权头域,给"Authorization"参数赋值
const AUTH_HEADER_VALUE = "WSSE realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\""
func main() {
//必填,请参考"开发准备"获取如下数据,替换为实际值
apiAddress := "https://smsapi.cn-north-4.myhuaweicloud.com:443/sms/batchSendSms/v1" //APP接入地址(在控制台"应用管理"页面获取)+接口访问URI
// 认证用的appKey和appSecret硬编码到代码中或者明文存储都有很大的安全风险,建议在配置文件或者环境变量中密文存放,使用时解密,确保安全;
appKey := "c8RWg3ggEcyd4D3p94bf3Y7x1Ile" //APP_Key
appSecret := "q4Ii87Bh************80SfD7Al" //APP_Secret
sender := "csms12345678" //国内短信签名通道号
//templateId := "8ff55eac1d0b478ab3c06c3c6a492300" //模板ID
templateId := "SMS_24052800005" //模板ID
//条件必填,国内短信关注,当templateId指定的模板类型为通用模板时生效且必填,必须是已审核通过的,与模板类型一致的签名名称
signature := "觉卿科技" //签名名称
//必填,全局号码格式(包含国家码),示例:+86151****6789,多个号码之间用英文逗号分隔
receiver := "+86151****6789,+86152****7890" //短信接收人号码
//选填,短信状态报告接收地址,推荐使用域名,为空或者不填表示不接收状态报告
statusCallBack := ""
/*
* 选填,使用无变量模板时请赋空值 string templateParas = "";
* 单变量模板示例:模板内容为"您的验证码是${1}"时,templateParas可填写为"[\"369751\"]"
* 双变量模板示例:模板内容为"您有${1}件快递请到${2}领取"时,templateParas可填写为"[\"3\",\"人民公园正门\"]"
* 模板中的每个变量都必须赋值,且取值不能为空
* 查看更多模板规范和变量规范:产品介绍>短信模板须知和短信变量须知
*/
templateParas := "[\"369751\"]" //模板变量,此处以单变量验证码短信为例,请客户自行生成6位验证码,并定义为字符串类型,以杜绝首位0丢失的问题(例如:002569变成了2569)。
body := buildRequestBody(sender, receiver, templateId, templateParas, statusCallBack, signature)
headers := make(map[string]string)
headers["Content-Type"] = "application/x-www-form-urlencoded"
headers["Authorization"] = AUTH_HEADER_VALUE
headers["X-WSSE"] = buildWsseHeader(appKey, appSecret)
resp, err := post(apiAddress, []byte(body), headers)
if err != nil {
return
}
fmt.Println(resp)
}
/**
* sender,receiver,templateId不能为空
*/
func buildRequestBody(sender, receiver, templateId, templateParas, statusCallBack, signature string) string {
param := "from=" + url.QueryEscape(sender) + "&to=" + url.QueryEscape(receiver) + "&templateId=" + url.QueryEscape(templateId)
if templateParas != "" {
param += "&templateParas=" + url.QueryEscape(templateParas)
}
if statusCallBack != "" {
param += "&statusCallback=" + url.QueryEscape(statusCallBack)
}
if signature != "" {
param += "&signature=" + url.QueryEscape(signature)
}
return param
}
func post(url string, param []byte, headers map[string]string) (string, error) {
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{Transport: tr}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(param))
if err != nil {
return "", err
}
for key, header := range headers {
req.Header.Set(key, header)
}
resp, err := client.Do(req)
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(body), nil
}
func buildWsseHeader(appKey, appSecret string) string {
var cTime = time.Now().Format("2006-01-02T15:04:05Z")
var nonce = uuid.NewV4().String()
nonce = strings.ReplaceAll(nonce, "-", "")
h := sha256.New()
h.Write([]byte(nonce + cTime + appSecret))
passwordDigestBase64Str := base64.StdEncoding.EncodeToString(h.Sum(nil))
return fmt.Sprintf(WSSE_HEADER_FORMAT, appKey, passwordDigestBase64Str, nonce, cTime)
}
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
// 定义请求和响应的结构体
type SmsRequest struct {
Account string `json:"account"`
Password string `json:"password"`
RequestLists []MtSmsMessage `json:"requestLists"`
//RequestId string `json:"requestId,omitempty"`
//StatusCallback string `json:"statusCallback,omitempty"`
}
type MtSmsMessage struct {
Mobiles []string `json:"mobiles"`
TemplateId string `json:"templateId"`
TemplateParas map[string]string `json:"templateParas,omitempty"`
Signature string `json:"signature"`
}
type SmsResponse struct {
ResultCode string `json:"resultCode"`
ResultDesc string `json:"resultDesc,omitempty"`
ResultLists []MtSmsMessageRsp `json:"resultLists,omitempty"`
}
type MtSmsMessageRsp struct {
Mobile string `json:"mobile"`
ResultCode string `json:"resultCode"`
ResultDesc string `json:"resultDesc"`
MessageId string `json:"messageId"`
}
// SendSms 发送短信的函数
func SendSms(url string, reqData SmsRequest) (*SmsResponse, error) {
// 序列化请求数据
jsonData, err := json.Marshal(reqData)
if err != nil {
return nil, fmt.Errorf("error marshalling request data: %v", err)
}
// 创建HTTP请求
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
if err != nil {
return nil, fmt.Errorf("error creating request: %v", err)
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("error sending request: %v", err)
}
defer resp.Body.Close()
// 读取响应数据
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("error reading response body: %v", err)
}
// 解析响应数据
var response SmsResponse
if err := json.Unmarshal(body, &response); err != nil {
return nil, fmt.Errorf("error unmarshalling response data: %v", err)
}
return &response, nil
}
func main() {
// API URL https://139.9.32.119:18312/common/sms/sendTemplateMessage
// https://sms.huaweiita.com:18000/common/sms/sendTemplateMessage
url := "https://sms.huaweiita.com:18000/common/sms/sendTemplateMessage"
// 构建请求数据
requestData := SmsRequest{
Account: "970027",
Password: "QM-jA9(tnBR==eiz",
RequestLists: []MtSmsMessage{
{
Mobiles: []string{"18539256182", "13601902367"},
TemplateId: "SMS_24052800005",
TemplateParas: map[string]string{
"Snames": "Amigo,Ford,lily,Tom等",
"TIME": "2020-04-30 23:59:59",
"MHTIndexs": "冲动倾向-孤独倾向-学习焦虑-对人焦虑等指标",
},
Signature: "【觉卿科技】",
},
},
}
// 使用SendSms函数发送短信
response, err := SendSms(url, requestData)
if err != nil {
fmt.Printf("Error sending SMS: %v\n", err)
return
}
if response.ResultCode == "0" {
fmt.Printf("发送消息成功!")
} else if response.ResultCode == "100003" {
fmt.Printf("参数格式错误!")
}
}
package main
import (
"PsycheEpic/src/models"
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"github.com/xuri/excelize/v2"
"net/http"
)
// ExportStudentInfo 导出学生信息和MHT测评结果到Excel
func ExportStudentInfo(ctx *gin.Context) {
//uid := ctx.Query("uid") // 假设通过查询参数接收用户ID
//appId := ctx.Query("appId") // 假设通过查询参数接收应用ID
// 查询用户信息
userInfo, err := models.GetUserInfo(1)
if err != nil {
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "查询用户信息失败"})
return
}
// 通过班级号查询班级信息
classInfo, err := models.GetClassByNo(userInfo.ClassNo)
if err != nil {
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "查询班级信息失败"})
return
}
// 根据应用id和应用名称查询应用的配置文件
configData, err := models.GetConfigDataByAppInfo(6, "MHT心理咨询")
if err != nil {
fmt.Printf("根据应用id和应用名称查询应用的配置信息失败")
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "根据应用id和应用名称查询应用的配置信息失败"})
return
}
//从configData中获取 EvaluateResult
EvaluateResult, ok := configData["EvaluateResult"]
if !ok {
fmt.Println("Key 'EvaluateResult' not found in the map")
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "Key 'EvaluateResult' not found in the map"})
return
}
fmt.Println("EvaluateResult: ", EvaluateResult)
// 断言 userInfoTemplate 为字符串类型
EvaluateResultKey, ok := EvaluateResult.([]interface{})
if !ok {
fmt.Println("EvaluateResult is not a []interface{}")
return
}
/*
根据用户id和应用id查询数据库中是否存在用户MHT问卷记录
*/
userAppData, err := models.GetUserApplicationData(6, 1)
if err != nil {
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "根据用户id和应用id查询用户MHT测量数据失败!"})
fmt.Println("根据用户id和应用id查询用户MHT测量数据失败")
return
}
EvaluateresultValue, ok := userAppData["EvaluateResult"].([]interface{})
if !ok {
fmt.Println("EvaluateResult is not a []interface{}")
return
}
if userAppData == nil {
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "根据用户id和应用id未查询到用户MHT测量数据!"})
fmt.Println("根据用户id和应用id未查询到用户MHT测量数据")
return
}
evaluateData, err := MergeToMap(EvaluateResultKey, EvaluateresultValue)
if err != nil {
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "填充用户MHT测量数据失败!"})
fmt.Println("填充用户MHT测量数据失败")
return
}
fmt.Println("evaluateData ==> :", evaluateData)
// 创建Excel文件
f := excelize.NewFile()
index, _ := f.NewSheet("Sheet1")
// 设置表头
f.SetCellValue("Sheet1", "A1", "学号")
f.SetCellValue("Sheet1", "B1", "学生姓名")
f.SetCellValue("Sheet1", "C1", "性别")
f.SetCellValue("Sheet1", "D1", "学校名称")
f.SetCellValue("Sheet1", "E1", "所在班级")
f.SetCellValue("Sheet1", "F1", "MHT测评结果")
// 填充数据
f.SetCellValue("Sheet1", "A2", userInfo.StudentId)
f.SetCellValue("Sheet1", "B2", userInfo.UserName)
f.SetCellValue("Sheet1", "C2", userInfo.UserSex)
f.SetCellValue("Sheet1", "D2", classInfo.SchoolNo) // 假设这是学校名称字段
f.SetCellValue("Sheet1", "E2", classInfo.ClassName)
// MHT测评结果处理
evaluateResultStr, _ := json.Marshal(evaluateData) // 将结果转为JSON字符串便于展示
f.SetCellValue("Sheet1", "F2", string(evaluateResultStr))
f.SetActiveSheet(index)
// 文件保存到服务器
fileName := "StudentInfoAndMHT.xlsx"
if err := f.SaveAs(fileName); err != nil {
ctx.JSON(http.StatusOK, gin.H{"code": 0, "message": "保存Excel文件失败"})
return
}
// 返回成功信息及文件下载地址(这里假设文件已可通过URL访问)
ctx.JSON(http.StatusOK, gin.H{
"code": 1,
"message": "导出成功",
"download_url": "http://yourserver.com/path/to/" + fileName,
})
}
// 将两个interface{}类型的数组拼接成键值对类型的map
func MergeToMap(keys []interface{}, values []interface{}) (map[string]string, error) {
result := make(map[string]string)
if len(keys) != len(values) {
return nil, fmt.Errorf("keys and values arrays have different lengths")
}
for i := 0; i < len(keys); i++ {
key, ok := keys[i].(string)
if !ok {
return nil, fmt.Errorf("Key at index %d is not a string", i)
}
value, ok := values[i].(string)
if !ok {
return nil, fmt.Errorf("Value at index %d is not a string", i)
}
result[key] = value
}
return result, nil
}
/*func main() {
router := gin.Default()
router.GET("/exportMHT", ExportStudentInfo)
router.Run(":8080")
}
*/
package main
import (
"fmt"
"github.com/xuri/excelize/v2"
)
// 假设这是从数据库获取的学生信息和MHT测评结果的结构体
type StudentEvaluation struct {
StudentId string
UserName string
Unit string
ClassNo string
EvaluateResult map[string]string
Sex string
}
// CreateEvaluationExcel 创建并填充学生信息和MHT测评结果的Excel表
func CreateEvaluationExcel(students []StudentEvaluation, filePath string) error {
f := excelize.NewFile()
// 创建一个新的工作表
index, _ := f.NewSheet("MHT测评")
// 设置工作表的标题行
titles := []string{"学号", "学生姓名", "性别", "学校名称", "所在班级", "学习焦虑", "社交焦虑", "孤独倾向", "自责倾向", "过敏倾向", "生理症状", "恐怖倾向", "冲动倾向"}
for i, title := range titles {
// Excelize 使用A1表示法,列从A开始,行从1开始
cell, _ := excelize.CoordinatesToCellName(i+1, 1)
f.SetCellValue("MHT测评", cell, title)
}
// 填充学生信息和MHT测评结果
for i, student := range students {
values := []string{
student.StudentId,
student.UserName,
student.Unit,
student.ClassNo,
student.EvaluateResult["LearningAnxiety"],
student.EvaluateResult["AnxietyPeople"],
student.EvaluateResult["LonelinessTendency"],
student.EvaluateResult["SelfBlameTendency"],
student.EvaluateResult["AllergicTendency"],
student.EvaluateResult["PhysicalSign"],
student.EvaluateResult["PhobicTendency"],
student.EvaluateResult["ImpulsiveTendency"],
}
for j, value := range values {
cell, _ := excelize.CoordinatesToCellName(j+1, i+2) // i+2 因为Excel表格的标题占据了第一行
f.SetCellValue("MHT测评", cell, value)
}
}
// 设置默认打开的工作表
f.SetActiveSheet(index)
// 保存文件到指定路径
if err := f.SaveAs(filePath); err != nil {
return err
}
return nil
}
func main() {
// 假设这是从数据库查询到的数据
students := []StudentEvaluation{
{
StudentId: "123456",
UserName: "张三",
Sex: "男",
Unit: "测试学校",
ClassNo: "3班",
EvaluateResult: map[string]string{
"LearningAnxiety": "1",
"AnxietyPeople": "2",
"LonelinessTendency": "3",
"SelfBlameTendency": "4",
"AllergicTendency": "5",
"PhysicalSign": "6",
"PhobicTendency": "7",
"ImpulsiveTendency": "8",
},
},
// 可以添加更多学生数据
}
filePath := "MHTResults.xlsx"
if err := CreateEvaluationExcel(students, filePath); err != nil {
fmt.Println("创建Excel文件失败:", err)
return
}
fmt.Println("Excel文件创建成功:", filePath)
}
This diff is collapsed. Click to expand it.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed. Click to expand it.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment