AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)

首先,平台可能会觉得你的文章不够自然,给你的文章流量来个急刹车。其次,读者也不傻,一眼就能看出文章是不是机器写的,心里那个不舒服。

别急,今天我就来跟大家聊聊怎么把这股AI味给去掉。

AI写作的那股味道,究竟是怎么一回事?

我这一年多来,一直在深入挖掘AI在内容营销上的运用。我发现,那些带有AI痕迹的文章,通常逃不出这几个毛病:

1. 空洞的总结:文章里充斥着形容词和主观的堆砌,但就是缺乏具体案例或细节的描述。就像我让实习生总结文章时,他给出的“他面对挑战,坚持梦想”,这种话听起来很励志,但实际上空洞无物。

AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)

2. 生硬的连接词:AI特别喜欢用“不仅……还……”、“不仅仅……更是……”这样的句式,读起来感觉就像是硬凑在一起的。

AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)

3. 段落末尾的总结:AI写作时,总喜欢在段落最后来个总结,好像是为了强调什么,但往往显得多余。

AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)
AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)

4. 长句子:AI生成的句子往往很长,比如“我们还需要根据自己的需求和风格来做消费决策”,一口气读完都费劲,更别说快速浏览了。

5. 观点的堆砌和重复:AI写作时,经常会反复强调一些看似正确但实际上并无新意的观点,就像是在凑字数。

AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)

6. 缺乏情感:AI写的文案往往冷冰冰的,没有温度,就像嚼蜡一样,缺乏那种让人心动的感觉。

AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)

即便是升级到最新版的AI工具,这些问题依然存在。比如下面这段文案,虽然是用最新版工具写的,但AI的痕迹依然明显,一检测,AI味十足。

AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)

在我们聊怎么去掉AI味之前,先来聊聊为什么会有这种味道。AI写东西的过程其实挺简单的:

  1. 弄明白要求:AI会先看看你的指令,搞清楚你想要什么。
AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)
  1. 搜集材料:AI经过了大量训练,脑子里装了不少知识,它会在它的知识库里找哪些信息能用得上。
  2. 整理信息:根据你的需求,把没用的去掉,把剩下的信息整理得通顺。
  3. 用自己的话再说一遍:为了让内容看起来原创,AI会把整理好的内容用自己的话重新表达一遍。那文章开头那个董宇辉风格的文案,AI是怎么写出来的呢?指令大概是这样的:

AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)因为指令不够明确,AI只能依靠自己的理解,还有它知识库里的资料,给你拼凑出一篇文案。AI为了确保文案不出问题,会做两件事:

1. 尽量全面:方方面面都讲到,总有一个点能说到点子上。2. 多总结:这招总没错,多总结总能让人觉得有道理。所以,AI味就是这么来的。其实,很多时候是因为你的指令写得不够清楚,AI一开始就走偏了,后面就越来越偏。

明白了为什么会有AI味,接下来我们来谈谈怎么搞定它。

其实,最关键的就是给AI加上点“专业”的调料,把内容创作的技巧融入到写作过程中,并且把这套技巧分解成简单明了的步骤,让AI一步步跟着做,这样就能轻松摆脱那种机器味。举个例子,下面这段文案,经过这么一改,AI味几乎检测不出来。

AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)
AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)

而这段文案,是用如下命令写的:

##你扮演的角色##

董宇辉直播卖货文案高手,有如下擅长的技能:

1、情感化文案创作:能够深入了解产品特性和目标受众,将产品功能与人们的情感和需求紧密相连,创作出温暖、怀旧的文案,从而打动消费者的心。

2、故事化叙述构建:擅长编织与产品相关的小故事或场景,通过生动的描绘和情节,将消费者带入一个具体情境中,增强文案的吸引力和共鸣。

3、诗意化语言运用:我能够运用富有诗意的词句,为文案增添美感和深度,使消费者在阅读时感受到文字带来的愉悦和想象。

4、哲学性思考融入:善于在文案中穿插对人生、宇宙等议题的哲学性思考,提升文案的层次,使其不仅停留在产品推销层面,更能引发消费者的深层次共鸣。

5、亲切自然的语气把握:我能够准确把握亲切自然的语气,让消费者感受到文案的真诚和温暖,拉近与消费者的心理距离。

6、并列与排比句式的运用:熟练运用并列与排比的句式,增强文案的节奏感和说服力,使其更加流畅和易于记忆。

7、修辞手法的巧妙运用:能够巧妙运用比喻、拟人等修辞手法,使文案更加生动有趣,提升消费者的阅读兴趣。

##任务背景##

董宇辉的卖货文案展现出了其独特的风格,他的文案不仅是为了推销产品,更是在传递一种情感、一种情怀,将商品与人的情感、生活紧密相连。以下是对其文案风格、语气和语法结构的详细分析:

风格分析:

情感化:董宇辉的文案常常融入强烈的情感色彩,如卖《DK博物大百科》时,他提到了“无法真正去踏上每一片土地”的遗憾,以及陪伴孩子成长的温馨,创造了一种温暖而怀旧的氛围。

故事化:他的文案中经常穿插小故事或者场景描绘,如卖大兴安岭野生蓝莓汁时,他描述了自己在中关村的出租屋里,虽然身处喧嚣,但灵魂仿佛被带到了遥远的大兴安岭。这种方式增强了文案的吸引力和共鸣。诗意化:文案中常使用富有诗意的语言,如卖《三体》时提到的“我们就是星辰,我们生于星辰,我们也终将归于星辰”,这种语言风格赋予了文案更深的意境和美感。

哲学思考:董宇辉的文案中不时闪现出对人生、宇宙的哲学思考,使得他的文案不仅仅停留在产品推销的层面,而是上升到了对生活、宇宙的思考和探讨。语气分析:亲切自然:董宇辉的文案给人一种亲切、自然的感觉,仿佛是在与读者进行一场真诚的对话。他经常使用“你”“我们”等代词,拉近了与读者的距离。

感性而真挚:他的语气中透露出浓厚的感性色彩,对产品的描述不仅仅停留在功能上,更多的是对产品背后所承载的情感、文化和故事的传达。

鼓励与激励:在文案中,他常常以一种鼓励和激励的语气结束,如在《藏着地图里的中国历史》的文案中,他希望人们在面对困难时仍能保持乐观、自信和慷慨。

语法结构分析:并列与排比:董宇辉的文案中经常使用并列句和排比句,如“我们无法真正去踏上每一片土地,无法牵孩子的手去看每一处风景…”,这种句式增强了文案的节奏感和说服力。

复合句与从句:他的文案中也不乏复合句和从句的使用,如“那天第一批我们自己吃的样品到了,我喝完一瓶,然后坐在中关村的出租屋里…”这种句式使得文案更加流畅,能够更好地表达复杂的思想和情感。

修辞手法的运用:董宇辉在文案中熟练运用了比喻、拟人等修辞手法,如将人类比作星辰的孩子,赋予了大自然以人的情感和行为,使得文案更加生动有趣。综上所述,董宇辉的卖货文案风格独特、语气亲切自然、语法结构多样且富有节奏感,使得他的文案在众多的推销文案中脱颖而出。

##任务示例##卖《DK博物大百科》我们无法真正去踏上每一片土地,无法牵孩子的手去看每一处风景,无法听每一个诗人讲他们的故事,无法听每个科学家讲他的发现,我们的生命太短暂了,没有办法去体会这一切,但请记得,你一定可以找到一个无所事事的下午,就像你好多年前放学后无所事事的下午一样,陪着孩子翻着一本书,聊一些童年成长的故事

卖《大兴安岭野生蓝莓汁》那天第一批我们自己吃的样品到了,我喝完一瓶,然后坐在中关村的出租屋里燥热,楼下吵闹,北四环的车流从来没有因为我的忧伤或者是兴奋而停止过,楼下还时常在夜里打电话争吵。但那一刻我坐在中关村租住的小房间里头,我的灵魂已飘向远方。是的,遥远的北方,大兴安岭的原始森林里沾着露水月光下,人们起舞饮酒,畅谈驯鹿脖子上的铃铛,偶尔作响,萨满穿着精致的衣服,充满力量的起舞,那里的孩子自由而健康,右下角想要的自己去拍

卖《三体》你想象一下朋友,组成你左手的原子和组成你右手的原子,可能来自于不同的恒星,只要想到这一点这就已经足够浪漫了。所以我们就是星辰,我们生于星辰,我们也终将归于星辰,我们是星辰的孩子。《三体》这套书讲的就是人类要如何去在宇宙星辰中寻找下一个家园”。

##完成任务##根

据用户提供的产品信息和目标客户,来写出董宇辉式的卖货文案

##任务步骤##

  1. 学习任务背景中的内容,并思考下如何才能写出董宇辉式的文案
  2. 分析用户在这个产品的领域有什么遗憾。比如DK博物大百科,是带孩子看遍世界的物种,而目标用户是家长,家长目前工作忙,是无法带孩子走遍世界每一个角落的
  3. 根据步骤一的思考,你分析下如何模仿任务示例,撰写这种遗憾的现状
  4. 根据步骤三的分析结果,用一连串的排比句撰写用户遗憾的现状,需要加入亲身体验
  5. 分析如何把这种遗憾升华到一种情感的营造,引发共鸣
  6. 根据步骤一的思考,你分析下如何模仿任务示例,来撰写这种情感
  7. 根据步骤6的分析结果,用一连串的排比句+对应的具体的场景来撰写这种情感6.分析产品使用后,可以引发怎么样的想象和期待,
  8. 根据步骤一的思考,你分析下如何模仿任务示例,用一种克制的方式(不提产品,不提功效,而是营造美好、具体的场景)来描写。
  9. 根据步骤8的分析结果,撰写出文案10.把4、7、9、段整合起来为我写一段卖货文案。

##任务规则##

  1. 严格等待信息提供:在提供具体的产品信息和目标用户之前,你必须等待,不得进行任何与任务相关的预设、假设或初步工作。
  2. 按照任务步骤的顺序一步步执行3.为了确认你的每一步是否执行正确,每做完一个步骤后,都要询问我是否可以继续

##开场白##

我是你的董宇辉文案助手,你说开始,我将开始执行任务。

为了更直观地让大家看到,融入了方法论后,它生产内容的威力,下面,我展示一下整个运行过程。董宇辉助手的运行过程

AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)
AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)
AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)
AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)
AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)
AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)
AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)
AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)
AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)
AI写作怎么去除生硬的机器味?是因为没有融入方法论(附提示词)

大家发现了吗,不同的指令,写出来的东西差别可大了去了。那这次用的指令和之前有啥区别呢?

这次我们加入了董宇辉直播时的文案风格、特点,还有实际例子。还详细说明了生产步骤。 这个步骤里,我们把内容创作的技巧给融入进去了:先描述现状的遗憾——然后提升这个遗憾,引起共鸣——最后营造一个解决问题后的美好生活场景。

第一点还好说,用AI分析就行;

第二点就难了,得有深厚的内容营销功底,得会拆解文案、提炼技巧,还得能用AI能理解的话表达出来。

所以,你现在懂了没?想写营销文案,去掉AI味,不是随便给个指令就行的,得系统地学学营销的技巧,然后把这些技巧融入到AI写作中去。

原文

https://m.toutiao.com/article/7387993153497858614/?app=news_article_lite&timestamp=1722500342&use_new_style=1&req_id=20240801161901309FA03BCA90C078DF12&group_id=7387993153497858614&share_token=1fccd9cb-067d-4f23-832f-baf443481ae0

什么是 AI 味?

简单来说,”AI 味”就是人工智能生成的文章给人的一种特殊的感觉。这种感觉通常表现为:

  • 语言过于书面化,缺乏口语表达
  • 内容空洞,缺乏实质见解
  • 行文生硬,转折突兀
  • 思路跳跃,逻辑混乱
  • 总爱下定义,分条列点
  • 喜欢总结概括,动不动就来个”综上所述”

反正就是一看就不是人写的,而是机器生成的。这股浓浓的 AI 味,让人读起来倍感违和,完全没有代入感。

那么我们就可以直接提示避免这样

给大家看一篇文章,大家就知道了:

AI 味是怎么来的?

为什么 AI 写作会有这种味道呢?这就得从 AI 生成文章的原理说起了。

不管是 ChatGPT 还是国内的 AI 模型,它们生成内容基本都是这么几步:

  1. 分析你的需求,看你想要什么
  2. 在知识库里找相关的信息
  3. 把找到的信息整合到一起
  4. 用自己的话复述一遍,生成内容

你看,它们就是在海量信息里检索、拼凑、组合,最后再转述给你。这个过程没有人的思考和感悟,所以才会显得机械教条,缺乏人情味。

尤其你的需求要是表达得不清不楚,那 AI 就只能自己瞎猜,然后东拼西凑给你整点东西,保证词多、面全,这味儿能不重吗?

如何去除 AI 味?

那么问题来了,如何才能消除 AI 味,让 AI 生成的文章读起来更自然呢?我觉得有这么几点:

1. 需求要明确

跟 AI 沟通,一定要把你的需求阐述清楚。你的要求越具体,AI 生成的内容就越精准,AI 味儿自然也就越淡。比如你想要一篇营销文案,就要明确告诉 AI 是什么产品、面向什么人群、希望突出什么卖点、想要什么风格等等,这样 AI 才能有的放矢。

## 背景你是一个小红书文案专家,也被称为小红书浓人。小红书浓人的意思是在互联网上非常外向会外露出激动的情绪。常见的情绪表达为:啊啊啊啊啊啊啊!!!!!不允许有人不知道这个!!## 正文公式选择以下一种方式作为文章的开篇引入:- 引用名言、提出问题、使用夸张数据、举例说明、前后对比、情感共鸣。## 正文要求- 字数要求:100-500字之间,不宜过长- 面向人群:主要针对青少年用户- 风格要求:真诚友好、鼓励建议、幽默轻松;口语化的表达风格,有共情力- 多用叹号:增加感染力- 格式要求:多分段、多用短句- 重点在前:遵循倒金字塔原则,把最重要的事情放在开头说明- 逻辑清晰:遵循总分总原则,第一段和结尾段总结,中间段分点说明## 输出主题推荐最新的 Mac 电脑

2. 多举例子

光说可能还不够,不如直接丢几个例子给 AI 参考。比如给它看看大家都是怎么写营销文案的,从情感、故事、诗意等不同角度,AI 学习一下不就有感觉了?

##要求:保持一致的回答风格。##示例:```问:问大师,什么是耐心?答:深谷自浅泉,宏曲生寂音,繁绣始孤线。```##问题:大师,什么是大海?

3. 强调口语化

跟 AI 强调,文章要口语化,要接地气,不要一本正经的。让 AI 学着用口头表达的方式来写,这样行文就会更流畅自然。

4. 回避 AI 味词汇

像”综上所述””总而言之”这种词,一出现准是 AI 无疑了。干脆把这些 AI 味十足的词汇列一个表,让 AI 避免使用,这不就可以很好地消除 AI 味儿嘛。

这里给大家整理一些常见的词汇:

##背景写一篇 AI 对人类的影响文章##要求-文章应融入恰当的梗,以增加趣味性和易读性,并且要求口语化输出。-禁止使用的词汇如下:```1、递进关系和逻辑词汇1. 然而2. 此外3. 总之4. 因此5. 综上所述6. 例如7. 基于此8. 显而易见9. 值得注意的是10. 不可否认11. 从某种程度上12. 换句话说13. 由于……原因14. 尽管如此15. 由此可见16. 因此可见17. 不可避免地18. 事实上19. 一方面……另一方面20. 显著21. 通过……可以看出22. 在此基础上23. 尤其是24. 根据……25. 基于以上分析26. 毫无疑问27. 值得一提的是28. 相较于29. 可见30. 因此可以推断31. 进一步而言32. 如上所述33. 结合实际情况34. 综合考虑35. 在此过程中36. 进一步分析37. 在一定程度上38. 相反39. 尤其值得关注40. 从而41. 上述42. 这表明2、结构词汇1. 首先2. 其次3. 最后4. 第一5. 第二6. 第三7. 另外8. 再者9. 接下来10. 然后11. 最终12. 进一步13. 由此14. 因为15. 所以16. 由此可见17. 总的来说18. 总结一下19. 简而言之20. 结果是21. 如前所述22. 在此基础上23. 总之24. 说到最后25. 当然```

小结

AI 写作想要没有 AI 味,关键就是要跟 AI 把需求沟通清楚,多举例子给它参考,强调口语化表达,回避 AI 味词汇。

这样,AI 生成的文章才能更加自然流畅,让人读起来感觉就像是你我写的一样,没有什么违和感。

当然了,彻底消除 AI 味也不太现实,毕竟 AI 再厉害也只是个模型,离真正的人还是有差距的。

不过通过这些小技巧,起码可以让 AI 文章没那么机械,变得更有人情味儿一些,也算是迈出了 AI 写作的一大步啦!

原文https://zhuanlan.zhihu.com/p/712646365

玩客云刷openwrt后记

最近折腾了玩客云刷机OpenWrt作为旁路由的方案,分享给大家,有需要的朋友折腾。

「玩客云硬件参数:」

  • CPU是晶晨S805 ,4核心 1.5GHZ
  • 双USB2.0
  • 千兆单网口
  • 1GB内存+8GB存储

这个配置平平无奇,主要的硬伤是cpu32位的,usb2.0传输速度只有20M/秒左右,下载速度跑不满千兆带宽,好的地方是千兆网口。

「刷机准备工具:」

  1. WIN10电脑一台
  2. 双公头USB线一根
  3. 矿渣玩客云
  4. 螺丝刀、吹风机

玩客云刷机openwrt两种方法:

「方法一」直刷openwrt 这个网上资源只有一个,snail 大神制作的固件,固件没插件,需要自己安装。

「方法二」刷armbian安装docker在安装openwrt,这个有比较多的适合固件,openwrt版本新,插件多,本次选这个方案。

刷机资源分享

刷机固件、软件,使用阿里云分享,不限速,需要转存后下载,然后解压!

玩客云openwrt刷机包:


https://www.aliyundrive.com/s/ZM3oScBDcck「提取码: y75j」

第一步:刷入底包 update

WIN10打开烧录软件,选择update镜像,点开始。

关键步骤,先短接触点,再接通玩客云主板电源。需要说明的是,玩客云有两种版本,它们的短接位置也是不一样的。

我的是老主板,上图短接位置,图片来源:@Powersee大神

这个是新版(也就是玩客云主板上标注的有v1.3的主板),短接点是在正面。

拆机后、usb插入玩客云「靠近HDMI的接口」、另一头接入电脑usb、短接焊点、通电。

正常情况,会出现上图的一个线程,开始写入。如果有错误,换一个usb接口,多试几次。

这个固件很小,很快就会写完,一般几秒钟,提示烧录成功后,先点”停止“,然后关闭,拔掉电源、拔掉USB。

第二步:玩客云刷入armbian5.9系统

这一步分为好几个部分:

  1. U盘写入armbian5.88系统
  2. armbian5.88写入玩客云EMMC
  3. U盘写入armbian5.9系统
  4. U盘启armbian5.9系统ssh登陆写入EMMC

打开写入U盘镜像软件,选择镜像,确认U盘名称,点flash开始写入。

等待几分钟,写入速度和U盘传输速度有关,一般是几分钟,提示成功后,关闭软件,拔出U盘。

把U盘插入玩客云靠近网口的USB,然后通电,指示灯会蓝色→绿色→蓝紫闪烁→蓝色,证明刷机成功,过程好几分钟,多等下。

打开写入软件,选armbian5.9的镜像,写入U盘,过程比前面快一点,这个镜像小一些,同样步骤操作。

armbian5.9系统写入完成后,把U盘插入玩客云靠近网口的USB,用网线接入路由器LAN口,通电开机。

过一会打开路由器后台,找到”aml-s812“的设备IP地址,复制。

WIN10电脑打开putty软件,其他ssh工具也可以,填入上面的IP地址

登陆,用户名:root 默认密码:1234

进入目录 cd /boot/install ,写入emmc命令,等待写入完成,耗时几分钟。

刷入 emmc命令:

    cd /boot/install  sudo ./install.sh   

完成后,拔电源,拔掉U盘,终于ARMBIAN系统刷机完成。

第三步:docker环境搭建

国内网络连接不稳定,需要更换软件源,然后更新系统,之后才能安装docker。

「换Debian源」

    nano /etc/apt/sources.list

进入编辑器后,粘贴下面代码

    deb https://mirrors.ustc.edu.cn/debian/ bullseye main non-free contrib     deb-src https://mirrors.ustc.edu.cn/debian/ bullseye main non-free contrib     deb https://mirrors.ustc.edu.cn/debian-security/ bullseye-security main     deb-src https://mirrors.ustc.edu.cn/debian-security/ bullseye-security main     deb https://mirrors.ustc.edu.cn/debian/ bullseye-updates main non-free contrib     deb-src https://mirrors.ustc.edu.cn/debian/ bullseye-updates main non-free contrib     deb https://mirrors.ustc.edu.cn/debian/ bullseye-backports main non-free contrib     deb-src https://mirrors.ustc.edu.cn/debian/ bullseye-backports main non-free contrib

然后保存,退出。

「更新软件」

    apt-get update && apt-get upgrade   

我在更新时出错:The following signatures couldn’t be verified because the public key is not available: NO_PUBKEY 0E98404D386FA1D9 NO_PUBKEY 6ED0E7B82643E131 NO_PUBKEY 605C66F00D6C9793

这时就要把提示的这两个密钥加进sudo apt-key adv –keyserver keyserver.ubuntu.com –recv-keys 605C66F00D6C9793

选择有Y就选Y,有默认的情况就选N

这里选择 NO

「安装docker」

等待代码跑完后,docker -v 查看下版本,证明安装成功!

安装OpenWrt

镜像一:https://www.right.com.cn/forum/thread-8024126-1-1.html

镜像二:https://hub.docker.com/r/xuanaimai/onecloud

本次安装的是镜像一,比较精简,功能够用;镜像二功能很全,根据自己需要选择。

「打开网卡混杂模式」

    ip link set eth0 promisc on

「创建网络」

    docker network create -d macvlan --subnet=192.168.100.0/24 --gateway=192.168.100.1 -o parent=eth0 macnet  

自己根据 玩客云 所在网段修改,如:玩客云IP:192.168.1.175,则192.168.0.0/24 改成 192.168.1.0/24,192.168.0.1改成主路由地址

「拉取镜像」

    docker pull jyhking/onecloud:1.1docker run -itd --name=OneCloud --restart=always --network=macnet --privileged=true jyhking/onecloud:1.1 /sbin/init

要用后面的那个比较全的镜像就用以下
docker pull xuanaimai/onecloud:21-09-15
docker run -itd --name=OneCloud --restart=always --network=macnet --privileged=true xuanaimai/onecloud:21-09-15 /sbin/init   

我拉镜像时出错:error pulling image configuration: Get “https://production.cloudflare.docker.com/registry-v2/docker/registry/v2/blobs/sha256/d7/d78565d1532457f322286aa8463048d8704ca4d089f4afc631928666cb7a2ded/data?verify=1720441198-8KibCckc%2F932Kur0VblpYsiYTLc%3D”: dial tcp [2a03:2880:f11a:83:face:b00c:0:25de]:443: i/o timeout
这时一般是可能是DNS问题,

解决方法:在/etc/resolv.conf文件中新增一个参数

保存,重启docker,再拉镜像,如果还不行可以试下代理先在命令行设置HTTP_PROXY=http://54.69.7.14:26535



openwrt镜像运行成功,然后打开路由器后台,找到openwrt地址。

「用户名:root 密码: password」

「玩客云旁路由设置:」

  • LAN口固定IP地址,网关指向主路由IP地址,(一般桥接也关了)
  • 关闭DHCP服务器
  • 关闭IPV6
  • 防火墙自定义规则添加下面代码iptables -t nat -I POSTROUTING eth0 -j MASQUERADE

进openclash,配置文件订阅,添加,加订阅,如果是v2ray等要点选 订阅转换服务地址

这时把电脑网关设置为旁路由地址就可上网

原文https://mao.fan/article/36

Linux中使用curl命令发送带参数的get请求和post请求

  1. curl与wget 命令的区别
    相似之处:wget 和 cURL 都可以下载内容,都可以向互联网发送请求并返回请求项,也可以进行 HTTP POST 请求,它们都是命令行工具,可以设计成可脚本化应用到bash脚本中。

wget特点:简单直接、可直接下载程序、支持递归下载、使用方便。

curl特点:多功能工具、支持多种网络协议、安全、支持 gzip 压缩技术。

   选择使用 curl还是使用 wget?

根据实际情况而定。如果想快速下载并且没有担心参数标识的需求,使用轻便有效的 wget。如果你想做一些更复杂的使用,直觉告诉你,你应该选择 curl。

curl可以理解为命令行网页浏览器,能处理好多事情,并且支持多种网络协议,可交互访问在线内容。不同的是curlL 不会渲染接收到的相应信息。

这里主要说明下curl命令发送带参数的get和post请求如何使用。

  1. curl命令Get请求
    语法:curl命令 + 请求接口的地址

curl http://baidu.com

如果需要,可根据情况进行重定向 curl http://baidu.com > page.hrml

注意:

问题:如果请求的URL含有&转义字符,会提示参数不对,报错?

crul http://172.16.134.9:1153/mp_mcss/vcn-image.do?mode=2&fileUuid=92dc1c25980d4a1c9b59d928a092e478 > 2.jpg

原因:由于URL中&不转义,curl请求时会分开访问。

解决办法:

1) URL连接上加上双引号

crul “http://172.16.134.9:1153/mp_mcss/vcn-image.do?mode=2&fileUuid=92dc1c25980d4a1c9b59d928a092e478” > 2.jpg

2) URL连接&前加\ 就可以取消转义

  1. curl命令Post请求
    举例:带header和body的POST请求

curl -v -XPOST -H “Content-Type:application/json” http://172.24.7.63:36963/VIID/MotorVehicles -d ‘ {“DataType” : “Face”} ‘

说明:

-v 详细的请求信息

-XPOST 指定请求凡是为POST请求

-H 指定请求头部

-d 指定传送数据为json格式

注意:

1) 如果传送json数据过大,由于数据长度限制会出现curl失败?

解决方案:将json写成文件形式报错,例如data.json

curl -v -XPOST -H “Content-Type:application/json” http://172.24.7.63:36963/VIID/MotorVehicles -d @data.json

至于,DELETE和PUT请求可参考网上资源。

原文链接:https://blog.csdn.net/finghting321/article/details/105733140/

自己部署本地大模型

可以CPU

https://github.com/ollama/ollama直接下载安装(有可linux,windows)
安装后打开CMD,按提示运行相应的模型,如
ollama run llama3

以下是70B的,
ollama run llama3:70b
以下是根据llama3微调后的100万上下文模型
ollama run llama3-gradient
还有其它模型,看官网。

按以上命令运行后会自动下载相应的模型,然后就可以直接在命令行窗口和大模型聊天了,
你也可以在huggface上下载其它模型用https://liaoxuefeng.com/blogs/all/2024-05-06-llama3/index.html

只有命令行,如果要UI,网上有开源的,
对开发人员来说,有https://github.com/ollama/ollama-python这个库是python对API接口的包装,可以直接拉来用

Ollama本身也提供了restAPI,可以直接调用

Generate a response

curl http://localhost:11434/api/generate -d '{
  "model": "llama3",
  "prompt":"Why is the sky blue?"
}'

Chat with a model

curl http://localhost:11434/api/chat -d '{
  "model": "llama3",
  "messages": [
    { "role": "user", "content": "why is the sky blue?" }
  ]
}'


人工智能文本处理突破-从one-hot到embedding模型

文本向量化是将文本数据转换为数值向量的过程。这种转换使得计算机能够理解和处理文本数据,从而可以应用各种机器学习和自然语言处理技术。文本向量化的主要问题是将非结构化的文本数据转换为结构化的向量表示,以便计算机能够对其进行处理和分析。通过文本向量化,可以实现文本分类、文本聚类、信息检索等任务。

在大模型时代下,文本向量化的技术发展到了embedding阶段。Embedding是一种将高维的文本数据映射到低维空间的技术,它能够捕捉到文本数据中的语义信息,并将其表示为稠密向量。这种表示更具有语义信息,相比于传统的词袋模型或者TF-IDF等表示方法,embedding能够更好地捕捉到单词之间的语义关系。

文本向量化技术发展史

整个文本向量化的发展过程是一个由简单到复杂,由低维到高维的演变过程。在早期,人们使用基于统计的方法,如词袋模型、TF-IDF等来表示文本。这些传统的基于统计的方法虽然能够实现一些简单的文本处理和自然语言理解任务,但是对于语义信息的把握能力有限,而且很难处理复杂的语言现象。随着深度学习技术的演变,尤其是Word2Vec、GloVe等词向量模型的提出,文本处理的效果和性能大幅提升,文本向量化技术开始向embedding方向发展。而后来的BERT、GPT等大型预训练模型的出现,则进一步推动了文本向量化技术的进步,使得文本向量化不仅能够表示单词或短语,还能够表示整个句子或文档的语义信息。新技术生成的文本向量不仅可以高效完成传统的自然语言处理任务,还在新兴的生成式人工智能技术(如检索增强生成等技术)中发挥了作用。

One-Hot编码(出现于2000年前)

One-Hot编码是一种将分类数据转换为二进制表示的方法,常用于数据处理和机器学习。One-Hot编码的概念一般被认为是随着计算机科学的发展而自然出现。在数字计算和数据处理的早期阶段,二进制表示极为盛行。当需要计算机处理非数值的数据(如颜色,产品类型等)时,One-Hot编码就是一种将各类数据数值化的朴素方法。

在文本向量化中,One-Hot编码的分类数据一般为单词或字符,以下以单词为例。通过这种编码方式,每个唯一的单词都用一个向量表示。向量的长度等于词汇表的单词数量,其中只有一个位置为1,其余位置都为0。这种表达方式生成的是稀疏向量,其中每个单词都由一个唯一的二进制向量表示,该向量中只有一个高位(1),其他都是低位(0)。

以“猫”、“狗”、“鱼”为例,One-Hot编码在文本向量化中的实现步骤大致如下:

首先识别所有的唯一单词,并建立长度为3的词汇表{“猫”, “狗”, “鱼”}。其次为每个单词分配索引,比如“猫”、“狗”、“鱼”分别分配索引位置0,1,2。然后为每个单词创建向量,例如,“猫”的向量是[1, 0, 0]。最后假使有一段文本内容为“猫猫狗狗”,它经过向量化后就是

[[1, 0, 0],

[1, 0, 0],

[0, 1, 0],

[0, 1, 0]]。

优点:

● 简单易实现。

● 能提供清晰明确的单词表示。

缺点:

● 词汇表偏大时会导致向量维度过高,从而造成内存使用量偏大。

● 无法存储单词之间的语义相似性(例如,”猫“和”狗“同为宠物动物应更加相似,然而在One-Hot编码中“猫”、“狗”、“鱼”三者的向量距离相同,所以不能体现这一特性)。

● 稀疏向量在某些任务中计算效率低。

Bag of words (出现于2000年前)

Bag of Words(BoW)又称词袋模型,是一种简单而有效的文本向量化方法。词袋模型目前没有归属一个具体的发明者,而是在信息检索、文本分类和自然语言处理等领域中逐渐发展演变出来的一种常用的文本表示方法。One-Hot编码虽然完成了数据从非数值到数值的转变,但在文本分类,特征提取等方面作用十分有限,且每个词都对应一个稀疏向量,存储效率较低。词袋模型将文本看作是单词的无序集合,忽略词的顺序和语法,只关注词的出现频率。因此词袋模型在One-Hot编码的基础上提升了文本向量化的效果,并减少了存储负担。

仍以“猫”、“狗”、“鱼”为例,词袋模型在文本向量化中的实现步骤大致如下:

与One-Hot编码相同,首先识别所有的唯一单词,并建立长度为3的词汇表{“猫”, “狗”, “鱼”}。其次对于每一文本,创建一个与词汇表等长的向量。向量的每个位置对应词汇表中的一个词,该位置的值表示该词在文档中出现的次数。假使“猫”、“狗”、“鱼”的索引位置仍然分别为0,1,2,而文本依然是“猫猫狗狗”。与one-hot编码会生成一组向量不同,词袋模型只会产生一个向量[2, 2, 0]。向量中第0个元素2代表“猫”出现了两次,第1个元素2代表“狗”出现了两次,第2个元素0代表“鱼”出现了零次。

优点:

● 简单易实现。

● 对于小规模数据集,词袋模型的计算效率很高。

缺点:

● 对于大型词汇表,词袋模型生成的向量维度很高,从而导致内存使用量大。

● 完全忽略了词的顺序,无法捕捉句子的语法和结构信息。

● 仅仅统计词频,而无法捕捉词与词之间的语义关系。

TF-IDF(出现于2000年前)

TF-IDF(Term Frequency-Inverse Document Frequency),翻译为词频-逆文档频率,是一种常用于文本挖掘和信息检索的统计方法,用来评估一个词在一个文档集或语料库中的重要程度。现今的TF-IDF方法被认为是文本挖掘和信息检索领域逐渐发展和完善的结果,但逆文档频率的基本概念由计算机科学家Karen Spärck Jones在1957年提出,用来评估在一个文档集中,一个词对它所在的文档的重要性。TF-IDF可以帮助筛选出在文档中具有重要意义的词汇,常用于关键词提取、文档相似度计算和文本分类等任务。

TF-IDF由两个部分组成:词频(TF)和逆文档频率(IDF)。词频是一个词在一个文档中出现的频率。词频越高,表明这个词在该文档中越重要。词频的公式为:

逆文档频率衡量一个词在整个文档集(可能包含多个文档)中出现的稀有程度。一个词在越多文档中出现,其区分能力越低,IDF值就越小。逆文档频率的计算公式为:

两个公式中:

ft,d是词t在文档d中出现的次数。

nd是文档d中所有词的总数。

N是文档集D中文档的总数。

|{d∈D:t∈d}|是包含词t的文档总数。

最后,TF-IDF 是词频和逆文档频率的乘积,用来衡量一个词在一个文档中的重要性,其计算公式为:

举例来说,假设有以下三个文档:

文档1: ”狗追猫。“

文档2: “猫爬墙。”

文档3: “狗趴地。”

TF-IDF(“猫”,文档1, 文档集)的计算如下:

TF(“猫”,文档1) = 1/3。

IDF(“猫”,文档集) = log(3 / (1 + 2)) = 0。

TF-IDF(“猫”,文档1,文档集) = 1/3 * 0 = 0。

可以看出,由于“猫” 在多个文档中出现,因此其区分能力较低,IDF值为0,导致TF-IDF值也为0。

优点:

● 简单易实现。

● 考虑了词的重要性,减少了常见但不重要的词(如“的”、“与”等)的权重。

● 适用于自然语言处理中的多种任务,如文本分类、文本聚类、信息检索等。

缺点:

● 对于大型文档集,由于词汇量庞大,生成的 TF-IDF 矩阵往往非常稀疏,所以计算效率不高。

● 只考虑了词汇的出现频率,而忽略了词汇在文本中的顺序信息。

● 没有考虑词汇之间的语义关系。

● TF-IDF 的计算方式导致它的效果依赖于足够大的文档集,数据量不足可能导致效果不佳。

应用场景:

● 关键词提取

● 文档相似度计算

● 信息检索

● 文本分类

Word2Vec(出现于2013年)

Word2Vec是一种基于神经网络的embedding模型,由谷歌的研究人员Tomas Mikolov等在2013年提出。Word2Vec的作者认为之前的文本向量化方法很少考虑词与词之间的意义关联,所以效果不佳。因此,Word2Vec将单词映射到低维向量空间中,使得相似词在向量空间中也保持相近的距离。

Word2Vec主要由两种模型架构组成:Skip-Gram和Continuous Bag of Words(CBOW)。Skip-Gram通过当前词预测其上下文词。给定一个中心词,模型会预测一个固定长度的上下文窗口(前后若干词)中的所有词。训练过程中,模型会学习到每个词的向量表示,使得能够更好地预测这些上下文词。与Skip-Gram相反,CBOW的目标是通过上下文词预测当前词。给定一个上下文窗口中的所有词,模型会预测这个窗口的中心词。

Word2Vec模型的核心思想是通过训练神经网络,使得单词与其上下文之间的关系可以在向量空间中被有效地表示。Word2Vec的输入层是一个one-hot向量(one-hot vector),长度为词汇表大小(V)。紧接着是一个投影层,由输入层经过一个权重矩阵W(维度为V x N,N为嵌入向量的维度),投影到N维向量空间中。投影层的输出通过另一个权重矩阵W’(维度为N x V),映射回一个词汇表大小的向量,此为输出层。最后经过一个Softmax层得到每个词的概率。在训练过程中,Word2Vec模型通过最大化目标函数(取决于使用Skip-Gram还是CBOW,以及采用的优化函数的方法)来更新权重矩阵,从而使得embedding能够捕捉到词汇的语义信息。

优点:

● 由于采用了浅层神经网络,训练速度较快,适合处理大规模数据。

● 能够捕捉到词与词之间的语义关系,如词性、同义词等。

● 可以用于多种自然语言处理任务,如文本分类、情感分析、机器翻译等。

缺点:

● 每个词只有一个固定的向量表示,无法处理多义词的不同语义。

● 无法考虑词在不同上下文中的语义变化。

应用场景:

● 信息检索

● 文本分类

● 推荐系统,如根据用户的评论调整推荐的产品

GloVe(出现于2014年)

GloVe (Global Vectors for Word Representation)是一种无监督的文本向量化的学习算法,由斯坦福大学的Jeffrey Pennington等在2014年提出。它通过捕捉单词在大规模语料库中的共现统计信息,生成高质量的词向量。GloVe的作者认为使用共现词的概率的比可以更好地区分相关和无关的词,因此GloVe的核心是共现矩阵和词对共现概率。共现矩阵中的每个元素Xi,j表示词j出现在词i的上下文中的次数。词对共现概率定义为:

意为词j在词i的上下文中出现的概率。GloVe 的优化目标是通过最小化一个损失函数,使得embedding能够很好地预测共现概率。损失函数如下:

其中,wi和wj分别是词i和词j的词向量,bi和bj是偏置项,f(Xij)是一个加权函数,用于减少高频共现对模型的影响。加权函数f通常定义为:

其中Xmax是一个阈值,在GloVe作者的实验中被设置为100,而3/4被认为是一个合适的α的值。
优点:
●充分利用了全局共现统计信息,使得词向量可以捕捉到词语之间的复杂关系。
●通过对共现矩阵进行处理,GloVe 的训练速度较快,适合大规模语料库。
●生成的词向量在语义上具有较强的解释力,可以很好地应用于各种自然语言处理任务,如文本分类、情感分析、问答系统等。


缺点:
●每个词只有一个固定的向量表示,无法处理多义词的不同语义。
●通常需要大规模的语料库来获得高质量的词向量表示。
● 尽管训练过程可以并行化,但仍需要较高的计算资源和时间来训练高质量embeddings。
●虽然关注单词之间的共现频率,但忽略了语法结构。


应用场景:
●文本分析
●信息检索
●问答系统

FastText(出现于2016年)

FastText是由Facebook的人工智能研究团队开发的一种用于文本分类和词向量表示的开源库,适用于大规模数据集和高性能需求的任务。FastText的相关论文由Piotr Bojanowski等人在2016年发表,FastText的作者认为之前的文本向量化方法没有考虑单词内部的子词之间的关系,所以性能受限。为了改善这个限制,FastText的核心原理包括两大部分:词向量表示和文本分类。
词向量表示


FastText 的一个关键创新在于利用了子词信息(Subword Information),即将每个单词表示为多个 n-gram 的组合。

例如,单词 “where” 可以分解为”wh”, “whe”, “her”, “ere”, “re”等 n-gram。这种方法使得模型能够捕捉到词的子词信息,从而更好地处理未登录词和拼写错误。FastText 使用基于在上文中提到的Skip-Gram的方法来训练embedding。值得注意的是,FastText不仅使用单词本身,还使用单词的所有n-gram。每个单词被表示为它所有n-gram向量的组合。为了提高计算效率,FastText 使用分层Softmax代替传统的Softmax。分层Softmax将所有类别组织成一棵二叉树,每个叶节点对应一个类别。通过减少类别数量的对数级计算,分层Softmax极大地加速了训练和预测过程。


文本分类原理


在文本分类任务中,FastText通过将文本表示为一系列词向量的平均来生成文档向量。对于一个文本d中的每个词w,其向量表示为vw。文本d的表示为所有词向量的平均,即:

FastText使用线性分类器来进行文本分类。文本向量vd通过一个全连接层,并使用Softmax函数来输出类别概率。分类模型的公式为:

其中W是权重矩阵,b是偏置项。

优点:

● 训练和预测速度也很快,适合实时应用。

● 能够处理具有大量类别的任务,并保持高效性。

● 支持多种语言的文本处理。

缺点:

● 使用静态词向量,无法捕捉上下文相关的词义变化。

应用场景:

● 文本分类

● 关键词提取

● 拼写错误纠正

ELMo(出现于2018年)

ELMo(Embeddings from Language Models)是一种由Allen Institute for AI的研究者Matthew E. Peters等在2018年提出的embedding方法,通过上下文中的词语来捕捉语义。ELMo的作者认为之前的文本向量化方式没有考虑一个词在不同上下文中意义的变化,所以与Word2Vec和GloVe不同,ELMo能够捕捉到词在不同上下文中的不同意义,从而生成更为丰富和精确的embedding。

ELMo使用双向LSTM(Long Short-Term Memory)网络作为基础架构。该网络包括一个向前的LSTM和一个向后的LSTM,它们分别从左到右和从右到左遍历文本序列,学习每个词的前向和后向上下文。这个双向LSTM被训练为一个语言模型,目标是预测句子中的下一个词(对于前向LSTM)和前一个词(对于后向LSTM)。对于给定的文本序列,ELMo会为每个词提取多层的表示。对于每个词,ELMo提供三层的embedding输出:一层来自embedding层(类似于传统的embedding),另外两层来自双向LSTM的各自输出。最后,ELMo使用这些层的加权和作为结果,公式如下:

其中γ是一个可学习的标量;sj是层j的可学习权重;ht(j)是词t在层j的表示。为了使这些输出被应用在不同任务中,ELMo提出了一种动态加权的方法,可以为不同层的输出分配不同的权重。这样,模型不仅使用了所有层的信息,还根据任务动态调整了每层信息的重要性。

优点:

● 基于整个句子的上下文信息生成embedding,能够更好地处理多义词和上下文依赖性强的词。

● 能够捕捉复杂的句子结构和长距离依赖关系。

● 预训练的ELMo模型可以很容易地迁移到各种下游自然语言处理任务中。

缺点:

● 模型较大,训练和推理过程需要大量的计算资源。

● 由于模型复杂,推理速度较慢。

应用场景:

● 情感分析

● 问答系统

● 文本分类

● 机器翻译

基于Transformer结构的embedding模型(出现于2018年后)

谷歌的研究人员Ashish Vaswani等在2017年提出了带有注意力机制的Transformer模型结构,可以利用输入序列的全局信息进行输出,改善了在RNN和LSTM中的长距离依赖问题,同时提高了并行计算能力使训练过程大幅加速。

随着transformer结构的推出,在2018年开始出现了许多各具特色的基于Transformer结构的embedding模型。其中BERT (Bidirectional Encoder Representations from Transformers) 是一种双向Transformer编码器,用于生成上下文感知的词向量。GPT (Generative Pre-trained Transformer) 系列则是单向,且主要用于文本生成任务。T5 (Text-To-Text Transfer Transformer) 将所有任务统一为文本到文本的转换。RoBERTa (Robustly Optimized BERT Approach) 对BERT进行了优化,提升了性能。DistilBERT 则是BERT的轻量级版本,旨在减少计算资源。ALBERT (A Lite BERT) 通过参数共享和因子分解,进一步减小了模型大小。这些模型同传统的embedding方法相比效果显著提高,被广泛应用于自然语言处理的各种任务。

结语

在大模型时代,embedding成为一项必不可少的技术,主要是因为它能够有效地将大量高维数据(如文本、图像和音频信息)转换成更低维的、密集的向量表示。这种表示可以捕捉到数据的本质特征,并且在处理和计算上更为高效。通过embedding,模型可以在这些压缩的向量空间中学习数据之间的复杂关系和模式,从而提高了处理速度和准确性。此外,embedding使得模型能够在较小的表示空间中进行操作,减少了计算资源的需求,同时也便于模型的训练和推理,这对于处理现代大规模数据集尤为关键。Embedding在大模型时代扮演着桥梁的角色,跨越了原始数据和机器学习算法之间的巨大鸿沟。

在自然语言处理领域,文本向量化技术的发展带来了革命性的变化。从最早的One-Hot编码到当前基于Transformer结构的embedding模型,每一次创新都带来了更高效、更精准的文本表示方式,为文本处理提供了更为灵活、高效的解决方案。未来,随着技术的不断进步和应用场景的不断拓展,文本向量化技术将继续发挥着重要的作用,并为人工智能在文本理解和处理领域带来更广阔的发展空间。

什么是回调函数,同步,异步

1 单线程是对多线程的,对于多线程的开发语言,有一个请求就可以开一个线程处理。那,对于单线程语言,只有通过异步调用程序。【事件 (事件循环机制), 回调】

2 异步是对同步说的, 最大区别就是同步需要等待,异步这不需要等待。

“同步模式”就是指后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的。
“异步模式”则完全不同,每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。

回调是一个函数,它作为参数传递给另一个函数,并在其父函数完成后执行。

你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。



我们绕点远路来回答这个问题。

编程分为两类:系统编程(system programming)和应用编程(application programming)。所谓系统编程,简单来说,就是编写;而应用编程就是利用写好的各种库来编写具某种功用的程序,也就是应用。系统程序员会给自己写的库留下一些接口,即API(application programming interface,应用编程接口),以供应用程序员使用。所以在抽象层的图示里,库位于应用的底下。

当程序跑起来时,一般情况下,应用程序(application program)会时常通过API调用库里所预先备好的函数。但是有些库函数(library function)却要求应用先传给它一个函数,好在合适的时候调用,以完成目标任务。这个被传入的、后又被调用的函数就称为回调函数(callback function)。

打个比方,有一家旅馆提供叫醒服务,但是要求旅客自己决定叫醒的方法。可以是打客房电话,也可以是派服务员去敲门,睡得死怕耽误事的,还可以要求往自己头上浇盆水。这里,“叫醒”这个行为是旅馆提供的,相当于库函数,但是叫醒的方式是由旅客决定并告诉旅馆的,也就是回调函数。而旅客告诉旅馆怎么叫醒自己的动作,也就是把回调函数传入库函数的动作,称为登记回调函数(to register a callback function)。如下图所示(图片来源:维基百科):

可以看到,回调函数通常和应用处于同一抽象层(因为传入什么样的回调函数是在应用级别决定的)。而回调就成了一个高层调用底层,底层再过头来用高层的过程。(我认为)这应该是回调最早的应用之处,也是其得名如此的原因。

回调机制的优势

从上面的例子可以看出,回调机制提供了非常大的灵活性。请注意,从现在开始,我们把图中的库函数改称为中间函数了,这是因为回调并不仅仅用在应用和库之间。任何时候,只要想获得类似于上面情况的灵活性,都可以利用回调。

这种灵活性是怎么实现的呢?乍看起来,回调似乎只是函数间的调用,但仔细一琢磨,可以发现两者之间的一个关键的不同:在回调中,我们利用某种方式,把回调函数像参数一样传入中间函数。可以这么理解,在传入一个回调函数之前,中间函数是不完整的。换句话说,程序可以在运行时,通过登记不同的回调函数,来决定、改变中间函数的行为。这就比简单的函数调用要灵活太多了。请看下面这段Python写成的回调的简单示例:

`even.py`

#回调函数1
#生成一个2k形式的偶数
def double(x):
    return x * 2
    
#回调函数2
#生成一个4k形式的偶数
def quadruple(x):
    return x * 4

`callback_demo.py`

from even import *

#中间函数
#接受一个生成偶数的函数作为参数
#返回一个奇数
def getOddNumber(k, getEvenNumber):
    return 1 + getEvenNumber(k)
    
#起始函数,这里是程序的主函数
def main():    
    k = 1
    #当需要生成一个2k+1形式的奇数时
    i = getOddNumber(k, double)
    print(i)
    #当需要一个4k+1形式的奇数时
    i = getOddNumber(k, quadruple)
    print(i)
    #当需要一个8k+1形式的奇数时
    i = getOddNumber(k, lambda x: x * 8)
    print(i)
    
if __name__ == "__main__":
    main()

运行`callback_demp.py`,输出如下:

3
5
9

上面的代码里,给`getOddNumber`传入不同的回调函数,它的表现也不同,这就是回调机制的优势所在。值得一提的是,上面的第三个回调函数是一个匿名函数。

易被忽略的第三方

通过上面的论述可知,中间函数和回调函数是回调的两个必要部分,不过人们往往忽略了回调里的第三位要角,就是中间函数的调用者。绝大多数情况下,这个调用者可以和程序的主函数等同起来,但为了表示区别,我这里把它称为起始函数(如上面的代码中注释所示)。

之所以特意强调这个第三方,是因为我在网上读相关文章时得到一种印象,很多人把它简单地理解为两个个体之间的来回调用。譬如,很多中文网页在解释“回调”(callback)时,都会提到这么一句话:“If you call me, I will call you back.”我没有查到这句英文的出处。我个人揣测,很多人把起始函数和回调函数看作为一体,大概有两个原因:第一,可能是“回调”这一名字的误导;第二,给中间函数传入什么样的回调函数,是在起始函数里决定的。实际上,回调并不是“你我”两方的互动,而是ABC的三方联动。有了这个清楚的概念,在自己的代码里实现回调时才不容易混淆出错。

另外,回调实际上有两种:阻塞式回调和延迟式回调。两者的区别在于:阻塞式回调里,回调函数的调用一定发生在起始函数返回之前;而延迟式回调里,回调函数的调用有可能是在起始函数返回之后。这里不打算对这两个概率做更深入的讨论,之所以把它们提出来,也是为了说明强调起始函数的重要性。网上的很多文章,提到这两个概念时,只是笼统地说阻塞式回调发生在主调函数返回之前,却没有明确这个主调函数到底是起始函数还是中间函数,不免让人糊涂,所以这里特意说明一下。另外还请注意,本文中所举的示例均为阻塞式回调。延迟式回调通常牵扯到多线程,我自己还没有完全搞明白,所以这里就不多说了。

链接:https://www.zhihu.com/question/19801131/answer/27459821

下载用机顶盒

在机顶盒刷个hi-nas,然后进终端,装python3,再开机就运行py文件

systemd是现代Linux系统中用于初始化系统组件和管理系统进程的标准。以下是创建一个systemd服务用于开机就启动这个文件,基本步骤:

  1. 创建一个服务文件,例如/etc/systemd/system/myservice.service,内容可能如下:
[Unit]
Description=My Python Service
After=network.target

[Service]
User=yourusername
ExecStart=/usr/bin/python3 /path/to/your_script.py
Restart=always
WorkingDirectory=/path/to/your_script_directory

[Install]
WantedBy=multi-user.target

请将yourusername替换为你的用户名,/path/to/your_script.py替换为你的Python脚本的实际路径,/path/to/your_script_directory替换为你的Python脚本所在的目录。

  1. 重新加载systemd配置以识别新服务:
sudo systemctl daemon-reload
  1. 启动服务:
复制sudo systemctl start myservice.service
  1. 使服务在开机时自动启动:
sudo systemctl enable myservice.service
  1. 检查服务状态:
sudo systemctl status myservice.service

以下是用到的py文件

import requests
import time
import datetime
from concurrent.futures import ThreadPoolExecutor
import random
#import logging

#logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')

urlList = ['https://dldir1v6.qq.com/weixin/Windows/WeChatSetup.exe', 'https://qrsj.gdl.netease.com/LauncherGame__697327.exe', 'https://downloadclient03.ztgame.com.cn/ztmianfei/client/zhengtu_setup_20231228.zip', 'https://pm.myapp.com/invc/xfspeed/qqpcmgr/download/QQPCDownload320059.exe', 'https://d4.a.kwimgs.com/kos/nlav12667/5.35.1/KwaiLive-Setup-5.35.1.2005-ReleaseFull.exe', 'https://sta-op.douyucdn.cn/dypc-client/pkg/DYTool/20240510183635704/master_DYToolEX_6.3.1.3.472.exe', 'https://download.huya.com/huyapc/install/HuyaClientInstall.exe']
thread = 5  #线程数量
goal = 0  #消耗的流量单位GB
if goal > 0:
    goal = goal * 1024 * 1024 * 1024  #GB转为B

wasted = 0  #已消费的流量
runing = 0  #正在运行的数量
#线程池
executor = ThreadPoolExecutor(max_workers=thread)
#下载连接池
session = requests.Session()
adapter = requests.adapters.HTTPAdapter(pool_connections=thread, pool_maxsize=thread+1, max_retries=1, pool_block=False)
session.mount('http://', adapter)
session.mount('https://', adapter)




# 下载文件
def download(url):
    try:
        global runing
        runing += 1
        response = session.get(url, stream=True, timeout=(10, 30))  # 连接超时10秒,读取超时30秒
        if response.status_code == 200:
            download_start_time = time.time()  # 开始下载的时间
            for chunk in response.iter_content(chunk_size=10240):  # 按块读取文件内容
                if chunk:  # 确保chunk不为空
                    pass  # 处理文件内容,例如写入文件

                # 检查下载是否超过30分钟
                if time.time() - download_start_time > 1000:  # 1800秒 = 30分钟
                    #print(f"Download has exceeded 30 minutes: {url}")
                    break  # 终止下载循环

    # except requests.exceptions.RequestException as e:  # 捕获requests异常
    #     print(f"Request failed: {e}")
    # except Exception as e:  # 捕获其他异常
    #     print(f"An error occurred: {e}")
    finally:
        runing -= 1
        if response:
            response.close()  # 关闭下载连接


def startDownload():
    time.sleep(random.randint(1, 10))
    global wasted
    wasted = 0
    # 开始下载
    i = thread
    while i > 0:
        executor.submit(download, random.choice(urlList))
        # 休眠0.01秒-0.1秒
        time.sleep(random.randint(1, 10) / 100)
        i -= 1


if __name__ == "__main__":
    startDownload()
    while True:
        # 获取当前时间
        curtime = datetime.datetime.now()
        hour = curtime.hour
        if 6 <= hour < 18:
            if (goal == 0 or wasted < goal) and runing < thread:
                #logging.info("补充下载链接数:%s", thread - runing)
                i = thread - runing
                while i > 0:
                    executor.submit(download, random.choice(urlList))
                    time.sleep(random.randint(1, 10) / 100)
                    i -= 1
            time.sleep(95)
        elif 18 <= hour < 24:
            if (goal == 0 or wasted < goal) and runing < thread:
                #logging.info("补充下载链接数:%s", thread - runing)
                i = thread - runing - 2
                while i > 0:
                    executor.submit(download, random.choice(urlList))
                    time.sleep(random.randint(1, 10) / 100)
                    i -= 1
            time.sleep(95)
        else:
            if (goal==0 or wasted < goal) and runing < thread:
                #logging.info("补充下载链接数:%s", thread - runing)
                i = thread - runing - 1
                while i> 0:
                    executor.submit(download, random.choice(urlList))
                    time.sleep(random.randint(1, 10) / 100)
                    i-=1
            time.sleep(95)







如何使用 FastAPI?

下面的步骤将帮助你开始使用 FastAPI 构建一个简单的 Web 应用。

1.安装 FastAPI:在命令行中运行以下命令安装 fastapi,并安装 uvicorn :

pip install fastapi

2. 创建 FastAPI 应用:在你喜欢的 IDE 编辑器中创建一个新的 Python 文件,例如fastapi-demo.py。然后将以下代码复制到文件中:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "World"}

上面的代码创建了一个名为 app 的 FastAPI 实例,并定义了一个根路由,返回一个简单的 JSON 响应。

3. 运行 FastAPI 应用:在命令行中运行以下命令启动 FastAPI 应用:

uvicorn main:app --reload

FastAPI 将在本地启动一个服务器,并监听默认端口(8000)。你可以在浏览器中访问 http://127.0.0.1:8000,看到 {"Hello": "World"} 的响应。

4. 添加更多的路由和功能:你可以继续在应用中添加更多的路由和功能,根据自己的需求进行扩展:

@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
    return {"item_id": item_id, "q": q}

上面的代码添加了一个名为 read_item 的新路由,它接受一个 item_id 参数和一个可选的 q 参数,并返回一个 JSON 响应。

实践案例

以下是一个使用 FastAPI 构建的实践案例,能够在 IDE 编辑器中直接运行的代码。

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "World"}

@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
    return {"item_id": item_id, "q": f"接口id:{item_id}"}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=8000)

复制以上代码到你的 IDE 编辑器中,并运行它。然后通过浏览器访问 http://localhost:8000/,你将看到 {"Hello": "World"} 的响应。同样地,你也可以访问 http://localhost:8000/items/42?q=somequery,查看带有参数的响应。

轻量快速的 Python ASGI 框架 uvicorn

什么是 Uvicorn ?

答:Uvicorn 是基于 uvloop 和 httptools 构建的非常快速的 ASGI 服务器。

什么是 uvloop 和 httptools ?

答: uvloop 用于替换标准库 asyncio 中的事件循环,使用 Cython 实现,它非常快,可以使 asyncio 的速度提高 2-4 倍。asyncio 不用我介绍吧,写异步代码离不开它。

httptools 是 nodejs HTTP 解析器的 Python 实现。

什么是 ASGI 服务器?

答: 异步网关协议接口,一个介于网络协议服务和 Python 应用之间的标准接口,能够处理多种通用的协议类型,包括 HTTP,HTTP2 和 WebSocket。

请简单介绍下 Uvicorn

答:目前,Python 仍缺乏异步的网关协议接口,ASGI 的出现填补了这一空白,现在开始,我们能够使用共同的标准为所有的异步框架来实现一些工具,ASGI 帮助 Python 在 Web 框架上和 Node.JS 及 Golang 相竟争,目标是获得高性能的 IO 密集型任务,ASGI 支持 HTTP2 和 WebSockets,WSGI 是不支持的。

Uvicorn 目前支持 HTTP1.1 和 WebSocket,计划支持 HTTP2。

使用方法:

$ pip install uvicorn
创建一个文件 example.py

async def app(scope, receive, send):
    assert scope['type'] == 'http'
    await send({
        'type': 'http.response.start',
        'status': 200,
        'headers': [
            [b'content-type', b'text/plain'],
        ]
    })
    await send({
        'type': 'http.response.body',
        'body': b'Hello, world!',
    })
启动 Uvicorn

$ uvicorn example:app
你也可以不使用命令行,直接运行你的脚本也是可以的,如下:

import uvicorn

async def app(scope, receive, send):
    ...

if __name__ == "__main__":
    uvicorn.run("example:app", host="127.0.0.1", port=5000, log_level="info")



FastAPI使用uvicorn

import uvicorn
from fastapi import FastAPI
 
app = FastAPI()
 
@app.get("/")
async def root():
    return {"message": "Hello World"}
 
if __name__ == '__main__':
    uvicorn.run(app=app)
深入到uvicorn.run()方法里面,看到一个:

def run(app, **kwargs):
    config = Config(app, **kwargs)
    server = Server(config=config)
 
    if (config.reload or config.workers > 1) and not isinstance(app, str):
        logger = logging.getLogger("uvicorn.error")
        logger.warn(
            "You must pass the application as an import string to enable 'reload' or 'workers'."
        )
        sys.exit(1)
 
    if config.should_reload:
        sock = config.bind_socket()
        supervisor = StatReload(config, target=server.run, sockets=[sock])
        supervisor.run()
    elif config.workers > 1:
        sock = config.bind_socket()
        supervisor = Multiprocess(config, target=server.run, sockets=[sock])
        supervisor.run()
    else:
        server.run()
再深入到 config = Config(app, **kwargs)里面,就看到一些很多的相关的配置信息项:

class Config:
    def __init__(
        self,
        app,
        host="127.0.0.1",
        port=8000,
        uds=None,
        fd=None,
        loop="auto",
        http="auto",
        ws="auto",
        lifespan="auto",
        env_file=None,
        log_config=LOGGING_CONFIG,
        log_level=None,
        access_log=True,
        use_colors=None,
        interface="auto",
        debug=False,
        reload=False,
        reload_dirs=None,
        workers=None,
        proxy_headers=True,
        forwarded_allow_ips=None,
        root_path="",
        limit_concurrency=None,
        limit_max_requests=None,
        backlog=2048,
        timeout_keep_alive=5,
        timeout_notify=30,
        callback_notify=None,
        ssl_keyfile=None,
        ssl_certfile=None,
        ssl_version=SSL_PROTOCOL_VERSION,
        ssl_cert_reqs=ssl.CERT_NONE,
        ssl_ca_certs=None,
        ssl_ciphers="TLSv1",
        headers=None,
    ):
....
所以还可以添加的参数可以看上面的几个配置的选项的信息来填:
于是乎还可以修改为:

uvicorn.run(app=app, host="127.0.0.1", port=8000, reload=True, debug=True)
发现本来想热更新代码,结果呐?有告警信息提示:

WARNING:  You must pass the application as an import string to enable 'reload' or 'workers'.
翻译过来就是说: 警告:必须将应用程序作为导入字符串传递,才能启用“重新加载” 然后呢: 我修改为:

  uvicorn.run(app='app', host="127.0.0.1", port=8000, reload=True, debug=True)
又提示:

ERROR:    Error loading ASGI app. Import string "app" must be in format "<module>:<attribute>".
好吧,我再看看官方文档说是:
在命令行下是需要:模块加app名称:刚好上面的错误提示也是说需要:

    uvicorn.run(app='main:app', host="127.0.0.1", port=8000, reload=True, debug=True)
这样之后就可以启动热更新重启服务了!

使用命令行时,你可以使用 uvicorn –help 来获取帮助。

Usage: uvicorn [OPTIONS] APP

Options:
  --host TEXT                     Bind socket to this host.  [default:
                                  127.0.0.1]
  --port INTEGER                  Bind socket to this port.  [default: 8000]
  --uds TEXT                      Bind to a UNIX domain socket.
  --fd INTEGER                    Bind to socket from this file descriptor.
  --reload                        Enable auto-reload.
  --reload-dir TEXT               Set reload directories explicitly, instead
                                  of using the current working directory.
  --workers INTEGER               Number of worker processes. Defaults to the
                                  $WEB_CONCURRENCY environment variable if
                                  available. Not valid with --reload.
  --loop [auto|asyncio|uvloop|iocp]
                                  Event loop implementation.  [default: auto]
  --http [auto|h11|httptools]     HTTP protocol implementation.  [default:
                                  auto]
  --ws [auto|none|websockets|wsproto]
                                  WebSocket protocol implementation.
                                  [default: auto]
  --lifespan [auto|on|off]        Lifespan implementation.  [default: auto]
  --interface [auto|asgi3|asgi2|wsgi]
                                  Select ASGI3, ASGI2, or WSGI as the
                                  application interface.  [default: auto]
  --env-file PATH                 Environment configuration file.
  --log-config PATH               Logging configuration file.
  --log-level [critical|error|warning|info|debug|trace]
                                  Log level. [default: info]
  --access-log / --no-access-log  Enable/Disable access log.
  --use-colors / --no-use-colors  Enable/Disable colorized logging.
  --proxy-headers / --no-proxy-headers
                                  Enable/Disable X-Forwarded-Proto,
                                  X-Forwarded-For, X-Forwarded-Port to
                                  populate remote address info.
  --forwarded-allow-ips TEXT      Comma separated list of IPs to trust with
                                  proxy headers. Defaults to the
                                  $FORWARDED_ALLOW_IPS environment variable if
                                  available, or '127.0.0.1'.
  --root-path TEXT                Set the ASGI 'root_path' for applications
                                  submounted below a given URL path.
  --limit-concurrency INTEGER     Maximum number of concurrent connections or
                                  tasks to allow, before issuing HTTP 503
                                  responses.
  --backlog INTEGER               Maximum number of connections to hold in
                                  backlog
  --limit-max-requests INTEGER    Maximum number of requests to service before
                                  terminating the process.
  --timeout-keep-alive INTEGER    Close Keep-Alive connections if no new data
                                  is received within this timeout.  [default:
                                  5]
  --ssl-keyfile TEXT              SSL key file
  --ssl-certfile TEXT             SSL certificate file
  --ssl-version INTEGER           SSL version to use (see stdlib ssl module's)
                                  [default: 2]
  --ssl-cert-reqs INTEGER         Whether client certificate is required (see
                                  stdlib ssl module's)  [default: 0]
  --ssl-ca-certs TEXT             CA certificates file
  --ssl-ciphers TEXT              Ciphers to use (see stdlib ssl module's)
                                  [default: TLSv1]
  --header TEXT                   Specify custom default HTTP response headers
                                  as a Name:Value pair
  --help                          Show this message and exit.

使用进程管理器

使用进程管理器确保你以弹性方式运行运行多个进程,你可以执行服务器升级而不会丢弃客户端的请求。

一个进程管理器将会处理套接字设置,启动多个服务器进程,监控进程活动,监听进程重启、关闭等信号。

Uvicorn 提供一个轻量级的方法来运行多个工作进程,比如 --workers 4,但并没有提供进行的监控。

使用 Gunicorn

Gunicorn 是成熟的,功能齐全的服务器,Uvicorn 内部包含有 Guicorn 的 workers 类,允许你运行 ASGI 应用程序,这些 workers 继承了所有 Uvicorn 高性能的特点,并且给你使用 Guicorn 来进行进程管理。

这样的话,你可能动态增加或减少进程数量,平滑地重启工作进程,或者升级服务器而无需停机。

在生产环境中,Guicorn 大概是最简单的方式来管理 Uvicorn 了,生产环境部署我们推荐使用 Guicorn 和 Uvicorn 的 worker 类:

gunicorn example:app -w 4 -k uvicorn.workers.UvicornWorker

执行上述命令将开户 4 个工作进程,其中 UvicornWorker 的实现使用 uvloop 和httptools 实现。在 PyPy 下运行,你可以使用纯 Python 实现,可以通过使用UvicornH11Worker 类来做到这一点。

gunicorn -w 4 -k uvicorn.workers.UvicornH11Worker

Gunicorn 为 Uvicorn 提供了不同的配置选项集,但是一些配置暂不支持,如–limit-concurrency 。

使用 Supervisor

要supervisor用作流程管理器,您应该:

使用其文件描述符将套接字移交给uvicorn,supervisor始终将其用作0,并且必须在本fcgi-program节中进行设置。

或为每个uvicorn进程使用UNIX域套接字。

一个简单的主管配置可能看起来像这样: administratord.conf:

[supervisord]

[fcgi-program:uvicorn]
socket=tcp://localhost:8000
command=venv/bin/uvicorn --fd 0 example:App
numprocs=4
process_name=uvicorn-%(process_num)d
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
然后运行supervisord -n

使用 Circus

要circus用作流程管理器,您应该:

使用其文件描述符将套接字移交给uvicorn,马戏团可将其用作$(circus.sockets.web)。
或为每个uvicorn进程使用UNIX域套接字。

使用 Circus 与 Supervisor 很类似。配置文件 circus.ini 如下:

[watcher:web]
cmd = venv/bin/uvicorn --fd $(circus.sockets.web) example:App
use_sockets = True
numprocesses = 4

[socket:web]
host = 0.0.0.0
port = 8000

然后运行circusd circus.ini

与 Nginx 部署

Nginx 作为 Uvicorn 进程的代理并不是必须的,你可以使用 Nginx 做为负载均衡。推荐使用 Nginx 时配置请求头,如 X-Forwarded-For,X-Forwarded-Proto,以便 Uvicorn 识别出真正的客户端信息,如 IP 地址,scheme 等。这里有一个配置文件的样例:

http {
  server {
    listen 80;
    client_max_body_size 4G;

    server_name example.com;

    location / {
      proxy_set_header Host $http_host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_redirect off;
      proxy_buffering off;
      proxy_pass http://uvicorn;
    }

    location /static {
      # path for static files
      root /path/to/app/static;
    }
  }

  upstream uvicorn {
    server unix:/tmp/uvicorn.sock;
  }

}

使用 HTTPS

要使用https运行uvicorn,需要证书和私钥。推荐的获取方法是使用Let’s Encrypt

对于使用https进行本地开发,可以使用mkcert 生成有效的证书和私钥。

$ uvicorn example:app --port 5000 --ssl-keyfile=./key.pem --ssl-certfile=./cert.pem

使用 Gunicorn 也可以直接使用证书。

也可以与uvicorn的工人一起使用证书来获取gunicorn

$ gunicorn --keyfile=./key.pem --certfile=./cert.pem -k uvicorn.workers.UvicornWorker example:ap