当前位置: 首页 > news >正文

零成本 AI 文案工具|Streamlit 三模式叙事生成完整源码分享

一、前言
平时我们想用AI写点小故事、随笔、文案,要么需要联网、要么要充会员、要么担心内容上传泄露隐私。
很多小伙伴电脑配置一般,跑不动大型AI项目,想找一个简单、干净、低配也能跑、断网也能用的AI文本生成工具,真的很难。
今天给大家分享我写的这款 Python + Streamlit AI叙事生成工具,主打一个:免费、本地、干净、无脑运行。
一共三种使用模式:
1.完全离线(没网也能跑,不用任何AI模型)
2. Ollama 本地大模型(纯本地推理,不上传数据)
3. 云端 API 接口(追求高质量生成)
不管你是学生练手、做课程设计、平时写文案、写小故事,这个项目都够用,界面好看、功能齐全、代码无报错。
二、项目能干啥?(真实实用功能)
不搞虚的,直接说能用的功能:

  • 四种写作风格:都市日常、古风、悬疑、治愈温情,日常写文案完全够用
  • 一键随机生成三套素材:人物、场景、剧情冲突自动搭配,不用自己苦想
  • 自定义角色和世界观:想写校园、科幻、末世都可以自己改
  • 可调剧情长短、起伏程度:想写短文、长文、平淡日常、跌宕剧情随便拖滑块
  • 支持续写:上次写一半,这次可以接着往下写
  • 历史记录保存复用:喜欢的写作风格可以一键重来
  • 一键导出TXT/MD:写完直接保存,方便复制到公众号、文档、作业
  • 双主题界面:深色炫酷、浅色干净,看你喜好切换
    三、环境搭建(超简单)
  1. 安装依赖
    新建 requirements.txt,写入下面两行:
    streamlit==1.35.0
    requests
    终端输入安装命令:
    pip install -r requirements.txt
  2. 运行项目
    把代码保存为 main.py,直接运行:
    streamlit run main.py
    自动弹出网页界面,不用前端、不用配置,开箱即用。
    四、完整可运行源码(已修复全部BUG)
    全网最稳版本,修复了 Ollama 接口报错、URL 解析异常等常见问题,直接复制即可运行。
    源码:

-- coding: utf-8 --

接地气 AI 故事生成工具|离线 + 本地大模型 + 云端三模式

低配电脑可跑、断网可用,适合练手/课程设计/文案创作

import streamlit as st
import random
import time
import requests
import datetime

页面全局配置

st.set_page_config(
page_title=“AI故事生成工具”,
page_icon=“🧠”,
layout=“wide”,
initial_sidebar_state=“expanded”
)

#初始化缓存(保存历史、自定义角色))
if “feature_cache” not in st.session_state:
st.session_state.feature_cache = {}
if “history_list” not in st.session_state:
st.session_state.history_list = []
if “custom_char_lib” not in st.session_state:
st.session_state.custom_char_lib = []
if “last_content” not in st.session_state:
st.session_state.last_content = “”

界面主题切换

def set_theme(mode):
if mode == “dark”:
css = “”"

“”"
st.markdown(css, unsafe_allow_html=True)

侧边栏主题

theme_opt = st.sidebar.radio(界面主题题", [“深色科技模式”, 浅色简约模式式"])
set_theme(“dark” if theme_opt == “深色科技模式” else “light”)
st.sidebar.divider()

三种推理模式切换

run_mode = st.sidebar.radio(“运行模式”, [
“纯离线使用(无需网络)”,
“Ollama本地大模型(不上网)”,
“云端API生成(高质量)”
])

api_key = “”
api_url = “”
ollama_host = “http://127.0.0.1:11434/api/generate”
ollama_model = “qwen:7b”

if run_mode == “云端API生成(高质量)”:
api_key = st.sidebar.text_input(“API Key”, type=“password”)
api_url = st.sidebar.text_input(“接口地址”)
elif run_mode == “Ollama本地大模型(不上网)”:
ollama_host = st.sidebar.text_input(“Ollama地址”, value=ollama_host)
ollama_model = st.sidebar.text_input(“模型名称”, value=ollama_model)

历史记录复用

st.sidebar.divider()
st.sidebar.markdown(### 📜 历史记录记录"if st.session_state.history_list:t for idx, item in enumerate(st.session_state.history_list[-5:])😃 if st.sidebar.button(f"复用记录 {idx+1}“, key=f"his_{idx}”)😃 st.session_state.feature_cache = item[“feat”]"]
else:
st.sidebar.caption(“暂无记录”)

四大写作素材库

style_material = {
“都市日常”: {
“char”: [“内敛沉稳的老手艺人”,“不甘平庸的打工人”,“外冷内热的小店店主”,“不善言辞的程序员”],
“scene”: [“深夜便利店”,“高层阳台”,“老街书店”,“夜市小摊”],
“conflict”: [“老店即将拆迁”,“捡到匿名旧信”,“反复偶遇陌生人”,“旧信物勾起往事”]
},
“古风叙事”: {
“char”: [“隐世郎中”,“落魄书生”,“镖局走卒”,“茶馆掌柜”],
“scene”: [“烟雨古巷”,“山间茶寮”,“渡口木船”,“破败书院”],
“conflict”: [“遗失祖传玉佩”,“故人十年之约”,“江湖旧仇浮现”,“一纸离别书信”]
},
“悬疑故事”: {
“char”: [“档案管理员”,“私家寻访人”,“旧物收藏家”,“夜班守馆人”],
“scene”: [“废弃码头”,“照相馆暗房”,“尘封储藏室”,“雾中小镇”],
“conflict”: [“长辈隐藏秘密”,“无主遗物线索”,“诡异重复梦境”,“一模一样的信物”]
},
“治愈温情”: {
“char”: [“旅行摄影师”,“图书馆管理员”,“返乡青年”,“糕点师傅”],
“scene”: [“山间村落”,“绿皮火车”,“雪天酒馆”,“午后花店”],
“conflict”: [“迟来多年留言”,“一场大雨邂逅”,“丢失的童年物件”,“萍水相逢的善意”]
}
emotion_list = [“温暖治愈、结局美好”,“留白开放式、引人遐想”,“现实写实、略带遗憾”,“平淡日常、温柔治愈”]"]

离线文字微调微def weight_adjust(text)😃:
modifiers = [“细微的”, “悄然的”, “静默的”, “温柔的”, “深沉的”, “淡淡的”]"]
return random.choice(modifiers) + textxt

离线生成核心(不用任何模型、断网也能用)

def offline_generate(char, scene, conflict, emotion, world, length, drama, gen_type):
scene = weight_fluctuate(scene)
conflict = weight_fluctuate(conflict)
len_tip = “长篇详细描写” if length > 0.7 else “简短精炼内容”
drama_tip = “剧情起伏大、冲突明显” if drama > 0.6 else “日常平缓叙事”

base_head = f"""【离线生成结果】

世界观:{world}
人物:{char}
场景:{scene}
核心剧情:{conflict}
整体风格:{emotion}
篇幅:{len_tip}
剧情强度:{drama_tip}

“”"
if gen_type == “短篇文艺随笔”:
body = f"““在{scene}平平淡淡的日子里,{char}早已习惯了一成不变的生原本安稳平静的日常,被{conflict}悄然打破。破。没有轰轰烈烈的剧情,只有普通人藏在心底的细碎情绪,整体风格{emotion}。””"
elif gen_type == “完整故事大纲”:
body = f"““1.铺垫:描绘{scene}的日常氛围,交代主角的生活状态;
2.转折:{conflict}突然出现,打破平静生活;
3.发展:主角顺着线索慢慢探索,发现背后的故事;
4.结尾:以{emotion}的风格收束全文,故事完整闭环。””"
else:
body = f"暮色慢慢铺满{scene},{char}本以为又是普通平淡的一天,直到{conflict}悄然出现。过往的回忆悄然翻涌,平凡的日常多了一丝波澜,整篇故事质感{emotion}。}。“”"

full_text = base_head + body if length > 0.6: full_text += "\n\n生活大多是平淡的,那些细碎的相遇、遗憾与温柔,拼凑成了普通人最真实的人生。" return full_text

Ollama本地大模型调用

def ollama_infer(char, scene, conflict, emotion, world, gen_type, model, host):
prompt = f"写一段{gen_type},世界观:{world},主角:{char},场景:{scene},剧情冲突:{conflict},整体风格:{emotion文笔自然流畅,直接输出正文。文。"
payload = {“model”: model, “prompt”: prompt, “stream”: False}
try:
res = requests.post(host, json=payload, timeout=30)
return res.json()[“response”] if res.status_code == 200 else “Ollama请求出错”
except Exception as e:
return f"本地模型连接失败,请确认Ollama已启动:{str(e)}"

云端API调用

def cloud_api_infer(char, scene, conflict, emotion, world, gen_type, key, url):
prompt = f"生成一段{gen_type},世界观{world},人物{char},场景{scene},剧情冲突{conflict},风格{emotion输出高质量正文。文。"
headers = {“Authorization”: f"Bearer {key}“, “Content-Type”: “application/json”}
data = {“model”: “general”,“messages”: [{“role”:“user”,“content”: prompt}],“temperature”:0.7}
try:
resp = requests.post(url, headers=headers, json=data, timeout=25)
return resp.json().get(“output”,{}).get(“text”,“接口返回数据异常”)
except Exception as e:
return 接口请求失败:败:{str(e)}”

页面主体

st.title(“🧠 免费AI故事生成器|离线可用+本地大模型”)
mode_tip = {
“纯离线使用(无需网络)”: 零网络、零模型,低配电脑随便跑随便跑",
“Ollama本地大模型(不上网)”: “✅ 本地AI推理,数据绝不外泄”,
“云端API生成(高质量)”: “✅ 全网高质量文案生成”
}
st.subheader(mode_tip[run_mode])
st.divider()

参数设置区域

col_a, col_b = st.columns([1,1])
with col_a:
st.markdown(“### 🔧 创作参数设置”)
style_sel = st.selectbox(“写作风格”, list(style_material.keys()))
custom_char = st.text_inp自定义主角(留空则自动随机)动随机)“)
custom_world = st.text_inp自定义世界观(留空则默认为日常)认日常)”)
gen_type = st.selectbox(“生成类型”, [“短篇文艺随笔”, “完整故事大纲”, “小说开篇正文”])
text_len = st.slid文章篇幅(比例)文章篇幅", 0.1, 0.9, 0.4, 0.1)
drama_level = st.slid剧情起伏程度(比例)起伏程度", 0.1, 0.9, 0.3, 0.1)

with col_b:
st.markdown(“### 📊 一键生成剧情素材”)
refresh_3 = st.button(“🎲 随机生成3套剧情方案”, use_container_width=True)
add_custom_char = st.text_input(“添加自定义人物素材”)
if add_custom_char and st.button(“保存人物”):
st.session_state.custom_char_lib.append(add_custom_char)
st.suc保存成功,下次可直接使用!可以直接用!")
st.divider()

mat_pool = style_material[style_sel] if refresh_3 or not st.session_state.feature_cache: group_list = [] for _ in range(3): ch = random.choice(mat_pool["char"] + st.session_state.custom_char_lib) if st.session_state.custom_char_lib else random.choice(mat_pool["char"]) group_list.append({ "char": ch, "scene": random.choice(mat_pool["scene"]), "conflict": random.choice(mat_pool["conflict"]), "emotion": random.choice(emotion_list) }) st.session_state.feature_cache = group_list for idx, g in enumerate(st.session_state.feature_cache): st.markdown(f"**方案{idx+1}**") st.write(f"人物:{g['char']}|场景:{g['scene']}") st.write(f"剧情:{g['conflict']}|风格:{g['emotion']}") if st.button(f"选用方案{idx+1}", key=f"use_{idx}"): st.session_state.active_feat = g

st.divider()
continue_write = st.checkbox(“开启上下文续写(接着上次内容写)”)
run_btn = st.button(“🚀 一键生成AI文案”, type=“primary”, use_container_width=True)

output_text = “”
if run_btn:
if “active_feat” not in st.session_state:
st.warning(“请先点击选用一套剧情方案!”)
else:
feat = st.session_state.active_feat
bar = st.progress(0)
for pct in range(0, 101, 10):
bar.progress(pct)
time.sleep(0.12)
bar.empty()

final_char = custom_char.strip() if custom_char.strip() else feat["char"] final_world = custom_world.strip() if custom_world.strip() else "普通现实生活世界观" prefix = f"接续上文创作:{st.session_state.last_content}\n" if (continue_write and st.session_state.last_content) else "" if run_mode == "纯离线使用(无需网络)": res_raw = offline_generate(final_char, feat["scene"], feat["conflict"], feat["emotion"], final_world, text_len, drama_level, gen_type) elif run_mode == "Ollama本地大模型(不上网)": res_raw = ollama_infer(final_char, feat["scene"], feat["conflict"], feat["emotion"], final_world, gen_type, ollama_model, ollama_host) else: res_raw = cloud_api_infer(final_char, feat["scene"], feat["conflict"], feat["emotion"], final_world, gen_type, api_key, api_url) output_text = prefix + res_raw st.session_state.last_content = output_text st.session_state.history_list.append({"feat": feat, "content": output_text})

结果展示与导出

st.divider()
st.markdown(“### 📄 生成结果”)
st.text_area(“文案内容”, output_text, height=420)
st.caption(f"当前总字数:{len(output_text)}")

if output_text:
ts = datetime.datetime.now().strftime(“%Y%m%d_%H%M%S”)
c1, c2 = st.columns(2)
with c1:
st.download_button(“📥 导出 TXT 文件”, output_text, f"AI文案_{ts}.txt")
with c2:
st.download_button(“📥 导出 MD 文件”, f"# AI故事生成结果\n{output_text}“, f"AI文案_{ts}.md”)

st.divider()
st.caption("纯学习开源## 五、项目总结(人话总结)项这个项目最大的优点就是不折腾、不氪金、不联网也能用。氪不用部署复杂大模型、不用调参、不用花钱开会员,低配电脑、学生机都能流畅运行。、平时写随笔、写小故事、凑文案、做课程设计、练习 Python Web 开发,都完全够用。 代码干净无冗余、已知 BUG 已修复,直接复制运行即可,非常适合新手入门练手。常适合新手入门练手。

http://www.jsqmd.com/news/1102072/

相关文章:

  • DALL-E 3 进阶工作流全图谱:Stable Diffusion协同链、Photoshop智能图层嵌入、Figma可编辑SVG导出(附12个已验证Prompt+PSD源文件包)
  • 【Gartner认证级评估】:ChatGPT企业版 vs Microsoft Copilot for Business vs Anthropic Enterprise——总拥有成本(TCO)深度比对
  • STM32与74HC32实现高效矩阵键盘控制方案
  • 邀您加入「天工计划·鸿蒙智能体开发者激励」,共创AI生态新未来
  • MPC5643L评估板硬件设计解析:电源、时钟与启动配置实战
  • Claude layer-zero:长上下文指令零遗忘的动态语义锚定技术
  • ASD433A评估板硬件配置与PowerPC MCU开发实战指南
  • TPA3128D2与PIC18LF45K40打造高性价比D类音频放大器
  • MPC5643L/SPC56EL评估板硬件设计解析与配置实战
  • Gofile批量下载神器:告别手动复制,5分钟掌握高效下载技巧
  • 抖音批量下载器终极指南:3分钟学会高效下载无水印视频和音乐
  • 终极指南:Wand-Enhancer开源工具深度解锁WeMod完整功能
  • Ubuntu 18.04 + Docker Compose 搭建 Laravel 开发环境实战
  • PowerPC评估板硬件设计解析:从电源管理到调试接口实战
  • 【独家信源】OpenAI新成立“AI治理特别委员会”:5条即将落地的合规红线,9月30日前必须完成自查
  • IPXWrapper终极指南:3步让Windows 10/11经典游戏重获联机能力
  • Ajax与XSS组合攻击:原理、实战与立体化防御策略
  • 【DALL-E 3 提示词炼金术】:基于17万条真实用户请求数据训练的语义解析模型,精准定位“模糊描述→像素级输出”的转化断点
  • PHP变量覆盖漏洞实战解析:从extract到可变变量的安全攻防
  • Oracle vs MySQL:互联网时代数据库选型的核心逻辑与实战指南
  • 经营异常移出后,企业还要核对哪些公开信息字段?
  • OpenAI企业版与Azure AI/Anthropic企业合同对比矩阵(含NDA条款逐条拆解):2024年采购决策不可跳过的7个法律锚点
  • 还在为字幕制作烦恼?Subtitle Edit 免费开源字幕编辑神器帮你轻松搞定
  • 如何永久保存微信聊天记录:WeChatMsg终极隐私保护指南
  • Python网站离线下载终极指南:一键完整保存任何网站
  • 5分钟掌握Windows任务栏透明化:TranslucentTB终极使用指南
  • 网盘直链下载助手LinkSwift:九大平台技术解析与深度配置指南
  • 汽车级MCU评估板硬件设计解析:从电源树到调试接口的实战指南
  • ASD433A评估板:PowerPC车规MCU硬件设计与调试实战指南
  • 如何快速掌握微信聊天记录管理:WeChatMsg完整使用指南