位置: IT常识 - 正文

【Unity】AI实战应用——Unity接入ChatGPT和对游戏开发实际应用的展望(unity ik)

编辑:rootadmin
【Unity】AI实战应用——Unity接入ChatGPT和对游戏开发实际应用的展望

推荐整理分享【Unity】AI实战应用——Unity接入ChatGPT和对游戏开发实际应用的展望(unity ik),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:unity ai,unity ik,unity iap,unity ik,unity ai,unity ar ui,unity iap,unity iap,内容如对您有帮助,希望把文章链接给更多的朋友!

ChatGPT for unity插件地址: GitHub - sunsvip/ChatGPTForUnity: ChatGPT for unity

用法:

打开Unity PackageManager界面.Add package from git URL粘贴插件地址添加 https://github.com/sunsvip/ChatGPTForUnity.git

————————————————————————————————————

几个资本大佬花钱让一群程序员研发出了AI,砸了程序员的大锅。尤其是ChatGPT 4.0发布后,认识的同事朋友们都在恐慌AI的发展,甚至有不少人开始抗拒。我的观点是:人工智能是大势所趋,势不可挡,那就驾驭它吧!

我司已经在商业项目中实际使用了AI, 包括Stable Diffusion及其扩展插件,当然也有爆火的ChatGPT。

Midjourney + Stable Diffusion + ControlNET + Lora以及Photoshop Stable Diffusion 等插件的结合使用已经强大到基本取代初中级原画师;

ChatGPT 4.0势头已经咄咄逼人,据说下一代会进化到运行时处理功能,比如对磁盘的读写等。用户让ChatGPT“创建一个cs代码”,它就能在电脑硬盘里创建一个代码文件。个人觉得任重道远,功能越强责任越大,如果没有有效解决安全问题之前,这一步很难到来。

ChatGPT已经能全面应用到游戏开发的各个环节了,策划的剧情设定、技术的代码编写优化、测试的测试用例等。我从去年12月开始使用ChatGPT,完全把它当成了一个搜索引擎,自从有了它几乎没使用多少次谷歌百度。4.0的到来彻底激发了我对ChatGPT实际应用的思考。

首先第一步肯定是先把ChatGPT接入Unity,先建立起通讯,以此为基础各种应用功能才能百花齐放。

工具效果预览:

 ChatGPT接口实现:

用UnityWebRequest实现一个与ChatGPT通讯的类,之后的各种功能基于此类。

一,获取API Key

ChatGPT提供了开放接口,仅需一个个人版的API Key就可以接入ChatGPT, API Key获取入口:https://platform.openai.com/account/api-keys

 二,使用UnityWebRequest发送Post请求和接收ChatGPT返回信息

ChatGPT URL:  https://api.openai.com/v1/chat/completions

上行数据结构如下:

{ "messages": [ { "role": "user", "content": "你是机器人吗"//要发送的问题 } ], "model": "gpt-3.5-turbo",//AI数据模型 "temperature": 0.7 //默认是1, 数值越大结果随机性越高}

 需要注意的是,messages是个数组,如果想连续对话就需要把发送历史塞到这个messages数组,gpt根据你的发送历史分析上下文给出处理结果。gpt消耗token不是根据发送请求次数计算,聊天历史越多单次发送请求消耗的token越多,所以及时清除历史(新建话题)可以节省token消耗。

下行数据结构如下:

{ "id": "chatcmpl-xxxxxxxxxxxxxxxxxx", "object": "chat.completion", "created": 1678987654, "model": "gpt-3.5-turbo-0301", "usage": { "prompt_tokens": 14, "completion_tokens": 23, "total_tokens": 37 }, "choices": [ { "message": { "role": "assistant", "content": "\n\n是的,我是一个AI语言模型,也可以被称为机器人。" //得到的回复 }, "finish_reason": "stop", "index": 0 } ]}

使用UnityWebRequest发送Post请求:

private IEnumerator Request(string input, Action<bool, string> onComplete, Action<float> onProgressUpdate) { var msg = new Message() { role = UserId, content = input, }; requestData.AppendChat(msg); messageHistory.Add(msg); using (webRequest = new UnityWebRequest(ChatgptUrl, "POST")) { var jsonDt = UtilityBuiltin.Json.ToJson(requestData); Debug.Log(jsonDt); byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonDt); webRequest.uploadHandler = new UploadHandlerRaw(bodyRaw); webRequest.downloadHandler = new DownloadHandlerBuffer(); webRequest.SetRequestHeader("Content-Type", "application/json"); webRequest.SetRequestHeader("Authorization", $"Bearer {this.ApiKey}"); //webRequest.certificateHandler = new ChatGPTWebRequestCert(); var req = webRequest.SendWebRequest(); while (!webRequest.isDone) { onProgressUpdate?.Invoke((webRequest.downloadProgress + webRequest.uploadProgress) / 2f); yield return null; } if (webRequest.result != UnityWebRequest.Result.Success) { Debug.LogError($"---------ChatGPT请求失败:{webRequest.error}---------"); onComplete?.Invoke(false, string.Empty); } else { var json = webRequest.downloadHandler.text; Debug.Log(json); try { ChatCompletion result = UtilityBuiltin.Json.ToObject<ChatCompletion>(json); int lastChoiceIdx = result.choices.Count - 1; var replyMsg = result.choices[lastChoiceIdx].message; replyMsg.content = replyMsg.content.Trim(); messageHistory.Add(replyMsg); onComplete?.Invoke(true, replyMsg.content); } catch (System.Exception e) { Debug.LogError($"---------ChatGPT返回数据解析失败:{e.Message}---------"); onComplete?.Invoke(false, e.Message); } } webRequest.Dispose(); webRequest = null; } }

 以上就是向ChatGPT发送请求并接受回复的核心代码,非常简单。然而不出意外的话会出现请求报错:Cert verify failed: UNITYTLS_X509VERIFY_FLAG_CN_MISMATCH, https证书验证失败。

所以还需要自定义验证类,直接跳过验证返回true:

class ChatGPTWebRequestCert : UnityEngine.Networking.CertificateHandler { protected override bool ValidateCertificate(byte[] certificateData) { //return base.ValidateCertificate(certificateData); return true; } }【Unity】AI实战应用——Unity接入ChatGPT和对游戏开发实际应用的展望(unity ik)

然后为UnityWebRequest势力指定验证Handler:

webRequest.certificateHandler = new ChatGPTWebRequestCert();

再次运行就能正常接收数据了。

完整代码:

using System;using System.Collections;using System.Collections.Generic;using System.Text;using System.Threading.Tasks;using Unity.EditorCoroutines.Editor;using UnityEditor;using UnityEngine;using UnityEngine.Networking;namespace UnityGameFramework.Editor.AIAssistant{ public class ChatGPT { const string ChatgptUrl = "https://api.openai.com/v1/chat/completions"; const string DefaultAPIKey = "替换自己的ChatGPT API Key"; const string DefaultModel = "gpt-3.5-turbo"; const float DefaultTemperature = 0; const string DefaultUserId = "user"; string ApiKey; string UserId; List<Message> messageHistory; public List<Message> MessageHistory => messageHistory; ChatGPTRequestData requestData; UnityWebRequest webRequest; public float ChatGPTRandomness { get => requestData.temperature; set { requestData.temperature = Mathf.Clamp(value, 0, 2); } } public bool IsRequesting => webRequest != null && !webRequest.isDone; public float RequestProgress => IsRequesting ? (webRequest.uploadProgress + webRequest.downloadProgress) / 2f : 0f; public ChatGPT(string apiKey = DefaultAPIKey, string userId = DefaultUserId, string model = DefaultModel, float temperature = DefaultTemperature) { this.ApiKey = apiKey; this.UserId = string.IsNullOrWhiteSpace(userId) ? DefaultUserId : userId; messageHistory = new List<Message>(); requestData = new ChatGPTRequestData(model, temperature); } /// <summary> /// 接着上次的话题 /// </summary> public void RestoreChatHistory() { var chatHistoryJson = EditorPrefs.GetString("ChatGPT.Settings.ChatHistory", string.Empty); var requestDataJson = EditorPrefs.GetString("ChatGPT.Settings.RequestData", string.Empty); if (!string.IsNullOrEmpty(chatHistoryJson)) { var jsonObj = UtilityBuiltin.Json.ToObject<ChatGPTRequestData>(requestDataJson); if (jsonObj != null) { requestData.messages = jsonObj.messages; } } if (!string.IsNullOrEmpty(requestDataJson)) { var jsonObj = UtilityBuiltin.Json.ToObject<List<Message>>(chatHistoryJson); if (jsonObj != null) { messageHistory = jsonObj; } } } public void SaveChatHistory() { var chatHistoryJson = UtilityBuiltin.Json.ToJson(messageHistory); var requestDataJson = UtilityBuiltin.Json.ToJson(requestData); EditorPrefs.SetString("ChatGPT.Settings.ChatHistory", chatHistoryJson); EditorPrefs.SetString("ChatGPT.Settings.RequestData", requestDataJson); } public void Send(string message, Action<bool, string> onComplete = null, Action<float> onProgressUpdate = null) { EditorCoroutineUtility.StartCoroutine(Request(message, onComplete, onProgressUpdate), this); } public async Task<string> SendAsync(string message) { bool isCompleted = false; string result = string.Empty; Action<bool, string> onComplete = (success, str) => { isCompleted = true; if (success) result = str; }; EditorCoroutineUtility.StartCoroutine(Request(message, onComplete, null), this); while (!isCompleted) { await Task.Delay(10); } return result; } private IEnumerator Request(string input, Action<bool, string> onComplete, Action<float> onProgressUpdate) { var msg = new Message() { role = UserId, content = input, }; requestData.AppendChat(msg); messageHistory.Add(msg); using (webRequest = new UnityWebRequest(ChatgptUrl, "POST")) { var jsonDt = UtilityBuiltin.Json.ToJson(requestData); Debug.Log(jsonDt); byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonDt); webRequest.uploadHandler = new UploadHandlerRaw(bodyRaw); webRequest.downloadHandler = new DownloadHandlerBuffer(); webRequest.SetRequestHeader("Content-Type", "application/json"); webRequest.SetRequestHeader("Authorization", $"Bearer {this.ApiKey}"); webRequest.certificateHandler = new ChatGPTWebRequestCert(); var req = webRequest.SendWebRequest(); while (!webRequest.isDone) { onProgressUpdate?.Invoke((webRequest.downloadProgress + webRequest.uploadProgress) / 2f); yield return null; } if (webRequest.result != UnityWebRequest.Result.Success) { Debug.LogError($"---------ChatGPT请求失败:{webRequest.error}---------"); onComplete?.Invoke(false, string.Empty); } else { var json = webRequest.downloadHandler.text; Debug.Log(json); try { ChatCompletion result = UtilityBuiltin.Json.ToObject<ChatCompletion>(json); int lastChoiceIdx = result.choices.Count - 1; var replyMsg = result.choices[lastChoiceIdx].message; replyMsg.content = replyMsg.content.Trim(); messageHistory.Add(replyMsg); onComplete?.Invoke(true, replyMsg.content); } catch (System.Exception e) { Debug.LogError($"---------ChatGPT返回数据解析失败:{e.Message}---------"); onComplete?.Invoke(false, e.Message); } } webRequest.Dispose(); webRequest = null; } } public void NewChat() { requestData.ClearChat(); messageHistory.Clear(); } public bool IsSelfMessage(Message msg) { return this.UserId.CompareTo(msg.role) == 0; } } class ChatGPTRequestData { public List<Message> messages; public string model; public float temperature; public ChatGPTRequestData(string model, float temper) { this.model = model; this.temperature = temper; this.messages = new List<Message>(); } /// <summary> /// 同一话题追加会话内容 /// </summary> /// <param name="chatMsg"></param> /// <returns></returns> public ChatGPTRequestData AppendChat(Message msg) { this.messages.Add(msg); return this; } /// <summary> /// 清除聊天历史(结束一个话题), 相当于新建一个聊天话题 /// </summary> public void ClearChat() { this.messages.Clear(); } } class ChatGPTWebRequestCert : UnityEngine.Networking.CertificateHandler { protected override bool ValidateCertificate(byte[] certificateData) { //return base.ValidateCertificate(certificateData); return true; } } class Usage { public int prompt_tokens; public int completion_tokens; public int total_tokens; } public class Message { public string role; public string content; } class Choice { public Message message; public string finish_reason; public int index; } class ChatCompletion { public string id; public string @object; public int created; public string model; public Usage usage; public List<Choice> choices; }}

使用方法一, 同步获取结果:

var ai = new ChatGPT();var str = await ai.SendAsync("你好");Debug.Log(str);

 使用方法二, 异步获取结果:

new ChatGPT().Send("你好", (success, message) => { if (success) Debug.Log(message); }, requestProgress => { Debug.Log($"Request progress:{requestProgress}"); });三,基于上面的ChatGPT类实现一个ChatGPT聊天窗口

为什么要写个聊天窗口:

1. https://chat.openai.com/chat 网页版登陆锁IP,禁止大陆IP登录,并且会验证时区,如果用美国的节点时区时间对不上拒绝登录,所以每次只能用台湾省的节点登录。

2. 虽然登录成功后不科学也能用,但是同一话题很快就会超时无法应答,刷新界面或新建话题才能正常使用,总之非常鸡肋。

而通过开放接口就没有这些问题,API请求会更加爽快。

聊天窗口功能设计:

1. 需要一个滚动列表展示双方对话记录,对话文本内容支持选择复制。

2. 问题输入框和发送按钮、新建话题(清除话题对话)

3. 对话历史存档。

代码实现,比较简单就不解释了,直接上源码:

using System;using UnityEditor;using UnityEngine;namespace UnityGameFramework.Editor.AIAssistant{ [EditorToolMenu("AI助手/ChatGPT", 5)] public class ChatGPTWindow : EditorToolBase { public override string ToolName => "ChatGPT"; Vector2 scrollPos = Vector2.zero; ChatGPT ai; private bool settingFoldout = false; string message; const string aiRoleName = "AI"; private float chatBoxWidthRatio = 0.85f; private float iconSizeRatio = 0.6f; private float chatBoxPadding = 20; private float chatBoxEdgePadding = 10; GUIStyle myChatStyle; GUIStyle aiChatStyle; GUIStyle aiIconStyle; GUIStyle myIconStyle; GUIStyle txtAreaStyle; GUIContent chatContent; bool isEditorInitialized = false; private float scrollViewHeight; private void OnEnable() { EditorApplication.update += OnEditorUpdate; ai = new ChatGPT(AppBuildSettings.Instance.ChatGPTKey); ai.ChatGPTRandomness = AppBuildSettings.Instance.ChatGPTRandomness; chatContent = new GUIContent(); ai.RestoreChatHistory(); } private void OnEditorUpdate() { if (EditorApplication.isCompiling || EditorApplication.isUpdating) { return; } try { InitGUIStyles(); isEditorInitialized = true; EditorApplication.update -= OnEditorUpdate; } catch (Exception) { } } private void InitGUIStyles() { aiChatStyle = new GUIStyle(EditorStyles.selectionRect); aiChatStyle.wordWrap = true; aiChatStyle.normal.textColor = Color.white; aiChatStyle.fontSize = 18; aiChatStyle.alignment = TextAnchor.MiddleLeft; myChatStyle = new GUIStyle(EditorStyles.helpBox); myChatStyle.wordWrap = true; myChatStyle.normal.textColor = Color.white; myChatStyle.fontSize = 18; myChatStyle.alignment = TextAnchor.MiddleLeft; txtAreaStyle = new GUIStyle(EditorStyles.textArea); txtAreaStyle.fontSize = 18; aiIconStyle = new GUIStyle(); aiIconStyle.wordWrap = true; aiIconStyle.alignment = TextAnchor.MiddleCenter; aiIconStyle.fontSize = 18; aiIconStyle.fontStyle = FontStyle.Bold; aiIconStyle.normal.textColor = Color.black; aiIconStyle.normal.background = EditorGUIUtility.FindTexture("sv_icon_dot5_pix16_gizmo"); myIconStyle = new GUIStyle(aiIconStyle); myIconStyle.normal.background = EditorGUIUtility.FindTexture("sv_icon_dot2_pix16_gizmo"); } private void OnDisable() { ai.SaveChatHistory(); } private void OnGUI() { if (!isEditorInitialized) return; EditorGUILayout.BeginVertical(); { scrollPos = EditorGUILayout.BeginScrollView(scrollPos); { scrollViewHeight = 0; foreach (var msg in ai.MessageHistory) { var msgRect = EditorGUILayout.BeginVertical(); { EditorGUILayout.BeginHorizontal(); { bool isMyMsg = ai.IsSelfMessage(msg); var labelStyle = isMyMsg ? myChatStyle : aiChatStyle; chatContent.text = msg.content; float chatBoxWidth = this.position.width * chatBoxWidthRatio; float iconSize = (this.position.width - chatBoxWidth) * iconSizeRatio; float chatBoxHeight = Mathf.Max(iconSize, chatBoxEdgePadding + labelStyle.CalcHeight(chatContent, chatBoxWidth - chatBoxEdgePadding)); if (isMyMsg) { GUILayout.FlexibleSpace(); } else { EditorGUILayout.LabelField(aiRoleName, aiIconStyle, GUILayout.Width(iconSize), GUILayout.Height(iconSize)); } EditorGUILayout.SelectableLabel(msg.content, labelStyle, GUILayout.Width(chatBoxWidth), GUILayout.Height(chatBoxHeight)); if (!isMyMsg) { GUILayout.FlexibleSpace(); } else { EditorGUILayout.LabelField(msg.role, myIconStyle, GUILayout.Width(iconSize), GUILayout.Height(iconSize)); } EditorGUILayout.EndHorizontal(); } EditorGUILayout.EndVertical(); } EditorGUILayout.Space(chatBoxPadding); scrollViewHeight += msgRect.height; } EditorGUILayout.EndScrollView(); } if (ai.IsRequesting) { var barWidth = position.width * 0.8f; var pBarRect = new Rect((position.width - barWidth) * 0.5f, (position.height - 30f) * 0.5f, barWidth, 30f); EditorGUI.ProgressBar(pBarRect, ai.RequestProgress, $"请求进度:{ai.RequestProgress:P2}"); } GUILayout.FlexibleSpace(); if (settingFoldout = EditorGUILayout.Foldout(settingFoldout, "展开设置项:")) { EditorGUILayout.BeginVertical("box"); { EditorGUILayout.BeginHorizontal(); { EditorGUILayout.LabelField("ChatGPT API Key:", GUILayout.Width(170)); AppBuildSettings.Instance.ChatGPTKey = EditorGUILayout.TextField(AppBuildSettings.Instance.ChatGPTKey); EditorGUILayout.EndHorizontal(); } EditorGUILayout.BeginHorizontal(); { EditorGUILayout.LabelField("结果随机性:", GUILayout.Width(170)); ai.ChatGPTRandomness = AppBuildSettings.Instance.ChatGPTRandomness = EditorGUILayout.Slider(AppBuildSettings.Instance.ChatGPTRandomness, 0, 2); EditorGUILayout.EndHorizontal(); } EditorGUILayout.EndVertical(); } } //EditorGUILayout.LabelField(scrollPos.ToString()); EditorGUILayout.BeginHorizontal(); { message = EditorGUILayout.TextArea(message, txtAreaStyle, GUILayout.MinHeight(80)); EditorGUI.BeginDisabledGroup(ai.IsRequesting); { if (GUILayout.Button("发送消息", GUILayout.MaxWidth(120), GUILayout.Height(80))) { if (!string.IsNullOrWhiteSpace(message)) { ai.Send(message, OnChatGPTMessage); } } if (GUILayout.Button("新话题", GUILayout.MaxWidth(80), GUILayout.Height(80))) { ai.NewChat(); } EditorGUI.EndDisabledGroup(); } EditorGUILayout.EndHorizontal(); } EditorGUILayout.EndVertical(); } } private void OnChatGPTMessage(bool arg1, string arg2) { scrollPos.y = scrollViewHeight; if (arg1) { message = string.Empty; } Repaint(); } }}

添加代码后,Toolbar的Tools工具栏会自动识别这个工具菜单,点击即可打开ChatGPT对话窗口:

 ChatGPT应用展望:

下一步就是为ChatGPT赋予双手,添加各种指令Handler。比如生成json文件、生成语言国际化Excel文件、修改优化代码、生成代码文件、生成Shader、一键拼UI等等。

分为三个模块:

1. 描述文本(发送给ChatGPT)

2. 动态追加描述内容:有时需要追加一些文本数据,比如让ChatGPT优化一段代码,需要动态追加把代码补充到描述文本。

3. 结果解析。得到目标结果,使用Handler解析ChatGPT返回结果,达成某种功能。ChatGPT返回的代码或json等数据都会用标签包住,通过解析标签就可以生成各种类型的文件。

最终就可以不用写程序,只写问题的描述文本,确保能从ChatGPT得到满意答案就可以实现某项功能。想要新增新的工具,扩展新的功能只需要在文件中添加修改问题描述文本即可。

比如语言国际化,我通过问题描述让ChatGPT从工程代码中扫描所有语言本地化函数GF.Localization.GetText()传入的国际化文本,并且把文本翻译成中文,把结果以key,value键值对保存输出json文件。最后我得到了ChatGPT返回的诸如{"Hello":”你好“}的所有国际化文本和翻译结果。

然后我只需要解析ChatGPT返回结果,生成语言国际化文件到工程中就完成了AI自动处理语言国际化的问题。

本文链接地址:https://www.jiuchutong.com/zhishi/298909.html 转载请保留说明!

上一篇:Chatgpt私有化部署(全流程)

下一篇:Vue中splice()方法:实现对数组进行增删改的操作(vue的slice)

  • 微信先拉黑再删除会怎样(微信先拉黑再删除还能加回来吗)

    微信先拉黑再删除会怎样(微信先拉黑再删除还能加回来吗)

  • 抖音里擦拭变美该怎么拍(抖音擦拭变美怎么拍)

    抖音里擦拭变美该怎么拍(抖音擦拭变美怎么拍)

  • 苹果手机系统在哪里看(苹果手机系统在哪里更新)

    苹果手机系统在哪里看(苹果手机系统在哪里更新)

  • 苹果手机一键截屏怎么设置(苹果手机一键截图在哪里)

    苹果手机一键截屏怎么设置(苹果手机一键截图在哪里)

  • 微信左下角显示1,却没有未读消息(微信左下角老是有个1)

    微信左下角显示1,却没有未读消息(微信左下角老是有个1)

  • 怎么删除撤回消息字迹(怎么删除撤回消息字迹微信)

    怎么删除撤回消息字迹(怎么删除撤回消息字迹微信)

  • 钉钉手机直播可以共享屏幕吗(钉钉手机直播可以连麦吗)

    钉钉手机直播可以共享屏幕吗(钉钉手机直播可以连麦吗)

  • 手机充到100马上拔还是一会拔(手机充到100继续充会怎样)

    手机充到100马上拔还是一会拔(手机充到100继续充会怎样)

  • 23a12v电池是几号电池(23a 电池)

    23a12v电池是几号电池(23a 电池)

  • 苹果手机wps不能以文件发送(苹果手机wps不能直接打开)

    苹果手机wps不能以文件发送(苹果手机wps不能直接打开)

  • 牛卡是什么手机卡(牛卡是什么软件)

    牛卡是什么手机卡(牛卡是什么软件)

  • 抖音无声音怎么回事(抖音没有声音怎么弄)

    抖音无声音怎么回事(抖音没有声音怎么弄)

  • 确认iphone密码验证失败(确认iphone密码验证失败是啥意思)

    确认iphone密码验证失败(确认iphone密码验证失败是啥意思)

  • 为什么网盘里的文件打不开(为什么网盘里的图片很模糊)

    为什么网盘里的文件打不开(为什么网盘里的图片很模糊)

  • 华为p9支持快充闪充吗(华为p9快充怎么开启)

    华为p9支持快充闪充吗(华为p9快充怎么开启)

  • 固态nvme需要开ahci吗(nvme固态和sata固态开机速度对比)

    固态nvme需要开ahci吗(nvme固态和sata固态开机速度对比)

  • 红米note8pro上市时间(红米note8pro 发布)

    红米note8pro上市时间(红米note8pro 发布)

  • 查找我的iphone要一直开着吗(查找我的iPhone要登陆iCloud)

    查找我的iphone要一直开着吗(查找我的iPhone要登陆iCloud)

  • 二维码使用了什么识别方式(二维码用处)

    二维码使用了什么识别方式(二维码用处)

  • 目前最窄下巴的手机(目前最窄下巴的女人面相)

    目前最窄下巴的手机(目前最窄下巴的女人面相)

  • airpods是自动充电吗(airpodspro自动充电)

    airpods是自动充电吗(airpodspro自动充电)

  • vivox27精英版有什么区别(vivox27精英版有256 g吗)

    vivox27精英版有什么区别(vivox27精英版有256 g吗)

  • vue实现思维导图(vue思维导图怎么下载)

    vue实现思维导图(vue思维导图怎么下载)

  • 基于URLOS快速安装Discuz论坛(urlparse安装)

    基于URLOS快速安装Discuz论坛(urlparse安装)

  • 进项税额转出要交企业所得税吗
  • 耕地占用税减半政策
  • 营利性医疗机构筹建是什么意思
  • 一般纳税人条件要求2020
  • 公司组织旅游的费用要交个税
  • 红字信息表状态是B900071
  • 季末资产总额填错了要紧吗
  • 培训机构开发票不能开公司抬头吗
  • 贴现利息支付方式
  • 当天收入支出日报表怎么做
  • 个人投资款怎么入账
  • 由于红字发票生成红字进项税转出如何做账?
  • 简易计税算税收优惠吗
  • 员工自己承担的商业保险费是多少
  • 金穗开发票时怎样添加商品?
  • 开发票时税点开里怎么算?
  • 小规模文化交流活动
  • 单位没车能用停车票不能用加油票吗?
  • 外出什么意思?
  • 减税降费各项政策
  • 税收分类编码选错了会罚款么
  • 小规模纳税人增值税减免
  • 研发成功的产品卖出去怎么做账
  • 其他应付款不用付了会计分录
  • 多结转成本会导致什么
  • 施工企业会计制度有哪些
  • 少数股东持股比例
  • 印花税减半征收优惠政策2023
  • xp系统可以安装cad吗
  • 收到商品的会计分录怎么写
  • 借支单还款后借支单要还么
  • php image
  • 保险公司的展业方式
  • 交易性金融资产的入账价值怎么算
  • 进货发票怎么抵税
  • PHP:imagecolorclosest()的用法_GD库图像处理函数
  • yii框架运行原理
  • 四川黄龙风景名胜区停车收费标准
  • 公司购买食品属于什么费用
  • php的两种运行方式
  • 手把手教你如何从一无所有到财务自由
  • 对抗生成网络算法
  • win11 退回
  • 用ipconfig/all命令不能显示
  • xml 入门
  • 企业应采用
  • 金税盘v2.0.41怎么扫码开票
  • sql有数据保护功能
  • phpcms二次开发教程
  • 个人所得税隔月交么
  • 商业承兑汇票贴现什么意思
  • 公司收取的门禁费用
  • sql2008用ip连接不了
  • 电影院租金一般多少为合理
  • 有限合伙企业分红原则
  • 小企业营业外支出坏账损失
  • 用友为什么引入不了账套
  • 建厂期间购买材料怎么办
  • 营改增后建筑业税率变化情况
  • 销项负数发票怎么冲减成本
  • MySQL execute、executeUpdate、executeQuery三者的区别
  • 深入理解mysql主从原理32讲
  • bios解除
  • xp系统本地用户和组在哪里
  • CentOS安装scp命令详解
  • win8 怎么样
  • win7系统如何隐藏盘符
  • 围绕摄像机旋转怎么设置
  • 细说javascript
  • JavaScript中的变量名不区分大小写
  • python提供三种基本数值类型
  • linux同名文件
  • unity3ds
  • javascript例题
  • nodejs function
  • 安卓手机如何查
  • 个税汇算清缴申报方式选哪个
  • 个人所得税法实施条例2011
  • 买新房子需要交契税吗
  • 苏州虎丘区税务局在哪里
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设