9.24 ai部署成功 ai随机生成人设以及ai对话

majiayan_branch
psnci6hgk 4 months ago
parent 71866729b1
commit f1bbb28b28

@ -86,7 +86,7 @@ onMounted(scrollToBottom)
onUpdated(scrollToBottom)
watch(messages, scrollToBottom, { deep: true })
const handleSend = () => {
const handleSend = async () => {
if (!canSend.value) return
const userMsg = {
senderId: props.selfId,
@ -102,7 +102,6 @@ const handleSend = () => {
// AI
const API_KEY = import.meta.env.VITE_ZHIPU_API_KEY
// idAI/AI
const aiMsg = {
senderId: props.activeContact?.id || 'ai',
text: 'AI思考中...',
@ -111,12 +110,21 @@ const handleSend = () => {
nextMessages = [...messages.value, aiMsg]
messages.value = nextMessages
emit('update:modelValue', nextMessages)
if (!API_KEY) {
aiMsg.text = 'API_KEY未配置请检查.env文件和重启项目'
messages.value = [...messages.value.slice(0, -1), aiMsg]
emit('update:modelValue', messages.value)
return
}
try {
axios.post(
const res = await axios.post(
'https://open.bigmodel.cn/api/paas/v4/chat/completions',
{
model: 'glm-4.5-air',
messages: [{ role: 'user', content: userText }]
model: 'glm-4-flash',
messages: [{ role: 'user', content: userText }],
thinking: { type: 'enabled' },
max_tokens: 1024,
temperature: 0.6
},
{
headers: {
@ -124,22 +132,26 @@ const handleSend = () => {
'Content-Type': 'application/json'
}
}
).then(res => {
const reply = res.data.choices?.[0]?.message?.content || 'AI无回复'
aiMsg.text = reply
aiMsg.timestamp = Date.now()
// AI
messages.value = [...messages.value.slice(0, -1), aiMsg]
emit('update:modelValue', messages.value)
}).catch(() => {
aiMsg.text = 'AI接口调用失败'
messages.value = [...messages.value.slice(0, -1), aiMsg]
emit('update:modelValue', messages.value)
})
} catch {
aiMsg.text = 'AI接口调用失败'
)
const reply = res.data.choices?.[0]?.message?.content || 'AI无回复'
aiMsg.text = reply
aiMsg.timestamp = Date.now()
messages.value = [...messages.value.slice(0, -1), aiMsg]
emit('update:modelValue', messages.value)
} catch (err) {
let errMsg = 'AI接口调用失败'
if (err?.response?.data?.msg) {
errMsg += `: ${err.response.data.msg}`
} else if (err?.response?.data?.message) {
errMsg += `: ${err.response.data.message}`
} else if (err?.message) {
errMsg += `: ${err.message}`
}
aiMsg.text = errMsg
messages.value = [...messages.value.slice(0, -1), aiMsg]
emit('update:modelValue', messages.value)
// console
// console.error('AI', err)
}
}
</script>

@ -7,53 +7,122 @@
</div>
<el-form :model="ocForm" label-width="120px" class="creation-form">
<el-form-item label="OC名称" required>
<!-- 1. 基础信息 -->
<el-divider>基础信息</el-divider>
<el-form-item label="角色名称" required>
<el-input v-model="ocForm.name" placeholder="请输入OC名称" />
</el-form-item>
<el-form-item label="性格描述">
<el-input
v-model="ocForm.personality"
type="textarea"
:rows="3"
placeholder="描述一下这个角色的性格特点"
/>
<el-form-item label="性别">
<el-radio-group v-model="ocForm.gender">
<el-radio label="男"></el-radio>
<el-radio label="女"></el-radio>
<el-radio label="其他">其他</el-radio>
</el-radio-group>
<el-input v-if="ocForm.gender===''" v-model="ocForm.genderOther" placeholder="自定义性别" style="width:120px;margin-left:8px;" />
</el-form-item>
<el-form-item label="生日">
<el-input v-model="ocForm.birthday" placeholder="如08-15 (月-日)" maxlength="5" />
</el-form-item>
<el-form-item label="年龄">
<el-input v-model="ocForm.age" placeholder="请输入年龄" />
</el-form-item>
<el-form-item label="种族">
<el-input v-model="ocForm.race" placeholder="如:人类、精灵、机器人等" />
</el-form-item>
<el-form-item label="职业">
<el-input v-model="ocForm.occupation" placeholder="请输入职业" />
</el-form-item>
<el-form-item label="生日">
<el-date-picker
v-model="ocForm.birthday"
type="date"
placeholder="选择生日"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
/>
</el-form-item>
<el-form-item label="爱好">
<el-input
v-model="ocForm.hobbies"
placeholder="请输入爱好,用逗号分隔"
/>
</el-form-item>
<el-form-item label="个人简介">
<el-input
v-model="ocForm.bio"
type="textarea"
:rows="3"
placeholder="介绍一下这个角色"
/>
</el-form-item>
<el-form-item label="头像">
<!-- 2. 外表形象 -->
<el-divider>外表形象</el-divider>
<el-form-item label="发型与发色">
<el-input v-model="ocForm.hair" placeholder="如:银色短发" />
</el-form-item>
<el-form-item label="瞳色">
<el-input v-model="ocForm.eyeColor" placeholder="如:琥珀色" />
</el-form-item>
<el-form-item label="大致身高">
<el-input v-model="ocForm.height" placeholder="如170cm" />
</el-form-item>
<el-form-item label="着装风格">
<el-input v-model="ocForm.clothes" placeholder="如:休闲运动、哥特礼服等" />
</el-form-item>
<el-form-item label="标志性特征">
<el-input v-model="ocForm.feature" placeholder="如:猫耳、机械臂等" />
</el-form-item>
<!-- 3. 性格与内心 -->
<el-divider>性格与内心</el-divider>
<el-form-item label="核心性格">
<el-checkbox-group v-model="ocForm.personality">
<el-checkbox label="开朗外向"/><el-checkbox label="安静内向"/><el-checkbox label="成熟稳重"/><el-checkbox label="天真烂漫"/><el-checkbox label="理性冷静"/><el-checkbox label="感性冲动"/><el-checkbox label="温柔体贴"/><el-checkbox label="傲娇冷淡"/><el-checkbox label="幽默搞怪"/><el-checkbox label="认真固执"/><el-checkbox label="悲观消极"/><el-checkbox label="乐观积极"/><el-checkbox label="腹黑"/><el-checkbox label="忠犬"/><el-checkbox label="其他"/>
</el-checkbox-group>
<el-input v-if="ocForm.personality?.includes('')" v-model="ocForm.personalityOther" placeholder="自定义性格" style="width:120px;margin-left:8px;" />
</el-form-item>
<el-form-item label="MBTI人格类型">
<el-input v-model="ocForm.mbti" placeholder="如INFP" />
</el-form-item>
<el-form-item label="最大优点">
<el-input v-model="ocForm.advantage" />
</el-form-item>
<el-form-item label="最大缺点">
<el-input v-model="ocForm.shortcoming" />
</el-form-item>
<el-form-item label="习惯性小动作">
<el-input v-model="ocForm.habit" />
</el-form-item>
<el-form-item label="口头禅">
<el-input v-model="ocForm.catchphrase" />
</el-form-item>
<!-- 4. 背景故事与关系 -->
<el-divider>背景故事与关系</el-divider>
<el-form-item label="成长环境">
<el-input v-model="ocForm.growup" placeholder="如:都市、乡村等" />
</el-form-item>
<el-form-item label="背景故事">
<el-input v-model="ocForm.story" type="textarea" :rows="2" />
</el-form-item>
<el-form-item label="想要隐藏的秘密">
<el-input v-model="ocForm.secret" />
</el-form-item>
<!-- 5. 喜好与日常 -->
<el-divider>喜好与日常</el-divider>
<el-form-item label="兴趣爱好">
<el-input v-model="ocForm.hobbies" placeholder="如:阅读、健身等" />
</el-form-item>
<el-form-item label="喜欢的食物">
<el-input v-model="ocForm.foodLike" />
</el-form-item>
<el-form-item label="讨厌的东西">
<el-input v-model="ocForm.hate" />
</el-form-item>
<el-form-item label="理想生活方式">
<el-input v-model="ocForm.life" />
</el-form-item>
<el-form-item label="周末日常">
<el-input v-model="ocForm.weekend" />
</el-form-item>
<!-- 6. 社区角色期待 -->
<el-divider>社区角色期待</el-divider>
<el-form-item label="社区主要活动">
<el-input v-model="ocForm.communityActivity" placeholder="如:在花店打工" />
</el-form-item>
<el-form-item label="关系期待">
<el-checkbox-group v-model="ocForm.relation">
<el-checkbox label="亲密无间的朋友"/><el-checkbox label="互相扶持的伙伴"/><el-checkbox label="需要照顾的后辈"/><el-checkbox label="值得信赖的前辈"/><el-checkbox label="略带距离感的熟人"/><el-checkbox label="其他"/>
</el-checkbox-group>
<el-input v-if="ocForm.relation?.includes('')" v-model="ocForm.relationOther" placeholder="自定义关系" style="width:120px;margin-left:8px;" />
</el-form-item>
<!-- 头像 -->
<el-divider>头像</el-divider>
<el-form-item label="头像URL">
<el-input v-model="ocForm.avatar" placeholder="头像URL可选" />
</el-form-item>
<el-form-item>
<el-button
type="primary"
@ -89,32 +158,109 @@ import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus'
import { addOC } from '../stores/ocStore.js'
import { currentUser } from '../stores/userStore.js'
import axios from 'axios'
const router = useRouter()
const loading = ref(false)
const ocForm = reactive({
name: '',
personality: '',
occupation: '',
birthday: '',
hobbies: '',
bio: '',
name: '', gender: '', genderOther: '', birthday: '', age: '', race: '', occupation: '',
hair: '', eyeColor: '', height: '', clothes: '', feature: '',
personality: [], personalityOther: '', mbti: '', advantage: '', shortcoming: '', habit: '', catchphrase: '',
growup: '', story: '', secret: '',
hobbies: '', foodLike: '', hate: '', life: '', weekend: '',
communityActivity: '', relation: [], relationOther: '',
avatar: ''
})
const handleAIGenerate = () => {
console.log('AI生成OC')
// AI
ocForm.name = '小' + Math.random().toString(36).substr(2, 4)
ocForm.personality = '活泼开朗,喜欢交朋友'
ocForm.occupation = '学生'
ocForm.birthday = '2000-01-01'
ocForm.hobbies = '音乐、绘画、运动'
ocForm.bio = '这是一个由AI生成的OC角色'
ocForm.avatar = `https://i.pravatar.cc/100?img=${Math.floor(Math.random() * 50) + 1}`
ElMessage.success('AI生成完成')
const handleAIGenerate = async () => {
ElMessage.info('AI生成中...')
const API_KEY = import.meta.env.VITE_ZHIPU_API_KEY
const prompt = `生成一个OC角色的JSON对象字段有
name, gender, genderOther, birthday, age, race, occupation, hair, eyeColor, height, clothes, feature, personality(数组), personalityOther, mbti, advantage, shortcoming, habit, catchphrase, growup, story, secret, hobbies(数组), foodLike, hate, life, weekend, communityActivity, relation(数组), relationOther, avatar
每个字段都要有合理虚构内容必须为中文不能留空不能为[]不能为null
只输出JSON对象本身不要任何推理解释reasoning注释代码块markdown标记或多余内容`;
try {
const res = await axios.post(
'https://open.bigmodel.cn/api/paas/v4/chat/completions',
{
model: 'glm-4-flash',
messages: [
{ role: 'user', content: prompt }
],
temperature: 0.9,
max_tokens: 1024,
thinking: { type: 'enabled' }
},
{
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
}
}
)
console.log('AI接口完整响应:', res.data)
let jsonStr = res.data.choices?.[0]?.message?.content || ''
// AImarkdown
jsonStr = jsonStr.replace(/^```json|```$/g, '').trim()
// JSON
let data = {}
let parsed = false
try {
data = JSON.parse(jsonStr)
parsed = true
} catch {}
if (!parsed) {
// {...}
const match = jsonStr.match(/\{[\s\S]*\}/)
if (match) {
try {
data = JSON.parse(match[0])
parsed = true
} catch {}
}
}
// Bcontentreasoning_contentreasoning_contentJSON
if (!parsed && res.data.choices?.[0]?.message?.reasoning_content) {
const reasoning = res.data.choices[0].message.reasoning_content
const match = reasoning.match(/\{[\s\S]*\}/)
if (match) {
try {
data = JSON.parse(match[0])
parsed = true
} catch {}
}
}
if (!parsed) {
ElMessage.error('AI生成内容解析失败原始内容已打印到控制台')
console.error('AI原始内容', jsonStr)
if (res.data.choices?.[0]?.message?.reasoning_content) {
console.error('AI reasoning_content', res.data.choices[0].message.reasoning_content)
}
return
}
// AIpersonality/relation
Object.keys(ocForm).forEach(k => {
if (data[k] !== undefined) {
if (Array.isArray(ocForm[k]) && typeof data[k] === 'string') {
ocForm[k] = data[k].split(/[,]/).map(s => s.trim()).filter(Boolean)
} else if (typeof ocForm[k] === 'string' && typeof data[k] !== 'string') {
ocForm[k] = String(data[k])
} else if (Array.isArray(ocForm[k]) && Array.isArray(data[k])) {
ocForm[k] = data[k].map(x => typeof x === 'string' ? x.trim() : String(x))
} else {
ocForm[k] = data[k]
}
}
})
console.log('AI同步到表单后的ocForm:', JSON.parse(JSON.stringify(ocForm)))
ElMessage.success('AI生成完成')
} catch (err) {
let msg = 'AI生成失败'
if (err?.response?.data?.msg) msg += ': ' + err.response.data.msg
else if (err?.message) msg += ': ' + err.message
ElMessage.error(msg)
}
}
const handleSubmit = async () => {

@ -58,6 +58,8 @@
import { computed, ref, watch } from 'vue'
import ContactsList from './ContactsList.vue'
import ChatWindow from './ChatWindow.vue'
import { ocList } from '../stores/ocStore'
import { currentUser } from '../stores/userStore'
const props = defineProps({
modelValue: {
@ -73,28 +75,15 @@ const modelValueLocal = computed({
set: value => emit('update:modelValue', value)
})
// mock user and contacts
const selfId = 'me'
const selfAvatar = 'https://avatars.githubusercontent.com/u/9919?v=4'
// 使OC
const selfId = currentUser.value.username || 'me'
const selfAvatar = currentUser.value.avatar || 'https://avatars.githubusercontent.com/u/9919?v=4'
const contacts = ocList
const contacts = ref([
{ id: 'u_alice', name: 'Alice', avatar: 'https://i.pravatar.cc/100?img=5', status: '在线', lastMessage: '好的', lastTime: Date.now() - 600000, unread: 0 },
{ id: 'u_bob', name: 'Bob', avatar: 'https://i.pravatar.cc/100?img=12', status: '离线', lastMessage: '明天见', lastTime: Date.now() - 3600000, unread: 2 },
{ id: 'u_carla', name: 'Carla', avatar: 'https://i.pravatar.cc/100?img=32', status: '在线', lastMessage: '在吗?', lastTime: Date.now() - 120000, unread: 1 }
])
// OC
const messagesByContact = ref({})
const messagesByContact = ref({
u_alice: [
{ senderId: 'u_alice', text: '你好~', timestamp: Date.now() - 7200000 },
{ senderId: selfId, text: '嗨!', timestamp: Date.now() - 7100000 }
],
u_bob: [
{ senderId: 'u_bob', text: '有空吗', timestamp: Date.now() - 5000000 }
],
u_carla: []
})
const activeContactId = ref('u_alice')
const activeContactId = ref(contacts.value.length > 0 ? contacts.value[0].id : '')
const activeContact = computed(() => contacts.value.find(c => c.id === activeContactId.value) || null)
const leftTab = ref('chat')
@ -126,7 +115,7 @@ const formatTime = (ts) => {
}
const handleSend = ({ contact, message }) => {
const handleSend = async ({ contact, message }) => {
const idx = contacts.value.findIndex(c => c.id === contact.id)
if (idx !== -1) {
contacts.value[idx] = {
@ -136,11 +125,46 @@ const handleSend = ({ contact, message }) => {
}
}
// mock auto-reply
setTimeout(() => {
// AIOC
setTimeout(async () => {
let personality = contact.bio || ''
if (Array.isArray(contact.hobbies) && contact.hobbies.length > 0) {
personality += ` 爱好:${contact.hobbies.join('、')}`
}
if (contact.occupation) {
personality += ` 职业:${contact.occupation}`
}
// AI
const API_KEY = import.meta.env.VITE_ZHIPU_API_KEY
let aiText = 'AI思考中...'
if (API_KEY) {
try {
const prompt = `你是${contact.name}${personality}。请用简洁轻快的语气回复对方这句话:${message.text}`
const res = await (await import('axios')).default.post(
'https://open.bigmodel.cn/api/paas/v4/chat/completions',
{
model: 'glm-4.5-air',
messages: [{ role: 'user', content: prompt }],
max_tokens: 128,
temperature: 0.7
},
{
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
}
}
)
aiText = res.data.choices?.[0]?.message?.content || '收到!'
} catch (e) {
aiText = 'AI接口异常自动回复收到'
}
} else {
aiText = 'AI KEY未配置自动回复收到'
}
const reply = {
senderId: contact.id,
text: '收到:' + message.text,
text: aiText,
timestamp: Date.now()
}
const list = messagesByContact.value[contact.id] || []

@ -4,11 +4,89 @@
创建oc 填写oc问卷或交给ai随机生成oc上传oc图片或通过填写问卷ai生成图片作为当前oc的头像。
确定oc头像后进入社区界面用户可以自定义oc的日程表或者让ai根据填写的问卷生成日程表游戏内时间需要与用户所处实际时间相同oc会根据自己的日程表安排自己的活动。小屋中包含卧室客厅厨房健身房餐厅超市花店体育馆酒店等等可拓展性活动场所所有oc都在社区里生活工作甚至学习上课社区里也有一些aiNPC和用户的oc一起生活。
进入手机界面用户可以给oc或已结识的NPC发消息进行交流ai会根据oc自身日程表当前的活动方式决策是实时回复还是延时回复比如oc当前正在休闲放松可以实时回复若进行体育运动如游泳就要延时回复NPC同理。
社区地图 暂定包含以下地点超市主卖日常用品饭店电影院商场综合性公寓甜品店植物园公园体育馆娱乐休闲区KTV台球厅电玩城等
我希望打开网站后首先出现登录注册页面,完成登录后直接显示社区界面,在当前界面右侧一排从上到下有三个按钮 依次是用户中心 oc列表 手机通信,
点击用户中心会出现用户中心弹窗,弹窗中包含用户头像,用户昵称和一些自我角色的个人信息,下拉最下方有退出登录按钮,点击后会回到登录注册页面。
点击oc列表出现oc列表界面弹窗初始列表为空白有一个“创建oc”按钮点击按钮后出现oc问卷用户完成问卷填写后点击提交oc信息会交给ai进行模拟出现oc头像选择窗口用户可以选择上传本地图片或者使用ai根据表单提交的信息生成。头像选择完毕后点击确定。
回到用户列表此时列表中会显示出刚创建的o头像及名称集成卡片点击卡片会出现oc的信息界面包含oc头像oc名称oc生日oc喜好oc职业oc日程表oc的社交圈oc的成就等等用户可以点击日程表进行修改点击社交圈可以添加好友点击成就可以查看自己或好友的成就。
OC角色创建问卷
欢迎来到OC创造者请填写以下问卷帮助我们了解你想要的OC角色。如果不想手动填写可以点击“AI随机生成”按钮自动创建。
1. 基础信息
角色名称_________________________
性别:□ 男 □ 女 □ 其他 _______
生日___月 ___日
年龄_________________________
种族人类、精灵、兽人、恶魔、机器人等可自定义_________________________
职业学生、骑士、程序员、魔法师、偶像、侦探等_________________________
2. 外表形象用于AI生成图片和视觉想象
发型与发色银色短发、金色长卷发、蓝色双马尾_________________________
瞳色琥珀色、湛蓝色、异色瞳_________________________
大致身高_________________________
着装风格休闲运动、哥特礼服、未来科技、古典汉服、学院风_________________________
标志性特征眼角的泪痣、总戴着兜帽、有一条机械臂、有猫耳和尾巴_________________________
3. 性格与内心这是AI对话和行为逻辑的核心
核心性格请选择1-3项
□ 开朗外向 □ 安静内向 □ 成熟稳重 □ 天真烂漫 □ 理性冷静
□ 感性冲动 □ 温柔体贴 □ 傲娇冷淡 □ 幽默搞怪 □ 认真固执
□ 悲观消极 □ 乐观积极 □ 腹黑 □ 忠犬 □ 其他 _______
MBTI人格类型可选_________________________ (e.g., INFP, ESTJ)
最大的优点_________________________
最大的缺点_________________________
习惯性小动作思考时捻头发、紧张时会结巴、说谎时眼神飘忽_________________________
口头禅“没问题”、“让我想想…”、“真是无聊”_________________________
4. 背景故事与关系(让角色更真实丰满)
成长环境繁华都市、宁静乡村、孤儿院长大、贵族世家、星际飞船_________________________
一段简要的背景故事或重要经历:
想要隐藏的秘密可选_________________________
5. 喜好与日常(用于生成日程表和对话内容)
兴趣爱好阅读、健身、烹饪、打游戏、观星、写诗_________________________
喜欢的食物_________________________
讨厌的东西_________________________
理想的生活方式悠闲度日、不断挑战自我、为社会做贡献、陪伴重要的人_________________________
通常如何度过周末_________________________
6. 社区角色期待决定OC在社区中的行为
在社区中你希望TA主要从事什么活动在花店打工、在健身房锻炼、在图书馆学习、在广场闲逛
你希望与TA建立什么样的关系
□ 亲密无间的朋友 □ 互相扶持的伙伴 □ 需要照顾的后辈
□ 值得信赖的前辈 □ 略带距离感的熟人 □ 其他 _______
提交 | AI随机生成 | 清空重填 | 取消创建
功能概述:
@ -19,19 +97,18 @@
修改个人日程表:用户可自定义或调整自己的日常活动安排。
退出登录:用户可安全退出当前账号,返回登录页。
创建OC用户可通过问卷或AI生成方式创建属于自己的OC角色。
修改OC信息用户可编辑已创建OC的详细资料。
删除OC用户可移除不再需要的OC角色。
管理OC用户可编辑或删除已创建OC的详细资料。
修改OC日程表用户可为每个OC单独设定或调整日程安排。
AI通信用户可与OC或NPC通过AI进行智能对话。
AI互动用户可与OC或NPC通过AI进行智能对话。
可补充的功能及描述
好友系统:用户可添加其他用户为好友,建立社交关系。
社区动态/广场用户和OC可在社区内发布动态、评论和点赞。
成就系统用户和OC可通过完成特定任务获得成就徽章。
消息通知:系统可推送好友请求、活动提醒等通知。
多社区/多世界切换:用户可创建或加入不同主题的社区世界。
社区活动/事件:定期举办线上活动或社区事件,丰富互动体验。
自定义社区场景:用户可自定义社区的外观、布局和活动场所。
*多社区/多世界切换:用户可创建或加入不同主题的社区世界。
*社区活动/事件:定期举办线上活动或社区事件,丰富互动体验。
*自定义社区场景:用户可自定义社区的外观、布局和活动场所。
虚拟经济系统:引入虚拟货币,用于购买装饰、道具等。
商城系统:用户可在商城购买服饰、家具等虚拟物品。
排行榜/活跃榜展示用户或OC的活跃度、成就排名。
@ -41,7 +118,7 @@ AI通信用户可与OC或NPC通过AI进行智能对话。
多语言支持:平台支持多种语言切换,适应不同用户群体。
夜间模式:支持界面夜间/白天主题切换。
API开放/插件扩展为开发者提供API或插件接口便于二次开发。
新手引导/帮助中心:为新用户提供操作指引和常见问题解答。
*新手引导/帮助中心:为新用户提供操作指引和常见问题解答。
数据统计与分析为用户提供社区活跃度、OC成长等数据可视化。
@ -50,7 +127,7 @@ API开放/插件扩展为开发者提供API或插件接口便于二次开
多个世界,多个社区,自定义社区场景和社区活动,自定义自然环境和社会背景(与实时性相悖?)
与时俱进 增加每日大事件和新闻功能
联机功能 邀请朋友加入自己的世界或加入朋友的世界
oc问卷内容
@ -62,6 +139,7 @@ API开放/插件扩展为开发者提供API或插件接口便于二次开
版本问题
--0.1目标:搭建平台雏形
0.0.1
按钮没有对其
oc创建后没有显示在列表中
@ -83,7 +161,15 @@ oc创建后没有显示在列表中
要求用户注册后的信息可以正常登录并保存在用户中心中,可以随时修改或查看
联系人列表只要有联系人头像名称就好,不显示最近一次聊天内容和时间
0.1.0--直至完成了整整意义上的平台雏形
0.1.0--完成了整体意义上的平台雏形
0.1.1
成功调用api进行对话将手机中的联系人替换成用户自己创建的ocai回复逻辑参考oc性格回复语句模拟现实聊天简洁轻快
oc问卷中生日只要月日即可不需要填写年份且ai随机生成的内容并没有同步到表单中
0.1.2
oc问卷ai随机生成成功实现但创建oc数量好像有最大限制超过4个后新创建的oc会覆盖掉最后一个
--0.2目标成功调用ai搭建基本社区地图
@ -98,173 +184,3 @@ Terminal window
irm https://raw.githubusercontent.com/yuaotian/go-cursor-help/refs/heads/master/scripts/run/cursor_win_id_modifier.ps1 | iex
### **第一步:搭建你的开发环境 (第1天)**
1. **安装 Node.js:**
* **是什么:** Node.js是JavaScript的运行环境前端很多工具都依赖它。
* **怎么做:** 访问 [Node.js 官网](https://nodejs.org/),下载并安装 **LTS长期支持版**。
* **验证:** 安装完成后打开命令行Windows: CMD 或 PowerShell; Mac: Terminal输入以下命令能显示版本号即成功。
```bash
node -v
npm -v
```
2. **安装代码编辑器 - Visual Studio Code (VS Code):**
* **是什么:** 目前最强大的免费前端开发编辑器。
* **怎么做:** 访问 [VS Code 官网](https://code.visualstudio.com/),下载安装。
* **安装必备插件:** 打开VS Code在左侧扩展商店中搜索并安装
* `Volar` (Vue 3官方推荐支持插件**必装**)
* `Auto Rename Tag` (自动重命名配对的HTML标签)
* `ESLint` (代码格式检查)
* `Live Server` (右键一键启动本地服务器预览HTML页面)
* `Chinese (Simplified) Language Pack` (如果需要中文界面)
3. **安装 Git:**
* **是什么:** 代码版本管理工具,团队协作核心。
* **怎么做:** 访问 [Git 官网](https://git-scm.com/) 下载安装。
* **配置:** 安装后,在命令行中设置你的用户名和邮箱(用于标识你的提交):
```bash
git config --global user.name "你的名字"
git config --global user.email "你的邮箱@example.com"
```
---
### **第二步创建你的第一个Vue项目 (第1-2天)**
我们使用Vue官方推荐的脚手架工具 `Vite` 来创建项目,它非常快!
1. **在命令行中创建项目:**
找一个你喜欢的文件夹,在地址栏输入 `cmd` 打开命令行,执行以下命令:
```bash
# 使用 npm 创建项目,项目名为 `oc-community-frontend`
npm create vite@latest oc-community-frontend -- --template vue
# 接下来按照提示操作
cd oc-community-frontend # 进入项目目录
npm install # 安装项目依赖(所有需要的代码库)
npm run dev # 启动开发服务器
```
2. **查看效果:**
执行 `npm run dev` 后,命令行会给出一个本地地址(通常是 `http://localhost:5173`。用浏览器打开它你会看到Vue的欢迎页面恭喜你项目成功运行了
3. **了解项目结构:**
用VS Code打开你刚创建的 `oc-community-frontend` 文件夹,你会看到类似下面的结构:
```
oc-community-frontend
├── node_modules/ # 所有安装的依赖包(不用动它)
├── src/ # 源代码目录(主要在这里工作!)
│ ├── assets/ # 静态资源,如图片、字体
│ ├── components/ # Vue组件目录可复用的小模块
│ ├── App.vue # 根组件(应用的主组件)
│ └── main.js # 项目的入口文件
├── index.html # 主HTML页面
├── package.json # 项目配置文件(记录了项目信息和依赖)
└── vite.config.js # Vite的配置文件
```
---
### **第三步:学习核心概念并开始修改 (第2-4周)**
你的目标是实现页面,而不是从零造轮子。所以我们要**现学现用**。
1. **学习最低限度的Vue语法**
* **单文件组件 (.vue文件)**`<template>` (HTML), `<script>` (JavaScript), `<style>` (CSS) 三部分。
* **响应式数据**:使用 `ref` 或 `reactive` 声明数据,数据变,页面自动变。
* **事件处理**`@click` 等指令,用于处理用户点击等操作。
* **条件渲染**`v-if` 和 `v-show`,控制组件显示隐藏。
* **循环渲染**`v-for`,用于渲染列表(如消息列表)。
* **组件通信**`props` (父传子)`$emit` (子传父)。
**如何学?** 只看文档的必要部分:
* **Vue 官方中文教程****[https://cn.vuejs.org/guide/essentials/application.html](https://cn.vuejs.org/guide/essentials/application.html)** 精读 **“基础”** 和 **“深入组件”** 章节。
2. **安装和使用UI组件库 (事半功倍!)**
* 在项目目录下运行命令安装 `Element Plus`:
```bash
npm install element-plus --save
```
* 在 `main.js` 文件中全局引入:
```javascript
import { createApp } from 'vue'
import App from './App.vue'
// 引入 Element Plus
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
```
* **现在你就可以在项目的任何地方使用Element Plus的组件了** 去它的官网 **[https://element-plus.gitee.io/zh-CN/](https://element-plus.gitee.io/zh-CN/)**,复制你需要的组件代码到你的 `.vue` 文件里,然后修改一下就行。
* **例如:** 你需要一个按钮就在官网找到Button组件复制代码贴到你的`<template>`里,改一下文字和`@click`事件函数名。
3. **划分页面与组件:**
根据你的项目,前端至少需要这些页面和组件:
* `LoginPage.vue` - 登录/注册页
* `OCCreationPage.vue` - 创建OC的页面表单+AI生成按钮
* `CommunityPage.vue` - 主社区页面显示背景图、OC位置
* `PhoneWidget.vue` - **可复用的手机组件**(里面包含聊天界面)
* `ChatWindow.vue` - **手机组件内部的聊天窗口组件**
在 `src/components` 下创建这些文件,然后在 `src/App.vue` 中通过路由切换它们,或者先用 `v-if` 简单切换。
---
### **第四步:与后端联调 (第5周起)**
当前端页面大概样子出来后,就要开始请求后端的数据了。
1. **安装Axios (用于发送HTTP请求)**
```bash
npm install axios
```
2. **学习如何使用:**
* 在你的组件脚本中 `import axios from 'axios'`。
* 在生命周期函数(如 `onMounted`或事件如按钮点击中调用API。
* **示例:登录请求**
```javascript
import { ref } from 'vue';
import axios from 'axios';
const username = ref('');
const password = ref('');
const handleLogin = async () => {
try {
// 假设后端地址是 http://localhost:8000
const response = await axios.post('http://localhost:8000/api/login', {
username: username.value,
password: password.value
});
// 登录成功保存token并跳转页面
console.log('登录成功', response.data);
} catch (error) {
// 登录失败,提示用户
console.error('登录失败', error);
}
};
```
3. **和后端同学约定API格式**
* 一起讨论每个接口的**URL、请求方法GET/POST、请求参数、返回数据格式**。
* 使用 **Apifox** 或 **Postman** 这类工具来模拟请求测试后端API是否正常工作然后再写到代码里。
### **给你的行动清单**
1. **[ ] 今天内**完成环境搭建和第一个Vue项目运行。
2. **[ ] 本周末**通读Vue核心概念文档跑通一个Element Plus的组件例子。
3. **[ ] 下周**画出前端页面的简单线框图并开始尝试实现登录页和OC创建页的静态样式只画样子不管功能
4. **[ ] 之后**和后端同学开会定好API接口开始尝试用Axios连接登录功能。
不要怕遇到问题随时搜索CSDN、掘金、StackOverflow、官方文档90%的问题都能找到答案。祝你顺利!
Loading…
Cancel
Save