OpenHarmony开发者论坛
标题:
[OpenHarmony学习计划] 亲戚称谓计算器 + LLM
[打印本页]
作者:
lishengzxc
时间:
2024-6-23 21:19
标题:
[OpenHarmony学习计划] 亲戚称谓计算器 + LLM
[md]![0030086000741113711.20240623203749.20672203875181820224293013290081.png](
https://forums-obs.openharmony.c ... r7qgrgdgradrfzp.png
"0030086000741113711.20240623203749.20672203875181820224293013290081.png")
# 概述
本项目是是学习 [
https://developer.huawei.com/con ... /101718800110527001
](
https://developer.huawei.com/con ... /101718800110527001
) 后的一份练习 demo
实现了以下特性:
* 自定义组件:[
https://developer.huawei.com/con ... rmonyos-guides-V5/3
\_3\_u81ea\_u5b9a\_u4e49\_u7ec4\_u4ef6-V5](
https://developer.huawei.com/con ... 4e49_u7ec4_u4ef6-V5
)
* 状态管理:[
https://developer.huawei.com/con ... state-management-V5
](
https://developer.huawei.com/con ... state-management-V5
)
* 应用架构设计基础——MVVM模式:[
https://developer.huawei.com/con ... rddetails/tutorials
\_Next-BasicArchitectureDesignPart1](
https://developer.huawei.com/con ... itectureDesignPart1
)
* 应用架构设计基础——三层架构:[
https://developer.huawei.com/con ... rddetails/tutorials
\_Next-BasicArchitectureDesignPart2](
https://developer.huawei.com/con ... itectureDesignPart2
)
* 网络请求:[
https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Faxios
](
https://ohpm.openharmony.cn/#/cn/detail/@ohos%2Faxios
)
接下来简要描述下开发流程,源码可以直接查看:[
https://gitee.com/lishengzxc/ohms-next-relationship
](
https://gitee.com/lishengzxc/ohms-next-relationship
)
# 开发流程
## 参考三层架构准备项目目录
![0030086000741113711.20240623204240.44787044389701801371695480030290.png](
https://forums-obs.openharmony.c ... igi3n7l9744aa2k.png
"0030086000741113711.20240623204240.44787044389701801371695480030290.png")
## 准备 UI
拆分 UI,实现计算显示部分组件 Display.ets 和 键盘部分 Ctrl.ets
### Display.ets
result 和 calcString 类似于 react 的 props 接受外部传入的值
```
@Component
export struct Display {
@Prop result: string = '';
@Prop calcString: string = '';
build() {
Column() {
Column() {
Text(this.result)
.fontSize(25)
.padding({ left: 16, right: 16 })
.width('100%')
.height('40%')
.textAlign(TextAlign.End)
}
Column() {
Text(this.calcString)
.fontSize(35)
.width('100%')
.height('60%')
.padding({ left: 16, right: 16 })
.textAlign(TextAlign.End)
.borderWidth({ bottom: 1 })
.borderColor('#ccc')
}
}.width('100%').height('25%')
}
}
```
### Ctrl.ets
使用 Grid 组件布局:[
https://developer.huawei.com/con ... ment-create-grid-V5
](
https://developer.huawei.com/con ... ment-create-grid-V5
)
需要注意 = 按钮需要占用 2 行;
按钮点击的时候执行父组件传入的方法,用来接受用户点了什么按钮
```
@Component
export struct Ctrl {
@Prop loading: boolean = false;
btns: string[][] = [
['Item', '父', '父亲'],
['Item', '母', '母亲'],
['Function', '回退', 'back', 'gray'],
['Function', '清空', 'clear', 'black'],
['Item', '兄', '哥哥'],
['Item', '姐', '姐姐'],
['Item', '夫', '老公'],
['Item', '妻', '老婆'],
['Item', '弟', '弟弟'],
['Item', '妹', '妹妹'],
['Function', '互换', 'change', 'blue'],
['Function', '=', '=', 'red'],
['Item', '子', '儿子'],
['Item', '女', '女儿'],
['Function', '?', '?']
];
onBtnClick?: (data: string[]) => void
layoutOptions: GridLayoutOptions = {
regularSize: [1, 1],
onGetRectByIndex: (index: number) => {
if (index === 11) {
// 控制 = 按钮占有 2 行
return [2, 3, 2, 1]
}
return [index / 4 - 1, index / 4 - 1, 1, 1];
}
}
build() {
Grid(undefined, this.layoutOptions) {
ForEach(this.btns, (data: string[]) => {
GridItem() {
if (data[1] === '=') {
Button(data[1])
.type(ButtonType.Normal)
.onClick(() => {
if (this.loading) return;
this.onBtnClick?.(data)
})
.width('100%')
.height('100%')
.borderRadius(20)
.opacity(this.loading ? 0.3 : 1)
.backgroundColor(data[3])
} else {
Button(data[1])
.type(ButtonType.Normal)
.onClick(() => {
if (this.loading) return;
this.onBtnClick?.(data)
})
.width('100%')
.height('100%')
.borderRadius(20)
.backgroundColor(data[3])
}
}
}, (data: string) => data[2])
}
.columnsGap(10)
.rowsGap(10)
.rowsTemplate('1fr 1fr 1fr 1fr')
.padding(10)
.columnsTemplate('1fr 1fr 1fr 1fr')
.width('100%')
.height('75%')
}
}
```
### 组合他们
<pre><br class="Apple-interchange-newline"/></pre>
```
import { Display } from '../view/Display';
import { Ctrl } from '../view/Ctrl';
import { llm } from '@ohos/commons';
@Preview
@Component
export struct Calculator {
@State result: string = '';
@State calc: string[] = [];
@State loading: boolean = false;
onBtnClick: (data: string[]) => string | void = (data: string[]) => {
const type = data[0];
const value = data[2];
if (type === 'Function') {
if (value === 'back') {
this.calc.pop();
}
if (value === '=') {
this.onCalc();
}
if (value === 'clear') {
this.calc = [];
this.result = '';
}
}
if (type === 'Item') {
this.calc.push(value);
}
}
onCalc() {
if (!this.calc.length) return;
if (this.calc.length === 1) {
this.result = this.calc[0]
}
this.askLLM();
}
askLLM() {
this.loading = true;
llm({
system: '你是一个亲戚称谓计算器,请根据我的提问回复我 应该称呼对方为什么,比如爸爸的爸爸,请回复我 {\"data\":\"爷爷\"}',
query: this.calc.join('的'),
appKey: 'sk-xxx', // 请使用真实的大模型 appkey
}).then((res) => {
console.log('llm', res);
this.calc = [JSON.parse(res as string).data]
this.result = this.calc[0];
this.loading = false;
})
}
build() {
Column() {
Display({ result: this.result, calcString: this.calc.join('的') })
Ctrl({ onBtnClick: this.onBtnClick, loading: this.loading })
}.width('100%').height('100%')
}
}
```
## 如何计算
> 我没有使用以下常见的本地称谓树的方式来表达称谓的数据结构
>
> ```
> {
> "爸爸": {
> "爸爸": "爷爷",
> "妈妈": "奶奶",
> "哥哥": "伯父",
> "弟弟": "叔叔",
> "姐姐": "姑妈",
> "妹妹": "姑妈",
> "丈夫": "未知",
> "妻子": "妈妈",
> "儿子": { "older": "哥哥", "middle": "我", "younger": "弟弟" },
> "女儿": { "older": "姐姐", "middle": "我", "younger": "妹妹" }
> }
> }
> ```
>
> 而是为了实践网络请求的场景,直接问大模型拿到结果
### 准备大模型账号
我使用的是通义千问,这个不特别展开如何申请账号,可以自己搜索阿里云-百炼自己摸索下
## 封装请求方法
```
import axios, { AxiosError, AxiosResponse } from '@ohos/axios'
interface iParams {
system: string,
query: string,
appKey: string,
}
interface iMsg {
role: string,
content: string
}
interface iInput {
messages: iMsg[]
}
interface iData {
model: string,
input: iInput
}
interface iOutput {
finish_reason: string,
text: string
}
interface iRes {
output: iOutput
}
export default (params: iParams) => {
return axios.post<string, AxiosResponse<iRes>, iData>('https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation', {
"model": "qwen-max",
"input": {
"messages": [
{
"role": "system",
"content": params.system
},
{
"role": "user",
"content": params.query
}
]
},
}, {
headers: {
'Authorization': `Bearer ${params.appKey}`,
'Content-Type': 'application/json'
}
})
.then((response: AxiosResponse<iRes>) => {
console.info('axios success', JSON.stringify(response));
return response.data.output.text;
})
.catch((error: AxiosError) => {
console.info('axios error', JSON.stringify(error));
});
}
```
## 请求大模型
```
llm({
system: '你是一个亲戚称谓计算器,请根据我的提问回复我 应该称呼对方为什么,比如爸爸的爸爸,请回复我 {\"data\":\"爷爷\"}',
query: this.calc.join('的'),
appKey: 'sk-xxx'
})
```
# 构建运行
![0030086000741113711.20240623210338.41016412977744940621048475927143.gif](
https://forums-obs.openharmony.c ... mh1hwzzamgxv0p2.gif
"0030086000741113711.20240623210338.41016412977744940621048475927143.gif")
[/md]
欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/)
Powered by Discuz! X3.5