基于coze+微信小程序实现图片上传并利用大模型解析

ops/2025/2/28 13:47:03/

项目截图:

实现代码(直接搬去可用)

前提:需要填写你的oss配置+coze的api授权配置!!!

<template><view class="container"><!-- 高斯模糊背景 --><view class="animated-bg"><view class="gradient-blob"></view><view class="gradient-blob two"></view><view class="gradient-blob three"></view><view class="gradient-blob four"></view><view class="overlay"></view></view><!-- 返回按钮 --><view class="back-button" @tap="goBack"><text class="back-icon">←</text><text class="back-text">返回</text></view><!-- 头部区域 --><view class="header"><text class="logo-text">单词识别助手</text><text class="subtitle">上传单词图片,快速获取详细释义</text></view><!-- 上传区域 --><view class="upload-section"><view class="upload-box" @tap="chooseImage" v-if="!tempFilePath"><text class="upload-icon">📷</text><text class="upload-text">点击上传单词图片</text><text class="upload-desc">支持拍照或从相册选择</text></view><view class="preview-box" v-else><image :src="tempFilePath" mode="aspectFit" class="preview-image"/><view class="action-buttons"><button class="action-btn cancel" @tap="cancelUpload">取消</button><button class="action-btn confirm" @tap="analyzeImage">识别</button></view></view></view><!-- 加载状态 --><view class="loading-state" v-if="loading"><view class="pulse-loader"><view class="pulse"></view><view class="pulse"></view><view class="pulse"></view></view><text class="loading-text">正在识别中...</text></view><!-- 只有当有单词数据时才显示结果区域 --><div class="word-info" v-if="wordInfo.word"><div class="word-header"><text class="word">{{ wordInfo.word }}</text><text class="phonetic">{{ wordInfo.phonetic }}</text></div><div class="word-content"><div class="item"><text class="label">词性:</text><text>{{ wordInfo.type }}</text></div><div class="item"><text class="label">中文含义:</text><text>{{ wordInfo.meaning }}</text></div><div class="item"><text class="label">例句:</text><text>{{ wordInfo.example }}</text></div><div class="item"><text class="label">相关词汇:</text><text>{{ wordInfo.similar }}</text></div></div></div></view>
</template><script>export default {data() {return {tempFilePath: '', // 临时图片路径loading: false,wordResult: null, // 模拟的识别结果// 模拟数据mockResult: {word: "Happiness",phonetic: "ˈhæpinəs",meanings: [{partOfSpeech: "名词",definition: "幸福;快乐;愉快;幸福感",example: "Money doesn't buy happiness."},{partOfSpeech: "名词",definition: "适当;恰当;正确",example: "She questioned the happiness of his choice of words."}]},ossConfig: {accessKeyId: '----------------填写你的-----------------',accessKeySecret: '----------------填写你的-----------------',bucket: '----------------填写你的-----------------',region: '----------------填写你的-----------------', // 根据你的实际地区修改endpoint: '----------------填写你的-----------------',},cozeConfig: {apiUrl: 'https://api.coze.cn/open_api/v2/chat',token: '----------------填写你的-----------------',botId: '----------------填写你的-----------------',userId: '----------------填写你的-----------------'},wordInfo: {word: '',phonetic: '',meaning: '',example: '',similar: '',pronunciation: ''}}},methods: {// 返回上一页goBack() {uni.navigateBack({delta: 1 // 返回的页面层数,1 表示返回上一页});},// 选择图片chooseImage() {uni.chooseImage({count: 1,sizeType: ['compressed'],sourceType: ['album', 'camera'],success: (res) => {this.tempFilePath = res.tempFilePaths[0];}});},// 取消上传cancelUpload() {this.tempFilePath = '';this.wordResult = null;},// Base64编码函数base64Encode(str) {const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';let output = '';let chr1, chr2, chr3, enc1, enc2, enc3, enc4;let i = 0;while (i < str.length) {chr1 = str.charCodeAt(i++);chr2 = str.charCodeAt(i++);chr3 = str.charCodeAt(i++);enc1 = chr1 >> 2;enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);enc4 = chr3 & 63;if (isNaN(chr2)) {enc3 = enc4 = 64;} else if (isNaN(chr3)) {enc4 = 64;}output = output +chars.charAt(enc1) + chars.charAt(enc2) +chars.charAt(enc3) + chars.charAt(enc4);}return output;},// 上传到OSSasync uploadToOSS(filePath) {return new Promise((resolve, reject) => {const date = new Date();date.setHours(date.getHours() + 1); // 设置policy过期时间为1小时后const policyText = {expiration: date.toISOString(), // 设置过期时间conditions: [["content-length-range", 0, 5048576000] // 设置上传文件的大小限制]};// 生成policy,使用自定义的base64编码函数const policy = this.base64Encode(JSON.stringify(policyText));// 生成signatureconst signature = this.computeSignature(policy, this.ossConfig.accessKeySecret);// 生成文件名const fileName = `word_images/${Date.now()}_${Math.random().toString(36).slice(2)}.jpg`;uni.uploadFile({url: this.ossConfig.endpoint,filePath: filePath,name: 'file',formData: {key: fileName,policy: policy,OSSAccessKeyId: this.ossConfig.accessKeyId,signature: signature,success_action_status: '200'},success: (res) => {if (res.statusCode === 200) {const url = `https://${this.ossConfig.bucket}.${this.ossConfig.region}/${fileName}`;resolve(url);} else {uni.showToast({title: '上传失败',icon: 'none'});reject(new Error('上传失败'));}},fail: (err) => {uni.showToast({title: '上传失败',icon: 'none'});reject(err);}});});},// 计算签名computeSignature(policy, accessKeySecret) {// 由于uni-app环境中可能没有crypto-js,这里使用一个简单的方法来计算const hmac = function(key, str) {const crypto = require('crypto');const hmac = crypto.createHmac('sha1', key);hmac.update(str);return hmac.digest('base64');};return hmac(accessKeySecret, policy);},// 调用Coze APIasync callCozeAPI(imageUrl) {try {const response = await uni.request({url: this.cozeConfig.apiUrl,method: 'POST',header: {'Authorization': `Bearer ${this.cozeConfig.token}`,'Content-Type': 'application/json','Accept': '*/*','Host': 'api.coze.cn','Connection': 'keep-alive'},data: {conversation_id: Date.now().toString(),bot_id: this.cozeConfig.botId,user: this.cozeConfig.userId,query: `请识别这张图片中的单词,图片地址是:${imageUrl}`,stream: false}});const responseData =  response;console.log(responseData)const result = JSON.parse(responseData[1].data.messages[1].content);	console.log(result)// 根据实际返回数据更新显示return result;} catch (error) {console.error('Coze API 调用失败:', error);uni.showToast({title: error.message || 'API调用失败',icon: 'none',duration: 3000});return null;}},// 修改原有的analyzeImage方法async analyzeImage() {this.loading = true;try {// 1. 上传图片到OSSconst imageUrl = await this.uploadToOSS(this.tempFilePath);console.log(imageUrl)// 2. 调用Coze APIconst result = await this.callCozeAPI(imageUrl);console.log(result)// 3. 处理返回结果this.wordInfo = {word: result.out2, // pearphonetic: result.yinbiao, // 英/peə(r)/;美/per/type: result.output, // 名词meaning: result.out, // 梨example: result.liju, // I like to eat pears.(我喜欢吃梨。)similar: result.xiangsi // apple(苹果)、banana(香蕉)等,都属于水果类词汇};} catch (error) {console.error('处理失败:', error);} finally {this.loading = false;}}}}
</script><style>.container {min-height: 100vh;position: relative;overflow: hidden;background: #f8f9fa;}.animated-bg {position: fixed;width: 100%;height: 100%;top: 0;left: 0;overflow: hidden;z-index: 0;background: linear-gradient(125deg, #00fff3, #ff00e6);animation: gradientBG 15s ease infinite;}.gradient-blob {position: absolute;width: 1000rpx;height: 1000rpx;background: linear-gradient(45deg,rgba(255, 49, 97, 0.5),rgba(255, 97, 162, 0.5));border-radius: 50%;filter: blur(80px);animation: blob-movement 20s infinite linear,color-shift 10s infinite alternate;opacity: 0.7;top: -300rpx;left: -300rpx;}.gradient-blob.two {background: linear-gradient(45deg,rgba(67, 206, 162, 0.5),rgba(24, 90, 157, 0.5));animation: blob-movement-2 25s infinite linear,color-shift-2 12s infinite alternate;animation-delay: -3s;top: 60%;left: 60%;}.gradient-blob.three {background: linear-gradient(45deg,rgba(255, 197, 84, 0.5),rgba(255, 159, 0, 0.5));animation: blob-movement-3 30s infinite linear,color-shift-3 8s infinite alternate;animation-delay: -5s;top: 40%;left: 30%;}.gradient-blob.four {background: linear-gradient(45deg,rgba(147, 88, 255, 0.5),rgba(19, 123, 255, 0.5));animation: blob-movement-4 28s infinite linear,color-shift-4 15s infinite alternate;animation-delay: -7s;top: 20%;left: 70%;}.overlay {position: absolute;top: 0;left: 0;right: 0;bottom: 0;background: rgba(255, 255, 255, 0.2);backdrop-filter: blur(20px);}@keyframes gradientBG {0% {background-position: 0% 50%;}50% {background-position: 100% 50%;}100% {background-position: 0% 50%;}}@keyframes blob-movement {0% {transform: translate(0, 0) scale(1) rotate(0deg);}33% {transform: translate(300rpx, 200rpx) scale(1.2) rotate(120deg);}66% {transform: translate(-200rpx, 400rpx) scale(0.8) rotate(240deg);}100% {transform: translate(0, 0) scale(1) rotate(360deg);}}@keyframes blob-movement-2 {0% {transform: translate(0, 0) scale(1.1) rotate(0deg);}33% {transform: translate(-250rpx, -300rpx) scale(0.9) rotate(120deg);}66% {transform: translate(300rpx, -200rpx) scale(1.2) rotate(240deg);}100% {transform: translate(0, 0) scale(1.1) rotate(360deg);}}@keyframes blob-movement-3 {0% {transform: translate(0, 0) scale(0.9) rotate(0deg);}33% {transform: translate(400rpx, -100rpx) scale(1.1) rotate(120deg);}66% {transform: translate(-300rpx, 200rpx) scale(0.8) rotate(240deg);}100% {transform: translate(0, 0) scale(0.9) rotate(360deg);}}@keyframes blob-movement-4 {0% {transform: translate(0, 0) scale(1) rotate(0deg);}33% {transform: translate(-200rpx, 300rpx) scale(1.1) rotate(120deg);}66% {transform: translate(250rpx, -250rpx) scale(0.9) rotate(240deg);}100% {transform: translate(0, 0) scale(1) rotate(360deg);}}@keyframes color-shift {0% {background: linear-gradient(45deg, rgba(255, 49, 97, 0.5), rgba(255, 97, 162, 0.5));}100% {background: linear-gradient(45deg, rgba(255, 182, 193, 0.5), rgba(255, 20, 147, 0.5));}}@keyframes color-shift-2 {0% {background: linear-gradient(45deg, rgba(67, 206, 162, 0.5), rgba(24, 90, 157, 0.5));}100% {background: linear-gradient(45deg, rgba(0, 255, 255, 0.5), rgba(0, 128, 128, 0.5));}}@keyframes color-shift-3 {0% {background: linear-gradient(45deg, rgba(255, 197, 84, 0.5), rgba(255, 159, 0, 0.5));}100% {background: linear-gradient(45deg, rgba(255, 215, 0, 0.5), rgba(255, 140, 0, 0.5));}}@keyframes color-shift-4 {0% {background: linear-gradient(45deg, rgba(147, 88, 255, 0.5), rgba(19, 123, 255, 0.5));}100% {background: linear-gradient(45deg, rgba(138, 43, 226, 0.5), rgba(65, 105, 225, 0.5));}}/* 头部样式 */.header {padding: 60rpx 40rpx;text-align: center;z-index: 1;position: relative;}.logo-text {font-size: 48rpx;color: #1a1a1a;font-weight: 600;letter-spacing: 2rpx;text-shadow: 0 2px 4px rgba(255, 255, 255, 0.2);}.subtitle {font-size: 28rpx;color: rgba(0, 0, 0, 0.7);margin-top: 16rpx;display: block;}/* 上传区域样式 */.upload-section {padding: 40rpx;z-index: 2;position: relative;}.upload-box {background: rgba(255, 255, 255, 0.2);backdrop-filter: blur(20px);border-radius: 20rpx;padding: 60rpx;display: flex;flex-direction: column;align-items: center;border: 2rpx dashed rgba(255, 255, 255, 0.5);}.upload-icon {font-size: 80rpx;margin-bottom: 20rpx;}.upload-text {font-size: 32rpx;color: #333;margin-bottom: 10rpx;}.upload-desc {font-size: 24rpx;color: rgba(0, 0, 0, 0.5);}.preview-box {width: 100%;border-radius: 20rpx;overflow: hidden;}.preview-image {width: 100%;height: 400rpx;border-radius: 20rpx;}.action-buttons {display: flex;justify-content: space-between;margin-top: 20rpx;gap: 20rpx;}.action-btn {flex: 1;padding: 20rpx;border-radius: 10rpx;text-align: center;font-size: 28rpx;}.action-btn.cancel {background: rgba(255, 255, 255, 0.3);color: #333;}.action-btn.confirm {background: linear-gradient(135deg, #7C3AED, #3B82F6);color: #fff;}.word-text {font-size: 40rpx;font-weight: bold;color: #333;}.phonetic {font-size: 28rpx;color: rgba(0, 0, 0, 0.6);margin-left: 20rpx;}.meanings {margin-top: 30rpx;}.meaning-item {margin-bottom: 20rpx;}.pos {font-size: 26rpx;color: #666;background: rgba(0, 0, 0, 0.1);padding: 4rpx 12rpx;border-radius: 6rpx;margin-right: 10rpx;}.definition {font-size: 30rpx;color: #333;display: block;margin: 10rpx 0;}.example {font-size: 26rpx;color: #666;display: block;font-style: italic;}/* 加载动画 */.loading-state {padding: 60rpx;text-align: center;}.pulse-loader {display: flex;justify-content: center;gap: 12rpx;}.pulse {width: 16rpx;height: 16rpx;background: #fff;border-radius: 50%;animation: pulse 1.5s infinite ease-in-out;}.pulse:nth-child(2) { animation-delay: 0.2s; }.pulse:nth-child(3) { animation-delay: 0.4s; }@keyframes pulse {0%, 100% { transform: scale(0.5); opacity: 0.2; }50% { transform: scale(1); opacity: 1; }}.loading-text {color: rgba(255,255,255,0.7);font-size: 28rpx;margin-top: 20rpx;display: block;}/* 结果卡片 */.result-wrapper {padding: 40rpx;}.result-card {background: rgba(255, 255, 255, 0.2);backdrop-filter: blur(15px);border-radius: 20rpx;padding: 30rpx;border: 1px solid rgba(255, 255, 255, 0.3);animation: slideUp 0.3s ease;}.result-header {display: flex;justify-content: space-between;align-items: center;margin-bottom: 20rpx;}.back-button {position: fixed;top: 40rpx;left: 20rpx;display: flex;align-items: center;padding: 10rpx 20rpx;background: rgba(255, 255, 255, 0.8);border-radius: 50rpx;backdrop-filter: blur(10px);z-index: 999;box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);}.back-icon {font-size: 36rpx;margin-right: 10rpx;color: #333;}.back-text {font-size: 28rpx;color: #333;}.word-info {padding: 20px;}.word-header {margin-bottom: 20px;}.word {font-size: 24px;font-weight: bold;margin-right: 10px;}.phonetic {color: #666;}.item {margin-bottom: 15px;}.label {color: #333;font-weight: bold;margin-right: 10px;}
</style>


http://www.ppmy.cn/ops/161977.html

相关文章

js 获取节点相对于屏幕的坐标位置,获取节点的宽高,获取鼠标事件回调的鼠标位置,计算鼠标相对于某个节点下的坐标

获取节点相对于屏幕的坐标位置&#xff1a; document.getElementById(svgBoxId).getBoundingClientRect() 获取节点的宽高&#xff1a; document.getElementById(svgBoxId).offsetWidth document.getElementById(svgBoxId).offsetHeight 获取鼠标事件回调的鼠标位置&#xff1a…

WPF13-MVVM进阶

目录 1. 窗体设置2. 字体图标3. 控件模板4. 页面逻辑4.1. 不使用MVVM4.2. MVVM模式实现本篇我们开发一个基于MVVM的登录页面,用来回顾下之前学习的内容 登录页面如下: 窗体取消了默认的标题栏,调整为带阴影的圆角窗体,左侧放一张登录背景图,右边自绘了一个关闭按钮,文本框…

【Linux】Vim 设置

【Linux】Vim 设置 零、起因 刚学Linux&#xff0c;有时候会重装Linux系统&#xff0c;然后默认的vi不太好用&#xff0c;需要进行一些设置&#xff0c;本文简述如何配置一个好用的Vim。 壹、软件安装 sudo apt-get install vim贰、配置路径 对所有用户生效&#xff1a; …

IP-----动态路由OSPF(2)

这只是IP的其中一块内容&#xff0c;IP还有更多内容可以查看IP专栏&#xff0c;前一章内容为动态路由OSPF &#xff0c;可通过以下路径查看IP-----动态路由OSPF-CSDN博客,欢迎指正 注意&#xff01;&#xff01;&#xff01;本部分内容较多所以分成了两部分在上一章 5.动态路…

[特殊字符] 蓝桥杯 Java B 组 之最小生成树(Prim、Kruskal) 并查集应用

Day 3&#xff1a;最小生成树&#xff08;Prim、Kruskal&#xff09; & 并查集应用 &#x1f4d6; 一、最小生成树&#xff08;MST&#xff09;简介 最小生成树&#xff08;Minimum Spanning Tree, MST&#xff09; 是一个 无向连通图 的 最小代价子图&#xff0c;它包含 …

倚光科技:助力玻璃非球面的打样与小批量生产

在现代光学和精密制造领域&#xff0c;非球面光学元件凭借其卓越的光学性能&#xff0c;已成为推动高端科技发展的核心组件。相比于传统的球面透镜&#xff0c;非球面透镜能够显著减少光学系统中的像差和畸变&#xff0c;大幅提升成像质量、系统紧凑性和能量利用率。因此&#…

【JavaScript】《JavaScript高级程序设计 (第4版) 》笔记-Chapter25-客户端存储

二十五、客户端存储 客户端存储 随着 Web 应用程序的出现&#xff0c;直接在客户端存储用户信息的需求也随之出现。这背后的想法是合理的&#xff1a;与特定用户相关的信息应该保存在用户的机器上。无论是登录信息、个人偏好&#xff0c;还是其他数据&#xff0c;Web 应用程序提…

【读书笔记·VLSI电路设计方法解密】问题57:逻辑合成过程中插入测试的目的是什么

如第3章第20题所述&#xff0c;可测试性设计&#xff08;Design for Testability, DFT&#xff09;是创建具有商业价值的产品时需要考虑的一个非常重要的问题。为了实现DFT功能&#xff0c;使设计能够检测制造缺陷&#xff0c;需要在设计中添加额外的测试电路&#xff0c;而这些…