【Unity编辑器扩展】语言国际化工具,生成多语言Excel自动翻译并导出多语言表

工具效果如图:

 多语言是个非常简单且常用的功能。但是重复工作量大,程序手动把多语言Key配置到多语言表经常会出现错漏,或者几经改版,有些Key已经不用却没有剔除,久而久之造成冗余。这中简单且重复的工作必须让工具来完成。

功能设计:

多语言通过Key,Value的形式保存,通过多语言API GF.Localization.GetText(Key)获取当前语言对应的Value值。

1. 一键扫描多语言文本。扫描prefab资源、excel数据表以及代码里的多语言文本,这里扫描的就是多语言的Key。

2. 多语言列表(添加到此列表即为支持该语言)。点击"+"号弹出未添加的语言列表,点击对应语言添加到语言列表。多语言列表的第一项记为“母语”,其它语言以“母语”为基准翻译为对应语言。

3. 一键翻译。由于ChatGPT请求次数有限制,Google翻译需要魔法上网。最终为了体验选择了接入百度翻译。我们只需要把“母语”的Value填写好,其它语言直接通过百度翻译生成Value。

4. 由于机器翻译结果还需要人工审核修正。为了方便,工具先生成多语言Excel文件,方便交给其它部门翻译。项目真正使用的多语言文件是工具将多语言Excel导出的json文件。

5. 多语言工具以列表的形式显示“母语”,可以手动修改Key,Value值。

6. 细节体验优化。由于每次扫描结果会覆盖原多语言文件,可以通过勾选【锁定】强制保留该行。同时也在Excel的第一列生成了【锁定】勾选框方便策划操作。

多语言”母语“

基于”母语“自动生成/翻译的其它语言

 7. 由于百度翻译免费翻译字节数有上限,为了节省翻译字节。一键翻译默认只翻译Value值为空白的行,如果想强制翻译所有行可以通过一键翻译的下拉按钮强制翻译全部行。

一键生成的多语言Excel

自动导出多语言Excel为json文件

功能实现:

1. 一键扫描多语言文本:

①扫描Prefab资源上的多语言文本:

GameFramework框架提供了UIStringKey专门用来填写多语言文本Key, 所以只需要从所有Prefab上获取UIStringKey脚本上填写的Key即可。

 扫描prefab上的多语言Key:

/// <summary>/// 扫描Prefab中的国际化语言/// </summary>public static List<string> ScanLocalizationTextFromPrefab(Action<string, int, int> onProgressUpdate = null){var assetGUIDs = AssetDatabase.FindAssets("t:Prefab", ConstEditor.PrefabsPath);List<string> keyList = new List<string>();int totalCount = assetGUIDs.Length;for (int i = 0; i < totalCount; i++){string path = AssetDatabase.GUIDToAssetPath(assetGUIDs[i]);var pfb = AssetDatabase.LoadAssetAtPath<GameObject>(path);onProgressUpdate?.Invoke(path, totalCount, i);var keyArr = pfb.GetComponentsInChildren<UnityGameFramework.Runtime.UIStringKey>(true);foreach (var newKey in keyArr){if (string.IsNullOrWhiteSpace(newKey.Key) || keyList.Contains(newKey.Key)) continue;keyList.Add(newKey.Key);}}return keyList;}

② 扫描数据表Excel中的多语言文本:

首先需要标记数据表多语言列,在数据表备注行用”i18n“标识,程序就自动扫描添加标识的列:

 扫描excel中的多语言文本:

/// <summary>/// 从DataTable Excel文件扫描本地化文本/// </summary>/// <param name="onProgressUpdate"></param>/// <returns></returns>public static List<string> ScanLocalizationTextFromDataTables(Action<string, int, int> onProgressUpdate = null){List<string> keyList = new List<string>();var appConfig = AppConfigs.GetInstanceEditor();var mainTbFullFiles = GameDataGenerator.GameDataExcelRelative2FullPath(GameDataType.DataTable, appConfig.DataTables);var tbFullFiles = GameDataGenerator.GetGameDataExcelWithABFiles(GameDataType.DataTable, mainTbFullFiles);//同时扫描AB测试表for (int i = 0; i < tbFullFiles.Length; i++){var excelFile = tbFullFiles[i];var fileInfo = new FileInfo(excelFile);if (!fileInfo.Exists) continue;onProgressUpdate?.Invoke(excelFile, tbFullFiles.Length, i);string tmpExcelFile = UtilityBuiltin.ResPath.GetCombinePath(fileInfo.Directory.FullName, GameFramework.Utility.Text.Format("{0}.temp", fileInfo.Name));try{File.Copy(excelFile, tmpExcelFile, true);using (var excelPackage = new ExcelPackage(tmpExcelFile)){var excelSheet = excelPackage.Workbook.Worksheets.FirstOrDefault();if (excelSheet.Dimension.End.Row >= 4){for (int colIndex = excelSheet.Dimension.Start.Column; colIndex <= excelSheet.Dimension.End.Column; colIndex++){if (excelSheet.GetValue<string>(4, colIndex)?.ToLower() != EXCEL_I18N_TAG){continue;}for (int rowIndex = 5; rowIndex <= excelSheet.Dimension.End.Row; rowIndex++){string langKey = excelSheet.GetValue<string>(rowIndex, colIndex);if (string.IsNullOrWhiteSpace(langKey) || keyList.Contains(langKey)) continue;keyList.Add(langKey);}}}}}catch (Exception e){Debug.LogError($"扫描数据表本地化文本失败!文件:{excelFile}, Error:{e.Message}");}if (File.Exists(tmpExcelFile)){File.Delete(tmpExcelFile);}}return keyList;}

③ 扫描代码中的多语言文本:

原理:搜索代码中所有调用国际化函数GF.Localization.GetText(string key)的地方,然后把调用时传入参数key的字符串值扫描出来。

首先只能通过静态解析cs代码,获取函数调用时传入参数的值。这比想象中复杂得多,比如:

1. 如果传入的是字符串常量很容易获取,但如果传入的是变量,就需要找到该变量的初始值赋值,变量又涉及到局部变量和全局变量。

2. 如果key中包含特殊字符会影响正则表达式的匹配,所以不能使用正则表达式。

3. 注释的代码不应该扫描。

为了工具安全完善,最终选择了用"高射炮打蚊子", 使用微软Roslyn作为CSharp静态解析库。但是这个解析库依赖dll太多直接导入Unity会有各种冲突,为了Unity工程的兼容性索性写个C#命令行程序,由Unity代码调用命令行程序扫描代码,把扫描结果存入缓存文件供Unity读取使用。而且命令行程序可以发布跨平台包,不用担心跨平台问题。

用Visual Studio新建C#命令行程序,为工程添加CodeAnalysis.CSharp库:

 命令行程序代码:

其中命令行args, 第一参数是cs代码文件名(完整路径),第二个参数是扫描结果输出到的文件(通过文本追加的方式把扫描结果列表追加到文本文件),剩余参数是目标函数名,因为获取国际化文本的函数可能有多个。

internal class Program{static int Main(string[] args){try{string csFile = args[0];string outputFile = args[1];List<string> funcNames = new List<string>();for (int i = 2; i < args.Length; i++){funcNames.Add(args[i]);}List<string> resultList = new List<string>();if ((File.GetAttributes(csFile) & FileAttributes.Directory) == FileAttributes.Directory){//如果传的是文件夹,扫描该文件夹下的所有cs文件var csFiles = Directory.GetFiles(csFile, "*.cs", SearchOption.AllDirectories);foreach (var item in csFiles){var codeText = File.ReadAllText(item);var strList = GetTextArgumentValues(codeText, funcNames);if (strList.Count > 0){resultList.AddRange(strList);}}}else{if (File.Exists(csFile)){var codeText = File.ReadAllText(csFile);var strList = GetTextArgumentValues(codeText, funcNames);if (strList.Count > 0){resultList.AddRange(strList);}}}resultList.Distinct();//去重resultList.RemoveAll(x => string.IsNullOrWhiteSpace(x));Console.WriteLine($"\n\n--------------Result List Count:{resultList.Count}--------------");for (int i = 0; i < resultList.Count; i++){var str = resultList[i];Console.WriteLine($"{i + 1}.\t[{str}]");}Console.WriteLine("--------------Result List End--------------");if (resultList.Count > 0){File.AppendAllLines(outputFile, resultList);}return 0;}catch (Exception err){Console.WriteLine($"Error:{err}");}return 1;}public static List<string> GetTextArgumentValues(string codeText, List<string> funcNames){List<string> argumentValues = new List<string>();SyntaxTree tree = CSharpSyntaxTree.ParseText(codeText);var root = (CompilationUnitSyntax)tree.GetRoot();var methodCalls = root.DescendantNodes().OfType<InvocationExpressionSyntax>().Where(i =>{return funcNames.Contains(i.Expression.ToString());});var compilation = CSharpCompilation.Create(typeof(object).Assembly.FullName, new SyntaxTree[] { tree }).WithOptions(new CSharpCompilationOptions(OutputKind.ConsoleApplication)).AddReferences(MetadataReference.CreateFromFile(typeof(object).Assembly.Location));var semanticModel = compilation.GetSemanticModel(tree);var methodCallsArr = methodCalls.ToArray();for (int i = 0; i < methodCallsArr.Length; i++){var call = methodCallsArr[i];var argumentList = call.ArgumentList;if (argumentList.Arguments.Count >= 1){var argExp = argumentList.Arguments[0].Expression;if (argExp is LiteralExpressionSyntax literal){Console.WriteLine($"{call} ------> {literal.Token.ValueText}");argumentValues.Add(literal.Token.ValueText);}else if (argExp is IdentifierNameSyntax variable){SymbolInfo symbolInfo = semanticModel.GetSymbolInfo(variable);if (symbolInfo.Symbol is IFieldSymbol fieldSymbol){if (fieldSymbol.HasConstantValue){argumentValues.Add((string)fieldSymbol.ConstantValue);Console.WriteLine($"{call} ------> {fieldSymbol.ConstantValue}");}}else if (symbolInfo.Symbol is ILocalSymbol localSymbol){var localVar = localSymbol.DeclaringSyntaxReferences.Last()?.GetSyntax() as VariableDeclaratorSyntax;if (localVar != null && localVar.Initializer != null){var localVarValue = semanticModel.GetConstantValue(localVar.Initializer.Value);if (localVarValue.Value != null){argumentValues.Add((string)localVarValue.Value);Console.WriteLine($"{call} ------> {localVarValue.Value}");}}}}}}return argumentValues;}}

2.  接入百度翻译开放API,实现一键翻译多语言

百度翻译官方接入文档:百度翻译开放平台

 注册后在开发者后台可以看到App id和密钥,用于发送翻译WebRequest请求参数。

开发者实名认证后可以变更为高级版,高级版每月可享受免费翻译100万个字符,相当于50万个汉字。一次请求能翻译6000个字符(3000汉字),每秒请求上限10次。

 以上限制就需要翻译时需要一次性塞入多条待翻译句子并且不能超过每次请求的上限字节。

比较坑的是百度翻译以换行符拆分句子,如果国际化文本中包含换行符翻译结果就不是我们想要的:

 所以我使用一个特殊字符"↕"做为自己的多条句子之间的分割符,拿到翻译结果再用"↕"分割字符串得到句子数组。

百度翻译上行字段:

var randomCode = System.DateTime.Now.Ticks.ToString();
var strBuilder = new StringBuilder();strBuilder.Append(BAIDU_TRANS_URL);strBuilder.AppendFormat("q={0}", UnityWebRequest.EscapeURL(srcText));strBuilder.AppendFormat("&from={0}", GetBaiduLanguage(srcLang) ?? "auto"); //自动识别源文字语言strBuilder.AppendFormat("&to={0}", GetBaiduLanguage(targetLang));//翻译到目标语言strBuilder.AppendFormat("&appid={0}", EditorToolSettings.Instance.BaiduTransAppId);strBuilder.AppendFormat("&salt={0}", randomCode);strBuilder.AppendFormat("&sign={0}", GenerateBaiduSign(srcText, randomCode));

生成签名:

/// <summary>/// 生成百度翻译请求签名/// </summary>/// <param name="srcText"></param>/// <returns></returns>private static string GenerateBaiduSign(string srcText, string randomCode){MD5 md5 = MD5.Create();var fullStr = GameFramework.Utility.Text.Format("{0}{1}{2}{3}", EditorToolSettings.Instance.BaiduTransAppId, srcText, randomCode, EditorToolSettings.Instance.BaiduTransSecretKey);byte[] byteOld = Encoding.UTF8.GetBytes(fullStr);byte[] byteNew = md5.ComputeHash(byteOld);StringBuilder sb = new StringBuilder();foreach (byte b in byteNew){sb.Append(b.ToString("x2"));}return sb.ToString();}

百度翻译语言代号获取,用ChatGPT帮我生成函数,结果只有几种是对的,无奈只能人工找对照表修改代号:

中文首字母名称代码语种检测名称代码语种检测名称代码语种检测
A阿拉伯语ara爱尔兰语gle奥克语oci
阿尔巴尼亚语alb阿尔及利亚阿拉伯语arq阿肯语aka
阿拉贡语arg阿姆哈拉语amh阿萨姆语asm
艾马拉语aym阿塞拜疆语aze阿斯图里亚斯语ast
奥塞梯语oss爱沙尼亚语est奥杰布瓦语oji
奥里亚语ori奥罗莫语orm
B波兰语pl波斯语per布列塔尼语bre
巴什基尔语bak巴斯克语baq巴西葡萄牙语pot
白俄罗斯语bel柏柏尔语ber邦板牙语pam
保加利亚语bul北方萨米语sme北索托语ped
本巴语bem比林语bli比斯拉马语bis
俾路支语bal冰岛语ice波斯尼亚语bos
博杰普尔语bho
C楚瓦什语chv聪加语tso
D丹麦语dan德语de鞑靼语tat
掸语sha德顿语tet迪维希语div
低地德语log
E俄语ru
F法语fra菲律宾语fil芬兰语fin
梵语san弗留利语fri富拉尼语ful
法罗语fao
G盖尔语gla刚果语kon高地索布语ups
高棉语hkm格陵兰语kal格鲁吉亚语geo
古吉拉特语guj古希腊语gra古英语eno
瓜拉尼语grn
H韩语kor荷兰语nl胡帕语hup
哈卡钦语hak海地语ht黑山语mot
豪萨语hau
J吉尔吉斯语kir加利西亚语glg加拿大法语frn
加泰罗尼亚语cat捷克语cs
K卡拜尔语kab卡纳达语kan卡努里语kau
卡舒比语kah康瓦尔语cor科萨语xho
科西嘉语cos克里克语cre克里米亚鞑靼语cri
克林贡语kli克罗地亚语hrv克丘亚语que
克什米尔语kas孔卡尼语kok库尔德语kur
L拉丁语lat老挝语lao罗马尼亚语rom
拉特加莱语lag拉脱维亚语lav林堡语lim
林加拉语lin卢干达语lug卢森堡语ltz
卢森尼亚语ruy卢旺达语kin立陶宛语lit
罗曼什语roh罗姆语ro逻辑语loj
M马来语may缅甸语bur马拉地语mar
马拉加斯语mg马拉雅拉姆语mal马其顿语mac
马绍尔语mah迈蒂利语mai曼克斯语glv
毛里求斯克里奥尔语mau毛利语mao孟加拉语ben
马耳他语mlt苗语hmn
N挪威语nor那不勒斯语nea南恩德贝莱语nbl
南非荷兰语afr南索托语sot尼泊尔语nep
P葡萄牙语pt旁遮普语pan帕皮阿门托语pap
普什图语pus
Q齐切瓦语nya契维语twi切罗基语chr
R日语jp瑞典语swe
S萨丁尼亚语srd萨摩亚语sm塞尔维亚-克罗地亚语sec
塞尔维亚语srp桑海语sol僧伽罗语sin
世界语epo书面挪威语nob斯洛伐克语sk
斯洛文尼亚语slo斯瓦希里语swa塞尔维亚语(西里尔)src
索马里语som
T泰语th土耳其语tr塔吉克语tgk
泰米尔语tam他加禄语tgl提格利尼亚语tir
泰卢固语tel突尼斯阿拉伯语tua土库曼语tuk
W乌克兰语ukr瓦隆语wln威尔士语wel
文达语ven沃洛夫语wol乌尔都语urd
X西班牙语spa希伯来语heb希腊语el
匈牙利语hu西弗里斯语fry西里西亚语sil
希利盖农语hil下索布语los夏威夷语haw
新挪威语nno西非书面语nqo信德语snd
修纳语sna宿务语ceb叙利亚语syr
巽他语sun
Y英语en印地语hi印尼语id
意大利语it越南语vie意第绪语yid
因特语ina亚齐语ach印古什语ing
伊博语ibo伊多语ido约鲁巴语yor
亚美尼亚语arm伊努克提图特语iku伊朗语ir
Z中文(简体)zh中文(繁体)cht中文(文言文)wyw
中文(粤语)yue扎扎其语zaz中古法语frm
祖鲁语zul爪哇语jav

无私献上获取百度翻译语言代码:

/// <summary>/// 根据语言类型返回对应的百度语言缩写/// </summary>/// <param name="lang"></param>/// <returns></returns>/// <exception cref="ArgumentException"></exception>public static string GetBaiduLanguage(Language lang){switch (lang){case Language.Afrikaans:return "afr";case Language.Albanian:return "alb";case Language.Arabic:return "ara";case Language.Basque:return "baq";case Language.Belarusian:return "bel";case Language.Bulgarian:return "bul";case Language.Catalan:return "cat";case Language.ChineseSimplified:return "zh";case Language.ChineseTraditional:return "cht";case Language.Croatian:return "hrv";case Language.Czech:return "cs";case Language.Danish:return "dan";case Language.Dutch:return "nl";case Language.English:return "en";case Language.Estonian:return "est";case Language.Faroese:return "fao";case Language.Finnish:return "fin";case Language.French:return "fra";case Language.Georgian:return "geo";case Language.German:return "de";case Language.Greek:return "el";case Language.Hebrew:return "heb";case Language.Hungarian:return "hu";case Language.Icelandic:return "ice";case Language.Indonesian:return "id";case Language.Italian:return "it";case Language.Japanese:return "jp";case Language.Korean:return "kor";case Language.Latvian:return "lav";case Language.Lithuanian:return "lit";case Language.Macedonian:return "mac";case Language.Malayalam:return "may";case Language.Norwegian:return "nor";case Language.Persian:return "per";case Language.Polish:return "pl";case Language.PortugueseBrazil:return "pt";case Language.PortuguesePortugal:return "pt";case Language.Romanian:return "rom";case Language.Russian:return "ru";case Language.SerboCroatian:return "sec";case Language.SerbianCyrillic:return "src";case Language.SerbianLatin:return "srp";case Language.Slovak:return "sk";case Language.Slovenian:return "slo";case Language.Spanish:return "spa";case Language.Swedish:return "swe";case Language.Thai:return "th";case Language.Turkish:return "tr";case Language.Ukrainian:return "ukr";case Language.Vietnamese:return "vie";default:throw new NotSupportedException($"暂不支持该语言:{lang}");}}

接入百度翻译示例代码:

private static void TranslateAndSave(List<LocalizationText> mainLangTexts, Language srcLang, List<LocalizationText> langTexts, Language targetLang, bool forceAll){int curTransIdx = 0;while (curTransIdx < langTexts.Count){string totalText = "";List<int> totalTextIdx = new List<int>();for (; curTransIdx < langTexts.Count; curTransIdx++){var text = langTexts[curTransIdx];string srcText = "";if (forceAll){var mainText = mainLangTexts.FirstOrDefault(tmpItm => tmpItm.Key.CompareTo(text.Key) == 0);if (mainText != null && !string.IsNullOrWhiteSpace(mainText.Value)){srcText = mainText.Value;}}else{if (string.IsNullOrWhiteSpace(text.Value)){var mainText = mainLangTexts.FirstOrDefault(tmpItm => tmpItm.Key.CompareTo(text.Key) == 0);if (mainText != null && !string.IsNullOrWhiteSpace(mainText.Value)){srcText = mainText.Value;}}}if (!string.IsNullOrWhiteSpace(srcText)){if ((totalText.Length + srcText.Length) > EditorToolSettings.Instance.BaiduTransMaxLength){curTransIdx -= 1; //如果长度超了下个请求接着这行break;}totalText += srcText + TRANS_SPLIT_TAG;totalTextIdx.Add(curTransIdx);}}if (string.IsNullOrWhiteSpace(totalText)){curTransIdx++;//如果一行字数就超过上限则跳过翻译这行continue;}totalText = totalText.Substring(0, totalText.Length - TRANS_SPLIT_TAG.Length);//去掉结分隔符TMP_EditorCoroutine.StartCoroutine(TranslateCoroutine(totalText, srcLang, targetLang, (success, trans, userDt) =>{if (success){ParseAndSaveTransResults(langTexts, targetLang, trans, userDt as int[]);}}, totalTextIdx.ToArray()));}}/// <summary>/// 解析翻译结果并保存到语言Excel/// </summary>/// <param name="targetTexts"></param>/// <param name="targetLang"></param>/// <param name="resultStr"></param>/// <param name="resultTextIdxArr"></param>private static void ParseAndSaveTransResults(List<LocalizationText> targetTexts, Language targetLang, TranslationResult trans, int[] resultTextIdxArr){if (string.IsNullOrWhiteSpace(trans.dst) || resultTextIdxArr == null) return;var srcTexts = trans.src.Split(TRANS_SPLIT_TAG);var resultTexts = trans.dst.Split(TRANS_SPLIT_TAG);if (resultTexts.Length != resultTextIdxArr.Length || resultTexts.Length != srcTexts.Length){Debug.LogError($"翻译失败, 翻译结果数量和索引数不一致.result count:{resultTexts.Length}, but index count:{resultTextIdxArr.Length}\n 翻译结果:{trans.dst}");return;}for (int i = 0; i < resultTextIdxArr.Length; i++){var idx = resultTextIdxArr[i];var srcStr = srcTexts[i];var dstStr = resultTexts[i].Trim();int leadingSpaces = srcStr.Length - srcStr.TrimStart().Length;int trailingSpaces = srcStr.Length - srcStr.TrimEnd().Length;dstStr = dstStr.PadLeft(dstStr.Length + leadingSpaces);dstStr = dstStr.PadRight(dstStr.Length + trailingSpaces);targetTexts[idx].Value = dstStr;}SaveLanguage(targetLang, targetTexts);}private static IEnumerator TranslateCoroutine(string srcText, Language srcLang, Language targetLang, Action<bool, TranslationResult, object> onComplete, object userData){var randomCode = System.DateTime.Now.Ticks.ToString();var strBuilder = new StringBuilder();strBuilder.Append(BAIDU_TRANS_URL);strBuilder.AppendFormat("q={0}", UnityWebRequest.EscapeURL(srcText));strBuilder.AppendFormat("&from={0}", GetBaiduLanguage(srcLang) ?? "auto"); //自动识别源文字语言strBuilder.AppendFormat("&to={0}", GetBaiduLanguage(targetLang));//翻译到目标语言strBuilder.AppendFormat("&appid={0}", EditorToolSettings.Instance.BaiduTransAppId);strBuilder.AppendFormat("&salt={0}", randomCode);strBuilder.AppendFormat("&sign={0}", GenerateBaiduSign(srcText, randomCode));//Debug.Log($"发送:{strBuilder}");// 发送请求using (var webRequest = UnityEngine.Networking.UnityWebRequest.Get(strBuilder.ToString())){webRequest.SetRequestHeader("Content-Type", "text/html;charset=UTF-8");webRequest.certificateHandler = new WebRequestCertNoValidate();webRequest.SendWebRequest();while (!webRequest.isDone) yield return null;if (webRequest.result != UnityEngine.Networking.UnityWebRequest.Result.Success){Debug.LogError($"---------翻译{targetLang}请求失败:{webRequest.error}---------");onComplete?.Invoke(false, null, userData);}else{var json = webRequest.downloadHandler.text;//Debug.Log($"接收:{json}");try{var responseJson = UtilityBuiltin.Json.ToObject<JObject>(json);if (responseJson.ContainsKey("trans_result")){var resultArray = responseJson["trans_result"].ToObject<TranslationResult[]>();if (resultArray != null && resultArray.Length > 0){var resultTrans = resultArray[0];onComplete?.Invoke(true, resultTrans, userData);}else{Debug.LogError($"---------翻译{targetLang}失败:{responseJson}---------");onComplete?.Invoke(false, null, userData);}}else{Debug.LogError($"---------翻译{targetLang}失败:{responseJson}---------");onComplete?.Invoke(false, null, userData);}}catch (System.Exception e){Debug.LogError($"---------翻译{targetLang}返回数据解析失败:{e.Message}---------");onComplete?.Invoke(false, null, userData);}}}}internal class TranslationResult{public string src;public string dst;}

工具完整代码参考:GitHub - sunsvip/GF_HybridCLR

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/8545.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Netflix 总用户达到 2.325 亿;马斯克打脸创建 X.AI 公司;印度首开苹果门店;谷歌老板对 AI 很担心?特斯拉营收增加,但净利润下降…《经济学人 | 第 17 期》

中国第一季度经济增长出于意料 China’s economy grew by 4.5% in the first quarter, year on year, beating the expectations of most economists. 中国第一季度经济同比增长4.5%&#xff0c;超出了大多数经济学家的预期。 特斯拉营收增加&#xff0c;但净利润下降 Tesla’…

学生用ChatGPT拿下全班最高分!教授惊呆!全美高校打响AI反击战...

点击下方卡片&#xff0c;关注“CVer”公众号 AI/CV重磅干货&#xff0c;第一时间送达 点击进入—>CV微信技术交流群 转载自&#xff1a;新智元 | 编辑&#xff1a;好困 Aeneas 【导读】ChatGPT爆火两个月&#xff0c;整个教育系统都被颠覆了。学生用得不亦乐乎&#xff0c…

基于ChatGPT实现电影推荐小程序!(原理、架构、设计、代码)

省时查报告-专业、及时、全面的行研报告库 省时查方案-专业、及时、全面的营销策划方案库 【免费下载】2023年4月份热门报告合集 无需翻墙&#xff0c;ChatGPT直接使用 万字干货&#xff1a;ChatGPT的工作原理 2023年创业&#xff08;有创业想法&#xff09;必读手册 ChatGPT等…

分享15个全球顶尖的AIGC图片生成平台

人工智能正在改变许多行业的格局&#xff0c;而其中改变最直观和影响最大的就是AIGC领域的图像创作。 发展至今已经有很多AI图像生成平台&#xff0c;他们的共同特点就是使用人工智能将文本转换为图像&#xff0c;这是一次革命性的突破&#xff0c;也就是说通过这些AI工具可以…

大bug!ChatGPT居然不懂最新的量子计算?

&#xff08;图片来源&#xff1a;网络&#xff09; 近期&#xff0c;背靠微软的AI语言模型ChatGPT风靡全网&#xff0c;以社交媒体为传播媒介&#xff0c;仅5天&#xff0c;注册用户数就超过100万&#xff0c;2个月破亿。随后谷歌眼红不已&#xff0c;匆忙召开自研AI搜索工具B…

IB考试如何达到45分满分?

2020年在IBO的最终考试当中&#xff0c;全球人仅有126个人的成绩达到了45分&#xff0c;占整体全体IB考生的1%&#xff0c;40分以上占全体IB课程考生的15%。满分45分是全球名校争抢的对象。当然拿到满分的学生一定是非常优秀的学生&#xff0c;平时在写作业&#xff0c;上课&am…

2022年第一试,快速通过ISACA的CISM考试

准备过程 2020年考过CISSP&#xff0c;2021年上半年考了CISA&#xff0c;2021年下半年考了高项。 2022年1月底通过ISACA的CISM考试&#xff0c;总体来说蛮顺利的。 由于有CISSP和CISA基础&#xff0c;就没有看CISM教材&#xff0c;主要还是刷题为主&#xff0c;有问题时查看一…

IB地理学什么?适合什么人学习?

IB精选&#xff1a;IB地理学什么&#xff1f;快速搞懂自己适不适合修读地理&#xff01; 核心目的 IB地理科是一个很特别的科目&#xff0c;目的是要帮助同学掌握一些认识和了解现实世界的技能。这个现实世界包括了两大部分。 第一个部分是自然环境&#xff0c;当中包括生态系…

银行测试的优势在哪里?

为什么做金融类软件测试举个栗子&#xff0c;银行里的软件测试工程师。横向跟互联网公司里的测试来说&#xff0c;薪资相对稳定&#xff0c;加班少甚至基本没有&#xff0c;业务稳定。实在是测试类岗位中的香饽饽&#xff01;一、什么是金融行业金融业是指经营金融商品的特殊行…

申请澳洲八大,IB成绩多高才有胜算?

鉴于IB文凭项目是全球通用的国际课程&#xff0c;因此几乎所有澳洲大学都可以接受IB文凭直接申请本科&#xff0c;包括澳洲八大。 首先我们要知道&#xff0c;澳洲八大究竟是哪八个顶级大学&#xff1f;澳洲的大学是按星级来分类的&#xff0c;五星级大学就是澳洲八大&#xf…

IB中文考试是什么?如何考?

近年来&#xff0c;IB课程的学员愈来愈遭受全球顶级高校的亲睐。特别是在美本申请办理中&#xff0c;由于IB因为学科难度系数较高&#xff0c;在藤校及英国TOP30录用中具有比较大优点。01.什么叫IB课程&#xff1f;IB的全名是International Baccalaureate&#xff0c;也就是国际…

IB大考期间上网讨论试题是作弊吗?

最近&#xff0c;IBO官方再次发文强调学术诚信&#xff08;Academic integrity&#xff09;的重要性。主页君也觉得有必要再次跟大家强调下在IBDP大考期间&#xff0c;考生需要遵守的学术诚信相关准则。学术诚信&#xff08;Academic integrity&#xff09;贯穿于IBDP课程学习、…

ChatGPT推出后,立场检测技术将如何发展?

&#xff08;ChatGPT推出后&#xff0c;立场检测技术将如何发展?&#xff09; 简介&#xff1a;这篇论文主要探讨了在ChatGPT推出之后&#xff0c;立场检测技术可能会有哪些发展。 首先&#xff0c;该论文对ChatGPT进行了介绍&#xff0c;ChatGPT是基于GPT-3.5接口构建的一个…

覃小龙34岁生日记:结合趋势,发挥优势,方能百战不殆

覃小龙34岁生日记:结合趋势&#xff0c;发挥优势&#xff0c;方能百战不殆&#xff01; 2023-2-20星期一 覃小龙 2023年2月17日&#xff0c;是我34岁生日&#xff0c;1989年出生的我&#xff0c;一晃眼&#xff0c;已经走过第34个年头了&#xff01; 从2016年创业到今天&#x…

OpenAI推出ChatGPT 官方APP对市场的影响

大家好&#xff0c;我是程序员炒家&#xff0c;励志成为程序员中炒股的一方游资。 情人节前一天晚上&#xff0c;我和相亲对象见面 身高160cm左右&#xff0c;留着大波浪的小姐姐 下半身穿着一身碎花长裙&#xff0c;上半身穿着浅色T恤&#xff0c;脚下穿着小白鞋 人看起来…

上海亚商投顾:ChatGPT概念领跌 两市约3800股下跌

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪 三大指数今日继续调整&#xff0c;创业板指午后一度跌超1%。ChatGPT、AIGC概念股集体走低&#xff0c;三六零跌超8…

上海亚商投顾:沪指震荡调整 酒店等消费股逆势活跃

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪 沪指今日震荡盘整&#xff0c;创业板指V型反弹&#xff0c;上证50跌超1%&#xff0c;保险、银行、券商等金融股下挫…

上海亚商投顾:三大指数均跌超1% 两市超4200股飘绿

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪 三大指数今日集体调整&#xff0c;沪指午后跌超1%&#xff0c;深成指、创业板指跌超1.5%&#xff0c;赛道股全线下…

十问旷视印奇、唐文斌:AI公司步入「深水区」,友商其实不是友商

郭一璞 李根 发自 凹非寺 量子位 报道 | 公众号 QbitAI AI明星公司旷视&#xff0c;刚庆祝了自己的9周岁生日。 以技术和理工天才云集著称的他们&#xff0c;把新的一岁用「指数之年」形容&#xff0c;以「向上生长」作为主题。 同时&#xff0c;一场规模盛大的智慧物流发布会在…

ChatGPT“爆红”启示:工业AI如何掀起新型“工业革命”?

数字智能时代&#xff0c;你还在加班写材料、熬夜敲代码&#xff1f;还在为海量的数据分析通宵达旦&#xff1f;如今&#xff0c;ChatGPT&#xff08;人工智能对话聊天机器人&#xff09;的诞生&#xff0c;让这些工作“一键生成”不是梦。随着Chat GPT“一夜爆红”&#xff0c…