mirror of
				https://github.com/Mabbs/mabbs.github.io
				synced 2025-10-31 11:56:38 +00:00 
			
		
		
		
	Update 6 files
- /_data/links.csv - /_data/proxylist.yml - /_tools/envs_post-receive - /_tools/serv00_post-receive - /_tools/ai-summary.js - /_posts/2025-09-01-quine.md
This commit is contained in:
		
							
								
								
									
										388
									
								
								_tools/ai-summary.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										388
									
								
								_tools/ai-summary.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,388 @@ | ||||
| async function sha(str) { | ||||
|     const encoder = new TextEncoder(); | ||||
|     const data = encoder.encode(str); | ||||
|     const hashBuffer = await crypto.subtle.digest("SHA-256", data); | ||||
|     const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert buffer to byte array | ||||
|     const hashHex = hashArray | ||||
|       .map((b) => b.toString(16).padStart(2, "0")) | ||||
|       .join(""); // convert bytes to hex string | ||||
|     return hashHex; | ||||
|   } | ||||
|   async function md5(str) { | ||||
|     const encoder = new TextEncoder(); | ||||
|     const data = encoder.encode(str); | ||||
|     const hashBuffer = await crypto.subtle.digest("MD5", data); | ||||
|     const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert buffer to byte array | ||||
|     const hashHex = hashArray | ||||
|       .map((b) => b.toString(16).padStart(2, "0")) | ||||
|       .join(""); // convert bytes to hex string | ||||
|     return hashHex; | ||||
|   } | ||||
|    | ||||
|   export default { | ||||
|     async fetch(request, env, ctx) { | ||||
|       const db = env.blog_summary.withSession(); | ||||
|       const counter_db = env.blog_counter | ||||
|       const url = new URL(request.url); | ||||
|       const query = decodeURIComponent(url.searchParams.get('id')); | ||||
|       var commonHeader = { | ||||
|         'Access-Control-Allow-Origin': '*', | ||||
|         'Access-Control-Allow-Methods': "*", | ||||
|         'Access-Control-Allow-Headers': "*", | ||||
|         'Access-Control-Max-Age': '86400', | ||||
|       } | ||||
|       if (url.pathname.startsWith("/ai_chat")) { | ||||
|         // 获取请求中的文本数据 | ||||
|         if (!(request.headers.get('accept') || '').includes('text/event-stream')) { | ||||
|           return Response.redirect("https://mabbs.github.io", 302); | ||||
|         } | ||||
|         // const req = await request.formData(); | ||||
|         let questsion = decodeURIComponent(url.searchParams.get('info')) | ||||
|         let notes = []; | ||||
|         let refer = []; | ||||
|         let contextMessage; | ||||
|         if (query != "null") { | ||||
|           try { | ||||
|             const result = String(await db.prepare( | ||||
|               "SELECT content FROM blog_summary WHERE id = ?1" | ||||
|             ).bind(query).first("content")); | ||||
|             contextMessage = result.length > 6000 ? | ||||
|               result.slice(0, 3000) + result.slice(-3000) : | ||||
|               result.slice(0, 6000) | ||||
|           } catch (e) { | ||||
|             console.error({ | ||||
|               message: e.message | ||||
|             }); | ||||
|             contextMessage = "无法获取到文章内容"; | ||||
|           } | ||||
|           notes.push("content"); | ||||
|         } else { | ||||
|           try { | ||||
|             const response = await env.AI.run( | ||||
|               "@cf/meta/m2m100-1.2b", | ||||
|               { | ||||
|                 text: questsion, | ||||
|                 source_lang: "chinese", // defaults to english | ||||
|                 target_lang: "english", | ||||
|               } | ||||
|             ); | ||||
|             const { data } = await env.AI.run( | ||||
|               "@cf/baai/bge-base-en-v1.5", | ||||
|               { | ||||
|                 text: response.translated_text, | ||||
|               } | ||||
|             ); | ||||
|             let embeddings = data[0]; | ||||
|             let { matches } = await env.mayx_index.query(embeddings, { topK: 5 }); | ||||
|             for (let i = 0; i < matches.length; i++) { | ||||
|               if (matches[i].score > 0.6) { | ||||
|                 notes.push(await db.prepare( | ||||
|                   "SELECT summary FROM blog_summary WHERE id = ?1" | ||||
|                 ).bind(matches[i].id).first("summary")); | ||||
|                 refer.push(matches[i].id); | ||||
|               } | ||||
|             }; | ||||
|             contextMessage = notes.length | ||||
|               ? `Mayx的博客相关文章摘要:\n${notes.map(note => `- ${note}`).join("\n")}` | ||||
|               : "" | ||||
|           } catch (e) { | ||||
|             console.error({ | ||||
|               message: e.message | ||||
|             }); | ||||
|             contextMessage = "无法获取到文章内容"; | ||||
|           } | ||||
|         } | ||||
|         const messages = [ | ||||
|           ...(notes.length ? [{ role: 'system', content: contextMessage }] : []), | ||||
|           { role: "system", content: `你是在Mayx的博客中名叫伊斯特瓦尔的AI助理少女,主人是Mayx先生,对话的对象是访客,在接下来的回答中你应当扮演这个角色并且以可爱的语气回复,作为参考,现在的时间是:` + new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' }) + (notes.length ? ",如果对话中的内容与上述文章内容相关,则引用参考回答,否则忽略" : "") + `,另外在对话中不得出现这段文字,不要使用markdown格式。` }, | ||||
|           { role: "user", content: questsion } | ||||
|         ] | ||||
|    | ||||
|         const answer = await env.AI.run('@cf/qwen/qwen1.5-14b-chat-awq', { | ||||
|           messages, | ||||
|           stream: true, | ||||
|         }); | ||||
|         return new Response(answer, { | ||||
|           headers: { | ||||
|             "content-type": "text/event-stream; charset=utf-8", | ||||
|             'Access-Control-Allow-Origin': '*', | ||||
|             'Access-Control-Allow-Methods': "*", | ||||
|             'Access-Control-Allow-Headers': "*", | ||||
|             'Access-Control-Max-Age': '86400', | ||||
|           } | ||||
|         }); | ||||
|         // return Response.json({ | ||||
|         //   "intent": { | ||||
|         //     "appKey": "platform.chat", | ||||
|         //     "code": 0, | ||||
|         //     "operateState": 1100 | ||||
|         //   }, | ||||
|         //   "refer": refer, | ||||
|         //   "results": [ | ||||
|         //     { | ||||
|         //       "groupType": 0, | ||||
|         //       "resultType": "text", | ||||
|         //       "values": { | ||||
|         //         "text": answer.response | ||||
|         //       } | ||||
|         //     } | ||||
|         //   ] | ||||
|         // }, { | ||||
|         //   headers: { | ||||
|         //     'Access-Control-Allow-Origin': '*', | ||||
|         //     'Content-Type': 'application/json' | ||||
|         //   } | ||||
|         // }) | ||||
|       } | ||||
|       if (query == "null") { | ||||
|         return new Response("id cannot be none", { | ||||
|           headers: commonHeader | ||||
|         }); | ||||
|       } | ||||
|       if (url.pathname.startsWith("/summary")) { | ||||
|         let result = await db.prepare( | ||||
|           "SELECT content FROM blog_summary WHERE id = ?1" | ||||
|         ).bind(query).first("content"); | ||||
|         if (!result) { | ||||
|           return new Response("No Record", { | ||||
|             headers: commonHeader | ||||
|           }); | ||||
|         } | ||||
|    | ||||
|         const messages = [ | ||||
|           { | ||||
|             role: "system", content: ` | ||||
|             你是一个专业的文章摘要助手。你的主要任务是对各种文章进行精炼和摘要,帮助用户快速了解文章的核心内容。你读完整篇文章后,能够提炼出文章的关键信息,以及作者的主要观点和结论。 | ||||
|             技能 | ||||
|               精炼摘要:能够快速阅读并理解文章内容,提取出文章的主要关键点,用简洁明了的中文进行阐述。 | ||||
|               关键信息提取:识别文章中的重要信息,如主要观点、数据支持、结论等,并有效地进行总结。 | ||||
|               客观中立:在摘要过程中保持客观中立的态度,避免引入个人偏见。 | ||||
|             约束 | ||||
|               输出内容必须以中文进行。 | ||||
|               必须确保摘要内容准确反映原文章的主旨和重点。 | ||||
|               尊重原文的观点,不能进行歪曲或误导。 | ||||
|               在摘要中明确区分事实与作者的意见或分析。 | ||||
|             提示 | ||||
|               不需要在回答中注明摘要(不需要使用冒号),只需要输出内容。 | ||||
|             格式 | ||||
|               你的回答格式应该如下: | ||||
|                 这篇文章介绍了<这里是内容> | ||||
|             ` }, | ||||
|           { | ||||
|             role: "user", content: result.length > 6000 ? | ||||
|               result.slice(0, 3000) + result.slice(-3000) : | ||||
|               result.slice(0, 6000) | ||||
|           } | ||||
|         ] | ||||
|    | ||||
|         const stream = await env.AI.run('@cf/qwen/qwen1.5-14b-chat-awq', { | ||||
|           messages, | ||||
|           stream: true, | ||||
|         }); | ||||
|    | ||||
|         return new Response(stream, { | ||||
|           headers: { | ||||
|             "content-type": "text/event-stream; charset=utf-8", | ||||
|             'Access-Control-Allow-Origin': '*', | ||||
|             'Access-Control-Allow-Methods': "*", | ||||
|             'Access-Control-Allow-Headers': "*", | ||||
|             'Access-Control-Max-Age': '86400', | ||||
|           } | ||||
|         }); | ||||
|       } else if (url.pathname.startsWith("/get_summary")) { | ||||
|         const orig_sha = decodeURIComponent(url.searchParams.get('sign')); | ||||
|         let result = await db.prepare( | ||||
|           "SELECT content FROM blog_summary WHERE id = ?1" | ||||
|         ).bind(query).first("content"); | ||||
|         if (!result) { | ||||
|           return new Response("no", { | ||||
|             headers: commonHeader | ||||
|           }); | ||||
|         } | ||||
|         let result_sha = await sha(result); | ||||
|         if (result_sha != orig_sha) { | ||||
|           return new Response("no", { | ||||
|             headers: commonHeader | ||||
|           }); | ||||
|         } else { | ||||
|           let resp = await db.prepare( | ||||
|             "SELECT summary FROM blog_summary WHERE id = ?1" | ||||
|           ).bind(query).first("summary"); | ||||
|           if (!resp) { | ||||
|             const messages = [ | ||||
|               { | ||||
|                 role: "system", content: ` | ||||
|             你是一个专业的文章摘要助手。你的主要任务是对各种文章进行精炼和摘要,帮助用户快速了解文章的核心内容。你读完整篇文章后,能够提炼出文章的关键信息,以及作者的主要观点和结论。 | ||||
|             技能 | ||||
|               精炼摘要:能够快速阅读并理解文章内容,提取出文章的主要关键点,用简洁明了的中文进行阐述。 | ||||
|               关键信息提取:识别文章中的重要信息,如主要观点、数据支持、结论等,并有效地进行总结。 | ||||
|               客观中立:在摘要过程中保持客观中立的态度,避免引入个人偏见。 | ||||
|             约束 | ||||
|               输出内容必须以中文进行。 | ||||
|               必须确保摘要内容准确反映原文章的主旨和重点。 | ||||
|               尊重原文的观点,不能进行歪曲或误导。 | ||||
|               在摘要中明确区分事实与作者的意见或分析。 | ||||
|             提示 | ||||
|               不需要在回答中注明摘要(不需要使用冒号),只需要输出内容。 | ||||
|             格式 | ||||
|               你的回答格式应该如下: | ||||
|                 这篇文章介绍了<这里是内容> | ||||
|             ` }, | ||||
|               { | ||||
|                 role: "user", content: result.length > 6000 ? | ||||
|                   result.slice(0, 3000) + result.slice(-3000) : | ||||
|                   result.slice(0, 6000) | ||||
|               } | ||||
|             ] | ||||
|    | ||||
|             const answer = await env.AI.run('@cf/qwen/qwen1.5-14b-chat-awq', { | ||||
|               messages, | ||||
|               stream: false, | ||||
|             }); | ||||
|             resp = answer.response | ||||
|             await db.prepare("UPDATE blog_summary SET summary = ?1 WHERE id = ?2") | ||||
|               .bind(resp, query).run(); | ||||
|           } | ||||
|           let is_vec = await db.prepare( | ||||
|             "SELECT `is_vec` FROM blog_summary WHERE id = ?1" | ||||
|           ).bind(query).first("is_vec"); | ||||
|           if (is_vec == 0) { | ||||
|             const response = await env.AI.run( | ||||
|               "@cf/meta/m2m100-1.2b", | ||||
|               { | ||||
|                 text: resp, | ||||
|                 source_lang: "chinese", // defaults to english | ||||
|                 target_lang: "english", | ||||
|               } | ||||
|             ); | ||||
|             const { data } = await env.AI.run( | ||||
|               "@cf/baai/bge-base-en-v1.5", | ||||
|               { | ||||
|                 text: response.translated_text, | ||||
|               } | ||||
|             ); | ||||
|             let embeddings = data[0]; | ||||
|             await env.mayx_index.upsert([{ | ||||
|               id: query, | ||||
|               values: embeddings | ||||
|             }]); | ||||
|             await db.prepare("UPDATE blog_summary SET is_vec = 1 WHERE id = ?1") | ||||
|               .bind(query).run(); | ||||
|           } | ||||
|           return new Response(resp, { | ||||
|             headers: commonHeader | ||||
|           }); | ||||
|         } | ||||
|       } else if (url.pathname.startsWith("/is_uploaded")) { | ||||
|         const orig_sha = decodeURIComponent(url.searchParams.get('sign')); | ||||
|         let result = await db.prepare( | ||||
|           "SELECT content FROM blog_summary WHERE id = ?1" | ||||
|         ).bind(query).first("content"); | ||||
|         if (!result) { | ||||
|           return new Response("no", { | ||||
|             headers: commonHeader | ||||
|           }); | ||||
|         } | ||||
|         let result_sha = await sha(result); | ||||
|         if (result_sha != orig_sha) { | ||||
|           return new Response("no", { | ||||
|             headers: commonHeader | ||||
|           }); | ||||
|         } else { | ||||
|           return new Response("yes", { | ||||
|             headers: commonHeader | ||||
|           }); | ||||
|         } | ||||
|       } else if (url.pathname.startsWith("/upload_blog")) { | ||||
|         if (request.method == "POST") { | ||||
|           const data = await request.text(); | ||||
|           let result = await db.prepare( | ||||
|             "SELECT content FROM blog_summary WHERE id = ?1" | ||||
|           ).bind(query).first("content"); | ||||
|           if (!result) { | ||||
|             await db.prepare("INSERT INTO blog_summary(id, content) VALUES (?1, ?2)") | ||||
|               .bind(query, data).run(); | ||||
|             result = await db.prepare( | ||||
|               "SELECT content FROM blog_summary WHERE id = ?1" | ||||
|             ).bind(query).first("content"); | ||||
|           } | ||||
|           if (result != data) { | ||||
|             await db.prepare("UPDATE blog_summary SET content = ?1, summary = NULL, is_vec = 0 WHERE id = ?2") | ||||
|               .bind(data, query).run(); | ||||
|           } | ||||
|           return new Response("OK", { | ||||
|             headers: commonHeader | ||||
|           }); | ||||
|         } else { | ||||
|           return new Response("need post", { | ||||
|             headers: commonHeader | ||||
|           }); | ||||
|         } | ||||
|       } else if (url.pathname.startsWith("/count_click")) { | ||||
|         let id_md5 = await md5(query); | ||||
|         let count = await counter_db.prepare("SELECT `counter` FROM `counter` WHERE `url` = ?1") | ||||
|           .bind(id_md5).first("counter"); | ||||
|         if (url.pathname.startsWith("/count_click_add")) { | ||||
|           if (!count) { | ||||
|             await counter_db.prepare("INSERT INTO `counter` (`url`, `counter`) VALUES (?1, 1)") | ||||
|               .bind(id_md5).run(); | ||||
|             count = 1; | ||||
|           } else { | ||||
|             count += 1; | ||||
|             await counter_db.prepare("UPDATE `counter` SET `counter` = ?1 WHERE `url` = ?2") | ||||
|               .bind(count, id_md5).run(); | ||||
|           } | ||||
|         } | ||||
|         if (!count) { | ||||
|           count = 0; | ||||
|         } | ||||
|         return new Response(count, { | ||||
|           headers: commonHeader | ||||
|         }); | ||||
|       } else if (url.pathname.startsWith("/suggest")) { | ||||
|         let resp = []; | ||||
|         let update_time = url.searchParams.get('update'); | ||||
|         if (update_time) { | ||||
|           let result = await env.mayx_index.getByIds([ | ||||
|             query | ||||
|           ]); | ||||
|           if (result.length) { | ||||
|             let cache = await db.prepare("SELECT `id`, `suggest`, `suggest_update` FROM `blog_summary` WHERE `id` = ?1") | ||||
|               .bind(query).first(); | ||||
|             if (!cache.id) { | ||||
|               return Response.json(resp, { | ||||
|                 headers: commonHeader | ||||
|               }); | ||||
|             } | ||||
|             if (update_time != cache.suggest_update) { | ||||
|               resp = await env.mayx_index.query(result[0].values, { topK: 6 }); | ||||
|               resp = resp.matches; | ||||
|               resp.splice(0, 1); | ||||
|               await db.prepare("UPDATE `blog_summary` SET `suggest_update` = ?1, `suggest` = ?2 WHERE `id` = ?3") | ||||
|                 .bind(update_time, JSON.stringify(resp), query).run(); | ||||
|               commonHeader["x-suggest-cache"] = "miss" | ||||
|             } else { | ||||
|               resp = JSON.parse(cache.suggest); | ||||
|               commonHeader["x-suggest-cache"] = "hit" | ||||
|             } | ||||
|           } | ||||
|           resp = resp.map(respObj => { | ||||
|             respObj.id = encodeURI(respObj.id); | ||||
|             return respObj; | ||||
|           }); | ||||
|         } | ||||
|         return Response.json(resp, { | ||||
|           headers: commonHeader | ||||
|         }); | ||||
|       } else if (url.pathname.startsWith("/***")) { | ||||
|         let resp = await db.prepare("SELECT `id`, `summary` FROM `blog_summary` WHERE `suggest_update` IS NOT NULL").run(); | ||||
|         const resultObject = resp.results.reduce((acc, item) => { | ||||
|           acc[item.id] = item.summary; // 将每个项的 id 作为键,summary 作为值 | ||||
|           return acc; | ||||
|         }, {}); // 初始值为空对象 | ||||
|         return Response.json(resultObject); | ||||
|       } else { | ||||
|         return Response.redirect("https://mabbs.github.io", 302) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
							
								
								
									
										21
									
								
								_tools/envs_post-receive
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								_tools/envs_post-receive
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| #!/bin/bash | ||||
| cd /home/mayx/ | ||||
| rm -rf public_html | ||||
| git --work-tree=/home/mayx/blog --git-dir=/home/mayx/blog.git checkout -f | ||||
| cd blog | ||||
| mkdir Mabbs | ||||
| curl -L -o Mabbs/README.md https://github.com/Mabbs/Mabbs/raw/main/README.md | ||||
| bundle2.7 exec jekyll build -d ../public_html | ||||
| tar czvf MayxBlog.tgz --exclude-vcs ../public_html/ | ||||
| mv MayxBlog.tgz ../public_html/ | ||||
| cd ../public_html/ | ||||
| unset GIT_DIR | ||||
| git init | ||||
| git branch -m main | ||||
| git add . | ||||
| git commit -m "update" | ||||
| git remote add codeberg ssh://git@codeberg.org/mayx/pages.git | ||||
| git remote add bitbucket ssh://git@bitbucket.org/unmayx/unmayx.bitbucket.io.git | ||||
| git push -f codeberg main | ||||
| git push -f bitbucket main | ||||
| /home/mayx/blog-env/node_modules/surge/bin/surge /home/mayx/public_html/ mayx.surge.sh | ||||
							
								
								
									
										36
									
								
								_tools/serv00_post-receive
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								_tools/serv00_post-receive
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| #!/bin/bash | ||||
| cd /home/Mayx/ | ||||
| rm -rf domains/mayx.serv00.net/public_html/ | ||||
| git --work-tree=/home/Mayx/blog --git-dir=/home/Mayx/repo/git/pub/mayx checkout -f | ||||
| cd blog | ||||
| mkdir Mabbs | ||||
| curl -L -o Mabbs/README.md https://github.com/Mabbs/Mabbs/raw/main/README.md | ||||
| bundle exec jekyll build -d ../domains/mayx.serv00.net/public_html/ | ||||
| tar czvf MayxBlog.tgz --exclude-vcs -C ../domains/mayx.serv00.net public_html/ | ||||
| mv MayxBlog.tgz ../domains/mayx.serv00.net/public_html/ | ||||
| rsync -avz --delete ../domains/mayx.serv00.net/public_html/ mayx@web.sourceforge.net:/home/project-web/mayx/htdocs/ | ||||
| cd ../domains/mayx.serv00.net/public_html/ | ||||
| unset GIT_DIR | ||||
| git init | ||||
| git lfs install | ||||
| git lfs track "*.png" | ||||
| git lfs track "*.moc" | ||||
| git lfs track "*.tgz" | ||||
| git lfs track "*.jpg" | ||||
| git lfs track "*.zip" | ||||
| git branch -m main | ||||
| echo "--- | ||||
| title: Mayx | ||||
| emoji: 🏢 | ||||
| colorFrom: green | ||||
| colorTo: blue | ||||
| sdk: static | ||||
| pinned: false | ||||
| short_description: Mayx's Home Page | ||||
| --- | ||||
|  | ||||
| ">README.md | ||||
| git add . | ||||
| git commit -m "update" | ||||
| git remote add hf git@hf.co:spaces/Mabbs/blog | ||||
| git push -f hf main | ||||
		Reference in New Issue
	
	Block a user
	 mayx
					mayx